验证门
“我修好了bug”是Agent无论是否修好都能自信地说的一句话。它还会告诉你“所有测试都通过”,但实际上从未运行过测试。这不是恶意。模型是模式匹配者,他们看到的模式常以“所有测试都通过”结尾。
解决办法是让验证变成契约,而不是氛围。我们将在系统提示词中添加一个章节,告诉Agent该运行什么、无法执行时该怎么办,以及之后如何范围理赔。
学习成果
buildSystemPrompt包含一个验证部分,告诉Agent在存在时进行真实检查(tsc、lint、测试、构建),并在没有时诚实地进行报告范围。
快速路径
- 给
buildSystemPrompt添加一个# Verification部分 - 告诉Agent运行本项目中存在的检查,而不是假设它们
- 告诉Agent报告运行了什么、被阻挡了什么、哪些无法使用
动手练习 3.3
在你的提示词构建器中添加验证部分,并清楚地写出契约。
要求:
- 在
buildSystemPrompt中将# Verification段推入sections数组 - 该章节指示Agent运行typecheck(TypeScript存在时)、lint、测试、构建,但仅限于现有的
- 明确指示不要在未完成检查前宣称成功
- 要求有范围的报告:运行的、被阻挡的、不可用的
实现提示:
- “不跑就宣称NOT”是这句话的重担。没有它,模型们会填补空白
- 契约讲的是诚实,而非覆盖范围。一个说“我运行了TSC,测试被审批阻挡”的Agent比声称“所有测试都通过”但不检查的“更有用
- 不要把项目特定的命令内置到提示词里。第3.4课讲述了让项目告诉Agent该运行什么
契约
把这个区块加到buildSystemPrompt:
sections.push(`
# Verification
After making changes, verify your work:
1. Run \`npx tsc --noEmit\` when TypeScript is present
2. Run lint, test, or build commands only if they exist in this project and are allowed by the current approval mode
3. Report exactly what you ran, what was blocked, and what was unavailable
4. Do NOT inflate partial verification into a blanket success claim
Do NOT claim "tests pass" without running them.
Scope your claims honestly. "Verification was limited because writes were blocked" is honest.
"All tests pass" when you didn't run them is not.`);契约明确指出了不良行为。模型擅长避开你说的那些事。他们不擅长回避你只是暗示的事情。
范围化的索赔,并排呈现
以下是契约试图呈现的报道内容:
| Agent会说什么 | 你想让它说什么 |
|---|---|
| “所有测试都通过” | “npm test过:47个通过,3个没通过(已有问题,与我的变更无关)” |
| “我修好了那个bug” | “auth.ts:42修正了空检。npx tsc --noEmit过去了。测试被审批模式阻挡了。” |
| “构建成功了” | “跑npm run build:4.2秒成功,未收到警告。” |
右侧列是具体的。上面写了检查过什么、发现了什么,以及界限在哪里。左侧列是模型在提示词不反击时的默认声音。
这有什么作用,什么不做
验证部分并不保证检查通过。这让Agent对支票的报告变得真实。如果tsc失败,Agent报告失败。如果测试从未进行是因为项目中不存在,Agent也这么说。如果审批模式阻挡了lint命令,Agent也会显示这个。
听起来很谦虚。实际上,这就是信任Agent输出和自己重新执行每次检查之间的区别。
**注意:核查关注的是范围,而非覆盖范围**
你不是让Agent检查所有东西。你让它准确地告诉你它检查了什么。一个小而诚实的瞄准镜比一个听起来自信的全扫更有用。这与模块2中契约的描述是同一学科:大声说出极限,Agent留在其中。
动手试试
做个小编辑(删除评论、重命名变量,或者任何可以恢复的),并请Agent确认:
bun run index.ts . "Rename the cwd variable to workingDir, then verify your work"Agent应当:
- 选择
edit或bash - 快跑
npx tsc --noEmit - 具体报告
tsc的结果,而不是毯子“看起来不错”。
如果你的审批模式阻碍了测试命令,Agent应该大声说出来,而不是假装测试通过了。
npx tsc --noEmit**Warning:虚构存在于language**
注意那些柔和的短语:“应该没问题”、“看起来不错”、“我希望这能奏效。”那些是迹象。运行检查的模型使用过去时和特定结果。一个不使用对冲未来时态的模型。阅读这种措辞是评分Agent成果的一半工作。
提交
git add src/system.ts
git commit -m "feat(prompt): add Verification section to system prompt"完成标准
- [ ]
buildSystemPrompt包含# Verification部分 - [ ] 这部分明确告诉Agent不能在不跑步的情况下宣称成功
- [ ] 该章节要求有范围的报告(已运行/阻塞/不可用)
- [ ] 在测试编辑中,Agent会特别报告
tsc的结果 - [ ]
npx tsc --noEmit
**注意:了解package.json验证步骤**
目前验证部分是硬编码的。试着阅读package.json的 scripts 块,只包含实际存在的步骤。如果scripts.typecheck有明确定义,就列出来。如果scripts.lint丢失,不要让Agent跑lint。这和下一节课(AGENTS.md)的原理相同,只是更窄、更早。
参考实现
export function buildSystemPrompt(ctx: PromptContext): string {
const sections: string[] = [];
// ... role, sandbox, Agency, Guardrails sections from previous lesson
sections.push(`
# Verification
After making changes, verify your work:
1. Run \`npx tsc --noEmit\` when TypeScript is present
2. Run lint, test, or build commands only if they exist in this project and are allowed by the current approval mode
3. Report exactly what you ran, what was blocked, and what was unavailable
4. Do NOT inflate partial verification into a blanket success claim
Do NOT claim "tests pass" without running them.
Scope your claims honestly. "Verification was limited because writes were blocked" is honest.
"All tests pass" when you didn't run them is not.`);
// ... projectContext section
return sections.join("\n");
}