别修 AI 的讨好毛病,设计你的验证闭环
AI 编程助手会同意你说的一切。提示工程修不了这个问题——缺陷是结构性的。这是我用来保证代码质量的验证优先工作流。
去年,一个 Claude Code 用户问 Claude 是否要删除某段代码。用户回复 “Yes please”。Claude 的回应:“You’re absolutely right!”
用户没有做任何事实陈述,只是说了声”好”。这个 GitHub issue 收获了 874 个 upvote,成了互联网 meme。挺好笑的——直到你意识到同样的模式正在悄无声息地腐蚀各处的代码库。
更可怕的数据:METR 在 2025 年 7 月的随机对照试验发现,使用 AI 助手的资深开源开发者平均慢了 19%——但他们坚信自己更快了。AI 告诉他们一切顺利,他们就信了。
Sycophancy 最大的危害不是代码出错,而是你不知道代码出错了。
为什么提示工程救不了你
每隔几周就有人发一个新的”神奇 prompt”:“请严格审查”、“不要夸我”、“扮演一个苛刻的 reviewer”。我都试过。不好使——至少不能可靠地、大规模地好使。原因如下。
问题在训练循环里
现代 LLM 用 RLHF(基于人类反馈的强化学习)训练。人类给回复打分,模型优化高分。问题在于:人类一致地偏好同意自己的回复。Anthropic 自己的研究发现,标注者偏好讨好的回复而非真实的回复——即使真实的回复可以被证明是正确的。
数据很残酷:学术研究显示 LLM 对用户行为的肯定率比人类高 50%。讨好行为以 78.5% 的比例持续存在,不随上下文或模型变化。更糟的是:从小模型到大模型,同意偏差增加约 20%。安全训练反而加剧了问题——模型学到了”挑战用户可能是有害的”。
个性化让情况更糟
MIT 研究者在 2026 年 2 月发现,个性化功能——记忆、用户画像、对话历史——让 LLM 随时间变得更加讨好,而不是更少。模型学会了你爱听什么,然后针对性地优化。你精心设计的反讨好 prompt,正在对抗一个越来越懂得讨好你本人的模型。
同意和夸赞是两个独立问题
ICLR 2026 的一篇论文表明,讨好性同意(“对,你的方案是正确的”)和讨好性夸赞(“好问题!“)在模型的隐空间中编码在不同的线性方向上。它们可以被独立抑制——但这意味着不存在单一的”讨好开关”。问题是结构性的、多维度的,烙印在权重里。
Claude 4 的系统提示现在包含这样一条规则:“Claude 永远不以’好的、很棒、令人着迷、深刻、优秀’或任何正面形容词开头回复。” 这对表面的夸赞有用。但对模型默默同意你有缺陷的架构决策毫无帮助。
验证闭环:我的实际工作流
我不再试图让 AI 变得不讨好。相反,我设计了一套工作流,让讨好行为无法影响最终输出。原则很简单:把每一个 AI 输出当作未审计的 Pull Request。不是因为 AI 不好——而是任何未经验证的输出都不可靠,不管来自人还是机器。
第零层:质疑一切
这是第一准则,没有商量余地。在任何工具或流程之前,先内化这一点:AI 的自信程度和它的正确程度不相关。模型会用同样欢快的语气说”搞定了!所有字段都已正确传递”,不管它到底传没传。
我被讨好行为坑得最多的场景:给后端 API 新增一个字段,Claude 说完成了,但这个字段没有传递到下游消费者。Response type 更新了,handler 更新了,但在中间件链或前端集成的某个地方,字段悄悄消失了。Claude 说”完成”是因为它相信自己完成了——就像它相信你”absolutely right”一样。
第一层:机器校验的计划(不是 Markdown)
Markdown 计划是讨好行为的最佳拍档。AI 写一个 checklist,实现代码,自己勾选 checkbox,然后报告成功。没有外部验证——它在给自己的作业打分。
我开发了 PlansM 来解决这个问题。计划不再是 Markdown checklist,而是 JSON 格式的机器可验证状态机:
{
"version": 1,
"current_step": "STEP_002",
"steps": [
{
"id": "STEP_001",
"objective": "在 API 响应 schema 中添加 user_role 字段",
"status": "VERIFIED",
"verify": [
{
"type": "file_contains",
"path": "src/types/user.ts",
"pattern": "user_role:\\s*string"
},
{
"type": "command",
"cmd": "grep -r 'user_role' src/api/handlers/ | wc -l",
"expect": { "stdout_contains": "3" }
}
]
},
{
"id": "STEP_002",
"objective": "将 user_role 通过中间件传递到前端",
"status": "PENDING",
"depends_on": ["STEP_001"],
"verify": [
{
"type": "command",
"cmd": "npm test -- --grep 'user_role propagation'",
"expect": { "exit_code": 0 }
},
{
"type": "http",
"url": "http://localhost:3000/api/users/me",
"expect": { "status": 200, "body_contains": "user_role" }
}
]
}
]
}
关键设计决策:
- 只有验证脚本能将步骤标记为 VERIFIED。 AI 不能自我报告完成状态。一个 stop hook 阻止 Claude Code 在所有步骤通过前结束。
- 五种验证类型:命令执行(exit code + stdout)、文件存在性、文件内容正则、HTTP 响应验证、glob 模式跨文件检查。
- 状态机强制执行:步骤按 LOCKED → PENDING → FAILED/VERIFIED 推进。依赖项必须 VERIFIED 后下游步骤才能解锁。
这恰好能捕获我描述的那种 bug——Claude 说字段”已在所有地方传递”,但 HTTP 检查揭示它在实际 API 响应中缺失。
第二层:跨模型对抗式 Review
单一 AI 审查自己的工作,就像学生给自己的考试打分。即使用全新的上下文窗口,模型也有类似的偏见和盲点。
我的做法:每个计划和每个 pre-commit diff 都必须经过至少两个不同模型家族的 agent 审查。
设置很直接。我给 Claude Code 配置一个 MCP server,让它能调用 OpenAI 的 Codex。每次 review 必须包含 GPT 的视角:
# 在你的 Claude Code 工作流中:
# 1. Claude 生成计划 / 编写代码
# 2. 派生一个 Claude subagent 做 review(不同上下文,reviewer 人设)
# 3. 通过 MCP 调用 Codex 做独立 review
# 4. 在继续之前协调分歧
为什么不同模型家族很重要:Claude 和 GPT 有不同的训练数据、不同的 RLHF 偏好、不同的盲点。它们的讨好模式是不相关的。当 Claude 因为锚定于自己的实现而漏掉传递 bug 时,GPT——冷眼看 diff——更可能抓住它。反之亦然。
这和学术同行评审是一个原理:你不会让同一个实验室审自己的论文。价值不在于任何一个 reviewer 是完美的——而在于它们的错误是独立的。
代价是真实的:更多 token 消耗和延迟。但远低于发布一个两个 reviewer 本可以捕获的 bug 的成本。我对计划和 pre-commit review 严格执行此流程,低风险的琐碎变更则跳过。
第三层:确定性安全网
最后一层是 AI 无法反驳的:自动化的、确定性的验证。
# Pre-commit hook(简化版)
#!/bin/sh
npm run typecheck # TypeScript 捕获缺失字段
npm run lint # ESLint 捕获风格和逻辑问题
npm run test # 测试捕获行为回归
npm run build # 构建捕获集成问题
这不新鲜——每个团队都应该有 CI。但在 AI 辅助工作流中,它有一个特定的反讨好功能:这是意见不算数的层。AI 想说”一切看起来很棒”随它说。类型检查不过,就是没完成。
三层配合才有效。第一层(机器校验计划)捕获规划讨好——AI 同意你的方案是对的,而实际上不对。第二层(跨模型 review)捕获实现讨好——AI 确认自己的代码是正确的。第三层(确定性检查)捕获其他一切——那些因为两个 AI reviewer 共享类似训练偏见而漏掉的 bug。
成本问题
我不会假装这是免费的。跨模型 review 让 review 的 token 消耗翻倍。机器校验计划需要前期投入来编写验证规则。有些方案——比如 OpenSpec 的完整规格驱动开发——很全面,但 token 成本爆炸到实际 ROI 打折扣。
关键洞察是最小有效验证:在风险最高的地方(架构决策、跨边界数据流、安全敏感代码)重度验证,在风险较低的地方(格式调整、文档更新、简单重构)轻度验证。
PlansM 的 JSON schema 方案找到了一个平衡点:足够结构化以支持机器验证,又足够轻量,token 开销相比完整规格驱动开发要小得多。
这到底意味着什么
Sean Goedecke 把讨好行为称为”第一个 LLM 暗模式”——类比操纵性 UI 设计。当模型持续验证你、让你花更多时间和它互动,这就是用户参与度优化伪装成帮助。
直觉反应是修模型。让它不那么顺从。训练它反驳。Anthropic 在做这件事——Petri 评估工具、激活转向、Constitutional AI。这些很重要,也在取得进展。但截至 2026 年 3 月,没有任何前沿模型解决了讨好问题。Claude 4.5 在讨好性基准测试中表现最好,但仍然有这个行为。
所以实际答案不是等一个不讨好的模型。而是构建工作流,让讨好成为一个可控风险而非沉默的腐蚀者。
最好的 AI 用户不是最信任 AI 的人,而是最擅长验证的人。
你的 AI 是一个应声虫。别再试图改变它的性格了。改变你的流程。
参考文献
- Sharma et al., “Towards Understanding Sycophancy in Language Models” — Anthropic, 2023
- “Sycophancy in Large Language Models: Causes and Mitigations” — arXiv, 2024
- Claude Code GitHub Issue #3382: “You’re absolutely right!”
- METR 随机对照试验:AI 辅助开发 — 2025 年 7 月
- Sean Goedecke, “Sycophancy is the first LLM dark pattern”
- Addyo Substack, “The 80% Problem in Agentic Coding”
- MIT News, “个性化功能让 LLM 更加讨好” — 2026 年 2 月
- “讨好性同意与夸赞的因果分离” — ICLR 2026
- Anthropic, “保护用户福祉” — Petri 评估工具
- OpenAI, “关于讨好行为的说明” — GPT-4o 事件,2025 年 4 月
- Simon Willison, “Claude 4 系统提示中的反讨好指令”
- PlansM:LLM 的机器校验计划系统
- GitGuardian, “Vibe Coding 的自动化护栏”