专题研修

27|贯穿案例:修复exclude,从原始失败到可恢复交付

专题研修约 3.2 千字1 组分步图解

目标:将输入、检索、补丁、工具、状态、测试和报告串成一个可运行案例。所有代码与样本为本书原创;控制器按脚本给出补丁,不是模型自主发现Bug,也不是对用户真实PSBuild仓库的审查。

本章目录

沿着对象与状态理解本章

完整修复案例的重点是每一步证据怎样连接,而不是预定多少个Agent角色。

下方图解的固定输入在“输入与适用条件”中声明。它用于解释本章机制,不与本章其他独立例子的数值暗中接续。

动态图解 · F34

测试是找反例,不是给代码盖绿章

为什么“测试都通过”仍可能交付错东西?

测试只能验证它实际检查的行为和版本。一条只断言“不报错”的测试无法证明排除规则正确。好的测试围绕需求构造能击中错误的输入;代码修改以后,旧绿色结果也不再自动属于新版本。

反例能让错误实现暴露问题的具体输入。
回归修改破坏了本来成立的行为。
交付证据当前版本对应的检查命令、结果与范围。

输入与适用条件:构造的文件筛选任务;通配符语义须由需求明确,不在动画里偷偷改变“匹配文件名”与“匹配完整路径”的规则。

1 / 6 · 明确需求

第1步,共6步

窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。

测试是找反例,不是给代码盖绿章:明确需求明确需求排除*.tmp,但保留其余文件构造小反例a.py、b.tmp、nested/c.tmp先看原始失败确认旧代码确实没有正确排除实施最小修改修复匹配语义,不改无关API测试针对行为检查保留、排除、嵌套和空规则绑定版本交付绿色结果属于当前代码,而非旧文件教学流程;高亮表示当前步骤,不表示真实耗时比例。

不先说匹配对象与目录语义,无法判断哪个输出才正确。

本步状态由图形与说明共同给出。

默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。

为什么需要

减少返工和虚假完成,而非让审查循环无限增长。

怎样实现

围绕可观察行为、反例和当前版本组织验证。

可能的代价与误解

测试与实现共用同一错误假设、只测顺利路径、频繁审查无实际修复。

如何判断是否做对

故意引入一处已知错误,测试应失败;恢复后再通过。

1. 为什么选这个问题

exclude看起来只是字符串匹配,却包含路径契约、目录边界、平台分隔符、用户输入与回归。这使任务足够小,可以完整展示,又足以暴露“只看起来写好了”的问题。生产实现若支持glob、gitignore、大小写或符号链接,需要另行定义;本例不暗中扩展范围。

契约是:路径相对仓库根;普通规则精确匹配;以斜杠结尾的规则匹配目录及后代;统一反斜杠分隔符;拒绝父级跳转。示例src/a.py不应被规则a.py排除,vendor/a.py应被vendor/排除,而vendor2/a.py不应被误排除。

2. 初始缺陷与失败证据

初始函数先取PurePosixPath(path).name,再检查规则列表。它丢掉目录,导致嵌套精确路径失配,也会误排除其他目录同名文件。只测试顶层a.py会漏掉这些错误。

实际运行8项测试,初始有5项失败,涉及嵌套路径、同名边界、目录规则、Windows分隔符与父级跳转。测试stdout、退出码和工件版本保存在reports/test_results.json的capstone字段。这些数字对应配套运行记录,不是预期结果。

检索阶段用Python AST返回函数范围;它仅帮助定位,并未完成类型推断或跨文件调用图。读取工具返回完整小文件及其版本,使补丁可以绑定已知前置状态。

3. 实施:只改需要改的行为

修复将路径规范化为相对POSIX表示,拒绝越界形式;普通规则比较完整相对路径;目录规则比较相等或prefix + '/'前缀,避免vendor误匹配vendor2。没有引入新的路由服务、全局配置层或通用匹配框架。

更新通过动作日志的CAS入口提交。expected必须等于刚读到的内容,防止覆盖并发修改;操作ID重复但参数不一致会被拒绝。工具写入范围限制在matcher.py,测试文件由教学Harness创建并固定执行。

这不是防御恶意Agent的完整隔离。生产中不可信代码与测试应在沙箱运行,验证资源可能要放在工作区外;本例重点证明正常故障窗口与版本新鲜度。

4. 验证:绿色结果必须属于当前文件

修改后再次运行相同8项测试,全部通过。随后调用完成检查,确认当前文件版本与最近通过测试的版本一致。实验再追加一条注释,故意使工件变化;再次finish被拒绝,说明旧绿色结果不会自动套到新文件。

对真实工程,注释变更是否需要重跑全部测试可以按风险优化,但必须先建立可信复用条件。不能让模型仅凭“改动很小”决定沿用陈旧验证。本例采取保守策略便于理解。

所列测试没有覆盖完整glob语义、文件系统符号链接、Unicode规范化、超大规则集性能或所有Windows路径格式。它的成功只相对于明确契约与列出的测试,不应被称为完整生产exclude库。

5. 另一个真实实验:写后崩溃

RecoveryTests.test_real_crash_and_reconcile在独立子进程中调用文件更新器,在os.replace之后、SQLite标记完成之前立即退出。父进程观察退出码75,再恢复同一操作。当前文件已等于目标版本,因此系统标记reconciled,不再次写入。

这个实验回答的是“本地副作用成功但日志未完成,如何恢复”。它与上面的功能Bug是两个独立维度。通过功能测试不能证明恢复可靠;通过恢复测试也不能证明匹配语义正确。高级实验要把这些维度分别验证。

6. 与真正LLM Agent的差距

离线Harness的动作是作者预先编排,因此没有测模型能否发现根因、选择工具、生成正确补丁或抵抗上下文干扰。它证明执行边界和验证机制可运行。用户不能把这份报告读成“某模型修复成功率100%”。

可选live_readonly.py展示真实API接入结构,但只允许只读文件分析,该入口未实测。若要升级为真实写代码评测,应先在可销毁仓库中提供受限patch工具、外部验收与预算,记录模型输出和全部调用,再多次运行。不要直接让未验证的适配器修改生产项目。

7. 读者应完成的扩展

扩展一:用户在read与replace之间改文件,验证系统返回stale而不覆盖。扩展二:测试命令超时,检查finish不能通过。扩展三:加入目录名相似、绝对路径和空规则的契约样本。扩展四:在不同候选补丁下比较功能正确性与复杂度,而不是只选代码最长者。

扩展五:增加真实模型只读分析,评价它是否提出正确根因,并把结果与脚本控制分开报告。扩展六:把无关长历史加入输入,测试是否影响约束和定位。这些是未运行的练习,不会预填成功结果。

8. 一份合格的交付报告示例

“修复了basename比较导致的相对路径误判;目录匹配增加边界分隔符;在当前工件上8项契约测试通过;同时验证了陈旧结果拒绝。未实现glob及完整跨平台路径库,也未验证生产性能。”

这段报告短,但知道做了什么、为什么、如何证明和边界在哪里。相比“全面优化、质量显著提升”,它更符合资深工程工作的证据标准。

运行示例 · S27

补丁成功后再加一处日志,为什么需要重新验证

输入与条件。修复exclude得到v8并通过测试;随后Agent增加日志代码形成v9,日志含未定义变量。

步骤与对象内部动作中间结果 / 新状态
1原验证R8只覆盖v8当时结果有效。
2追加修改v9引入新运行路径原绿灯不能覆盖。
3重跑调用触发日志分支发现NameError,当前任务失败。
4直接修复去掉或修正日志,形成v10再运行相关测试。
5交付关联v10与其验证结果不得继续引用R8冒充最新。

把过程连起来。最后一次有意义修改之后,验证证据需要重新与目标版本对齐。

边界与反例。不要求每次文字注释变动重跑最贵全套;验证范围应与实际变更风险相称。

依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。

记录保存在本机浏览器。

输入关键词即可检索。

↑ ↓ 选择 Enter 打开Esc 关闭 · 仅本地搜索

阅读设置

阅读设置仅保存在本机浏览器,不上传任何数据。