Appearance
Coding Agent 到底怎样工作:从模型回答到工具执行循环
系列第 02 篇
关键词:Harness、Tool Calling、Context Window、Permission、Stop Condition
最后核验:2026-07-20
对应视频:第 02 集《Coding Agent 到底怎样工作:模型、工具与验证闭环》
当一个 Chat 模型回答“可以在 OrderService 中增加取消逻辑”时,它只生成了一段建议。当一个 Coding Agent 搜索 OrderService、打开相关测试、修改多个文件、运行 Maven、根据编译错误补上接口方法,再展示 Diff 时,它已经进入了完全不同的运行模式。
两者可能使用相同模型,但工程风险不一样。前者的输出仍然停留在文本层;后者通过工具改变了文件系统和进程状态。理解 Agent 不能只研究 Prompt,还要理解负责组织模型、工具、权限和上下文的 Harness。Harness 决定模型能看到什么、能做什么、何时需要审批、失败后怎样恢复,以及什么条件下可以停止。
阅读路线:先看全局,再进入机制
视频版先展示整章地图,再逐层展开。博客沿用同一判断顺序,但保留更多机制、案例、失败模式和生产边界:
- 模型不是 Agent:先拆开模型、Harness、上下文、工具、权限和反馈。
- 工具与上下文:理解一次调用如何购买新信息,以及工作记忆怎样退化。
- 权限与停止:把审批、沙箱和完成条件放进执行循环。
- 可靠轨迹:从第一次偏离的位置诊断失败,而不是笼统归因于模型。
这四步不是目录装饰,而是一条决策链:模型不是 Agent → 工具与上下文 → 权限与停止 → 可靠轨迹。阅读后面的案例时,可以随时回到这条链判断当前问题发生在哪一层。
真实问题:为什么模型明明懂代码,Agent 仍会走错
一个常见调试场景是:Agent 先搜索一个宽泛关键词,读到旧模块中的相似实现,然后围绕旧实现制定计划。之后每一步都很连贯:它编辑正确的语法,运行局部测试,甚至补充文档。但任务真正相关的是另一个模块。问题不是某一行代码生成错误,而是第一轮环境观察选错了证据。
另一个场景是 Agent 修改后运行 mvn -Dtest=OrderServiceTest test,看到通过便宣布完成,却没有运行 MockMvc 集成测试。它并非故意撒谎,而是停止条件只要求“相关测试通过”,而“相关”由它自己判断。没有外部定义的完成门禁,自评会自然偏向结束。
要解决这类问题,需要把 Agent 看成控制系统:它接收状态,选择动作,动作改变环境,环境反馈再次进入决策。任何一环的信息不完整或权限过宽,都会放大后续偏差。
机制:Agent 的六层运行结构

最上层是用户目标。系统指令和仓库规则为目标增加边界。上下文承载当前能被模型使用的信息。模型根据这些信息产生下一动作。工具执行动作并返回结果。反馈被加入上下文,循环继续。权限系统横切整个过程,决定某个动作能否自动执行、需要审批或必须拒绝。
这六层中,模型只是决策器。搜索是否能定位正确文件、编辑器能否精确应用修改、终端是否保留完整退出码、浏览器是否能稳定截图、上下文是否在压缩后保存关键非目标,都属于系统能力。
1. 工具循环不是“模型一次想完”

一次典型循环可以写成:
text
observation -> choose action -> invoke tool -> receive result -> update state例如修复测试失败时,第一轮模型只知道错误摘要。它可能先搜索错误类名,读取实现与测试;工具返回代码后,模型才有足够信息提出修改;编辑工具返回成功不代表代码正确,还要运行测试;测试失败又形成新 observation。Agent 的“思考”分布在整个轨迹上,并非第一轮就拥有完整方案。
因此,工具结果的质量非常重要。一个只返回“command failed”的终端工具,迫使模型猜测;一个返回退出码、标准错误、失败测试名和堆栈的工具,能让下一动作基于证据。结构化反馈通常比更长的 Prompt 有用。
2. Harness 是 Agent 产品差异的核心

Harness 至少承担六类职责:
- 提示编排:合并系统指令、用户目标、仓库规则与工具说明。
- 工具路由:把模型产生的调用转换为实际搜索、编辑、Shell 或 MCP 请求。
- 上下文管理:选择文件、裁剪长输出、压缩历史、恢复会话。
- 运行控制:处理超时、重试、后台会话、并发和中断。
- 用户交互:展示 Diff、请求审批、接收纠偏和排队消息。
- 证据记录:保存命令、日志、截图、提交和最终摘要。
比较 Codex、Claude Code、Cursor 或 Copilot 时,只问“默认模型是谁”会漏掉大部分实际体验。某个 Harness 可能让模型在代码搜索上表现更稳定,另一个在 UI 浏览器验证上更完整,第三个在 Git 平台留下更清晰的审计轨迹。
3. 上下文窗口是有损工作记忆

Agent 会话把系统指令、对话、读取的文件、命令输出和工具结果共同放入上下文。随着调试深入,长日志和多轮修改会快速占用预算。达到阈值后,Harness 可能裁剪旧结果或压缩历史。压缩通常能保留“我们要增加取消功能”,却容易丢失“不要修改数据库结构”或“重复取消不能再次保存”这样的细粒度否定条件。
这解释了为什么长会话后 Agent 有时像“忘记”早期约束。模型不是拥有持久记忆,而是在每次推理时读取当前上下文。关键约束如果只存在于二十轮之前的聊天中,就可能在压缩后变弱。稳定信息应进入任务文件、AGENTS.md、测试或计划,而不是依赖对话历史。
4. 工具描述会影响工具选择

当一个 Agent 同时拥有文件搜索、代码语义搜索、Web 搜索、多个 Git 工具、三个数据库 MCP 和两个相似的浏览器工具时,模型需要先从大量候选中选择。每个工具的描述本身也占用上下文。相似工具越多,选错概率和参数错误越高。
工具工程的原则不是“尽可能连接”,而是“当前任务最小充分”。需要查本地代码时不必开放生产数据库;只读分析时不必开放写 Issue;已有可靠 CLI 时不必为了协议统一再包一层含义模糊的工具。
一个好工具应有明确名称、窄输入 Schema、结构化结果、稳定错误语义、幂等或 dry-run 能力。Agent 很难可靠使用要求人类从噪声日志中凭经验挑重点的命令,因此团队常需要把复杂内部流程包装成更清晰的脚本或 Skill。
5. 权限不是弹窗数量,而是破坏半径

理想权限模型不是所有动作都询问,也不是全部自动批准。只读文件搜索通常可以自动执行;工作区内的文件编辑可以根据仓库信任级别批准;测试和构建命令可以进入白名单;网络、越界路径、系统配置和破坏性操作应逐次审批或拒绝;组织策略则必须独立于模型,用户会话不能通过 Prompt 覆盖。
频繁弹窗会产生审批疲劳。用户一旦形成“总是点允许”的习惯,权限系统只剩形式。解决办法是把安全且高频的动作做成窄白名单,把高风险动作保持少量而明确,而不是取消所有门禁。
沙箱也不是正确性证明。它限制文件系统、网络和进程的影响范围,却不会阻止 Agent 在允许目录里写出错误业务逻辑。权限和验证解决的是两个不同问题:前者控制“最多能破坏什么”,后者判断“结果是否符合预期”。
6. Agent 为什么提前停止

语言模型很擅长判断文本是否“像一个完成的答案”。代码修改后没有显眼语法错误,文件之间看起来一致,它就可能认为任务完成。如果没有可执行检查,用户自然成为唯一反馈环:错误要等人工阅读或线上行为才暴露。
有效停止条件应尽可能外部化:
text
停止前必须满足:
1. 新增测试在实现前能够失败;
2. 实现后相关测试通过;
3. 全量测试和静态检查通过;
4. Diff 不包含范围外文件;
5. 未验证项在最终报告中明确列出。更严格的系统可以用 Stop Hook 重新运行检查,在失败时阻止 Agent 结束。也可以由独立验证会话尝试反驳结果。关键不是无限重试,而是让“完成”由外部信号定义。
7. 轨迹质量比最后一段代码更值得观察

可靠轨迹通常有几个特征:搜索范围逐步缩小;每次读取都与当前问题有关;修改量与任务范围匹配;测试从窄到宽;失败后回到最近证据,而不是继续增加假设。
失败轨迹则常见全仓无目标扫描、一次修改几十个文件、运行错误命令后绕过检查、连续追加 Prompt 修补错误方向。即使最后侥幸通过测试,这种轨迹也难以审查和复现。
当发现轨迹已经建立在错误假设上,最有效做法往往不是继续说“再检查一下”,而是回退到干净节点,修正任务或计划后重新执行。错误轨迹越长,模型越倾向于维护自己已经产生的结构。
8. Plan Mode 不是形式化仪式

Plan Mode 的价值是把不可逆或高成本动作推迟到关键判断被审查之后。Agent 先只读探索,列出当前调用链、相似实现、约束和候选方案;在存在多个合理方案时,计划记录选择理由、文件改动面、测试策略和风险;用户确认后再开放编辑权限。
对于改错别字、增加一条日志或已有模式下的小测试,计划可能比实现还长,应直接执行并验证。判断标准不是文件数量,而是方向错误的代价:跨模块、陌生系统、数据迁移和公共接口适合先计划;能够用一句话准确描述 Diff 的任务通常不需要正式计划。
可运行实践:观察一个最小 Agent 循环
在任何支持终端的 Coding Agent 中,可以用下面的请求观察它是否真正形成闭环:
text
读取订单服务和现有测试,先不要修改。
找出创建订单从 HTTP 到存储的调用链,并列出证据文件。
然后运行现有测试,报告命令、退出码和测试数量。
如果基线通过,给出增加取消订单能力的最小计划;
计划必须包含范围、非目标、失败测试和最终验证命令。检查的不是回答是否漂亮,而是:它是否先搜索再下结论;是否引用真实文件;是否运行正确目录下的命令;是否区分测试输出中的预期警告与真正失败;是否在计划中保留非目标;是否没有提前编辑。
进一步可以故意给它一个不存在的文件名,观察它会否直接声称已读取,还是先用搜索纠正事实。一个可靠 Agent 应让环境证据覆盖用户和模型的错误假设。
失败模式
失败一:只优化 Prompt,不检查工具结果
复杂 XML Prompt 可以让目标更有结构,却不能修复错误工作目录、缺失依赖、被截断日志或搜索索引过期。先检查 Agent 实际读到了什么、命令在哪个目录运行、退出码是什么,再决定是否需要改写 Prompt。
失败二:把大输出当成充分上下文
完整粘贴几万行日志通常降低定位效率。更好的方式是保留失败测试名、第一处根因堆栈、环境版本和复现命令,必要时让 Agent按符号继续读取。上下文的目标是支持下一决策,而不是保存所有字节。
失败三:工具调用失败后不断重试
如果命令因为缺少网络、Secret 或系统依赖失败,重复同一调用只消耗时间。Agent 应区分暂时失败、参数错误和能力缺失;报告阻塞条件,寻找本地替代或请求明确授权,而不是尝试绕过权限。
失败四:让实现 Agent 自己证明自己正确
同一会话拥有相同假设和上下文,容易产生确认偏差。实现者可以运行测试,但复杂逻辑还应由新上下文 Review、静态工具和责任人检查。第二意见的任务应是“尝试找到能推翻实现的场景”,而不是“总结为什么正确”。
失败五:把 Plan 当成冻结事实
计划基于探索时的证据。实现中如果发现接口、测试或环境与计划不符,应暂停并更新计划。机械坚持过时计划,与没有计划一样危险。
生产边界
工具调用把 Prompt Injection 从“让模型说错话”升级为“诱导模型采取动作”。仓库文件、Issue、网页、日志和 MCP 返回都可能包含伪装指令。Agent 必须把外部内容视为不可信数据,敏感工具保持审批,凭据采用最小 Scope,网络采用白名单,执行环境保留审计。
长时间后台任务还要考虑环境漂移:依赖是否锁定,服务是否可在 VM 内启动,Secrets 是否只在任务内有效,分支是否限制 push 目标,任务结束后环境是否清理。一个人类开发者都无法按 README 复现的仓库,不会因为换成 Agent 就自动可复现。
生产环境还需要观察 Agent 自身:每类任务使用了哪些工具、平均多少轮、最常在哪一步失败、人工在何处接管、哪些命令重复报错。这里的目的不是监控开发者输入,而是识别系统性摩擦。如果大量任务都在安装依赖时失败,应修复环境脚本;如果 Agent 总读错模块,应改进仓库地图或搜索入口;如果测试通过后仍大量返工,应重新审视验收覆盖,而不是简单更换模型。
实践清单
- [ ] 能画出当前 Agent 的模型、Harness、工具、反馈和权限边界。
- [ ] 关键任务使用真实环境证据,而不是模型常识。
- [ ] 工具集合保持当前任务最小充分。
- [ ] 命令结果包含工作目录、退出码和关键失败信息。
- [ ] 稳定约束进入仓库文件或测试,不只存在于对话。
- [ ] 长日志经过聚焦,保留根因和复现信息。
- [ ] 高风险动作由客户端或组织策略强制审批。
- [ ] 停止条件绑定测试、构建、截图或真实路径。
- [ ] 复杂改动使用新上下文进行反驳式 Review。
- [ ] 轨迹明显偏离时回退重做,不无限追加 Prompt。
读完之后,你应该能完成什么
- 能画出 Coding Agent 的完整工具调用循环。
- 能区分模型问题、Harness 问题和仓库环境问题。
- 能为任务配置外部停止门禁。
- 能用只读实验校准搜索、工具和证据质量。
如果只能复述概念,却不能完成上述动作,说明还没有把内容转化成工程能力;可以回到对应机制图、失败模式和实践清单重新核对。
小结
Coding Agent 的能力来自模型与环境的组合。模型选择下一动作,Harness 管理上下文和工具,权限限制破坏半径,测试和真实路径决定是否完成。理解这套机制后,很多“模型忽然变笨”的问题会变得可诊断:可能是搜索选错、上下文污染、工具反馈不足、权限缺失或停止条件过弱。
下一篇将把这些机制映射到 2026 年主流产品,建立不依赖营销名称的选型维度,并单独讨论中文团队的网络、数据和组织治理问题。
