Home Projects Blog Resume Contact 中文
Back to list
2026年7月2日 5,197 words 11 min read

12:从用户目标到验证结果:把 Coding Agent 的运行链路串起来

前面 11 篇,我基本是按模块拆 Claude Code:Agent Loop、工具、提示词、记忆、上下文、计划、权限、观测、恢复、扩展和 subagent。

#Claude Code#Coding Agent#工程化#Agent Runtime

12:从用户目标到验证结果:把 Coding Agent 的运行链路串起来

前面 11 篇,我基本是按模块拆 Claude Code:Agent Loop、工具、提示词、记忆、上下文、计划、权限、观测、恢复、扩展和 subagent。

拆开以后,每个模块都能单独解释一件事。但真正写 agent 时,难点不是把这些模块摆齐,而是让它们在一次任务里接上。

用户给出一个目标以后,系统要一轮一轮地装配上下文、判断下一步、调用工具、回收结果、更新状态,再决定继续、恢复、询问用户,还是验证收束。

所以这一篇不再新增模块,而是把前面拆散的东西重新放回运行链路里。

这篇回答的问题是:

一个 coding agent 接到用户目标以后,如何把目标、上下文、工具、权限、失败、验证和最终回答串成一条可持续推进的链路?

先看总图:任务是一轮一轮推进的

先把图放出来。

Coding Agent 从用户目标到最终回答的运行链路

这张图里,左侧蓝色节点是任务主链路。黄色节点是主循环的分流点。右侧灰色卡片说明每个节点具体做什么。绿色卡片是运行记录最终落到哪里。

这条链路最重要的地方在“下一步判断”。

工具执行完以后,系统不会直接走向最终回答,而是先把结果回流,更新任务状态,再判断下一步:

  • 线索还够,就继续推进,回到本轮上下文组装。
  • 失败可以恢复,就回到模型判断下一步,换策略继续。
  • 缺少业务判断或权限确认,就询问用户。
  • 完成条件满足,才进入验证收束和最终回答。

这就是 coding agent 和一次性问答最不一样的地方。它不是一次生成答案,而是在真实项目里反复看、想、做、回收反馈。

后面就按这张图从上往下写。

每到一个节点,我会看三件事:

  1. 这一节点在运行链路里负责什么。
  2. 它把前面哪些模块接到了一起。
  3. 如果这个节点没做好,agent 会在哪里失控。

先把对应关系摆一下:

链路节点主要接住的前文模块
任务进入Agent Loop、Planning & Task State
加载规则、记忆和行为协议Prompt System、Memory、Hooks & Extension
组装本轮上下文Context Management
模型判断下一步Agent Loop、Prompt System、Subagent
动作裁决Permission & Safety、Hooks
工具执行Tool System、MCP
结果回流Tool System、Context Management、Observability
更新任务状态Planning & Task State、Observability
下一步判断Agent Loop、Fallback & Recovery
验证收束Planning、Observability、Recovery
最终回答Task State、Observability、Memory

这张表不是重新分模块,只是帮后面的链路对上前文。

真正的阅读顺序,还是沿着一次任务往下走。

1. 用户目标:先接住原始意图

用户输入通常不是一份机器能直接执行的任务定义。

比如一句:

帮我修一下后台文章保存后一直 loading 的问题,改完后跑一下相关测试。

这里面有目标,也有隐含范围和完成条件。

“后台文章保存”说明范围大概在后台页面、保存接口、表单状态或请求处理附近。“一直 loading”说明现象可能和前端状态、接口异常、错误分支有关。“改完后跑测试”说明任务完成不只看代码有没有改,还要有验证证据。

所以 agent 第一件事不是猜代码,也不是直接给建议,而是把用户原话接住,保留它的原始意图。

这一步如果做得太粗,后面就容易跑偏。用户要的是“修复并验证”,agent 却可能只解释原因;用户说的是“后台文章保存”,agent 却可能全仓库乱搜。

2. 任务进入:把一句话变成任务状态

目标进入以后,系统要建立任务状态。

任务状态不是很复杂的东西。它至少要让系统知道:

  • 这次目标是什么。
  • 大概范围在哪里。
  • 完成条件是什么。
  • 当前风险高不高。
  • 现在处在任务的哪个阶段。
  • 已经知道了哪些事实。
  • 还有哪些阻塞点。

这一步对应前面讲的 Agent Loop 和 Planning & Task State。

Agent Loop 负责让任务启动起来;Task State 负责把目标、计划、证据和阻塞点放在一个能持续更新的位置。

如果没有任务状态,agent 很容易变成“上一轮想起什么就做什么”。任务一长,就会忘记为什么开始、已经试过什么、还差什么验证。

所以任务进入这一步,本质是在给后面的循环立一个工作台。

3. 加载规则、记忆和行为协议:先带上稳定背景

任务状态有了以后,agent 不能只拿用户一句话去问模型。

它还要加载稳定背景。

这里会接上三类东西。

第一类是行为协议。比如系统提示、工具描述、输出风格、协作规则。它们决定 agent 默认怎么行动,什么时候先观察,什么时候可以改文件,最终回答要说明哪些证据。

第二类是项目规则。比如 CLAUDE.md 里的开发约定、常用命令、目录结构、不能修改的路径、测试方式。

第三类是记忆。比如用户偏好、历史摘要、项目经验、上一次任务留下的可复用信息。

这些内容不是越多越好。

记忆和规则的价值,是让 agent 少走弯路。它知道这个项目常用什么命令,知道用户希望最终回答简洁,知道某些目录是生成产物。
但这些内容也不能代替观察。记忆里写着“前端用 Astro”,下一步最好还是通过文件结构或配置确认。

这一节点把 Prompt System、Memory System 和一部分扩展入口接起来。slash command 或 skill 也会在这里影响任务入口:它们可能带来额外规则、模板或能力。

4. 组装本轮上下文:每一轮都重新整理工作台

加载规则以后,系统要组装本轮模型输入。

这里是 Context Management 的位置。

一个常见误解是,把上下文理解成“把相关材料都塞给模型”。真实任务里这样很快会失控。仓库太大,历史太长,命令输出也可能很吵。

更合适的做法是,每一轮都重新整理工作台:

  • 稳定规则放进去。
  • 当前任务状态放进去。
  • 和下一步有关的文件片段放进去。
  • 工具结果只放摘要和关键证据。
  • 太长的历史先压缩。
  • 暂时无关的材料留在外面,需要时再读。

上下文组装的目标,不是让模型看见最多信息,而是让模型看见下一步真正需要的信息。

这也是为什么“继续推进”会回到这个节点。

每一轮工具执行以后,系统拿到的新事实不一样,下一轮应该看的材料也不一样。搜索结果、文件片段、测试错误、权限拒绝,都会改变下一轮上下文。

5. 模型判断下一步:回答、观察、行动还是提问

上下文准备好以后,模型才开始判断下一步。

这一步不是简单生成答案。对 coding agent 来说,模型可能有几类选择:

  • 直接回答用户。
  • 搜索代码。
  • 读取文件。
  • 修改文件。
  • 运行命令。
  • 更新计划。
  • 询问用户。
  • 委派一个 subagent 做局部任务。

比如面对“保存后一直 loading”,比较稳的下一步通常不是马上改代码,而是先观察现场:看工作区状态、搜索保存逻辑、读取关键文件片段、确认验证命令。

如果任务很局部,单 agent 直接推进就够了。
如果任务需要独立审查、长文档检索、并行测试分析,subagent 可以被用作一个有边界的执行单元。它拿到限定任务、限定上下文和工具权限,最后把证据和摘要回传主 agent。

这里接上了 Agent Loop、Prompt System 和 Subagent。

Agent Loop 决定“下一轮做什么”;Prompt System 约束“以什么方式做”;Subagent 是局部复杂任务的可选分支。

6. 动作裁决:模型想做,不等于系统就执行

模型判断出下一步以后,动作还要经过裁决。

这是 Permission & Safety 的位置,也会接上 hooks。

读文件、搜索代码、写文件、执行命令、访问网络、调用外部系统,它们的风险不同。系统不能只看“模型想这么做”,还要看这次动作的工具类型、参数、路径、命令内容和当前权限模式。

比如:

  • 搜索当前仓库,通常是低风险。
  • 读取普通源码文件,通常可以直接执行。
  • 写文件会改变仓库,需要看路径、范围和已有改动。
  • 执行 shell 命令要看命令是否只读、是否会写文件、是否访问网络。
  • 读取敏感文件或执行破坏性命令,需要拒绝或询问用户。

hook 可以在这里补团队规则。比如某类命令执行前必须检查,某些路径不允许自动写,某些工具结果要额外记录。

这一步的关键是:权限不是 prompt 里的温柔提醒,而是运行时的硬边界。

如果没有动作裁决,agent 能力越强,风险越大。它可能覆盖用户未提交改动,可能跑错命令,也可能把不该读的文件读进上下文。

7. 工具执行:让 agent 接触真实仓库

动作通过裁决以后,才进入工具执行。

工具系统让 agent 真正能动手。

最小的本地 coding agent,至少要能做几类事:

  • 看目录和工作区状态。
  • 搜索关键词和调用点。
  • 读取关键文件片段。
  • 小范围编辑文件。
  • 运行测试、构建或检查命令。

扩展以后,工具还可以接浏览器、数据库、issue 系统、MCP 服务、设计稿或内部平台。

但无论工具多复杂,它都应该返回能继续使用的结果。

比如搜索工具最好返回路径、行号、命中片段和命中原因。命令工具最好返回工作目录、命令、退出码、标准输出、错误输出、是否超时。编辑工具最好返回改动文件和 diff 摘要。

工具结果如果只是“一大段输出”,下一轮模型还要重新猜重点。
工具结果结构清楚,后面的上下文管理、任务状态和观测系统才能接住它。

8. 结果回流:输出要变成下一轮证据

工具执行完以后,最重要的不是“有输出了”,而是输出怎么回到系统里。

结果回流至少有三条去向。

第一,进入上下文。
下一轮模型需要看到关键证据,比如哪个文件命中、哪条测试失败、哪一行报错。

第二,进入任务状态。
系统要更新已知事实、当前假设、计划进度、阻塞点和验证证据。

第三,进入运行记录。
后面要能复盘这次工具调用发生了什么,为什么发生,结果是什么。

这里把 Tool System、Context Management 和 Observability 接在一起。

工具结果只显示在终端里,它只是输出。
进入上下文、任务状态和记录以后,它才变成 agent 能继续使用的证据。

9. 更新任务状态:把做过什么、知道什么、还差什么写清楚

结果回流以后,任务状态要更新。

这一步看起来像记账,但它决定长任务能不能稳住。

比如 agent 搜到了后台保存逻辑,读到了某个文件,发现 loading 只在成功分支复位。任务状态就应该记住:

  • 已经定位到相关文件。
  • 当前假设是什么。
  • 哪些证据支持这个假设。
  • 下一步准备确认什么。
  • 是否有已有用户改动需要小心。

如果后面运行测试失败,任务状态也要更新:失败在哪里、是否可恢复、下一步需要读什么、是否该换策略。

这一步接上 Planning & Task State 和 Observability。

计划不是写完就放那儿。计划会被工具结果修正。任务状态也不是静态摘要,而是每一轮执行后的工作现场。

10. 下一步判断:继续、恢复、询问,还是收束

这是整条链路最关键的节点。

更新完任务状态以后,系统要判断下一步怎么走。

大致有四种出口。

  1. 继续推进。
    新证据足够明确,任务还没完成,就回到“组装本轮上下文”,开始下一轮。

  2. 失败恢复。
    命令失败、测试失败、权限被拒绝、上下文不足时,系统要判断能不能换路。能恢复,就回到“模型判断下一步”,带着失败证据重新决策。

  3. 询问用户。
    缺少业务判断、权限需要确认、目标边界不清楚时,系统要问用户,而不是硬猜。

  4. 验证收束。
    完成条件已经满足,验证证据也够了,才进入收束。

这里接上 Agent Loop 和 Fallback & Recovery。

前面 09 里有一句对我很重要:

重试应该带着新信息发生。

如果失败以后只是反复跑同一个命令,那不是恢复,只是在原地打转。真正的恢复,是先把失败分类,再决定读更多信息、换工具、改计划、询问用户,或者停下来说明阻塞。

11. 询问用户:用户补充会改变任务状态

询问用户不是打断流程,而是主循环的一种正常出口。

有些判断 agent 自己不该替用户做。

比如:

  • 有两个业务方案,应该选哪个。
  • 当前文件已有未提交改动,是否可以基于它继续改。
  • 某个命令可能影响数据,是否允许执行。
  • 任务边界不清楚,是修一个 bug,还是顺手重构一片代码。

用户回答以后,不是简单把回答追加到聊天记录里。

它应该回到任务状态:目标可能更新,约束可能变化,权限边界可能改变,下一轮上下文也要重新组装。

这一步解释了为什么图里“询问用户”会回到“更新任务状态”。

用户不是链路外的干扰,而是任务状态的重要来源。

12. 验证收束:用证据判断能不能停

很多弱一点的 agent,会在改完代码以后马上总结。

但 coding agent 的停止条件应该来自验证。

验证收束至少要看几件事:

  • 完成条件是否满足。
  • 相关测试、构建或检查是否通过。
  • 改动范围是否集中。
  • 是否引入了额外文件或生成产物。
  • 失败是否已经处理,或者明确说明了阻塞。
  • 剩余风险是否需要告诉用户。

比如修复 loading 问题,最小验证可能是跑前端检查、相关测试,或者至少确认修改路径和错误分支逻辑。
如果没有跑完整浏览器流程,也要把它作为剩余风险说清楚。

验证不是最后附带跑一下命令,而是主循环判断能不能停下来的证据。

13. 最终回答:从状态和证据里压缩结果

最终回答应该来自任务状态和验证证据,而不是临场发挥。

它通常要交代:

  • 做了什么。
  • 改了哪些文件。
  • 为什么这样改。
  • 怎么验证。
  • 还有什么风险。
  • 是否建议后续补测试或继续处理。

如果任务产生了可复用经验,还可以生成记忆候选。

但记忆候选不等于自动长期保存。一次具体 bug 的细节,通常留在会话记录、diff 或任务记录里就够了。项目常用命令、稳定约定、用户反复强调的偏好,才更适合进入长期记忆。

这一步把 Task State、Observability 和 Memory 接起来。

最终回答看起来只是一段文字,但它背后应该有一条完整链路支撑:目标、证据、工具结果、权限记录、验证结果和剩余风险。

如果我自己做 Agent,会先跑通这条链路

如果从零做一个 coding agent,我现在会先做一条很小但闭合的主链路。

第一版不需要很花。

最小能力为什么先做
任务状态让目标、完成条件和风险可见
上下文组装让模型每轮看见该看的材料
工具协议让模型意图能变成受控动作
权限裁决控制写文件、命令和外部调用风险
结果回流让工具输出变成下一轮证据
失败恢复让任务卡住时能换路
验证收束用证据判断任务是否完成
运行记录让过程可复盘

我会先让这条链路在本地仓库里跑通,再考虑更复杂的扩展。

原因很简单:主链路不稳,扩展能力只会放大混乱。

没有任务状态,接 skill 也会跑散。
没有权限裁决,接 MCP 会扩大风险。
没有结果回流,工具越多,上下文越乱。
没有运行记录,subagent 多了以后更难知道谁做了什么。
没有验证收束,最终回答就只是模型自信地说“完成了”。

所以第一版目标不是能力最多,而是闭环清楚。

用户目标能进入系统,系统能观察真实仓库,能做最小修改,能验证结果,能记录过程,失败时能换路或停下。

这就已经是一个 coding agent 的骨架了。

系列最终收束

现在回到 00 里那个问题:

AI Agent 如何从一次聪明的回答,变成一个可维护、可调试、可协作的工程系统?

写完这一圈,我的答案更清楚了。

模型能力当然重要,但它只是链路中的一环。

真正让 agent 成为工程系统的,是用户目标进入以后,系统能持续维护状态、选择上下文、裁决动作、执行工具、回收结果、恢复失败、验证结果,并把过程留下来。

Claude Code 对我最大的启发,也在这里。

它的价值不只是“能写代码”,而是把写代码这件事放进了一套运行时链路里:有工具、有规则、有权限、有上下文、有失败恢复、有记录,也有最终验证。

以后再看其他 coding agent,我会先问同一个问题:

它能不能把一个模糊用户目标,沿着一条可观察、可控制、可验证的链路,一轮一轮推进到结果?

如果能,这个 agent 才真的从“会回答”往“能工作”走了一步。

参考资料

本系列前文