核心循环:ReAct 的工程化
先解释 ReAct:Reasoning + Acting,让模型在「推理一步」和「行动一步」之间交替——想一下该做什么,做一个动作,看一眼结果,再想下一步。Coding Agent 就是这个循环的工程化产品,围绕一个目标持续运转:
- 目标:接收任务,比如「修复这个失败的测试」
- 计划:拆解出步骤——先看什么文件、改哪里、怎么验证
- 执行:调用工具,读文件、改文件、跑命令
- 观察:读取工具返回的结果——报错、输出、diff
- 修正:根据观察更新计划,回到执行
循环持续到任务完成,或者触发「需要人决策」的中断条件。与聊天机器人的一次性问答不同,这里的每轮「输出」不只是文字,还包括对真实世界的动作——写一个文件、执行一条命令都会真实生效,所以「观察」环节读到的必须是工具返回的真实结果,而不是模型想象的产物。听起来简单,工程难度全在循环的每个环节怎么做得稳,下面逐个看。
上下文管理是生命线
模型一次只能「看见」上下文窗口里的内容,上下文管理因此是 Agent 的第一生命线。常见手段有四类:
- 仓库级检索:不把整个仓库塞进去,而是先用关键词搜索(grep 类)或语义检索定位相关文件,再按需读取片段
- 选择性读取:读文件支持按行号范围读取,而不是把大文件整个读入
- 历史压缩:长任务把早期的对话与观察摘要成一段小结,给后续步骤腾出空间
- 任务清单外置:把 todo 清单作为结构化状态维护在上下文里,每完成一项就更新——防止十几步之后「忘了最初要干什么」
上下文溢出是大多数失控的起点:早期约束被挤出窗口,Agent 就开始违反自己几分钟前定下的规矩。
验证闭环:能跑测试的 Agent 强得多
同一个模型,接上「能跑测试」的环境,表现会强一大截。原因在反馈信号的性质:测试是廉价、客观、机器可读的结果反馈——通过就是不通过,不需要模型自我感觉良好,也不需要人守在旁边。
验证手段按可靠性排:
- 测试(单元测试、集成测试):最理想的反馈
- 编译与类型检查:次优,至少保证代码是「对的形状」
- Lint 与静态检查:抓风格问题与常见错误
- 人工确认:没有自动化信号时的兜底,Agent 应该在关键节点停下来问,而不是硬着头皮宣布完成
这也是为什么测试覆盖好的仓库,Agent 干活质量明显更好——不是模型变强了,是反馈信号变清晰了。
权限与沙箱
Agent 会执行命令、改文件,权限设计必须分级:
- 只读:搜索、读文件、跑无副作用的命令——默认允许
- 工作区写入:改文件、新建文件——允许但限制在项目目录内
- 执行与网络:跑 shell 命令、安装依赖、访问网络——逐次确认或白名单
默认最小权限的原因很直接:模型有偶发幻觉,错误不可能完全避免,而不同操作的代价不对称——读错的代价是几秒,删错文件、推错分支的代价可能是几小时甚至几天。沙箱(容器、受限运行环境)把这个不对称再压低一层。
典型失败模式
- 在同一个错误上打转:改一版、报错、再改一版还是同样的错。根因往往是缺新信息而不是缺努力——正确做法是换假设、找新证据,而不是把同一个修法再试一遍。工程上的对策是给「重复同一操作」设计数:连续几次结果相同,就强制换思路、扩大检索范围,或者停下来求助
- 过度自信的大范围删改:为了一个局部目标重构半个仓库。好的 Agent 会先做小步验证,差的会一把梭
- 上下文溢出后遗忘约束:改完新功能,把早期约定的兼容性要求弄丢了。这正是任务清单外置与历史压缩要防的事
整体流程
graph TD
A[接收目标] --> B[制定计划]
B --> C[执行工具调用]
C --> D[观察结果]
D --> E[验证测试与编译]
E --> F{通过?}
F -->|是| G[完成任务]
F -->|否| H[修正计划]
H --> B
小结
- Coding Agent 的核心是 ReAct 循环:目标、计划、执行、观察、修正,工程难度在把每个环节做稳
- 上下文管理是生命线:检索代替全量、选择性读取、历史压缩、任务清单外置
- 验证闭环决定上限:测试是廉价且客观的反馈信号,测试覆盖越全,Agent 表现越好
- 权限默认最小,读、写、执行分级授权
- harness(工具集、循环与验证机制的设计)与模型同样重要:同一个模型配上不同的 harness,表现可以差出量级
读者留言
COMMENTS 暂无还没有留言,来说第一句?