第 3 章:从一次请求看懂 Agent 的闭环
本章目标:不再静态拆部件,而是沿着一次真实任务执行过程,理解 Agent 如何把“目标、状态、动作、反馈”串成闭环。
本章对应总纲:docs/ebook-outline.md中“第 3 章正文写作提纲(2026-03-31 归档)”。
3.1 为什么必须看“过程”,而不只看“能力清单”
上一章我们把 Agent 拆成了模型、工具、状态、规划、执行循环五个部件。
但只知道部件名字还不够。因为很多系统的问题,根本不出在“有没有这些部件”,而出在:
- 它们是怎么串起来的
- 信息是怎么流动的
- 错误是在哪一轮被发现的
- 系统为什么会继续、回退、停下,或者问人
所以这一章不再讲“Agent 有哪些零件”,而是讲:
当一个真实请求进入系统后,这个系统到底怎么运转?
只有把过程走一遍,你才会真正明白为什么 Agent 的本质是闭环,而不是“更长的回答”。
3.2 从一句用户请求开始:目标是怎么被建立的
假设用户说:
请帮我修复这个 TypeScript 报错。
表面看,这是一句很普通的话。但对一个 Agent 来说,第一件事不是立刻开始写代码,而是建立任务语义。
系统通常要先回答几件事:
- 用户真正目标是什么?
- 这是解释型请求,还是执行型请求?
- 需要读哪些上下文才知道怎么下手?
- 当前是否有足够信息直接行动?
这一步的关键,不是“理解文字”,而是把文字转成可推进的目标状态。
3.2.1 一个好系统不会把模糊目标直接拿去执行
“修复这个报错”本身其实信息不完整。
至少还缺:
- 报错在哪个文件
- 报错信息是什么
- 是类型设计问题,还是调用点问题
- 用户是要建议,还是要直接修改代码
所以一个靠谱的 Agent 往往会先做目标澄清。澄清不一定非要问用户,也可能通过读取环境补全。
这就是为什么读取文件、搜索代码、检查错误信息,往往会出现在真正行动之前。
3.3 第一轮:感知当前环境,而不是凭空猜
3.3.1 闭环的起点一定是感知
Agent 的第一轮动作通常不是“修”,而是“看”。
因为如果系统对当前环境没有认知,任何后续动作都只是撞大运。
在修 TypeScript 错误这个例子里,感知阶段可能包括:
- 读取报错文件
- 查看错误行附近代码
- 搜索相关类型定义
- 找调用链
- 读取测试或构建脚本
- 查看当前变更范围
这一步回答的问题是:
现在到底发生了什么?
3.3.2 为什么感知必须依赖真实环境
普通问答系统最容易犯的毛病,就是拿“常见情况”代替“当前情况”。
比如它会说:
- 这可能是类型不匹配
- 可以加类型断言
- 可以把参数改成可选
这些都不一定错,但它们不基于当前代码状态。
Agent 不一样。它必须优先读取现实,而不是优先输出经验。
这也是为什么一个真正的 coding agent 总要不断读代码、查符号、看报错、跑检查。它不是啰嗦,它是在接地。
3.4 第二轮:基于当前状态做局部判断
当系统已经看到环境后,下一步才轮到判断。
在这个阶段,模型通常会做几类事:
- 压缩和整理刚读到的信息
- 识别最可能的错误源头
- 判断下一步最有价值的动作
- 决定是继续搜,还是直接改
3.4.1 判断不是终局真理,而是当前最优动作选择
这是很多人容易误解的地方。
Agent 并不需要在一开始就“想明白全部问题”。它更常做的是:
在当前信息条件下,选出最合理的下一步。
比如:
- 如果报错点已经很明确,就直接改
- 如果类型定义不清楚,就继续跳转定义
- 如果影响范围可能很大,就先找引用
- 如果风险高,就先确认边界
这是一种局部最优推进,不是一次性全知推理。
3.4.2 为什么这一步不能被误解成“想好了再做”
因为真实工程不是考试。
很多问题只有你动手以后,反馈才会暴露更多信息。所以好的 Agent 不会在原地空想太久,而是会在“先想一点”和“赶紧验证”之间找平衡。
这就是实用主义。
3.5 第三轮:执行动作,真正改变系统状态
3.5.1 动作是闭环的转折点
到这一步,系统才从“理解问题”进入“推进任务”。
在修错误的例子里,动作可能是:
- 编辑类型定义
- 修改调用点
- 补充返回值约束
- 删除错误的断言
- 调整泛型参数
一旦动作发生,系统状态就真的变了。文件被改了,仓库被改了,环境被推进了。
这就是 Agent 和纯建议系统之间最现实的差别。
3.5.2 为什么动作必须受边界约束
一个系统能行动,不代表它应该乱动。
动作层必须受到至少三种约束:
- 能力边界:它到底能调哪些工具
- 权限边界:哪些操作需要确认
- 任务边界:用户让它修错,不代表它可以顺手重构半个项目
Claude Code 这类系统之所以适合作为样本,就是因为它把这些边界写得很明:
- 风险操作要确认
- 能用专用工具就别滥用 shell
- 不要超范围改动
- 不要顺手做一堆“改进”
这很重要。没有边界的 Agent,不是强,是危险。
3.6 第四轮:读取反馈,判断刚才那一步有没有真的生效
3.6.1 没有反馈,动作就只是碰运气
真正把 Agent 和 workflow 拉开差距的,不只是它会执行,而是它执行完会看结果。
比如代码改完后,系统通常不会凭感觉宣布成功,而会继续:
- 运行类型检查
- 重新查看错误输出
- 检查是否引入新错误
- 对照原目标判断是否已经完成
这一步的核心问题是:
刚才那一步,真的把问题推进了吗?
3.6.2 反馈为什么是下一轮决策的输入
如果检查通过,说明当前路径可能是对的。
如果检查失败,系统就会获得新信息:
- 原假设错了
- 只修了一半
- 改动影响了别的地方
- 当前修法引入了新类型冲突
这些信息不会被浪费,而会直接变成下一轮判断输入。
于是闭环开始形成:
- 先动作
- 再看反馈
- 再调整路径
这不是“失败了再说”,而是系统设计里的基本回路。
3.7 第五轮:更新状态,并决定继续、回退、停机还是求助
当反馈回来以后,Agent 不只是看到结果,还要更新自己的状态视图。
它需要知道:
- 这个问题现在是否已解决
- 哪条路径已经证伪
- 哪些中间结论值得保留
- 当前任务是否进入新阶段
然后它要做一个比“成功/失败”更细的决策。
3.7.1 四种典型去向
一个成熟的 Agent,在每轮反馈后通常会进入四种去向之一:
继续当前路径
说明方向对,只需要再补一刀。回退并换路
说明刚才的判断有问题,得重新定位原因。停机并交付
说明目标已经满足,可以结束任务。请求人类输入
说明现在缺的是决策授权、业务判断或额外信息,不该乱猜。
3.7.2 人类介入不是失败,而是闭环的一部分
很多人误以为真正的 Agent 应该“全自动到底”。这很幼稚。
现实世界里,很多任务天然需要 human-in-the-loop:
- 删除重要文件前要确认
- 改 API 行为前要确认兼容性
- 多种合理实现之间可能需要用户拍板
- 权限不足时必须请人介入
所以“问人”不是破坏闭环,而是闭环的一种合法分支。
好系统知道什么时候该自主,什么时候该停下来问。
3.8 用一个简化流程图看懂完整闭环
现在可以把前面的过程压缩成一个最小运行模型:
- 用户提出目标
- 系统感知当前环境
- 模型判断下一步动作
- 工具执行动作
- 系统读取反馈
- 更新状态
- 判断:继续 / 回退 / 结束 / 求助
- 如果未结束,回到第 2 步
你会发现,这个结构并不玄学。它甚至很朴素。
Agent 的神秘感,很多时候只是因为大家平时只看到了“模型输出”,没有看到后面的这条运行链。
3.9 为什么很多系统看起来像 Agent,却经常不是
因为它们往往只覆盖了这条链的前几步:
- 理解请求
- 生成解释
- 给出建议
但没有真正把:
- 动作
- 反馈
- 状态更新
- 继续迭代
串起来。
于是用户会产生错觉:
- 它说得很像会做事
- 它也能列步骤
- 它还能解释每一步为什么
但这仍然不等于它真的在推进任务。
一句难听但准确的话是:
很多系统不是在执行任务,只是在模仿执行任务时该说的话。
真正的分水岭,不在它能不能把步骤讲出来,而在它有没有把步骤跑起来。
3.10 用 Claude Code 看一个现实中的闭环样本
这一套逻辑,放到当前项目里看就很直观。
Claude Code 这类环境里,一个典型任务往往会经过:
- 用户给出目标
- 系统先读相关文件和上下文
- 搜索定义、引用和约束
- 必要时补足上下文
- 编辑文件
- 运行测试或检查
- 根据结果继续修正
- 在风险操作前请求确认
- 完成后停止
表面上看,这像一串朴素动作;但如果对照当前仓库,你会发现它背后其实有几条很硬的闭环设计规则。
先看 plugins/README.md:16 与 plugins/README.md:19。code-review、feature-dev、pr-review-toolkit 这些插件都不是一次性吐出结论,而是把分析、审查、架构、复核拆成多段执行角色。这说明当前项目默认的不是“一次想完”,而是:先做一轮动作,再根据回来的信息继续推进。
再看 examples/settings/settings-strict.json:1,它把 Bash 放进 ask,把 WebSearch / WebFetch 放进 deny。这不是权限配置的小细节,而是在告诉你闭环里有几种分叉必须被显式建模:
- 可以直接继续的路径
- 必须停下来确认的路径
- 当前运行根本不允许走的路径
也就是说,一个成熟闭环不是只有“做完再看结果”这么简单,它还要把继续、停机、求助、禁止都纳入同一运行结构里。
如果再把 plugins/README.md:48 的标准目录结构一起看,你会更容易看清设计思路:
commands/负责给任务建立入口agents/负责承载独立执行角色hooks/负责在生命周期节点插手.mcp.json负责接外部能力
这几层合起来,才让“闭环”变成可运行的系统,而不是脑子里的流程图。
所以当前项目真正值得学的,不是某个提示词写法,而是它怎么把闭环压成几条可重复使用的规则:
- 先读现实,再做判断,别拿经验代替当前状态
- 动作之后一定要接反馈,别把“我觉得应该好了”当完成
- 继续、回退、停机、求助都要显式存在,别把异常路径留给运气
- 风险边界要进入闭环本身,而不是等出事了再补一个安全说明
这条链说明它不是“增强聊天”,而是“受控执行系统”。
3.11 一个系统什么时候才算“真的在推进任务”
判断标准其实可以非常简单。
如果一个系统面对任务时:
- 会先读当前状态
- 能选择并执行动作
- 会检查动作结果
- 会根据结果继续调整
- 在完成、失败或需要授权时才停下
那它就在推进任务。
反过来,如果它只是:
- 输出建议
- 列一个计划
- 说“你可以这样做”
- 然后把剩下的全留给人
那它更像顾问,而不是 Agent。
顾问也有价值,但别叫错名字。
3.12 本章小结
这一章真正想让你看到的,不是某个酷炫功能,而是一条朴素但决定性的运行链。
你现在应该记住六件事:
- 理解 Agent,不能只看能力清单,必须看任务是如何被推进的。
- 一次请求进入系统后,第一步通常是感知环境,而不是直接输出答案。
- 判断的目标不是一次想明白全部,而是选出当前最合理的下一步。
- 动作之后必须读取反馈,否则系统只是碰运气。
- 反馈会更新状态,并决定继续、回退、停机还是请求人类介入。
- 真正的 Agent,不是更会描述任务,而是真的把这条闭环跑起来。
下一章我们进入更底层的问题:模型在这个闭环里到底承担什么责任,又有哪些事情是再强的模型也不该替系统结构背锅的。