十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从操作系统视角理解AI Agent:进程、系统调用与内存管理的核心映射

从操作系统视角理解AI Agent:进程、系统调用与内存管理的核心映射 1. 引言当AI Agent遇见操作系统最近和几个做AI应用开发的朋友聊天发现一个挺有意思的现象大家讨论AI Agent时经常不自觉地借用操作系统的概念。比如会说某个Agent“卡住了”需要“重启一下”或者说多个Agent之间“通信不畅”又或者抱怨大模型的“上下文窗口”太小导致“信息处理不过来”。这些说法听起来很自然但仔细一想它们背后其实都对应着操作系统里那些经典的概念进程状态、进程间通信IPC、内存管理。这让我意识到对于很多开发者尤其是从应用层转向AI系统设计的开发者来说用操作系统的视角来理解AI Agent可能是一条非常高效的路径。我们不必一开始就陷入复杂的强化学习、思维链CoT或是各种Agent框架的细节里。相反我们可以先问自己一个更基础的问题如果把一个AI Agent看作一个在“计算环境”中运行的“程序”那么操作系统是如何管理、调度和支撑这个“程序”的呢这个类比之所以强大是因为操作系统经过几十年的发展已经形成了一套极其成熟和抽象的模型用于管理并发、资源、错误和通信。而当前AI Agent系统面临的许多挑战——如长程任务规划、工具调用稳定性、多Agent协作、状态持久化——恰恰是操作系统早已深入研究并提供了解决方案的问题域。因此这篇文章我想和你一起从一个软件工程师熟悉的领域——操作系统——出发来重新审视AI Agent。我们会重点探讨三个核心映射关系AI Agent与进程、工具调用与系统调用、以及大模型上下文与内存/上下文窗口。通过这种“降维理解”我们不仅能更清晰地把握AI Agent的工作机制还能直接从操作系统的设计智慧中汲取灵感来构建更鲁棒、更高效的Agent系统。无论你是刚开始接触AI Agent还是已经在实践中遇到了瓶颈希望这个视角能给你带来一些新的启发。2. AI Agent一个特殊的“用户进程”在操作系统中进程Process是资源分配和独立运行的基本单位。每个进程都有自己独立的地址空间、一套寄存器状态、打开的文件描述符以及各种系统资源。当我们双击一个.exe文件时操作系统就会为其创建一个进程实体。那么一个AI Agent是什么我们可以将其视为一个在“AI运行时环境”中创建的、具有特定目标的智能进程。这个类比并非牵强附会让我们从几个关键特性来拆解。2.1 进程的五大状态与Agent的生命周期一个经典的操作系统进程其生命周期通常被描述为五种状态新建New、就绪Ready、运行Running、阻塞Waiting、终止Terminated。一个AI Agent的“一生”也惊人地遵循着类似的轨迹。新建New当你通过代码初始化一个Agent为其设定名称如claude.exe、角色指令System Prompt和可用工具列表时就相当于操作系统在“创建进程控制块PCB”。此时Agent拥有了自己的“身份”和“初始内存映像”即初始提示词但尚未开始执行任何推理任务。就绪ReadyAgent初始化完成等待被“调度”。在Web服务中这可能意味着Agent实例已加载到内存在等待一个HTTP请求用户提问的到来。这个请求就是它的“CPU时间片”开始的信号。许多开发者遇到的“Agent启动慢”问题往往就发生在这个阶段比如大模型加载耗时、向量数据库连接未就绪等。运行RunningAgent接收到输入用户查询或上一个Agent的输出开始其核心的“思考-行动”循环。这对应着进程占用CPU执行指令。在此状态下Agent会解析输入规划步骤并可能决定调用工具发起系统调用或直接生成回复。阻塞Waiting这是Agent与普通程序最相似也最容易出问题的地方。当Agent决定调用一个外部工具如执行一个数据库查询、调用一个天气API时它不能干等着结果。在同步调用模型下它就像进程发起了一个阻塞式的I/O操作如read一个网络socket必须挂起自己释放出“思考资源”即大模型的推理能力等待外部工具返回结果。此时Agent处于“阻塞”状态。很多Agent框架的异步设计就是为了优化这个阶段避免宝贵的模型算力被闲置。终止Terminated任务完成成功或失败或达到预设的步骤/时间限制后Agent结束运行。在无状态的Web服务中这次会话的Agent实例可能会被销毁在长时运行的Agent系统中其最终状态成功、失败、以及过程中的关键信息会被持久化到日志或数据库中就像进程退出后留下退出码和日志文件一样。注意这里有一个关键区别。传统进程的“运行”状态是独占CPU的。而AI Agent的“运行”本质上是向大模型服务发起一个网络请求并等待其流式返回。因此一个Agent系统可以同时有多个Agent处于“运行”状态即多个并发的模型推理请求这更像操作系统的多线程模型。我们可以把一个Agent看作一个“线程”而承载这些Agent的服务器或运行时环境才是真正的“进程”。2.2 进程控制块PCB与Agent的“记忆体”操作系统为每个进程维护一个数据结构——进程控制块PCB用来保存进程的一切信息进程ID、状态、优先级、程序计数器、内存指针、上下文数据等。那么AI Agent的“PCB”是什么我认为它由两部分构成静态配置Static Configuration这相当于进程的“可执行文件”。它包括角色指令System Prompt定义了Agent的“人格”和能力边界就像程序代码。工具列表Tools/Functions定义了Agent可以发起的“系统调用”接口。模型参数使用哪个大模型GPT-4, Claude, GLM等以及温度Temperature、Top-p等推理参数。这类似于为进程指定了运行它的“CPU架构和指令集”。动态上下文Dynamic Context这相当于进程的“运行时堆栈和内存数据”。它是Agent在单次会话或任务中积累的状态主要包括对话历史Message History用户与Agent之间的多轮问答。这是最重要的上下文。中间步骤Intermediate StepsAgent在思考过程中产生的链式思维CoT、工具调用记录及结果。这对于任务恢复和调试至关重要。会话元数据如会话ID、创建时间、当前步骤索引等。这个“动态上下文”就是Agent的“工作内存”它直接受限于大模型的上下文窗口Context Window。就像进程的地址空间有大小限制一样Agent能“记住”和“处理”的信息总量是有限的。当上下文超出窗口限制时就需要进行“内存交换”——即通过摘要、选择性遗忘或向量检索等策略将最重要的信息保留在窗口内将较旧或次要的信息移出。这个过程我们会在第4节详细讨论。2.3 进程的独立性与Agent的隔离性操作系统保证进程间的隔离性一个进程的崩溃通常不会直接影响另一个进程。在AI Agent系统中我们也需要类似的隔离。错误隔离一个处理文件上传的Agent如果因为解析畸形文件而“崩溃”抛出异常不应该导致处理聊天对话的另一个Agent服务不可用。这就要求Agent运行时具有良好的异常捕获和恢复机制或者采用微服务架构让不同的Agent运行在独立的容器或进程中。资源隔离多个Agent可能共享同一个大模型API密钥和额度。如果没有隔离和配额管理一个陷入死循环疯狂调用模型的Agent可能会耗尽所有资源导致其他Agent“饿死”。这就像操作系统需要防止某个进程独占CPU或内存。安全隔离当Agent可以执行代码如Python REPL工具或操作文件系统时必须施加严格的沙箱Sandbox限制防止恶意或错误的操作危害主机系统。这对应着操作系统通过系统调用接口和权限位如chroot,seccomp来限制进程对底层资源的访问。理解了Agent作为一个“进程”的基本模型后我们接下来看它如何与外界交互这就引出了操作系统另一个核心概念——系统调用。3. 工具调用Agent的“系统调用”接口在操作系统中用户进程运行在“用户态”它不能直接操作硬件或执行特权指令。当它需要读写文件、申请内存、创建网络连接时必须通过一种受控的接口向操作系统内核发起请求这个接口就是系统调用System Call。对于AI Agent而言它运行在由大模型构成的“用户态”中其核心能力是理解和生成自然语言。但它要完成实际任务几乎必然需要与外部世界交互查询数据库、发送邮件、控制智能设备、执行代码。这些对外部资源的访问就是通过工具调用Tool Calling / Function Calling来实现的。我们可以将工具调用精准地类比为Agent的“系统调用”。3.1 系统调用的机制与工具调用的实现一次典型的系统调用如open(“file.txt”, O_RDONLY)过程如下准备参数进程将系统调用号如SYS_open和参数文件名、标志放入指定的寄存器或栈中。陷入内核进程执行一条特殊的指令如int 0x80或syscall引发一个软中断CPU从用户态切换到内核态。内核处理操作系统内核根据调用号找到对应的处理函数验证参数合法性执行实际操作如查找文件、分配文件描述符。返回结果内核将结果成功返回文件描述符失败返回错误码放入指定位置并切换回用户态。进程继续进程检查返回值决定后续流程。工具调用的流程与此高度同构准备参数模型推理大模型根据当前对话上下文和可用工具的描述类似于系统调用的API文档生成一个结构化的调用请求。例如{“name”: “get_weather”, “arguments”: {“city”: “北京”}}。这对应着进程准备系统调用参数。陷入“运行时”框架分发Agent框架如LangChain, LlamaIndex, Semantic Kernel接收到模型的工具调用请求。这个框架扮演了“内核”或“运行时”的角色。它验证工具名称和参数格式是否合法。“内核”处理执行工具框架找到注册的get_weather函数并以安全的方式执行它可能是在沙箱中可能是调用一个远程API。这对应内核执行实际的文件操作或网络操作。返回结果工具执行完毕将结果如{“city”: “北京”, “temperature”: “22°C”}或错误信息返回给框架。Agent继续框架将工具执行结果作为新的上下文信息再次喂给大模型。模型结合这个结果生成下一步的回复或决策。这对应进程根据系统调用返回值决定后续代码路径。3.2 工具调用的“错误处理”与“权限控制”系统调用有完善的错误处理机制通过返回-1和设置errno。工具调用也必须如此。工具执行失败比如调用数据库查询工具时连接超时。框架不应该让整个Agent崩溃而应该将格式化的错误信息如“Database connection timeout after 5s”返回给模型。一个设计良好的Agent其提示词System Prompt应该教导它如何处理这类错误例如重试、尝试替代方案或向用户请求帮助。这就好比一个健壮的程序需要处理open()文件可能失败的情况。参数验证失败模型可能生成不合法的参数比如要求send_email工具发送邮件但recipient字段不是一个有效的邮箱格式。框架在执行前应进行参数校验并返回清晰的错误。这对应内核检查文件路径是否合法。权限控制则更为关键。操作系统通过用户ID、组ID和文件权限位来控制进程能访问哪些资源。在Agent系统中我们需要类似的“权限模型”工具白名单不是所有注册的工具都对每个Agent开放。一个处理内部数据的Agent可能有权调用数据库查询工具但绝不应该有调用“服务器关机”工具的权限。这需要在框架层面实现基于Agent身份的工具路由和鉴权。资源访问范围即使调用同一个工具不同Agent的访问范围也应不同。例如HR Agent可以查询员工基本信息但财务Agent则不能。这需要在工具实现内部进行额外的授权检查。3.3 同步 vs 异步阻塞与并发的抉择这是工具调用设计中的一个核心权衡点直接对应着操作系统I/O模型的同步与异步。同步阻塞式调用Agent发起工具调用后便停止“思考”等待结果返回。这是最简单直观的模式但效率低下。如果调用一个需要5秒的API那么承载该Agent的线程或协程就会被阻塞5秒无法处理其他请求。这就像在一个单线程程序里进行同步的网络请求。异步非阻塞式调用Agent发起调用后立即“让出”控制权。框架记录这个调用及其回调然后可以去处理其他Agent的请求。当工具执行完成后再通过事件驱动或回调函数的方式唤醒原来的Agent继续执行。这极大地提高了系统的并发吞吐量。现代的Agent框架如LangGraph的StateGraph普遍支持这种异步工作流。选择哪种模式取决于你的应用场景。对于简单的、线性的、交互式的对话Agent同步模式足够简单可靠。对于复杂的、需要并行调用多个工具或长时间运行的任务型Agent异步模式是必须的。理解了Agent如何通过“系统调用”与外界交互后我们还需要关注它的“内部状态”是如何被管理的这就涉及到另一个至关重要的限制——上下文窗口。4. 上下文窗口Agent的“物理内存”与“交换策略”在计算机中进程的地址空间是有限的它由物理内存RAM支撑。当物理内存不足时操作系统会将暂时不用的内存页“交换Swap”到磁盘上需要时再换入。这个过程对进程是透明的但会带来性能损耗。对于AI Agent而言大模型的上下文窗口Context Window就是它的“物理内存”。这是一个硬性限制决定了单次推理时模型能够“看到”的文本 tokens 总数例如GPT-4 Turbo是128KClaude 3 Opus是200K。所有我们提供给模型的提示词系统指令、对话历史、工具描述、工具结果、用户当前问题都必须装进这个窗口。4.1 上下文窗口的“内存布局”我们可以把上下文窗口想象成一段线性的、昂贵的“内存”。它的布局大致如下[系统指令固定] [工具定义可选固定/动态] [对话历史动态增长] [当前查询动态]系统指令相当于操作系统的“内核代码”或进程的“静态代码段”它定义了Agent的基本行为准则通常固定不变占用窗口开头的一部分。工具定义描述Agent可调用工具的JSON Schema或自然语言说明。如果工具很多这部分会非常庞大。一种优化策略是“动态链接”只在模型可能需要调用某个工具时才将其描述插入上下文而不是一次性加载所有工具描述。对话历史这是占用空间最大且增长最快的部分相当于进程的“堆Heap”和“栈Stack”存储了运行时数据。当前查询用户的最新问题或触发Agent思考的指令。随着对话轮数增加“对话历史”部分会不断膨胀最终可能挤占其他部分的空间甚至直接超出窗口限制导致模型无法处理报错或丢失早期记忆。4.2 应对窗口限制的“内存管理”策略当上下文接近或超过窗口限制时我们必须进行“内存管理”。以下是几种常见的策略它们与操作系统的内存管理算法有着有趣的对应关系滑动窗口Sliding Window这是最简单粗暴的方式只保留最近N轮对话例如最近10轮。这就像操作系统简单的“先进先出FIFO”页面置换算法把最老的对话“置换”出去。优点是实现简单缺点是会永久丢失早期的关键信息可能导致Agent忘记最初的任务目标。摘要压缩Summarization当历史对话达到一定长度时调用模型自身对之前的对话内容进行摘要然后用一段简短的摘要文本来替代大段的原始历史。这相当于把不常用的内存数据“压缩”后存放。例如将前20轮关于旅行规划的讨论总结成“用户计划在五月去日本东京和大阪预算中等偏好文化和美食”。后续对话都基于这个摘要进行。这种方法能保留核心信息但摘要过程本身有信息损耗和成本需要额外调用一次模型。向量检索Vector Retrieval / RAG这是目前最主流和强大的策略。它将整个对话历史甚至包括外部知识库拆分成片段转换成向量存入向量数据库。当需要回忆信息时根据当前对话的语义从向量数据库中检索出最相关的几个片段动态地插入到上下文窗口中。这完美对应了操作系统的虚拟内存和按需调页Demand Paging机制向量数据库相当于“磁盘”存储着全部的历史记忆。当前上下文窗口相当于“物理内存”。检索过程相当于“缺页中断”当模型需要某段记忆某个“页面”时系统根据“访问模式”当前语义去“磁盘”向量库中查找并加载最相关的片段到“内存”上下文中。这种方法实现了“大内存”的假象让Agent能够在有限的上下文窗口内访问近乎无限的历史和知识。结构化状态Structured State对于任务型Agent我们不必把所有原始对话都塞进上下文。可以设计一个结构化的状态对象例如一个JSON来记录任务的关键进展、已收集的信息、下一步计划等。每次推理时只将这个结构化的状态和当前指令喂给模型。这就像进程不直接操作大量原始数据而是维护一个精炼的、结构化的内存数据结构。LangGraph的State概念就是这一思想的体现。4.3 策略选择与混合使用在实际项目中这些策略往往是混合使用的对于超长文档处理向量检索RAG是基石。在多轮对话中可以结合滑动窗口保留最近几轮原始对话以保证连贯性和摘要压缩对更早的对话进行摘要。对于复杂工作流结构化状态是管理进度的最佳方式。关键在于你需要像系统架构师设计内存管理子系统一样去设计Agent的上下文管理策略。评估标准包括信息保留的完整性、检索/压缩的延迟、额外成本模型调用、向量数据库开销以及对最终任务成功率的影响。5. 从操作系统视角看多Agent协作与调度单个Agent已经可以类比为一个进程。那么当我们需要多个Agent协作完成一个复杂任务时例如一个“规划Agent”分解任务一个“研究Agent”搜集信息一个“写作Agent”生成报告我们就进入了多进程/分布式系统的领域。操作系统中关于进程间通信IPC和进程调度的理论在这里同样极具指导意义。5.1 Agent间通信AIC超越简单的消息传递操作系统提供了多种IPC机制管道、消息队列、共享内存、信号量、套接字等。在多Agent系统中Agent间的通信AIC也需要类似的抽象。直接消息传递管道/消息队列最简单的形式。Agent A直接将输出作为Agent B的输入。这适合线性的、主从式的工作流。但就像无名管道只能用于父子进程之间这种紧耦合的方式缺乏灵活性。黑板模型Blackboard / 共享状态Shared State这类似于共享内存。所有Agent都可以读写一个公共的、结构化的状态空间例如一个全局的JSON对象或数据库中的一张表。规划Agent将任务列表写入“任务队列”执行Agent从中领取任务并将结果写回。这提供了强大的协作能力但引入了并发控制的难题如何防止两个Agent同时修改同一个字段导致数据损坏这就需要引入“锁”或“事务”的概念。在一些高级框架中状态管理是核心关切。发布-订阅Pub-SubAgent可以向特定“频道”发布消息而关心该事件的Agent会订阅并接收。这类似于消息队列或事件总线实现了Agent间的解耦。例如一个“任务完成”事件被发布后监控Agent和日志Agent可以同时做出反应。设计AIC机制时必须考虑通信的可靠性消息会不会丢、顺序性消息是否按发送顺序到达、以及语义清晰度传递的是纯文本还是结构化的数据。5.2 Agent调度谁在“运行”何时运行在操作系统中进程调度器决定哪个就绪进程获得CPU时间片。在多Agent系统中当有多个Agent任务等待执行时例如一个Web服务器同时接收了多个用户的复杂请求我们也需要一个“调度器”。这个调度器需要做出几个关键决策调度单位我们是调度一个个独立的“Agent任务”还是调度更细粒度的“推理步骤”或“工具调用步骤”调度策略先来先服务FCFS简单但可能导致短任务被长任务阻塞。优先级调度为来自VIP用户或高价值业务的Agent任务赋予更高优先级。这需要定义清晰的优先级体系。基于资源的调度考虑每个Agent任务对稀缺资源如大模型API的速率限制、GPU内存的预估消耗。防止资源饥饿。并发控制如何管理对共享工具或资源的并发访问例如两个Agent不能同时写入同一个文件。这需要引入锁机制或串行化访问队列。在实际的Agent平台中这个“调度器”可能由消息队列如RabbitMQ, Kafka的工作队列模式、或专门的工作流引擎如Airflow, Prefect来担任。它们负责排队、分发和重试任务。5.3 容错与持久化当Agent“崩溃”时进程可能崩溃Agent亦然。它可能因为模型生成错误格式导致解析失败、工具调用超时、或遇到未处理的异常而中途退出。一个健壮的Agent系统必须具备容错和持久化能力。检查点Checkpointing这是从操作系统和数据库领域借鉴的经典容错技术。在Agent执行的关键步骤例如完成一个子任务、成功调用一个重要工具后将其完整状态包括对话历史、中间结果、下一步计划持久化到数据库或文件中。当Agent因任何原因中断后可以从最近的一个检查点恢复执行而不是从头开始。这就像游戏中的存档点。重试与回退Retry Rollback对于可重入的工具调用如查询API在失败时进行指数退避重试。对于不可重入或具有副作用的操作如发送邮件、支付则需要更谨慎的回退机制或者确保操作的幂等性。看门狗Watchdog设置超时监控。如果一个Agent任务在预期时间内没有进展例如超过5分钟没有产生新的有效步骤看门狗进程可以将其终止、记录错误日志并可能触发告警或重启流程。将多Agent系统视为一个分布式操作系统用这些成熟的系统设计思想来武装它是构建可靠、可扩展的AI应用的关键。6. 实战设计一个具备操作系统特质的简单Agent系统理论聊了很多现在我们动手设计一个简单的任务型Agent系统并刻意融入我们讨论过的操作系统概念。假设我们的目标是构建一个“智能文档分析员”Agent它能根据用户问题从一组上传的文档中查找信息并生成总结报告。6.1 系统架构设计我们不使用复杂的框架而是用Python和一些基础库来勾勒核心思想。进程模型与Agent实例化class DocumentAnalysisAgent: 一个Agent‘进程’的类定义 def __init__(self, agent_id, system_prompt, model_client, tools): self.agent_id agent_id # 进程PID self.state NEW # 进程状态 NEW, READY, RUNNING, BLOCKED, TERMINATED self.context [] # 动态上下文消息历史 self.system_prompt system_prompt # 静态配置代码段 self.available_tools tools # 系统调用接口表 self.model_client model_client # “CPU” - 大模型服务 self.checkpoint_file f./checkpoints/{agent_id}.json # 用于持久化 def load_checkpoint(self): 从检查点恢复状态 if os.path.exists(self.checkpoint_file): with open(self.checkpoint_file, r) as f: saved_state json.load(f) self.context saved_state[context] print(f[Agent {self.agent_id}] 状态已从检查点恢复。) else: self.context [{role: system, content: self.system_prompt}] def save_checkpoint(self): 保存当前状态到检查点 checkpoint_data { agent_id: self.agent_id, context: self.context } os.makedirs(os.path.dirname(self.checkpoint_file), exist_okTrue) with open(self.checkpoint_file, w) as f: json.dump(checkpoint_data, f) print(f[Agent {self.agent_id}] 检查点已保存。)工具调用系统调用的实现# 工具注册表相当于系统调用表 tool_registry {} def register_tool(name, func, description): 向系统注册一个工具系统调用 tool_registry[name] { function: func, description: description } # 定义几个工具 def search_in_documents(query): 模拟文档搜索工具 # 这里应该是真实的向量检索或全文搜索逻辑 time.sleep(0.5) # 模拟I/O延迟 return f根据查询‘{query}’在文档中找到了相关段落...模拟结果 def summarize_text(text): 模拟文本摘要工具 # 这里可以调用大模型的摘要能力 return f摘要结果{text[:50]}... # 模拟摘要 register_tool(search_docs, search_in_documents, 在已上传的文档集合中搜索相关信息。) register_tool(summarize, summarize_text, 对给定的文本进行摘要。) class AgentRuntime: Agent运行时环境扮演‘内核’角色 staticmethod def execute_tool_call(tool_call, agent_id): 执行一个工具调用包含权限检查和错误处理 tool_name tool_call.get(name) if tool_name not in tool_registry: return {error: f工具 {tool_name} 未注册或无权访问。} # 这里可以添加基于agent_id的权限检查 # if not has_permission(agent_id, tool_name): # return {error: 权限拒绝} try: tool_func tool_registry[tool_name][function] # 参数验证可以更复杂这里简单传递 result tool_func(**tool_call.get(arguments, {})) return {result: result} except Exception as e: # 将异常转化为Agent可理解的错误信息 return {error: f工具执行失败: {str(e)}}上下文管理虚拟内存/交换策略class ContextManager: 管理Agent的上下文窗口 def __init__(self, max_tokens8000): self.max_tokens max_tokens self.vector_db None # 这里可以接入Chroma, Pinecone等 def add_to_context(self, agent_context, new_message): 向上下文中添加新消息并实施管理策略 agent_context.append(new_message) estimated_tokens self._estimate_tokens(agent_context) if estimated_tokens self.max_tokens * 0.9: # 达到窗口90%时触发管理 print([ContextManager] 上下文窗口接近上限执行优化...) # 策略1: 滑动窗口保留最近10条消息 if len(agent_context) 10: # 保留系统提示和最新的9条对话 system_msg agent_context[0] recent_msgs agent_context[-9:] agent_context [system_msg] recent_msgs # 策略2: 如果还是太长对最老的用户-Assistant交互进行摘要 # 这里省略具体的摘要调用逻辑 # new_summary call_model_for_summary(old_messages) # 用摘要替换掉那部分历史 return agent_context def _estimate_tokens(self, messages): 简单估算token数生产环境应使用tiktoken等库 total_text .join([msg.get(content, ) for msg in messages]) # 粗略估算英文约1 token ~ 4字符中文约1~2字符 return len(total_text) // 36.2 运行循环与状态切换让我们把上面这些组件组合起来看一个简化的Agent主循环def agent_main_loop(agent, user_query): Agent‘进程’的主执行循环 agent.state RUNNING # 1. 将用户查询加入上下文 agent.context context_manager.add_to_context(agent.context, {role: user, content: user_query}) # 2. 调用模型进行推理 try: response agent.model_client.chat_completion(agent.context) except Exception as e: agent.state TERMINATED print(f模型调用失败: {e}) return # 3. 解析响应检查是否包含工具调用 if response.get(tool_calls): agent.state BLOCKED # 进入阻塞状态等待I/O print(f[Agent {agent.agent_id}] 准备执行工具调用...) for tool_call in response[tool_calls]: # 4. 陷入“内核”运行时执行工具 tool_result AgentRuntime.execute_tool_call(tool_call, agent.agent_id) # 5. 将工具结果作为新消息加入上下文 agent.context.append({ role: tool, content: json.dumps(tool_result), tool_call_id: tool_call.get(id) }) agent.state READY # 工具执行完毕回到就绪态等待下次调度 # 保存检查点因为这是一个关键步骤之后 agent.save_checkpoint() # 注意这里没有直接继续循环而是等待外部调度器再次触发 # 在实际异步框架中这里会通过回调或事件来触发后续推理 else: # 没有工具调用直接生成最终回复 final_answer response[choices][0][message][content] agent.context.append({role: assistant, content: final_answer}) print(f[Agent {agent.agent_id}] 任务完成回复: {final_answer[:50]}...) agent.state TERMINATED这个简化的例子展示了Agent作为“进程”的状态流转RUNNING - BLOCKED - READY通过“系统调用”工具调用与外界交互并由“内核”运行时管理其执行和资源。上下文管理器则在后台默默地执行着“内存交换”策略。6.3 从简单到复杂引入调度器与通信要让它成为一个真正的多Agent系统我们还需要在最外层添加一个调度器Scheduler和一个用于Agent间通信的机制例如一个简单的内存消息队列。import threading import queue import uuid class AgentScheduler: 一个简单的FIFO Agent调度器 def __init__(self, max_workers5): self.task_queue queue.Queue() # 就绪队列 self.worker_pool [] # 模拟的“CPU核心”线程池 self.lock threading.Lock() def submit_task(self, agent, initial_query): 提交一个Agent任务 task_id uuid.uuid4() self.task_queue.put((task_id, agent, initial_query)) print(f[Scheduler] 任务 {task_id} 已提交。) def worker_loop(self): 工作线程的主循环从队列中取任务执行 while True: task_id, agent, query self.task_queue.get() print(f[Worker] 开始执行任务 {task_id}, Agent状态: {agent.state}) if agent.state in [NEW, READY]: agent_main_loop(agent, query) # 执行一轮 # 如果Agent未终止且还有后续步骤例如工具调用后重新放入队列 if agent.state READY: # 这里需要一种机制获取下一步的输入可能是来自其他Agent的消息 # 我们简化处理假设它自动继续处理工具结果 next_input [系统] 请基于工具结果继续分析。 self.task_queue.put((task_id, agent, next_input)) self.task_queue.task_done() def start(self, num_workers3): 启动调度器 for i in range(num_workers): worker threading.Thread(targetself.worker_loop, daemonTrue) worker.start() self.worker_pool.append(worker)这个调度器非常原始但它演示了核心概念一个共享的任务队列就绪队列多个工作线程CPU核心从中获取任务Agent并执行。Agent在执行工具调用阻塞I/O后状态变为READY并重新入队等待下次被调度以处理工具结果。这就实现了一个简单的并发执行环境。通过这个从零开始的设计过程我们可以深刻体会到构建一个Agent系统本质上就是在设计一个专用的、智能化的“操作系统”或“运行时”。你需要考虑进程管理、系统调用、内存管理、进程间通信和调度。现有的高级框架如LangChain, LangGraph, AutoGen之所以复杂正是因为它们在底层封装了这些通用问题的稳健解决方案。理解这些底层概念能帮助你在使用这些框架时做出更明智的架构选择并在它们不满足需求时知道如何定制或扩展。
返回列表