跳转至

第 4 章 Agent 的基本架构设计

如果说第 3 章解决的是“如何从系统视角看 Agent”,那么这一章要进一步回答“一个 Agent 在工程上到底应该怎么拆”。到这一层,讨论已经不能停留在概念上,而必须进入架构角色、职责划分和运行时边界。

很多团队在做 Agent 时,会把模型、Prompt、工具、记忆、知识库、控制逻辑全部揉进一个执行函数里。原型阶段这样做当然很快,但代价也非常直接:难以调试、难以演进、难以评测,稍微复杂一点就会失控。因此,一个可持续演进的 Agent 系统,必须尽早完成角色拆分。

本章讨论的不是某个具体框架如何实现,而是一套更稳定的架构问题:系统里有哪些核心角色,它们各自负责什么,又应该如何协同。

4.1 Model、Prompt、Tools、Memory、Knowledge 的关系

构建 Agent 时,最常见的五个词是 Model、Prompt、Tools、Memory 和 Knowledge。它们都很重要,但很多设计混乱,恰恰来自于没有区分清楚这些角色的职责边界。

先看 Model。模型是 Agent 中最核心的推理与生成引擎。它负责理解任务、解释上下文、做动作选择,并把判断转化成自然语言或结构化动作。模型的强弱会影响 Agent 的上限,但模型本身不应该承担所有系统责任。

Prompt 的职责则是控制。它不是“写给模型看的文案”,而是系统对模型行为施加约束和提供角色信息的接口。一个好的 Prompt 应该帮助模型理解任务目标、输出格式、行为边界、工具使用原则和风险约束。换句话说,Prompt 更像是控制协议的一部分,而不是知识库存储区。

Tools 的职责是行动。它们为 Agent 提供触达外部环境的能力,包括查询、检索、执行、写入和调用。工具的本质是把环境中的真实能力包装成模型可调度的结构化接口。

Memory 的职责是持久化与复用。它保存的是能够跨轮次、跨任务继续发挥作用的信息,例如用户偏好、长期背景、历史经验和稳定约束。Memory 不一定每次都进入上下文,但必须在需要的时候能够被有条件地召回。

Knowledge 的职责是补充事实依据。它解决的是“模型不知道”或“模型知道得不够准”的问题。Knowledge 既可以来自文档库、数据库、搜索系统,也可以来自结构化业务数据。它强调的是事实来源与可引用性,而不是长期偏好。

这五者之间最容易混淆的两个边界分别是:

第一,Prompt 与 Knowledge 的边界。很多系统把大量事实直接塞进 Prompt,试图靠超长系统提示词解决知识问题。这种做法在原型阶段可能有效,但一旦知识规模扩大、时效性变强或权限要求上升,就会立刻失控。Prompt 适合放规则和控制信息,不适合承担大规模知识承载。

第二,Memory 与 Knowledge 的边界。Knowledge 关注的是公共事实、任务事实和外部依据,Memory 关注的是跨任务保留的个体化信息和历史经验。前者更像“查资料”,后者更像“想起来”。

把这些边界分清,后续架构设计才不会陷入“什么都往上下文里塞”的混乱模式。

工程提示

如果一个系统难以解释“这条信息为什么在 Prompt 里,而不在 Knowledge 或 Memory 里”,那通常说明架构边界还没有划清。

4.2 Controller 与 Runtime 的职责划分

在很多 Agent 系统里,真正决定可维护性的,不是模型选型,而是控制逻辑和运行时逻辑是否被拆开。一个实用的划分方式,是把系统分成 ControllerRuntime 两层。

Controller 负责决策编排。它关注的是任务层面的逻辑,例如:

  • 当前任务处于哪个阶段。
  • 需要装配哪些上下文。
  • 这一步应该交给模型思考、工具执行还是人工确认。
  • 当动作失败时应该重试、回滚还是中止。
  • 是否需要进入下一轮规划或调用其他子流程。

Runtime 负责执行承载。它关注的是动作真正如何发生,例如:

  • 模型调用接口。
  • 工具调用器。
  • 超时控制与重试策略。
  • 会话状态存储。
  • 日志、追踪和指标上报。
  • 安全检查与权限校验。

这个拆分的价值在于:Controller 决定系统“想做什么”,Runtime 决定系统“如何安全、稳定地把事情做出来”。如果两者耦合在一起,就会出现非常典型的问题:Prompt 改一点,工具执行逻辑跟着变;工具重试策略改一点,任务编排也要跟着改;想做评测时,却发现连动作边界都无法抽出来。

更进一步看,Controller 与 Runtime 的分离还能帮助系统支持不同粒度的演进:

  • 模型可以替换,而不重写整个执行器。
  • 工具可以扩展,而不改动主任务逻辑。
  • 状态存储可以替换,而不改变决策结构。
  • 同一套 Controller,可以运行在同步 API、异步任务队列或多 Agent 协作环境中。

对软件工程师来说,这种拆分并不陌生。它和业务逻辑层与基础设施层的分离是同一个思想,只不过在 Agent 系统里,这种边界会因为模型引入的不确定性而显得更加重要。

flowchart TB
    A["接口层"] --> B["Controller"]
    B --> C["上下文装配"]
    C --> D["模型调用"]
    B --> E["工具执行"]
    D --> F["Runtime"]
    E --> F
    F --> G["状态 / Memory / Knowledge"]
    F --> H["日志 / 追踪 / 权限"]

工程提示

不要把 Runtime 误解为“只是一个模型 SDK 包装层”。只要系统涉及工具、状态、重试、安全和追踪,Runtime 就已经是一个独立的工程对象。

4.3 同步执行与异步执行

Agent 进入真实业务后,一个很快会出现的问题是:这个系统到底应该同步运行,还是异步运行?

同步执行的优点很直接:交互体验顺畅,实现简单,调用链短,尤其适合问答型和短任务型 Agent。用户发起请求后,系统在一个请求生命周期中完成上下文装配、模型推理、工具调用和结果返回。只要任务足够短、外部依赖可控,同步模式会非常高效。

但同步模式也有明显边界。一旦任务开始变长,或者执行链路包含多个慢工具、审批节点、人工确认或高失败率外部依赖,同步模式就会变得脆弱。请求超时、链路中断、用户等待过久和资源占用失衡,都会迅速出现。

异步执行则适合更长链路的任务。系统可以先接收任务,生成任务 ID,把后续执行交给后台调度器或任务队列,再通过轮询、回调、消息推送或通知中心把结果反馈给用户。异步模式的优势主要体现在:

  • 更适合长任务和多步骤任务。
  • 更容易插入人工审批和阶段性检查。
  • 更容易在失败后从中间状态恢复。
  • 更容易做资源调度、优先级控制和重试编排。

但异步模式也会带来更高的系统复杂度,尤其是在状态管理、任务可见性和用户体验方面。用户不再只关心“结果对不对”,还会关心“现在执行到哪里了”“为什么还没完成”“失败后是否还会继续重试”。这要求系统具备比同步模式更完整的状态表达和通知机制。

工程上不必把两者对立起来。很多成熟系统都会采用混合模式:

  • 简单任务同步处理。
  • 长任务切换为异步流程。
  • 关键节点同步确认,非关键节点后台推进。

关键不在于“选哪种模式更先进”,而在于任务的真实执行特征决定了哪种模式更合适。

4.4 状态、记忆与知识在架构中的位置

在一个成熟的 Agent 架构里,状态、记忆和知识通常不会混在同一个存储层里。它们服务的问题不同,因此在架构中的位置也应该不同。

状态层通常直接服务于当前任务运行。它保存的是会话上下文、任务阶段、中间结果、工具返回摘要、待执行动作和错误信息。状态层要求读写频繁、延迟较低、更新及时,并且要支持任务恢复和执行追踪。

记忆层服务的是跨任务复用。它关注的是长期保留的信息,例如用户偏好、长期背景、历史决策经验、稳定配置和个体化习惯。记忆层强调选择性写入、条件召回、冲突更新和时效管理。它不应该成为“什么都存”的垃圾场。

知识层服务的是事实补充。它可以是文档检索系统、结构化数据库、业务报表库、搜索引擎或语义索引。知识层的核心要求是来源可靠、可检索、可引用、可更新,尤其要能处理时效性和权限问题。

这三层在运行时会频繁协作,但不能被混为一谈。一个常见的坏味道是:所有历史消息、所有文档内容、所有用户偏好都被原样拼进模型上下文,试图靠一次长输入解决所有问题。这通常意味着:

  • 状态没有结构化。
  • 记忆没有筛选机制。
  • 知识没有检索与引用层。
  • 最终导致模型输入冗长、成本上升、注意力稀释、错误难排查。

更合理的做法是:

  • 状态层保存当前任务的运行事实。
  • 记忆层保存未来值得复用的信息。
  • 知识层按需提供任务相关依据。
  • 上下文装配层在每次决策前把三者有选择地拼装进模型输入。

这样的分层,才符合 Agent 作为长期演进系统的需要。

工程提示

“把所有信息都喂给模型”不是架构方案,只是延迟问题暴露的一种方式。

4.5 Agent 架构中的约束、观测与恢复

一个只讨论能力模块、不讨论约束和恢复的 Agent 架构,通常还不具备生产价值。因为在真实环境中,系统一定会遇到以下情况:

  • 模型输出不符合预期。
  • 工具调用失败。
  • 外部系统返回异常。
  • 用户中途修改目标。
  • 人工审批拒绝继续执行。
  • 部分步骤执行成功,部分步骤失败。

这意味着架构设计里必须预留三个支撑面。

第一是约束。系统必须能够约束模型和动作边界,例如输出格式要求、可调用工具白名单、风险动作确认、权限隔离和阶段性终止条件。约束不是附加物,而是决定 Agent 是否可控的核心部分。

第二是观测。系统必须能看见自己在做什么,包括模型输入输出摘要、工具调用链路、状态变更、错误码、重试记录和用户反馈。没有观测,任何优化都只能靠猜。

第三是恢复。系统必须能处理失败后的路径,例如重试、回滚、补偿、转人工、从中间状态继续执行。没有恢复能力的 Agent,往往只适合演示,不适合真实任务。

从架构角度看,这三者不应该等到系统出问题后再补,而应该在 Controller 和 Runtime 设计阶段一起纳入考虑。否则,后面再加往往代价很高。

4.6 一个建议的基础分层

综合前面的讨论,一个面向生产演进的 Agent 基础分层可以粗略表示为:

  1. 接口层:负责接收请求、展示结果、承接用户交互。
  2. 控制层:负责任务编排、状态判断、动作选择、终止条件控制。
  3. 上下文层:负责组装 Prompt、状态摘要、知识片段、工具说明和约束信息。
  4. 执行层:负责模型调用、工具调用、结果标准化、重试和超时处理。
  5. 状态与存储层:负责状态、记忆、知识和审计数据的读写。
  6. 观测与治理层:负责日志、追踪、指标、安全、权限和评测。

这并不是唯一正确的分法,但它足够贴近大多数 Agent 系统会遇到的真实问题。更重要的是,这种分层让你可以比较自然地回答下面这些问题:

  • 这段逻辑应该放在 Prompt 里,还是放在控制层里?
  • 这条信息应该进入状态,还是进入记忆?
  • 这个失败应该在执行层处理,还是在控制层决定是否继续?
  • 这个工具描述应该归属哪个上下文装配节点?

当这些问题都能被清晰回答时,架构通常已经开始走向稳定。

4.7 本章小结

Agent 的基本架构设计,本质上是在回答一个问题:如何把模型能力嵌入一个可控、可恢复、可演进的软件系统中。Model、Prompt、Tools、Memory 和 Knowledge 都有自己的职责,但真正让它们发挥作用的,是 Controller、Runtime、状态层和执行层之间清晰的协作关系。

从工程视角看,好的 Agent 架构并不追求“把所有智能都塞进模型里”,而是追求分层清晰、职责明确、闭环稳定。只有这样,后续在 Prompt、Planning、Tool Use、RAG、Memory、评测和安全上的设计,才会有稳定的承载基础。

下一章开始,我们会进一步聚焦到控制层中的一个核心部件:Prompt。也就是系统究竟如何通过指令、规则和上下文组织,把模型的行为约束到可用范围内。