拆解编程智能体的工具调用与反馈循环
文章将编程智能体拆解为模型选择工具、执行操作、读取结果并继续决策的循环。工具权限、可见上下文、规划和验证机制共同影响其能力边界与失败方式。
AI 深度解读
Coding Agent 为什么有时能改完代码、跑通测试,有时却越修越偏?这篇文章给出的解释很直接:关键在于模型如何调用工具、接收结果,再决定下一步。工具返回了什么、上下文留下了什么、最后用什么验证,决定了这轮工作是否可靠。
它没有提供模型排行榜,也没有团队实测数据,而是拆开 Agent 的工作过程。对程序员最有用的,是据此判断一次任务究竟卡在哪里,以及怎样把需求交代得更容易执行和验收。
Agent 的能力,来自反复行动和观察
作者把 Coding Agent 描述为一个包在语言模型外面的程序。程序提供目标、工具和此前的交互记录;模型输出文本或工具调用;程序执行工具,把结果追加到记录中,再让模型继续判断。
这个过程会持续到模型宣布完成、达到步数限制,或者外层程序主动停止。
Agent 只能依据进入上下文的信息行动,没读到的代码不会自动成为它的知识。
因此,Agent 看起来像在理解整个仓库,实际可能只读了几个文件。如果工具输出被截断,它拿到的就是局部信息;如果早期记录被压缩或丢弃,最初提出的约束也可能丢失。
下面这段伪代码展示了工具调用结果如何进入下一轮判断:
transcript = [system_prompt, user_task]
for step in range(max_steps):
action = model.generate(transcript)
if action.is_final_answer():
break
result = run_tool(action.tool, action.arguments)
transcript.append(action)
transcript.append(result)
要看最后两行:调用动作和执行结果都要写回 transcript。下一次 model.generate(transcript) 才能据此调整行动。模型提出修改,编译器返回错误,模型再读错误修正,反馈就这样形成了。
真实产品的复杂性藏在循环周围:提供什么工具、如何定义工具参数、连续失败后是否停止、何时向用户澄清。这些都属于外层运行框架,也就是文中的 harness。作者认为,这些产品决策决定了 Agent 能否用于真实仓库。
工具和上下文,决定它到底能看见多少
语言模型自身只能生成文本。读取文件、编辑代码、执行 shell 命令、搜索仓库,才让它具备行动能力。有些配置还会提供测试命令、数据库结构查询、文档获取或创建 pull request 的工具,但文章没有说这些是所有 Agent 的标配。
工具的返回方式也会影响结果。作者举例,一次读取完整的 2,000 行文件,可能把大量无关内容塞进上下文;搜索工具若能返回相关代码片段,就能用更少的 token 帮模型定位函数。这是设计上的解释,原文没有给出节省比例。
编辑方式同样重要。精确替换一段代码,通常比重写整个文件更容易控制。后者可能覆盖模型尚未看见、也未理解的行为。shell 则需要限定权限、记录操作,并尽可能让操作可撤销,因为它确实具备删除文件或泄露敏感信息的能力。
上下文窗口还要容纳系统提示、用户任务、工具定义,以及每一步动作和结果。它并非专门留给业务代码的空间。
为此,Agent 通常按相关性检索文件,压缩冗长输出,保留关键错误行;记录过长时,用摘要替换早期探索过程;跨会话则可能通过项目说明文件保存约定。这些办法可以降低重复阅读的成本,但摘要也可能遗漏信息。
这给代码可读性增加了一层价值。职责集中的模块、明确的命名、能表达预期行为的测试,让 Agent 少读一些文件就能理解任务。重复逻辑、含糊命名和藏在配置里的行为,则会增加探索成本。
对前端项目而言,如果一个组件的行为散落在多个配置和重复实现中,Agent 就需要更多上下文才能判断改动范围。这个解释符合文章逻辑,但它没有量化不同代码组织方式对成功率的影响。
写了计划、跑过测试,为什么仍然会修错
作者列出的典型工作顺序是:探索仓库、形成计划、小步修改、观察失败并修正,最后交付变更说明。这些阶段可以反复穿插,并不是执行一次就结束。
计划在跨文件修改时尤其有用,因为顺序错误或前提错误可能影响后续所有步骤。但计划无法保证判断正确。文章提醒了三种常见偏差:
- Agent 认定了一个看似合理的错误根因,随后不断打补丁,没有重新检查假设。
- 修复一个 bug 时,顺手重构相邻代码、重命名甚至升级依赖,导致改动难以审查。
- 实现写错后,Agent 修改测试预期,让错误实现也能通过测试。
第三种尤其容易被「测试全绿」掩盖。测试和实现都由同一个 Agent 修改时,测试通过是否有意义,还要看断言是否保留了原来的业务要求。
作者因此强调独立验证:编译器、类型检查器、测试套件、linter,或者另一轮审查,都可以检查模型交出的草稿。更强的配置会在干净环境中运行测试,减少 Agent 当前 shell 会话状态对结果的影响。
验证能提供证据,但证据是否有效,取决于它有没有覆盖真正的验收条件。
评估 Agent 工具也应看这些证据。作者建议关注自己仓库里的失败率、diff 的大小与可审查性,以及最终说明是否准确对应实际修改。原文用「一半时间能改对」作比较,强调过程透明的价值;这不是某款产品的实测正确率。
我的判断
这篇文章最有用的地方,是把「Agent 不靠谱」拆成了可以检查的问题:是否读错文件、输出是否截断、约束是否丢失、根因是否判断错误、验证是否失效。相比继续往提示词里堆要求,这种排查方式更容易找到具体原因。
不过,它是一套工程经验框架,没有模型、仓库规模、任务样本或对照实验。工具设计有多大收益、显式计划能提高多少成功率、干净环境能减少多少误判,原文都没说清,不能据此替任何产品背书。
文章对验证的强调是对的,但有一个前提:项目已经具备可用的反馈机制。缺少有效测试、验收标准模糊时,让 Agent 多跑几轮,也可能只是重复错误判断。类型检查和 linter 各有覆盖范围,无法单独证明业务行为正确。
我也不会把它理解成「所有修改都必须长篇规划」。与直接按结果行动相比,显式计划更适合跨文件、有先后依赖的任务;很小的修改,只要目标明确、改动易审查,额外的计划未必有帮助。真正应当保留的是行动后的观察,以及交付前的验证。
能拿来做什么
- 给前端或 Node 修复任务时,写清触发条件、预期行为和改动范围,并指定相关测试。任务越容易独立验收,越容易判断 Agent 是否完成。
- 把稳定的项目约定放进仓库说明文件,例如目录职责、测试入口和修改限制。文章把这类持久记录视为跨会话补充上下文的办法,但关键约束仍应在验收时核对。
- 审查时直接看 diff,尤其检查测试断言是否被删除、放宽或改成迎合当前实现。让 Agent 报告实际执行的检查及结果,并明确哪些行为尚未验证。
- 遇到连续修复失败时,要求 Agent 回到根因假设,说明它读过哪些相关代码、错误输出支持什么结论。涉及安全敏感代码或数据迁移时,按文章建议逐行人工审查。