验证与纠偏
Agent 的产出应当被当成陌生人的 PR:能跑不代表对,对不代表安全,安全也不代表你能维护。
把输出当外部代码
底层是下一 token 预测,不是推理机器。它能写出语法正确、逻辑通顺、事实上错误的代码,而且语气和正确时没有区别。
课程里直说了两件事:审查正确性与安全漏洞;关键代码考虑手写。第二句常被忽略——加密、权限判断、金额计算、并发原语,这类代码的错误在测试里往往不显形。安全漏洞则要单独扫:
- 命令拼接与
shell=True - 路径穿越
- 用户输入直接拼进 SQL
- 日志里打出 token
验证可能比写更贵
读一段陌生实现并确认它正确,有时比从零写更费脑力。这就是「用 AI 省时间」最大的隐藏成本:省下的是打字,花掉的是审查。
对策是挑任务:优先选择有机器判据的活(编译、类型检查、测试、diff 可读)。审查本身可以分层:
- 先看测试与类型检查是否通过
- 再按风险读鉴权、数据写入、外部请求、并发
- 剩下的看结构与命名,不必逐字读
| 任务 | 机器判据 | 审查难度 |
|---|---|---|
| 修 lint 报错 | 有 | 低 |
| 补单元测试 | 覆盖率可测 | 中 |
| 重构接口 | 测试可测 | 中 |
| 并发控制 | 难复现 | 高 |
| 权限与加密逻辑 | 无 | 很高 |
三个典型失败
- 改测试而不是改代码。 让
pytest变绿最省力的路径是修改断言、加skip、删掉失败用例。这类改动通常很隐蔽,混在几十行 diff 里。 - 编造 API。 不存在的参数、错位的参数顺序、看起来合理的配置键。知识截止后的库尤其容易中招,先查
llms.txt或源码。 - 顺手删边界。 把判断改成恒真、把异常捕获后
pass、把超时调大,测试确实绿了,问题还在。 - 调试螺旋。 同一处反复微调,每次都宣称找到原因,实际上在原地打转,甚至开始解释「这是环境问题」。课程称之为 gaslighting:它用自信的语气让你怀疑自己的判断。
bash
git diff --stat # 改动范围是否离谱
git diff -- tests/ # 测试文件被动过吗
rg -n 'skip|xfail|noqa' tests/ # 被静默的检查
pytest -q # 自己跑,不听转述打断螺旋
规则很简单:同一个错误出现两轮,就停止让它继续改。
- 要求它先复现问题,给出最小用例,再动手
- 让它写出假设和验证方式,而不是直接改代码
rewind回到出错之前,换一个思路重来- 自己读代码十分钟,往往比再给它三轮更快
如果它开始修改无关文件、增加防御性 try/except、或者把断言放宽,基本可以确定在掩盖问题而不是解决问题。
- 换模型或换工具偶尔有用,但先改的应该是你的描述。多数螺旋始于一个含糊的验收标准。
- 让另一个 agent 做只读审查只能当补充,两者共享同样的训练偏差。
- 意见一致不等于验证通过,人工抽查关键路径仍然不可省。
留下的东西
提交粒度要小,一个功能一个提交,方便 git revert。合并前确认几件事:
- 测试是你自己跑的,不是转述的
- diff 从第一行读到最后一行,包括
package.json、pyproject.toml、锁文件和 CI 配置 - 新增依赖能说出理由,能删就删
- 原来的错误处理和边界判断还在,没有被
try/except一笔带过
回归验证看三处:原 bug 的用例、相邻分支、被改动的公共函数。删掉的代码同样要读,它可能带走了唯一的校验。
对长期项目,读不懂的代码就是负债。vibe coding 出的原型可以留着,但进入维护期前,至少把核心路径重写或彻底读懂一遍。