AI Agent 工作原理详解
收录于 AI 浏览量
上一篇《AI Agent 的核心推理逻辑详解》回答的是“Agent 的大脑怎么想”——循环、ReAct、思维链,是认知视角。这篇换一个视角:系统视角,回答“Agent 的身体怎么跑”。从你按下回车,到 Agent 交付结果,中间的工程链路到底发生了什么。
两条视角缺一不可:推理循环是灵魂,工程链路是身体。理解了这条链路,你就能看懂 Agent 为什么有时会卡住、会超时、会“忘事”——以及一个 Agent 产品的好坏,究竟差在哪些工程细节上。
一、全景:一次任务的完整生命周期
flowchart TD
A[用户输入目标] --> B[初始化会话]
B --> C{循环继续?}
C --> D[上下文组装]
D --> E[调用大模型推理]
E --> F{是工具调用?}
F --> G[权限门控]
G --> H[沙箱执行工具]
H --> I[结果回填上下文]
I --> C
F --> J[生成最终回答]
J --> K[流式输出交付]
整个过程分三个阶段:
- 初始化:创建会话,加载系统提示词、工具定义、项目约定(如 AGENTS.md),把用户目标写入上下文;
- 循环:上下文组装 → 模型推理 → 权限门控 → 工具执行 → 结果回填,转到达成为止。这正是上一篇讲的“感知 → 推理 → 行动 → 观察”四拍循环的工程实现;
- 交付:模型判定任务完成,生成最终回答,流式输出给用户。
一个关键认识:整个系统里只有“模型推理”这一步是不确定的,其余全是确定性工程。组装、门控、执行、回填、重试——都是普通代码。Agent 产品之间的差距,大部分来自这些工程环节的质量,而不是模型本身。
二、上下文组装:每一轮循环前的“装弹”
模型是无状态的:每次调用都要把它需要知道的一切重新装进上下文窗口。每一轮循环开始前,系统在做一次精细的拼装:
| 组装内容 | 作用 | 典型占比 |
|---|---|---|
| 系统提示词 | 身份、行为规范、输出格式约定 | 小而固定 |
| 环境信息 | 当前目录、操作系统、日期、项目结构摘要 | 小而固定 |
| 工具定义 | 每个工具的名称、参数 schema、使用说明 | 随工具数增长 |
| 检索的记忆 | 从长期记忆(文件、向量库)取回的相关内容 | 按需 |
| 对话历史 | 用户目标、历轮推理与行动 | 滚动增长 |
| 最近观察 | 上几轮工具执行的结果 | 保留最近、折叠更早 |
窗口是有限的(几万到几十万 token),组装的核心是一套预算与淘汰策略:
- 大文件不整读:读文件结果太长时只回传相关行,或截断后附“已截断”标记;
- 旧观察折叠:几轮之前的大型工具结果压缩成一行摘要,给新观察腾位;
- 输出预留:永远给模型的回复留足空间,否则生成会被拦腰截断。
这解释了一个常见现象:Agent “忘事”往往不是模型忘了,而是组装时被截掉了。所以重要的约束(编码规范、项目约定)要写进每次都会被读到的文件里,让每一轮组装都重新装进去——这正是 AGENTS.md 这类约定的原理。
三、工具执行的幕后流水线
模型输出的只是一个 JSON:tool 名字加一包参数。从 JSON 到真实动作,中间是一条五级流水线:
- 解析与校验:参数是否符合 schema?文件路径是否在允许范围内?类型错误直接拒绝,不打扰模型;
- 权限门控:按 allow / ask / deny 规则放行、暂停等待人工批准、或直接拒绝。拒绝时把原因回传给模型,让它换一条路;
- 执行:在受控环境里真正运行——写文件、跑命令、发请求。每一步都有超时上限,卡住的进程要能被杀掉;
- 结果处理:截断过长的输出、统一错误格式、附上耗时等元信息;
- 回填:把处理后的结果以“工具消息”身份追加进上下文,驱动下一轮推理。
这条流水线里最容易被低估的是错误归一化:无论底层是文件不存在、网络超时还是权限拒绝,回传给模型的错误信息都要结构化、可读、可行动——“Permission denied: 写入 /etc/hosts 被策略禁止,可尝试写入项目目录”远比一个裸堆栈有用。模型据错改道的质量,直接取决于错误信息的质量。
四、流式输出与人工介入
用户看到的“正在思考……”“正在读取文件……”背后是两条并行管线:
- token 流:模型的推理与回答逐 token 流式推送,前端边收边渲染;
- 动作流:每轮工具调用开始前,把“我要做什么”先推给界面,执行完再把结果摘要推出来。
人工介入在工程上只有一种实现:暂停循环,把人的决定当作新的输入塞回上下文。权限门控里的 ask 挡如此,用户中途打断、修改要求也如此——对系统来说,人和工具没有本质区别,都是“往循环里注入一条消息”。这个统一视角能解释几乎所有交互设计:确认弹窗、计划审批(如 OpenCode 的 plan 模式先审后跑)、中途纠偏,全都是同一机制的不同包装。
五、失败恢复:三层防线
Agent 一定会失败:命令会报错、网络会抖动、模型会误判。成熟的系统有三层防线:
- 工具级重试:瞬时故障(网络抖动、限流)在执行层自动重试,不消耗模型的推理步数;
- 循环级反思:把完整错误信息回传给模型,让它换思路重试——上一篇讲的 Reflexion 机制,工程上的前提就是错误不被截断、不被吞掉;
- 会话级检查点:长任务定期落盘(已完成的步骤、关键中间产物),崩溃后能从断点续跑,而不是从零再来。
配合预算控制:步数、时间、token 消耗都设上限。触顶时的正确姿势不是静默失败,而是触发一次收尾推理——“预算快用完了,总结当前进展,说明已完成什么、还差什么”——让失败的循环也留下可用的产出。
六、多 Agent 调度:分形的工程化
上一篇讲了子代理的概念:派生独立会话,只回传结论。工程上还要回答三个问题:
- 怎么隔离:每个子代理有独立的上下文窗口和会话状态,主线的中间垃圾不会污染子代理,反之亦然;
- 怎么派发:任务之间有依赖就串行(前一个的产出是后一个的输入),相互独立就并行(同时读五个文件、同时调研三个方案)。并行是 Agent 提速的最大来源之一;
- 怎么回传:子代理的完整过程被丢弃,只有最终结论进入主上下文——主上下文只增关键信息,不增过程噪声。
调度器本身也可以是一个模型调用:“把这件事拆给谁、并行还是串行、每个子任务的自包含描述怎么写”。拆得不好的调度会把并行变成互相等待,这也是 Agent 产品间真实存在的差距。
七、可观测性:Agent 的黑匣子
Agent 是长链路系统,出了问题必须能回放。生产级 Agent 都有完整的 trace:每一轮循环记录装进了什么上下文、模型输出了什么、调用了哪个工具、耗时与 token 消耗多少。调试 Agent 基本只有一种手段——读 trace,看到底是组装丢了信息、模型选错了工具,还是执行层报了错。
在 trace 之上是评估(evals):用固定任务集回归测试 Agent 的改动有没有让它变好。没有 evals 的 Agent 迭代近似盲飞——改了提示词觉得“好像好点了”,无法证明。
八、小结
| 环节 | 一句话 |
|---|---|
| 生命周期 | 初始化 → 循环(组装→推理→门控→执行→回填)→ 交付 |
| 确定性分界 | 只有模型推理不确定,其余全是确定性工程 |
| 上下文组装 | 每轮“装弹”,预算与淘汰策略决定 Agent 的记性 |
| 工具流水线 | 校验 → 门控 → 执行 → 归一化 → 回填,与模型完全解耦 |
| 人工介入 | 暂停循环,把人的决定当作一条消息塞回上下文 |
| 失败恢复 | 工具重试、循环反思、会话检查点,三层防线 |
| 多 Agent | 独立上下文、按依赖并行、只回传结论 |
| 可观测性 | trace 回放是调试的唯一手段,evals 是迭代的标尺 |
把两篇合起来看:推理逻辑篇讲灵魂怎么转,这篇讲身体怎么跑。再回头看 OpenCode 这类工具的每一个功能——plan 模式是权限门控与人工审批的包装,上下文压缩是组装策略的一环,子代理是调度器的产物——所有产品特性都能在这条工程链路上找到位置。