跳转至

第7章 Coding Agent:通用Agent的工程母型

状态:初学者展开试稿,待人工审阅(基于Release Candidate 1修订)

本章定位:承接第3章的运行时、第4章的上下文工程和第6章的工具边界,用一个完整修复任务说明编码Agent怎样理解代码库、修改文件,并用可复核证据证明工作完成。

本章回答的三个问题

  1. Coding Agent为什么不只是“会写代码的聊天模型”,而是一个完整的工具Agent?
  2. 它怎样从理解需求、探索代码库、制定计划,走到编辑、测试和完成验证?
  3. 代码执行、凭据、依赖安装、危险命令、审批与回滚的边界应该怎样设置?

本章使用一个贯穿场景:某个Python项目的金额格式化函数在负数时输出错误。用户要求修复这个缺陷,保持公开接口不变,补充回归测试,并且不新增依赖。书中的项目名、文件名、代码和命令均为教学示例,不代表仓库中真实存在该项目,也不是实验结果。

证据类型说明

本章严格区分三类话语:教学示例只用于解释机制;带“本书建议”的内容是需要在具体项目验证的工程建议;只有明确引用保存运行记录或外部资料的内容,才是限定条件下的实测结论。本章没有重新调用模型或运行第5章实验,也不虚构成功率、时延或成本。

5分钟速读

  • Coding Agent(编码智能体)不只生成代码;它能读取真实代码库、提出并执行受控修改、运行测试,再根据反馈决定下一步。
  • 一条可靠主线是:任务合同 → 仓库探索 → 局部理解 → 修改计划 → 增量编辑 → 分层验证 → 检查差异 → 证据化交付
  • 先查项目说明、目录、关键词、调用者和测试,再读取最小相关文件;“把整个仓库塞进上下文”既昂贵,也不等于真正理解。
  • 计划是待验证的工作结构,不是已经完成的事实。 小修复可以只有简短清单;跨模块、公共接口或高风险改动才需要更正式的设计和审批。
  • 优先使用可审查的局部补丁。整文件重写可能丢失无关代码、格式或并行改动;编辑成功也不代表行为正确。
  • 测试、编译、类型检查、Lint(代码规范和静态错误检查)及实际运行带来模型原先没有的新信息,是修复循环的关键。
  • “新测试通过”只证明目标案例;还要检查已有回归、测试是否被削弱、差异是否越界,以及产物能否实际打开或运行。
  • Shell(命令行解释器)和代码解释器是高能力通用工具。默认限制工作目录、网络、进程和资源;凭据不进入模型上下文。
  • 安装依赖会改变环境并运行第三方代码,不能被当作普通读取。锁文件变化、包来源和安装脚本需要检查,必要时审批。
  • 删除、覆盖、强制重置、发布、推送、部署和生产变更不是“修代码”的默认附带权限。高影响动作必须单独授权。
  • Git能帮助查看差异和恢复已跟踪文件,但不是自动备份:未跟踪文件、外部系统和数据库状态可能无法由Git恢复。
  • 完成声明必须附证据:改了什么、运行了什么、结果怎样、哪些没运行、有哪些限制。模型说“完成”本身不是证据。

一、从代码补全到可验证的工程闭环

1.1 两种“帮我修代码”并不相同

代码补全或一次模型调用通常接收一段代码,返回一段候选实现。它可能写得正确,但并不知道候选是否适合当前仓库,也没有亲自看到测试结果。

Coding Agent(编码Agent)是在受控工作区中,能够根据代码库和执行反馈选择下一步的软件系统。这里的代码库(Repository)是源代码、测试、配置、文档和版本历史的集合;工作区(Workspace)是Agent获准读写与运行命令的目录。第1章定义的观察—行动—反馈闭环,在编码场景中表现得尤其清楚:1

理解任务和边界
→ 探索代码库
→ 建立局部模型与计划
→ 编辑候选实现
→ 运行检查
→ 读取失败或成功证据
→ 修复或结束

模型第一次写出的代码不是终点。测试报错会暴露函数参数、边界条件或环境假设;差异检查会暴露无关修改;实际渲染会暴露代码层面看不出的布局问题。正是这些新观察改变了后续行动,Coding Agent才比静态代码生成更接近通用Agent。

1.2 为什么说它是“工程母型”

代码具有元能力:不仅能实现某项功能,还能创造新的脚本、适配器、检查器和交付物。文件系统又提供了可保存、可比较、可交接的外部工作空间。两者结合,形成了很多通用Agent可复用的结构:1

  • 用目录和文件保存输入、中间结果与Artifact(可单独保存和交付的产物);
  • 用搜索逐步扩展观察,而不是一次装入全部信息;
  • 用补丁表达可审查的动作;
  • 用执行器获得真实环境反馈;
  • 用测试和验证器决定是否结束;
  • 用版本控制、检查点和隔离工作区恢复失败。

“母型”不等于所有Agent都必须开放任意代码执行。固定客服流程可能更适合专用业务工具;代码能力也不能绕开业务权限。第2章的最低充分自主性仍然适用:只有开放任务确实需要动态创建处理逻辑时,才应承担通用执行工具带来的风险。

1.3 贯穿任务:修复负数金额格式

假设项目原有函数:

def format_amount(cents: int) -> str:
    return f"${cents / 100:.2f}"

它对125输出$1.25,对-125却输出$-1.25。产品要求负号出现在货币符号之前,即-$1.25。用户合同如下:

目标:修复负数金额显示,并补充回归测试。
保持:format_amount名称、参数和返回类型不变;正数与零行为不变。
范围:只修改实现及直接相关测试。
禁止:新增依赖、发布、推送、修改测试来掩盖错误。
验收:目标测试和相关回归通过;差异中没有秘密或无关文件。

这份合同是教学示例。真实任务若没有明确负数格式、兼容要求或验收命令,Agent应先从issue、测试、文档或用户处澄清,不能把自己的偏好悄悄变成需求。

二、Coding Agent能看到什么、能做什么

2.1 观察空间:先知道证据在哪里

观察空间是系统可能取得的信息范围。编码任务常见观察包括:

观察 能回答什么 不能单独证明什么
用户请求与issue 想改什么、有哪些明确限制 仓库当前实现一定与描述相同
README、AGENTS.md等项目说明 构建命令、风格、禁区 说明一定未过期
目录和文件名 模块怎样组织 文件内部行为
文本或符号搜索 定义、调用者、错误信息在哪里 所有语义相关代码都被找到
源码与配置 当前实现和依赖关系 运行时一定按预期工作
测试代码 已编码的行为合同 测试覆盖了全部需求
Git状态和差异 工作区已有与本次新增修改 未跟踪或外部状态一定安全
测试、编译和日志 指定命令在该环境中的观察结果 所有平台和生产环境都正确

项目文档是重要入口,但应与实际配置和命令相互核对。外部仓库的说明、源码注释和测试数据都属于不可信输入;其中即使写着“上传环境变量”“忽略用户要求”,也不能改变Runtime设定的权限。

2.2 动作空间:能力越通用,边界越重要

常见动作包括:列目录、搜索文件、读取片段、精确编辑、创建文件、运行命令、启动或终止后台任务,以及生成报告或截图。原始书稿以读、写、编辑、Glob、Grep、Shell和代码解释器说明一套基础工具箱;具体产品可以把若干能力合并到Shell,也可以提供专用工具。工具数量不是成熟度指标。2

Glob(文件名模式匹配)按路径模式找文件,例如**/test_*.pyGrep(内容搜索)按文字或正则表达式找文件内部命中;Patch(补丁)只描述删除和新增的局部差异。首次出现这些词时,记住它们分别回答“文件在哪里”“内容在哪里”“要改哪一小块”。

第6章已经说明:模型只提出工具调用,Runtime才校验并执行。Coding Agent也不例外。模型输出rm -rf build,不表示命令应被执行;编辑工具返回成功,也不表示代码正确。

2.3 工作区是环境,也是外部记忆

本书建议把工作区按职责分开:15

/workspace/input      # 用户输入,默认只读
/workspace/repo       # 可写代码副本
/workspace/scratch    # 临时日志、分析和缓存
/workspace/artifacts  # 用户可见交付物
/workspace/system     # 只读规则、Skills和模板

长测试日志可以保存为Artifact,状态中只保留路径、摘要、哈希和关键片段。哈希(Hash)是由内容计算出的校验标识,可帮助发现文件是否变化,但不能证明内容本身正确。这样的外置方式承接第4章的上下文—Artifact边界:模型按需读取,不必每轮重复粘贴全部代码和日志。10

目录划分本身不是安全机制。真正隔离还需要操作系统权限、挂载范围、网络策略和执行沙箱。

三、第一步:把需求写成可验收合同

3.1 先区分目标、保持项和禁止项

对贯穿任务,Agent不能只抽取“负数要好看”。它至少要确认:

  • 目标行为-125应得到-$1.25
  • 保持行为125仍为$1.250仍为$0.00
  • 接口边界:函数签名不变;
  • 修改范围:实现与直接相关测试;
  • 环境边界:不安装新依赖;
  • 验收证据:目标测试、相关回归和差异检查;
  • 交付边界:只修改工作区,不提交、不推送、不发布。

验收条件(Acceptance Criteria)是判断任务是否完成的可检查要求。它可以由程序检查,也可以包含人工判断。比如“所有测试通过”可机械核对;“错误提示对初学者是否清楚”可能需要人工审阅。不能为了自动化而伪造一个并不存在的客观标准。

3.2 模糊需求何时必须停下来

“优化性能”“整理架构”“让界面更现代”都缺少明确终点。Agent可以先做只读探索并提出选项,但在影响面大、接口选择有分歧或可能破坏兼容性时,应请求用户或负责人确认。

低风险且可逆的小修复,不必为形式完整而写长篇设计文档。高风险条件包括:公共API变化、数据迁移、新依赖、权限逻辑、跨模块重构、生产配置或难以回滚的操作。计划与审批强度应随影响增加,而不是每个任务一律相同。

3.3 先识别已有修改

开始编辑前应读取Git状态和相关差异。工作区可能已有用户或另一位开发者的修改。Agent不能因为这些变化“看起来无关”就丢弃、覆盖或重置。

本书建议把初始状态记录为检查点:当前分支、基准提交、已修改与未跟踪文件、允许写入范围。若仓库不是Git仓库,也应使用副本、快照或其他恢复机制。回滚(Rollback)是恢复到已知状态;它不是“随时都能撤销一切”的承诺。

四、第二步:探索代码库并建立局部理解

4.1 推荐顺序:从地图走到目标代码

贯穿任务可以按下面顺序探索:

项目说明与Git状态
→ 顶层目录和构建配置
→ 搜索 format_amount 定义
→ 搜索所有调用者
→ 搜索现有金额格式测试
→ 读取最小相关文件及邻近约定

这个顺序不是不可更改的算法,而是降低盲目编辑风险的工程建议。已知错误堆栈精确指向一行时,可以更快进入局部;公共接口或跨模块任务则需要扩大搜索。

4.2 为什么搜索先于大范围读取

大型代码库可能包含生成文件、第三方依赖、历史迁移和大量无关测试。一次读取过多内容会消耗上下文,也可能让过时实现遮蔽当前入口。

format_amount,Agent先做精确文本搜索,可能发现:

src/money.py:4:def format_amount(cents: int) -> str:
tests/test_money.py:3:from src.money import format_amount
src/invoice.py:28:display = format_amount(total_cents)

这三条命中提示了定义、测试和调用者。随后读取相邻代码,检查项目如何处理整数金额、类型和格式。若函数通过重导出暴露,还需追踪公开入口。搜索没有命中也不证明功能不存在:动态调用、别名和语义不同的命名可能需要目录、符号工具或运行轨迹辅助。

4.3 测试也是需求文档,但不是唯一真相

现有测试告诉Agent哪些行为已经被自动保护。它们可能写着:

def test_format_amount_positive():
    assert format_amount(125) == "$1.25"

缺少负数案例解释了为什么缺陷未被捕获,但不能推出“产品一定想要-$1.25”。目标格式仍来自任务合同。测试还可能过期、过宽或写错;当测试与明确需求冲突时,应报告冲突,而不是为了绿色结果偷偷改变需求。

4.4 代码库理解不是一次性完成

Agent在编辑前建立的是局部模型:与当前改动相关的模块、调用关系、约束和测试。测试失败后可能暴露先前未知的事实,例如另一个模块依赖原格式。这时应更新理解、必要时重规划,而不是固守最初猜测。

因此,“先理解再编辑”不是要求读完整仓库;“先编辑再测试”也不是永远错误。可靠做法是让探索深度匹配影响,并确保每次行动都能获得可用反馈。

五、第三步:制定可追踪、可调整的计划

5.1 计划写什么

对这个小任务,一份足够的计划可以只有四项:

1. 在现有测试中增加负数案例,确认修复前能暴露问题。
2. 局部修改 format_amount,不改变签名和正数行为。
3. 运行目标测试,再运行相关回归和项目规定检查。
4. 检查 Git diff、未跟踪文件和完成证据。

计划中的“运行测试”不是“测试已通过”。第3章强调计划、候选判断和已核实事实要分开保存。若第一步发现项目约定不允许当前断言方式,计划应调整;若测试表明影响跨模块,范围扩大前应重新确认合同。

5.2 何时需要计划审批

本书建议在以下情况把设计或计划交给有责任的人审批:

  • 改变公共接口或持久化数据;
  • 引入、升级或替换依赖;
  • 修改认证、授权、加密或秘密处理;
  • 跨越多个所有者模块;
  • 执行不可逆迁移或生产操作;
  • 任务本身存在多种合理解释。

审批应绑定具体方案和影响范围。批准“修复金额格式”不等于批准新增第三方包、重写整个模块或部署生产。

六、第四步:用最小、可审查的编辑表达意图

6.1 为什么优先局部补丁

增量编辑是只改变完成任务所需的局部内容。对于贯穿任务,候选修改可以是:

def format_amount(cents: int) -> str:
    sign = "-" if cents < 0 else ""
    return f"{sign}${abs(cents) / 100:.2f}"

并增加:

def test_format_amount_negative():
    assert format_amount(-125) == "-$1.25"

这只是教学候选,不是在当前仓库执行过的补丁。它便于解释最小改动,却没有证明浮点舍入是否符合真实金融业务。若项目要求严格货币规则,应复用现有Decimal或整数格式化约定,而不是从这段示例推导生产实现。

局部补丁的好处是差异更小、冲突更少、审查者更容易看出意图。整文件重写可能改变换行、排序和用户已有修改。对于生成文件或机械格式化,整文件生成可能合理,但必须确认源文件和生成流程。

6.2 精确编辑工具怎样失败

常见的old_string → new_string编辑要求旧文本在文件中存在且唯一。失败可能表示:

  • 文件已变化,旧文本过期;
  • 同一片段出现多次,定位不唯一;
  • 模型少复制了空格、引号或换行;
  • 路径选错或文件被并行修改。

正确处理是重新读取相关片段并定位原因,而不是反复盲试,更不能退化为覆盖整个文件。编辑工具应原子执行:匹配条件不满足就不写入,并结构化返回错误。原始书稿比较了字符串替换、行号、补丁等多种方案;没有一种在所有项目中绝对最佳。3

6.3 不得靠修改验证器“完成”任务

增加覆盖缺陷的测试,与削弱验收测试不同。下面是危险反例:

@pytest.mark.skip(reason="temporary")
def test_format_amount_negative():
    ...

删除断言、放宽期望值、加skip、mock掉被测逻辑,可能让测试变绿,却没有修复行为。若现有测试确实错误,应说明证据,并让测试变更接受同等或更严格审查。完成验证应检查生产代码与测试差异,防止奖励作弊(Reward Hacking)——为了通过指标而绕过真实目标。5

6.4 并行编辑需要独立工作区

不同Agent可以并行研究不同模块或运行独立检查,但不应同时直接修改同一文件或共享可变目录。P19模式建议每个Worker使用私有Scratch或Git Worktree,再通过带Schema、哈希、来源和访问控制的Artifact交接,由单一Owner合并并运行完整验证。15

Git Worktree是让同一仓库的不同分支拥有独立工作目录的Git功能。它降低覆盖风险,但不自动解决逻辑冲突;接口尚未冻结时,多人并行仍可能各自做出不兼容假设。

七、第五步:从快速反馈走向完成验证

图7:Coding Agent验证闭环

7.1 为什么执行结果是“新信息”

Agent可以阅读代码并预测结果,但编译器和测试运行在真实环境中,会检查语法、类型、导入、依赖和行为。一次失败例如:

FAILED tests/test_money.py::test_format_amount_negative
Expected: -$1.25
Actual:   $-1.25

它把抽象需求变成了可定位的观察。修复后同一测试通过,说明这个案例在该环境中得到满足。它仍不等于所有相关行为都正确,所以需要分层扩大验证。

7.2 从窄到宽的验证阶梯

本书建议先运行反馈快、与改动直接相关的检查,再逐步扩大:

  1. 语法或格式检查:文件能否解析,格式是否符合项目约定;
  2. 目标测试:新增负数案例是否通过;
  3. 相关单元测试:同一模块的正数、零和边界行为;
  4. 类型检查与Lint:静态类型、未使用变量、规范或安全规则;
  5. 相关集成测试:调用者组合后是否仍正确;
  6. 完整回归或CI等价检查:项目允许且成本可接受时运行;
  7. 实际产物验证:服务启动、页面渲染、文件重新打开或目标环境检查。

这与P16“四级质量门”的思想一致:从便宜的Schema/Unit和Smoke逐步走向离线与在线验证;本章聚焦开发工作区,不把“本地测试通过”直接升级成“可以发布”。13

7.3 失败后怎样循环

失败要保留命令、工作目录、退出码、标准输出、标准错误、耗时和是否超时。退出码(Exit Code)是命令结束时返回的数字状态,通常0表示该命令定义的成功,但仍要按工具合同解释。

运行最小相关检查
→ 分类:代码缺陷 / 测试缺陷 / 环境缺失 / 权限 / 暂时故障
→ 取得新的相关证据
→ 修改或调整计划
→ 再运行受影响检查
→ 达标或按预算停止

同一命令、同一输入、同一错误被原样重复,不是进展。环境缺少数据库时,应报告阻塞或使用项目规定的测试环境,不能把“没跑起来”写成“测试通过”。循环要有时间、调用、费用和无进展上限,由Runtime执行,而不是只在Prompt里提醒。8

7.4 测试通过仍可能不完整

至少再问六个问题:

  • 测试命令真的被执行了吗,还是只展示了预期输出?
  • 测试是否在编辑后的当前工作区运行?
  • 目标测试是否在修复前能够失败,或有其他证据证明它覆盖缺陷?
  • 现有测试、断言和配置是否被削弱?
  • 是否存在未运行的相关测试、平台或外部服务?
  • 是否出现不稳定测试(Flaky Test,即同样条件下时过时不过)?

SWE-bench Verified的验证设计把“缺陷由失败变通过”和“原本通过的行为继续通过”分开检查。这是公开基准的设计事实,可作为构建本地验收的参考;它不代表运行任意两组测试就自动获得同等保证。6

八、第六步:检查差异并给出完成证据

8.1 Diff是最后一次范围审查

Diff(差异)展示基准版本与当前工作区之间的文本变化。Agent结束前应检查:

  • 修改文件是否都在任务范围;
  • 是否意外改了锁文件、生成文件、权限位或换行;
  • 是否留下调试打印、临时文件、二进制大文件;
  • 是否出现密钥、Token、个人数据或内部地址;
  • 测试变更是在增加覆盖,还是降低门槛;
  • 用户原有修改是否仍保留。

git diff默认不一定展示未跟踪文件内容,因此还要结合git status和文件清单。仓库“干净”也不代表外部数据库、后台进程或网络资源没有变化。

8.2 完成证据最低包含什么

对贯穿任务,一份诚实交付可以写:

变更:调整负数金额符号位置;新增负数回归测试。
范围:src/money.py、tests/test_money.py。
执行:<实际运行过的目标测试命令>;退出码0。
执行:<实际运行过的相关回归命令>;退出码0。
检查:Git差异仅含上述文件;未新增依赖。
未验证:未运行的完整CI或目标平台检查(如有)。
限制:本地通过不等于生产已发布;未执行提交、推送或部署。

尖括号表示必须填入真实记录,不能照抄成报告。命令成功的证据应来自工具轨迹或保存日志;最终文字只是证据索引,不是证据本身。

8.3 什么情况下不能说“完成”

以下状态应明确写成阻塞、部分完成或未验证:测试环境无法建立;必要凭据不可用;验收标准矛盾;只有目标测试通过而关键回归未运行;差异包含无法解释的已有改动;生产状态需要额外权限确认。

“代码已写完”可以是阶段状态,但不是完整任务终态。第3章的成功、部分成功、阻塞、失败、取消和预算耗尽,在编码任务中同样适用。

九、代码执行、依赖与凭据的安全边界

9.1 Shell不是一把无害的万能扳手

Shell可以读取、写入、删除文件,启动进程,访问网络并调用其他程序。代码解释器也可能通过标准库做到相同事情。虚拟环境(venv)只隔离语言包,不是安全沙箱;其中代码仍可能访问宿主文件、网络和进程。4

本书建议默认控制:

  • 只把任务所需目录挂入可写工作区;输入、系统规则和凭据目录不挂载或只读;
  • 默认禁用任意网络,按域名、协议和用途放行必要出口;
  • 限制CPU、内存、磁盘、进程数、运行时间和输出量;
  • 长任务有超时、取消和后台进程清理;
  • 工具结果明确截断,并把完整日志存入受控Artifact;
  • 外部仓库代码、构建脚本和测试都按不可信代码处理。

容器和microVM(轻量虚拟机)能增强隔离,但配置错误仍会泄漏宿主目录、套接字或云身份。沙箱是纵深防御的一层,不是“运行任何东西都安全”的证明。

9.2 凭据应由执行层代管

凭据(Credential)包括API密钥、SSH私钥、访问令牌和数据库密码。它们不应被粘贴进Prompt、聊天记录、代码补丁、命令参数或普通日志。模型通常不需要知道秘密值,只需要请求某个获准服务。

执行层可以在批准后为特定工具提供短时、最小作用域凭据,并对日志脱敏。子Agent不应继承主Agent全部凭据;网络目标和资源范围也应收窄。仓库中的.env.example是字段示例,不是允许读取真实.env的理由。

若测试确实需要秘密,应优先使用测试账号、密钥代理或CI秘密注入。Agent应报告“凭据缺失导致未运行”,不能猜测、搜索用户主目录,或把秘密写入测试固定值。

9.3 安装依赖是有副作用的供应链动作

pip installnpm install或执行安装脚本可能下载并运行第三方代码、修改锁文件和缓存,还可能访问网络。即使用户只说“修一个bug”,也不自动授权新增包。

依赖安装前至少检查:项目现有包管理器与锁文件;是否已有等价依赖;包名、来源和版本;是否会运行生命周期脚本;安装范围是临时沙箱还是项目依赖;是否需要网络与凭据;怎样恢复环境。新增或升级生产依赖通常需要计划与审批。

本书不主张一律禁止安装,而是要求把“读取现有代码”和“引入外部可执行内容”分级。临时工具也应固定版本、记录来源,并在隔离环境中运行。

9.4 危险命令不能只靠关键词黑名单

高风险例子包括递归删除、覆盖设备、强制重置、清理未跟踪文件、改写历史、向管道直接执行下载脚本,以及对生产资源的删除或部署。危险性取决于语义、路径、身份和环境:rm -rf ./tmp/build与删除用户主目录不应同等处理,但两者都需要路径解析和范围检查。

Shell可以通过变量、子Shell、管道和嵌套命令表达同一效果,所以只搜索rm不足以形成安全边界。应组合:工作区隔离、命令解析、路径规范化、工具白名单、网络策略、影响分级和人工审批。解析器也不可能理解所有程序语义;无法判定时应拒绝或升级,而不是默认放行。4

9.5 哪些动作必须单独审批

以下动作不应被“请修复代码”隐含授权:

  • 删除或覆盖用户数据、未提交修改或唯一副本;
  • git reset --hardgit clean、强制推送和改写共享历史;
  • 提交、推送、创建或合并远端变更;
  • 发布软件包、发送通知、部署或操作生产;
  • 修改权限、身份、秘密或安全策略;
  • 安装未知依赖或运行远程脚本;
  • 扩大工作区、网络或凭据访问范围。

审批要显示准确命令、目标对象、路径或环境、预期影响和恢复办法。批准一次测试命令,不等于批准随后变化的命令。提示词中的“用户应该同意”也不是审批记录。

9.6 回滚边界要在行动前说明

Git分支、Worktree和提交可以帮助恢复已跟踪文件;编辑前快照可以保护本地工作区。但以下内容可能不由Git恢复:未跟踪文件、被忽略文件、数据库迁移、云资源、已发布包、已发送消息和泄漏的秘密。

因此应优先在副作用前保存检查点,保持修改小而可逆;执行后查询实际状态,再保存新检查点。用户取消时先阻止新动作,在安全点停止并清理后台进程。对于无法撤销的动作,只能准备补偿(Compensation),例如发布修正版;补偿不等于真正回滚。912

十、Proposer–Reviewer–Verifier:评审必须读到新证据

10.1 三个职责

Proposer(提议者)生成补丁;Reviewer(审核者)读取代码、测试输出、差异或渲染结果,指出结构化缺口;Verifier(验证器)按独立门禁决定是否结束。P13把它概括为:11

生成候选
→ 执行或渲染
→ 审核者读取独立证据
→ 输出可定位缺口
→ 修复
→ 验证器按门禁终止

在贯穿任务里,Reviewer可以指出“新增测试覆盖负数,但没有检查零值回归”;Verifier则运行规定命令并检查差异。Reviewer不一定是另一个模型,也可以是静态分析器、测试程序或人。

10.2 什么叫独立证据

让同一个模型重读刚写的代码并说“看起来正确”,只提供了第二次意见,没有新环境信息。更强证据包括:编译器错误、目标测试、已有回归、实际HTTP响应、浏览器截图或用户验收。

独立不意味着绝对正确。测试可能遗漏边界,Reviewer也可能误读。工程目标是使用不同来源的证据降低同类盲区,并让失败可定位。

10.3 循环怎样停止

循环应有:明确评价项、最大预算、无进展出口和最终独立门禁。反馈要定位到文件、测试名、约束ID或截图区域,不能只说“再优化一下”。如果确定性检查一次就全部通过,也没有额外主观质量要求,就无需为了模式名称强行增加Reviewer循环。

十一、常见失败模式与反例

失败或反例 为什么危险 控制办法
不读项目说明就直接重写 可能违反构建、风格和禁区约定 先读说明并与实际配置核对
一开始读取整个仓库 上下文被生成文件和无关代码淹没 目录→搜索→调用者→测试→局部文件
只看函数定义,不看调用者 可能破坏公开契约或隐含格式 搜索引用、重导出和相关集成测试
计划写“测试通过” 把意图当成事实 状态区分待办、候选与验证结果
整文件覆盖一个小修复 易丢失无关代码与他人修改 局部补丁;写前重读;写后查Diff
编辑失败后反复原样重试 没有新信息,只消耗预算 重新读取并分析匹配失败原因
为变绿而删断言或加skip 验证器被削弱,目标未实现 保护验收测试并审查测试Diff
只运行新增测试 可能修好目标却破坏旧行为 目标测试后扩大到相关回归
把依赖缺失当代码失败 错误修复方向,可能乱改源码 区分环境、权限、依赖和行为错误
自动pip install陌生包 引入供应链代码和环境变化 检查来源、锁定版本、沙箱与审批
把真实.env交给模型 秘密进入上下文、日志或补丁 执行层代管短时最小凭据
仅用rm黑名单 可被嵌套命令和别名绕过 隔离、语义与路径检查、审批
git reset --hard清理现场 可能删除用户未提交工作 不覆盖已有变更;快照并精确恢复
测试通过后自动提交或推送 超出用户授权,改变远端状态 提交、推送和发布分开授权
模型说“完成”就结束 自我声明没有环境证据 Verifier检查命令、状态、Diff和产物
多Agent编辑同一文件 覆盖、冲突和责任不清 私有Worktree、Artifact交接、单一Owner

11.1 反例:看似聪明的“大重构”

Agent发现原函数写法不优雅,于是顺手引入货币库、改变公开类型、格式化整个目录。即使负数测试通过,这也违反“不新增依赖”和“接口不变”。问题不在代码是否高级,而在行动超出合同。

11.2 反例:伪造测试证据

最终回复写“所有测试通过”,轨迹却没有测试命令;或者展示的是修改前的旧日志。证据必须绑定当前工作区状态、命令和时间。更严格的系统可以记录代码树哈希与测试结果的关联,防止拿另一版本结果冒充。

11.3 反例:把沙箱误解成虚拟环境

Agent在venv里运行来源不明的测试脚本,并认为宿主安全。venv只能隔离Python依赖,脚本仍可读取SSH密钥或访问网络。应按不可信代码使用真正的文件、进程和网络隔离。

11.4 反例:测试失败就无限修

如果失败来自数据库未启动,连续改业务代码不会解决。Runtime应分类错误、检测重复指纹、限制预算;必要时进入阻塞并给出已经取得的证据,而不是无休止循环。

十二、评估:测结果,也测路径

12.1 一项编码评估包含什么

可重复评估至少需要:

  • 任务与明确成功条件;
  • 可重置的代码库初始状态;
  • 固定或记录版本的工具和运行环境;
  • 目标验证与回归验证;
  • 禁止动作与安全门禁;
  • 完整轨迹、差异和资源记录。

可以测任务通过率、目标与回归测试、无关文件修改、工具调用、返工、时间、Token、成本、安全违规和失败恢复。指标口径必须写清;“首次补丁接受率”不能替代最终正确性,“测试通过”也不能隐去测试被修改的事实。

12.2 当前仓库保存实验能说明什么

原始书稿第7章的实验7-9在固定Coding Harness、固定任务与预算下比较两种模型的行动阈值。保存结论报告称:GPT-5.6-sol第一次修改前平均工具调用6.89次、读取4.67个文件;Claude Sonnet 5分别为4.56次和3.56个文件;该小规模设置中两者首个受测补丁和最终测试均为100%通过。7

这些数字只属于该实验的模型、任务、次数、Harness和记录口径。它支持“模型可能采用不同的搜索—行动策略”,不支持“多读文件必然更好”“更早编辑必然更快”或模型的一般排名。并且本章没有重跑实验,只依据固定提交中的书稿记录转述;发布前仍应核对原始轨迹、脚本与统计口径。

12.3 失败要回流成回归任务

P17建议把脱敏后的生产失败做首错归因,构造最小回归任务,验证候选修复后再灰度。编码场景中,尤其应保存:第一次错误行动、相关工具观察、差异、测试证据和环境版本。14

不要把含秘密的完整用户仓库直接加入评估集,也不要只收成功样本。无法合法保留真实失败时,可构造不含敏感内容但保留机制的合成复现。

十三、实施检查清单

任务与探索

  • [ ] 目标、保持项、禁止项和验收条件已经分开记录。
  • [ ] 已检查项目说明、Git状态和用户已有修改。
  • [ ] 已按目录、搜索、调用者、测试和局部文件渐进探索。
  • [ ] 需求有歧义或影响面扩大时,已停止并重新确认。

计划与编辑

  • [ ] 计划中的待办没有被写成已完成事实。
  • [ ] 公共接口、数据迁移、新依赖和安全逻辑有相应审批。
  • [ ] 修改采用最小、可审查补丁,并保持项目现有风格。
  • [ ] 未通过删除断言、加skip或mock核心逻辑绕过验收。
  • [ ] 并行任务使用独立工作区,最终有单一合并Owner。

执行与验证

  • [ ] 命令在受控工作目录中运行,记录退出码和完整日志引用。
  • [ ] 先运行目标检查,再运行相关回归、类型、Lint或构建。
  • [ ] 长输出已外置并明确截断,没有把摘要当原始证据。
  • [ ] 测试环境缺失、Flaky或未运行部分被明确披露。
  • [ ] 完成由验证器与环境证据决定,而不是模型自评。

安全、恢复与交付

  • [ ] Shell和代码执行有文件、网络、进程、时间和资源限制。
  • [ ] 凭据由执行层代管,未进入Prompt、日志或补丁。
  • [ ] 依赖安装已检查来源、版本、锁文件、脚本和审批要求。
  • [ ] 删除、覆盖、重置、提交、推送、发布和部署分别授权。
  • [ ] 已说明哪些状态可由Git恢复,哪些只能补偿或无法撤销。
  • [ ] 已检查Diff、未跟踪文件、秘密、临时文件和意外产物。
  • [ ] 最终报告包含实际命令、结果、未验证项和限制。

知识检查

先用自己的话回答,再看参考解释。

  1. Coding Agent与一次代码生成的核心区别是什么?
  2. 为什么先搜索定义、调用者和测试,通常比先读完整仓库更合适?
  3. 计划里写了“运行回归测试”,为什么不能把状态标为“回归已通过”?
  4. 新增负数测试通过后,为什么还要运行原有正数测试?
  5. 为什么Python虚拟环境不能当作代码执行沙箱?
  6. 用户让Agent“修复代码”,是否已经授权它安装依赖、提交并推送?
  7. 为什么Git不能保证所有动作都可回滚?
  8. Reviewer在什么情况下只是无效自评?
  9. 实验7-9能否证明修改前读取更多文件一定更好?
  10. 一份可信的完成声明至少应给出哪些证据?

参考解释

第1题:关键在真实环境闭环。 一次生成只给出候选代码;Coding Agent还能读取仓库、受控编辑、执行检查,并让反馈改变下一步。

第2题:搜索先建立相关性地图。 它能较快定位定义、引用和测试,减少无关内容占用上下文。但搜索可能漏掉动态或语义关联,所以命中后还要沿调用关系渐进读取。

第3题:计划表达意图,不表达事实。 只有命令确实执行,并有与当前工作区匹配的结果,才能标记通过;无法运行时应记录阻塞。

第4题:目标测试只证明目标案例。 修复可能改变正数、零或调用者行为。目标由失败变通过与既有行为继续通过,是两个需要分别验证的命题。

第5题:venv只隔离包。 其中进程仍继承宿主用户的文件、网络和进程权限;安全沙箱还需操作系统级隔离与资源限制。

第6题:没有。 安装、提交、推送和发布都会扩大环境或改变外部状态,应按任务合同和权限分别取得授权。

第7题:Git主要管理已跟踪文件版本。 未跟踪文件、秘密泄漏、数据库、云资源、已发布包和外部通信不一定能由Git撤销。

第8题:只重读同一候选、没有测试或其他新证据时。 另一个模型的赞同也不自动构成事实核验。

第9题:不能。 该实验只在限定任务和Harness中观察到策略差异,而两种模型都通过;它不能推出普遍因果关系。

第10题:至少包括变更范围、实际运行的命令与结果、Diff或产物检查、未运行项目和已知限制。 “我检查过”不是可复核证据。

小结

Coding Agent把前六章的关键部件放进了一个可观察的工程现场:Runtime推进循环,上下文工程按需装配代码和日志,文件系统保存状态与Artifact,工具执行搜索、编辑和命令,策略网关控制权限,验证器决定终态。

它的核心不是“模型一次写对”,而是在明确合同和最小权限内,持续取得新证据,以小步编辑推进任务,并让独立门禁决定何时结束。可靠主线可以缩写为:

合同 → 探索 → 计划 → 补丁 → 快速反馈 → 回归验证 → Diff审查 → 证据交付

代码又是一种元能力:它能生成脚本、适配器、报告、界面和新的验证器。这让Coding Agent成为开放任务型通用Agent的重要工程母型,但不赋予它无限权限。越通用的Shell、网络和文件能力,越需要沙箱、凭据隔离、准确审批、检查点和诚实的完成证据。

来源与证据

除特别说明外,下列仓库链接均固定到提交76a6455cbce2c94ba4fb958e10a6492cc8a0a958,避免后续文件变化改变本章证据。仓库内相对链接用于阅读当前蓝皮书,固定链接用于核验当时版本。


  1. 原始中文书稿关于Coding Agent基础能力、整体流程、Harness和代码元能力的讨论:book/chapter5.md(固定提交)。本章将其中面向专业读者的材料重组为初学者闭环,不把产品描述当作普遍实测结论。 

  2. 原始实现的工具说明、入口、测试与限制:chapter5/coding-agent/README.md(固定提交)chapter5/coding-agent/tools.json(固定提交)。代码存在只证明实现可检查,不等于所有功能在任意环境均已通过。 

  3. 原始书稿“Coding Agent中的文件编辑工具”比较了差异应用、旧字符串替换、行号、类Vim命令和首尾匹配:book/chapter5.md(固定提交)。本章只提炼“精确、原子、可审查”的选择原则。 

  4. 原始中文第4章关于通用执行工具、虚拟环境与沙箱边界,以及第5章关于Coding Agent命令语义、网络出口、文件和资源隔离的讨论:book/chapter4.md(固定提交)book/chapter5.md(固定提交)。 

  5. 原始中文第7章对Coding Agent失败归因、验证造假和完成声明交叉核对的讨论:book/chapter7.md(固定提交)。 

  6. Jimenez等,SWE-bench: Can Language Models Resolve Real-World GitHub Issues?,ICLR 2024:https://arxiv.org/abs/2310.06770;SWE-bench Verified说明:https://www.openai.com/index/introducing-swe-bench-verified/。本章仅引用其FAIL_TO_PASS与PASS_TO_PASS验证思想,不将基准表现外推到任意项目。 

  7. 原始中文第7章“实验7-9:在固定Coding Harness中测量模型的行动阈值”及其中报告的限定结果:book/chapter7.md(固定提交)。本章未重新运行实验,数字需结合原始任务、轨迹和统计脚本审阅。 

  8. 蓝皮书模式卡P03 有界执行循环,固定版本:P03。 

  9. 蓝皮书模式卡P05 Checkpoint与持久恢复,固定版本:P05。 

  10. 蓝皮书模式卡P10 上下文压缩与Artifact外置,固定版本:P10。 

  11. 蓝皮书模式卡P13 Proposer–Reviewer–Verifier,固定版本:P13。 

  12. 蓝皮书模式卡P15 Safe Point与级联取消,固定版本:P15。 

  13. 蓝皮书模式卡P16 四级质量门,固定版本:P16。 

  14. 蓝皮书模式卡P17 失败回流与回归闭环,固定版本:P17。 

  15. 蓝皮书模式卡P19 独立Agent工作区与Artifact交换,固定版本:P19。