AI 基建
0%
第六部分 · 编排 · 第 38 章

智能体架构

作者Changkun Ou
阅读时长约 13 分钟

如果每一步和每个分支都能在执行前写明,固定工作流就足够了。当下一项操作取决于尚未出现的信息时,智能体才真正有用,例如测试结果、搜索结果、用户决定或已经变化的环境。智能体架构就是那个封闭的决策循环:它把观测转化为下一个有边界的动作。

这个循环不只是一个模型加一份工具清单。它还需要控制器、整理后的上下文、动作接口、环境、状态转移和终止规则。工具调用只是动作接口的一种,可执行代码、图形界面操作、消息和环境原生命令也可以是动作接口。规划和记忆是循环中的设计选择,并不是每个智能体都必须具备的一组固定组件。

2023 年的两个重要系统分别展示了这片设计空间的一部分。ReAct 把显式的语言推理与特定任务的动作交错起来,让后续决定能够利用新观测 (Yao et al. 2023)。Toolformer 则生成、执行并筛选面向五个固定 API 的候选调用,再用保留下来的调用微调模型 (Schick et al. 2023)。它们证明模型可以学习并使用动作接口,但并不定义唯一正确的智能体架构。

一轮交互就是一次状态转移

在第 tt 轮,运行时构造模型输入,控制器提出决定,随后运行时更新持久状态:

xt=C(g,u,st,At,bt),ytπθ(xt),dt=D(yt),st+1=U(st,dt,ot+1).\begin{aligned} x_t &= \mathcal{C}(g,u,s_t,A_t,b_t), \\ y_t &\sim \pi_\theta(\cdot\mid x_t), \\ d_t &= \mathcal{D}(y_t), \\ s_{t+1} &= \mathcal{U}(s_t,d_t,o_{t+1}). \end{aligned}

其中,tt 是轮次索引,gg 是任务目标,uu 包含用户指令与约束,sts_t 是本轮开始前的持久会话状态,AtA_t 是本轮暴露的动作规范集合,btb_t 记录剩余的词元、动作次数、时间与成本预算,C\mathcal{C} 是上下文整理器。它输出有边界的控制器输入 xtx_t。参数为 θ\theta 的控制器 πθ\pi_\theta 采样输出 yty_t,解码器 D\mathcal{D} 把输出解析成决定 dtd_t。更新器 U\mathcal{U} 将旧状态、决定与观测 ot+1o_{t+1} 合并,得到下一状态 st+1s_{t+1}。方程中的每个符号都对应一项可以记录和测试的运行时对象。

解析后的决定必须有明确类型。一个实用的最小集合是:

dt{act(at),ask(qt),final(rt),stop(et)}.d_t \in \{\operatorname{act}(a_t),\operatorname{ask}(q_t), \operatorname{final}(r_t),\operatorname{stop}(e_t)\}.

其中,ata_t 是请求执行动作或一批明确动作,qtq_t 是向用户提问的问题,rtr_t 是提交最终回答,ete_t 是结构化终止原因。动作产生的 ot+1o_{t+1} 可以是工具结果、执行错误或策略拒绝,用户回复也可以成为观测。最终回答必须在完成条件通过后才能离开循环。终止原因应记录成功、终局失败、取消、预算耗尽或其他已声明的终止条件。

状态 sts_t 与模型上下文 xtx_t 不是同一个对象。状态可以保存完整事件日志、审批记录、外部资源句柄,以及绝不能进入提示词的数据。上下文则是经过选择和格式化的状态视图。将二者分开后,脱敏、摘要、回放和更换模型都不需要改写会话记录。

运行时选择任务、当前工作状态、相关观测、允许的动作和剩余预算。
控制器请求运行测试。可见的推理轨迹可有可无,但请求的动作及其参数不能省略。
引用监视器在产生任何副作用前检查动作规范、权限、审批策略和预算。
分发器在超时限制内执行获准的测试命令,并记录输出、状态、来源和请求标识符。
这次失败成为持久事件,并更新用于整理下一轮输入的工作状态。
完成检查仍未通过,循环因此继续。只有成功、终局失败、取消或预算耗尽时才退出。
图 38.1. 一轮受控交互。模型提出带类型的决定,运行时负责防护、执行、记录,并判断是否允许进入下一轮。
S 持久状态 C 整理有边界的上下文 S->C P 控制器提出决定 C->P D 决定类型? P->D G 验证并授权动作 D->G 动作 Q 等待用户输入 D->Q 提问 V 验证是否完成 D->V 最终回答 X 携带已记录结果退出 D->X 终止 E 执行并规范化观测 G->E 允许 U 更新状态 G->U 拒绝 / 无效 E->U Q->U 回复 V->U 未完成 V->X 已完成 U->S
图 38.2. 一个封闭的智能体循环。持久状态被整理成上下文,控制器提出带类型的决定,运行时则分别处理提问、受保护的动作、最终回答和终止条件。

图 38.2 中的控制器可以采用 ReAct。ReAct 在动作之间插入可见的语言推理 (Yao et al. 2023),但通用循环并不要求展示这类轨迹。模型可以在内部推理,外部规划器可以提供计划,确定性工作流也可以决定部分状态转移。必须保持可观测的是决定记录,包括所选分支、动作参数、观测来源、审批结果、已消耗预算和完成证据。

架构是一组契约

规划、记忆和工具使用这些常见标签很有用,却混合了策略、状态与接口问题。把每项运行时角色写成契约,生产架构会清楚得多:

角色 契约 缺失后的故障
控制器 根据整理后的上下文提出一个带类型的决定。 自由文本被误当成可执行命令。
上下文整理器 选择、排序、标注并限制模型输入。 持久状态与恰好能放进一次提示词的内容混为一谈。
状态存储与更新器 保存事件,并据此推导下一份工作状态。 重试会丢失历史,或把同一观测应用两次。
动作目录 定义可用操作、参数规范、副作用和结果规范。 控制器无法区分合法操作与看似合理的文本。
引用监视器 验证、授权、请求审批并执行预算限制。 模型输出绕过产品的权限边界。
分发器与环境 执行获准动作,返回带状态和来源的规范化观测。 超时和部分失败被误当成任务结果。
完成检查器 独立于控制器的声明,检查用户要求的最终状态。 一句自信的最终回答让未完成任务提前结束。
终止策略 在成功、失败、取消或资源耗尽时停止。 循环四处游走、无限重试,或无上限地消耗资源。

这种拆分也将架构与运行框架的实现分开。架构规定状态必须留存、动作必须经过防护;第 41 章 中的运行框架则用队列、租约、重试、检查点和崩溃恢复,让这些契约在故障后仍然成立。

根据任务选择控制模式

智能体架构之所以有多种形态,是因为控制器不必对所有任务采用同一种模式。

模式 适用场景 必需反馈 主要故障模式
固定工作流 步骤和分支在执行前已经明确。 在声明的检查点返回状态。 未编码的情况无处可去。
反应式下一步动作 最新观测决定下一个小步骤。 几乎每次动作后都返回观测。 控制器四处游走,或丢失全局目标。
滚动时域规划 提前安排若干步骤有助于协调,但环境可能变化。 每次动作或检查点后重新规划。 重新规划成本占主导,或继续执行已经过时的计划前缀。
先规划后执行 依赖关系可预测,观测很少改变计划。 在步骤边界验证。 早期假设失效,连带破坏后续步骤。
分层规划器与执行器 高层分解与底层动作选择需要不同上下文或模型。 子目标完成信号与升级机制。 规划器与执行器对状态或成功条件理解不一致。
评估器与改进器 检查候选结果比一次就生成正确结果更便宜。 能指导修改的验证反馈。 评估器奖励表面变化,或改进过程永不停止。
分支搜索 生成多个候选很便宜,而且能够可靠比较。 评分器与明确的搜索预算。 成本增长快于有效多样性。

工作流能够表达任务时,通常应优先使用工作流。它成本更低,更容易测试,也更容易授权。只有当系统只能在设计时尚不可见的观测出现后才能选择动作时,由模型控制的循环才值得承担额外成本。

规划不是开关,而是一种节奏

一份不可修改的计划可能很快过时,但这并不意味着规划无用。真正的设计问题是何时制定计划、计划覆盖多远,以及什么情况触发修改。ReAct 用显式推理和动作展示了逐步适应 (Yao et al. 2023)。Reason for Future, Act for Now 会规划未来轨迹,只执行第一个动作,纳入反馈后再次规划 (Liu et al. 2024)。Plan-and-Act 则把训练过的高层规划器与执行器分开,并报告了长时程网页任务上的结果 (Erdogan et al. 2025)。这些系统采用的是不同的规划节奏,并不是同一套正确架构的迭代版本。

写下来的计划属于状态,不代表权限。每一步仍需检查当前前置条件、权限和预算。常见的重新规划触发条件包括前置条件失败、意外观测、用户约束发生变化、动作被拒绝、超时、完成检查失败,或剩余预算达到阈值。计划还应记录支撑它的观测,否则摘要可能保留步骤,却删掉当初证明该步骤合理的假设。

自适应控制不要求展示推理轨迹。ReAct 等研究系统中,这类轨迹可能有用;但运行审查应依靠稳定的产物,例如计划版本、决定类型、动作参数、验证器输出和状态转移。Reflexion 是一种具体方案,它把任务反馈转成文本反思,留给后续尝试使用 (Shinn et al. 2023)。这说明无需更新模型权重也能更新上下文状态,却不构成通用的正确性保证。

选择动作表示方式

动作接口决定控制器能表达什么,也决定运行时能验证什么。三种常见表示方式有不同取舍:

表示方式 优点 运行时必须执行的边界
结构化函数调用 明确的操作名与带类型参数支持规范验证、逐次审批和稳定日志。 完成语法检查后还要验证语义,授权具体操作与目标,并规范化所有结果和错误。
可执行代码 循环、变量、筛选和多项操作可以组合进一个动作。 在沙箱中运行,管控每项外部能力,限制 CPU、内存、网络和时间,并保存代码及其副作用。
环境原生动作 文本命令、机器人控制、点击、按键或消息可以直接对应环境。 限制合法动作集合,标识目标状态,并根据最新观测验证副作用。

Toolformer 研究模型如何学会在何时、以何种方式调用一小组固定 API (Schick et al. 2023)。CodeAct 研究另一种动作表示,也就是可执行 Python。作者在 API-Bank 和 M³ToolEval 上测试 17 个模型,与其比较的文本和 JSON 格式相比,报告成功率最高提高 20 个百分点 (Wang et al. 2024)。结果仅适用于这些模型、接口和基准,不能证明代码始终更安全或更便宜。

接口设计本身就会改变智能体表现。SWE-agent 为仓库浏览、编辑和测试设计了智能体与计算机之间的接口,再在软件工程任务上评测 (Yang et al. 2024)。更普遍的结论不是每个智能体都需要这套接口,而是动作名称、参数形状、观测格式和反馈延迟都属于架构,并非中性的连接层。

无论采用哪种表示,模型只负责提出动作,引用监视器决定是否允许执行。带副作用的请求需要稳定的幂等键,避免传输重试重复购买、发消息或写入。长期运行的工作需要持久句柄来标识,不能把一条仍然打开的连接当作身份。只有依赖关系和副作用互不冲突时,才能安全地并行动作。

让每一个分支都明确

最小循环不是“不断调用模型,直到它不再输出工具调用”。没有调用可能表示最终回答、澄清问题、拒绝、格式错误或模型故障。更安全的架构骨架如下:

state = initialize(task, user_constraints, permissions, budgets)

loop:
    stop = check_termination(state)
    if stop exists:
        return recorded_outcome(stop, state)

    context = assemble_context(state)
    raw = controller(context)
    decision = decode_typed_decision(raw)

    if decision is invalid:
        state = record_parse_error(state, raw)
        continue  # bounded by the parse-retry budget

    if decision is ask_user:
        suspend until reply or cancellation
        state = record_user_reply(state, reply)
        continue

    if decision is final_response:
        evidence = verify_completion(state, decision)
        if evidence passes:
            return recorded_outcome(success, state, evidence)
        state = record_failed_completion(state, evidence)
        continue

    if decision is requested_action:
        verdict = validate_authorize_and_budget(decision, state)
        if verdict denies:
            state = record_observation(state, verdict)
            continue
        request_id = idempotency_key(session_id, turn_id, decision)
        result = execute_with_timeout(decision, request_id)
        state = record_observation(state, normalize(result))

这份骨架可以向用户提问、请求执行动作、提交最终回答或终止。解析错误、授权拒绝、超时和工具故障都成为带类型的观测,不再作为异常悄悄抹掉一轮交互。终止检查覆盖成功、失败、取消和预算耗尽。运行框架可以用不同方式实现重试与恢复,但必须保留这些结果。

区分自主性与权限

自主性描述由谁选择下一项操作,权限描述系统可以执行哪些操作。它们是两条彼此独立的轴。控制器可以自主搜索只读语料库,却只有很小权限;固定工作流也可能拥有部署软件或转移资金的广泛权限。

这个区别会改变架构审查。增加规划器、延长任务时程或动态发现工具,可能增加自主性,却不改变权限。挂载可写凭据、扩大文件系统范围或移除审批门,即使控制循环不变,也会扩大权限。影响范围取决于权限、可达范围与可逆性,不能由“智能体化”这样的模糊标签决定。安全与授权控制见 第 56 章;架构必须暴露这些控制可以介入的决定点。

下层约束:上下文是一笔共享预算

上下文窗口必须同时容纳指令、任务数据、工作状态、动作规范,以及留给输出的空间。其词元记账方式是:

Bctx=Bfixed+Btask+Bstate,t+Btools,t+Bout,tW,Btools,t=aAts(a).B_{\mathrm{ctx}} = B_{\mathrm{fixed}} + B_{\mathrm{task}} + B_{\mathrm{state},t} + B_{\mathrm{tools},t} + B_{\mathrm{out},t} \le W, \qquad B_{\mathrm{tools},t}=\sum_{a\in A_t}s(a).

其中,BctxB_{\mathrm{ctx}} 是第 tt 轮预留的总词元数,BfixedB_{\mathrm{fixed}} 用于系统与策略指令,BtaskB_{\mathrm{task}} 用于用户目标和固定任务数据,Bstate,tB_{\mathrm{state},t} 用于选中的会话状态,Btools,tB_{\mathrm{tools},t} 用于已挂载的动作规范,Bout,tB_{\mathrm{out},t} 为控制器输出预留空间,WW 是模型支持的上下文上限。集合 AtA_t 包含第 tt 轮暴露的动作,s(a)s(a) 是动作规范 aa 序列化后的词元长度。每一项都是第 tt 轮的实际词元预算。等式只是记账,并不表示每一份预算具有相同价值。

再挂载一个动作会产生确定的词元成本,但它对动作选择的影响需要实测,不是一条普遍成立的指数曲线,也不存在固定的工具数量阈值。结果取决于模型、任务、规范的相似程度、描述方式和提示词。BFCL 评测串行与并行调用、弃权,以及有状态的多轮行为 (Patil et al. 2025)。ACEBench 又加入含糊或不完整的指令和多轮智能体场景 (Chen et al. 2025)。这些基准揭示了多种故障,却没有给出一个适用于所有模型的目录规模上限。

应根据真实工作负载,在扁平目录、分阶段挂载、检索或显式发现之间选择。测量所需动作存在时的选择质量,加入无关工具和相似规范,测试没有动作适用时能否弃权,并在动态选择规范时报告检索召回率。工具检索可以节省上下文,也可能恰好隐藏解决任务所需的唯一动作。

争议所在

显式规划与隐式规划之间没有普遍胜者。显式计划有助于协调长任务,也方便审查;反应式控制则能用较少的规划开销适应变化。Plan-and-Act 为独立规划器与执行器提供了限定场景的证据 (Erdogan et al. 2025);ReAct 和滚动时域系统则为更紧密的反馈提供了限定场景的证据 (Yao et al. 2023; Liu et al. 2024)。能否迁移取决于任务分布、模型、验证器和成本预算。

动作暴露方式同样没有定论。扁平目录简单且易于审计;检索或发现可以节省上下文,却增加召回失败。结构化函数调用便于逐项设防;可执行代码能组合多个操作,却把更多责任交给沙箱和引用监视器。应在相同的运行边界内比较这些选择,不能把它们排成一条通用的智能体成熟度阶梯。

把架构当作完整系统来验证

比较架构时,必须使用相同的模型检查点、任务分布、工具实现、权限和预算。否则,更强的模型、更宽的凭据或更多词元都可能被误认成更好的控制循环。

层面 测量项
任务结果 带置信区间的完成率;按任务类型和时程统计的完成率;独立的最终状态验证;用户纠正次数。
控制质量 无效动作率;不必要动作率;重新规划频率;动作被拒绝、失败或产生误导观测后的恢复率;过早提交最终回答的比例。
安全与权限 审批频率;权限拒绝率;意外副作用;重复副作用;超出请求范围的操作。
状态质量 回放成功率;事件缺失或重复;上下文截断;观测来源;动态动作检索召回率。
成本与服务 模型调用次数;输入与输出词元;动作数;工具与模型延迟;墙钟时间;每个完成任务的成本。

检查失败时,应按状态转移检查失败,而不只看最终分数。需要确定究竟是哪一环出了问题:所需事实从未进入上下文,控制器选错决定类型,动作规范含糊,授权拒绝了合法操作,环境返回误导性观测,状态更新器遗漏观测,还是完成检查器过早放行。它们属于不同的契约,需要不同的修复。

至此,架构已经明确了状态边界,却还没有决定哪些内容只保留一轮、一个会话,或跨越多个会话。下一章讨论 第 39 章

延伸阅读

  • Yao et al., “ReAct: Synergizing Reasoning and Acting in Language Models” (ReAct 的 ICLR 归档论文,把显式文字推理轨迹与任务专用动作交错执行), 2023. arXiv:2210.03629
    ReAct 让语言模型交替生成文字推理与环境动作,使后续决策能够纳入新观察。
  • Schick et al., “Toolformer: Language Models Can Teach Themselves to Use Tools” (从筛选后的生成调用中学习何时以及如何调用五个固定 API), 2023. arXiv:2302.04761
    Toolformer 生成候选 API 标注,执行调用并按语言模型损失筛选,再微调模型决定何时及如何使用五个固定 API。
  • Liu et al., “Reason for Future, Act for Now: A Principled Architecture for Autonomous LLM Agents” (规划未来轨迹,只执行第一步,再根据反馈重新规划), 2024. proceedings.mlr.press
    RAFA 实现滚动时域控制:规划未来动作、执行第一步、保存反馈,再从更新后的状态重新规划。
  • Erdogan et al., “Plan-and-Act: Improving Planning of Agents for Long-Horizon Tasks” (把训练得到的高层规划器与环境专用执行器分开), 2025. proceedings.mlr.press
    Plan-and-Act 训练规划器生成高层计划,再由独立执行器把计划转换成长时程网页任务中的环境动作。
  • Shinn et al., “Reflexion: Language Agents with Verbal Reinforcement Learning” (保存来自任务反馈的文字反思,供后续试验使用,而不更新权重), 2023. proceedings.neurips.cc
    Reflexion 把任务反馈转成保存在情节记忆中的文字反思,通过上下文而非参数更新来改变后续决策。
  • Wang et al., “Executable Code Actions Elicit Better LLM Agents” (在 API-Bank 和 M3ToolEval 上比较可执行 Python、文本和 JSON 动作格式), 2024. arXiv:2402.01030
    CodeAct 以可执行 Python 作为动作表示,并在其评测模型与基准上报告了相对比较格式最高 20 个百分点的成功率提升。
  • Yang et al., “SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering” (研究智能体计算机接口如何改变软件工程任务中的行为), 2024. proceedings.neurips.cc
    SWE-agent 为代码仓库导航、编辑与测试设计模型接口,说明动作与观察接口本身会影响智能体表现。
  • Patil et al., “The Berkeley Function Calling Leaderboard (BFCL): From Tool Use to Agentic Evaluation of Large Language Models” (评估串行调用、并行调用、弃答和有状态多轮行为), 2025. proceedings.mlr.press
    BFCL 评测串行、并行、弃权和有状态多轮函数调用,而不是把工具使用简化为单一参数匹配分数。

评论

登录后评论