一个 Agent 系统的核心组成:从系统视角拆解关键模块

本文是「Agent 基础与工程」系列专栏的第 3 篇。专栏总览参见:《Agent 基础认知与工程架构全景》。


很多开源框架用高度封装的几行 API 掩盖了底层的复杂性。这种封装在写 Demo 时很方便,但当系统需要支持任务断点恢复、细粒度权限控制、耗时调试或多步骤追踪时,如果对内部模块缺乏清晰的职责拆解,代码维护成本会迅速攀升。

脱离具体的第三方库,一个可维护的生产级 Agent 系统通常由以下七个核心模块协作构成。


系统模块结构


七大模块的核心职责

1. Goal & Specification(目标与完成规范)

在 Agent 系统中,目标通常以非结构化的自然语言给出。为了让系统可落地,目标需要包含三项明确约束:

  • 目标定义(Objective):明确系统最终产出的交付物(如修复特定 Bug 并生成 Patch,或输出指定格式的对比表格)。
  • 完成判据(Definition of Done, DoD):系统依据什么判断任务完成。优先使用客观外部反馈(如自动化测试全部通过、特定文件已写入并经校验),而非仅依赖模型的主观文本生成。
  • 资源上限(Resource Budget):最大执行步数限制、Token 消耗上限与单次工具超时阈值。

2. State(状态机与执行上下文)

大模型 API 本身是无状态的,跨步骤的记忆与进度追踪必须在外部由代码显式维护。

一个结构良好、支持序列化落盘的状态设计,能让系统在中途异常中断后具备恢复能力(Resume)。在工程实现中,状态通常可以建模为如下的数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from typing import List, Dict, Any, Optional
from pydantic import BaseModel, Field

class TodoItem(BaseModel):
id: str
task: str
status: str = "pending" # pending | in_progress | completed | failed

class AgentState(BaseModel):
# 会话元数据
session_id: str
goal: str
current_turn: int = 0
max_turns: int = 20

# 消息历史(物理轨迹)
messages: List[Dict[str, Any]] = Field(default_factory=list)

# 结构化工作区状态
todo_list: List[TodoItem] = Field(default_factory=list)
active_files: List[str] = Field(default_factory=list) # 已读取或已修改的文件列表

# 资源与退出状态
token_usage_total: int = 0
is_finished: bool = False
exit_reason: Optional[str] = None

把 todo_list 和 active_files 作为独立字段显式维护,比让模型在漫长对话中纯靠文字自述更可控,能有效减少在已排查过的死路上重复尝试。

3. Model(推理与意图解析)

模型负责语义理解与单步推断。系统与模型的交互需要做好分层:

  • Prompt 组装:动态拼接系统指令、当前状态和近期工具观测。
  • 结构化输出契约:采用原生 Function Call 协议输出带类型的参数,而不是让模型输出非标准文本再去用正则表达式匹配。
  • 差异化模型路由:简单的分类和初筛交由轻量模型处理,核心逻辑推理与复杂代码修改调用高推理能力模型。

4. Tools(工具与执行环境)

工具是 Agent 与外部环境交互的接口。生产级工具管线需包含以下四道处理机制:

  1. Schema 校验:使用 JSON Schema 或 Pydantic 严格限定入参格式与默认值。
  2. 环境隔离:涉及命令执行或写磁盘的工具,运行在独立容器或非特权子进程中,避免影响宿主机运行环境。
  3. 输出体积控制:避免直接把数万行的原始日志打入上下文,工具层需做行数截断或提取关键异常片段。
  4. 状态幂等与回退:对有副作用的写操作提供备份或取消机制。

5. Memory(分层记忆系统)

根据生命周期和访问方式,记忆通常划分为四层:

记忆类型 存储位置 生命周期 访问方式 适用内容
工作记忆 (Working Memory) 内存中的当前消息列表 当前会话 随请求全量携带 本轮任务的目标、前几步的操作结果
情景记忆 (Episodic Memory) 磁盘日志(如 JSONL 文件) 永久 按 Session ID 调取 历史任务完整运行轨迹,便于排查回溯
语义记忆 (Semantic Memory) 向量数据库 / 全文索引 跨任务长期保存 Embedding 相似度检索 / BM25 检索 团队规范、设计文档、业务专有词汇
程序记忆 (Procedural Memory) 预设代码脚本 / Skill 文件 跨任务长期保存 按工具名匹配加载 固化的操作流程、特定接口调用范例

6. Planner / Policy(规划与决策模式)

规划层决定了 Agent 是如何组织思考步骤的:

  • ReAct:思考与行动交替进行。每执行一步工具,观察返回结果后再决定下一步,适合信息未知、需要边查边推进的任务。
  • 分步规划(Plan-and-Solve):任务开始时先生成多步计划清单,按清单顺序依次执行;只有当某一步失败时才触发重新规划。
  • 执行前自检(Critique / Reflection):在提交高风险变更前,启动一轮核对逻辑(如运行测试用例或静态语法检查),依据客观结果判断是否通过。

7. Guardrails & Harness(护栏与运行时管控)

模型是概率生成的,系统运行的确定性必须由外层代码兜底:

  • 轮数与成本硬限制:当任务超过预设步数或 Token 阈值时强制停止。
  • 敏感命令拦截:通过正则匹配与静态语法分析,阻断高危系统命令。
  • 人工确认门禁(Human-in-the-loop):对于发送邮件、推送到远程仓库或删除线上资源等高风险操作,暂停循环等待人类审批确认。

轮次交互时序

将各模块拼装起来后,一个完整执行轮次的时序如下:


常见架构缺陷

  1. 依赖自然语言提示词维护状态:把整个待办清单和已读文件全写在 Prompt 字符串里让模型“记住”。长上下文下,模型极易产生幻觉或漏看。应当用独立数据结构管理状态,并在每轮组装时显式注入。
  2. 工具返回值未加过滤:直接把爬虫抓取的整个原始 HTML 或几千行编译日志塞入消息历史,迅速消耗上下文窗口。
  3. 缺乏客观物理事实源:以模型的自然语言断言作为任务成功的依据,而不是依靠实际的命令退出码、测试结果或文件变更做确认。

小结

  • 生产级 Agent 由 Goal、State、Model、Tools、Memory、Planner 和 Guardrails 七个子系统配合运作。
  • 显式、可序列化的状态机是支持任务恢复、避免循环打转的基础。
  • 护栏与调度逻辑位于模型之外,负责对执行轮数、工具权限与异常退出提供确定性保障。

理清了系统的组成架构后,下一个核心问题是:许多系统在本地 Demo 中表现正常,一进入真实环境却容易出现卡死、死循环或逻辑混乱,这背后的工程断层到底在哪里?

下一篇将分析导致系统不稳定的具体原因:《为什么很多 Agent Demo 一落地就不稳定:从工程视角看原型到生产的断层》。


系列导航与参考