1. 为什么“主 agent 说 done”不等于任务真的完成
用 Claude Code 做长任务时,最容易产生一种错觉:终端里测试绿了,文件也改完了,主 agent 还给出一句类似“done”的总结,这件事就可以关掉了。这个时刻其实最危险。因为实现者刚刚经历了一整段上下文,它知道自己为什么这么改,也知道自己曾经试过哪些路径。这段历史会让它天然站在自己的实现一边。
Claude Code 官方 Best practices 里把这一层防线叫作 adversarial review step,也就是在宣布任务完成前,让一个 subagent 用 fresh context 只看 diff 和验收标准,专门报告 gap,而不是复述实现者的思路。这里的关键词不是 review,而是 fresh context。普通代码审查容易被上下文带着走,尤其是实现者自己回头看自己的 diff 时,很容易把脑子里的计划自动补进代码里。
fresh subagent context 的价值就在这里:它只看到实际变更和我们给出的检查标准,看不到前面那段艰难推理,也看不到实现者如何说服自己。这种隔离让审查更像工程里的第三方验收,而不是同一个人把自己的作业再读一遍。Claude Code 的 subagent 本来就是独立上下文窗口,拥有自己的 system prompt、工具权限和权限设置,适合把会污染主会话的大量搜索、日志、文件阅读和局部判断移出去。
这篇要解决的问题很具体:主 agent 宣布完成后,怎么让另一个 Claude 以 adversarial review 视角挑刺,并且用 TaoToken 统一 Key 把主 agent 和审查 subagent 的模型调用收敛到一套配置里。适合已经在用 Claude Code 做多文件改动、又不想每次都靠人眼从零扫 diff 的开发者。下面给出 settings.json 配置骨架、subagent 提示词、code-review 触发流程,以及一次可复现的挑刺验证动作。
2. TaoToken 前置:统一 Key 与 settings.json 骨架
TaoToken 在这里扮演的角色是统一模型接入层。官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api 。它的价值在于:主 agent 和审查 subagent 可能用不同模型、不同上下文窗口,如果每个都单独配 Key、单独改环境变量,配置会散落在多个文件里。统一 Key 之后,settings.json 里只维护一份接入信息,subagent 继承主会话的模型接入配置,减少“主 agent 能跑、subagent 报 401”这类问题。
先拿到 Key。进入控制台创建 API Key,地址是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,创建完成后在 API Keys 页面管理,地址是 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。Key 只显示一次,复制后放进环境变量,不要硬编码进仓库。
Claude Code 的配置分两层:一层是环境变量,负责告诉它走哪个 API 入口;一层是 settings.json,负责权限、工具白名单和 subagent 相关设置。下面是一个可用的骨架,放在项目根目录的.claude/settings.json,或者用户级的~/.claude/settings.json。
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "sk-你的TaoTokenKey", "ANTHROPIC_MODEL": "claude-sonnet-4-5", "ANTHROPIC_SMALL_FAST_MODEL": "claude-haiku-4-5" }, "permissions": { "allow": [ "Read", "Grep", "Glob", "Bash(git diff:*)", "Bash(git status:*)", "Bash(git log:*)" ], "deny": [ "Write", "Edit", "Bash(rm:*)", "Bash(git push:*)" ] } }这里有两个设计点值得说明。第一,ANTHROPIC_BASE_URL指向 TaoToken 的 API 入口,主 agent 和 subagent 共用这一份,不需要为审查者单独配一套。第二,permissions.deny里显式禁掉Write和Edit,这是给审查 subagent 用的只读约束。审查者不要顺手改代码,让 reviewer 直接修改实现,角色边界就混了。更健康的结构是 reviewer 只输出 gap,implementer 决定如何修,修完再 review。
如果你希望审查 subagent 用更便宜、更快的模型,可以在 subagent 定义里单独指定模型,而不是改全局配置。Claude Code 的 subagent 支持在自己的 frontmatter 里声明 model 字段,这样主 agent 用 Sonnet 做实现,审查者用 Haiku 做快速挑刺,成本更可控。
注意:
ANTHROPIC_AUTH_TOKEN建议通过 shell 环境变量注入,settings.json 里只写占位符或引用,避免 Key 进入 git 历史。如果团队共用仓库,把.claude/settings.local.json加入.gitignore。
3. 可复制配置:subagent 定义与审查提示词
Claude Code 的 subagent 放在.claude/agents/目录下,每个 subagent 一个 Markdown 文件,带 YAML frontmatter。下面是一个专门做 adversarial review 的 subagent 定义,文件名adversarial-reviewer.md。
--- name: adversarial-reviewer description: 在实现 agent 宣布完成后,以 fresh context 审查当前 diff 是否满足验收标准,只报告 gap,不报告风格偏好。 model: claude-haiku-4-5 tools: - Read - Grep - Glob - Bash --- 你是一个对抗式代码审查者。你没有参与实现,也看不到实现者的推理过程。你只做一件事:拿验收标准核对当前 diff,找出「已经承诺但没有交付」的部分。 审查输入: - work to check:当前 git diff(用 `git diff HEAD` 获取) - plan to check against:PLAN.md 或任务描述中的验收标准 只报告以下类型的 finding: 1. requirement 没有实现 2. edge case 没有测试覆盖 3. scope 之外的变更(改了任务范围外的文件) 4. 会影响 correctness、security、data integrity 的缺陷 不要报告: - 命名风格、抽象层次、目录偏好 - 未来可扩展性建议 - 个人审美判断 每条 finding 必须包含:关联文件、相关变更、失败原因、建议验证方式。无法确认的标记为 uncertainty,不要装作已经证明。 输出格式: ## Findings - [severity: blocking/optional] 文件:行号 — 问题描述 — 验证方式 ## Uncertainty - 无法确认的点这个提示词的关键不是写得多漂亮,而是验收边界非常清楚。work to check 是当前 diff,plan to check against 是 PLAN.md,finding 的定义是 requirement 没实现、edge case 没测试、scope 外变更,排除项是 style preferences。这样的审查指令能显著减少噪声,因为 reviewer 没有被邀请重新设计整个模块。
接下来是触发流程。主 agent 完成实现后,不要直接说 done,而是显式调用 subagent。在 Claude Code 会话里可以这样写:
实现已完成,测试通过。现在调用 adversarial-reviewer subagent, 按 PLAN.md 核对当前 diff。只报告 blocking 级别的 gap。如果你用的是 bundled skills,Claude Code 自带/code-review,它会在 fresh subagent 里审查当前 diff 并把 findings 返回当前 session。这个模式适合通用 bug 检查,例如空值处理、并发问题、权限遗漏、状态不一致、异常路径没有覆盖。但如果任务开始前已经有 PLAN.md,就不应该只让 reviewer 泛泛查 bug,而是用上面的自定义 subagent 把计划和 diff 绑定起来逐条核对。
两者的分工可以这样理解:/code-review适合查 bug,自写 prompt 适合查计划落地。日常 bug fix 直接跑/code-review;有明确验收标准的长任务,用adversarial-reviewer按 PLAN.md 核对。
4. 验证请求:一次可复现的挑刺动作
光有配置不够,得验证审查者真的在挑刺,而不是复述实现。下面用一个最小可复现的例子走一遍。假设我们要实现一个 rate limiter,PLAN.md 里写了四条验收标准:相同 userId 在同一窗口内被限制、跨窗口 reset 有测试、并发请求不会绕过计数、无 userId 时走默认规则。
先让主 agent 实现,然后故意留一个缺口:并发计数没有加锁。实现完成后,主 agent 大概率会说“测试通过,完成”。这时候触发审查:
# 确认当前 diff 范围 git diff HEAD --stat # 在 Claude Code 会话里触发审查 subagent # 输入:调用 adversarial-reviewer,按 PLAN.md 核对 diff审查 subagent 在 fresh context 里只看到 diff 和 PLAN.md,它会逐条核对。预期输出类似:
## Findings - [blocking] src/rateLimiter.ts:42 — 并发请求下 count 读取与写入之间没有原子性, 两个请求可能同时读到旧值并各自加一,导致实际放行数超过限制。 验证方式:写一个并发测试,同时发起 10 个请求,断言放行数不超过窗口上限。 - [blocking] tests/rateLimiter.test.ts — PLAN.md 要求「跨窗口 reset 有测试」, 当前测试只覆盖了单窗口内限制,没有覆盖窗口切换后的计数重置。 验证方式:mock 时间推进到下一个窗口,断言计数归零。 ## Uncertainty - 无 userId 时的默认规则在 diff 中未体现,无法确认是否实现。拿到 findings 后,主 agent 按 blocking 级别修复,修完再触发一次 re-review。因为 reviewer 是 subagent,实现会话可以直接收到 gaps 并继续修复,不需要我们在多个窗口之间复制审查意见。这个循环看起来多了一步,实际常常更快。
这里可以对照一下/code-review和自定义 subagent 的输出差异。/code-review更可能报出空值处理、异常路径这类通用问题,但不一定知道 PLAN.md 里写了“跨窗口 reset 有测试”。自定义 subagent 因为拿到了验收标准,能直接指出“这条 requirement 没交付”。两者可以叠加使用:先跑/code-review扫通用 bug,再用adversarial-reviewer核对计划落地。
如果你想把审查能力接到更长的编码任务里,Coding Plan 提供了适合长期编码和 Agent 场景的额度方案,地址是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。对于需要反复触发 review loop 的任务,统一 Key 加固定额度比每次单独配 Key 更省心。
5. 本篇常见错排查
5.1 subagent 报 401 或模型不可用
最常见的原因是 subagent 没有继承主会话的接入配置。检查.claude/settings.json里的env段是否包含ANTHROPIC_BASE_URL和ANTHROPIC_AUTH_TOKEN。如果 subagent 定义里单独写了 model 字段,确认这个模型名在 TaoToken 的模型列表里存在。可以在模型对话页面先验证模型可用性,地址是 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=chat&utm_campaign=rewrite ,确认能正常返回再回到 Claude Code。
5.2 审查者开始改代码
如果 reviewer 输出了 Edit 或 Write 操作,说明工具权限没限制住。回到 settings.json,在permissions.deny里加上Write和Edit,并在 subagent frontmatter 的 tools 列表里只保留 Read、Grep、Glob、Bash。审查者只输出 gap,修改交给实现者,这个边界不能松。
5.3 findings 全是风格问题
这通常是 prompt 没写清楚排除项。检查 subagent 提示词里有没有明确写“不要报告命名风格、抽象层次、目录偏好”。如果没有,reviewer 会把个人偏好伪装成阻塞项,把项目推向 over-engineering。加上排除项后,findings 会收敛到 correctness 和 stated requirements。
5.4 审查者找不到 PLAN.md
确认 PLAN.md 在项目根目录,并且 subagent 有 Read 权限。如果 PLAN.md 在子目录,在提示词里写清楚路径。另一个做法是把验收标准直接写进触发指令里,不依赖文件,适合临时任务。
5.5 diff 太大导致审查超时
如果一次改动涉及几十个文件,审查 subagent 的上下文会被撑满。这时候按模块拆分,每次只审查一个模块的 diff。或者用 agent teams 把审查拆成 security、tests、performance 多个 teammate 并行,team lead 汇总 findings。agent teams 目前是 experimental,需要启用CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS,适合并行探索真正有价值的任务,顺序强、同文件竞争多的任务还是单 subagent 更合适。
5.6 审查通过但上线后出问题
subagent reviewer 能降低漏检概率,不能替代生产环境里的权限隔离、branch protection、CI 必过规则、数据库变更审批和 rollback 设计。command safety 交给 permission mode 和 hooks,业务正确性交给测试和 adversarial review,上线责任交给 PR review 和人类审批。每一层只做自己擅长的事,不把所有风险压到一句 prompt 上。
6. 把审查接进你的日常编码流程
如果你已经在用 Claude Code 做多文件改动,建议把 adversarial review 做成固定习惯。每次进入 done 之前,先看git diff是否干净地指向目标任务。普通 bug fix 直接跑/code-review;有 PLAN.md 的长任务,调用adversarial-reviewer按计划核对 diff。reviewer 输出 findings 后,按 correctness 和 stated requirements 分级,只修阻塞项,style preference 记录为 optional,不让它拖着实现走向过度设计。
接入配置上,统一 Key 放在 settings.json 的 env 段,subagent 继承主会话配置,减少 401 和模型不可用的问题。API Key 在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 管理,接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 可以查到模型列表和参数说明。如果你用 Claude Code 的 Anthropic 兼容模式,参考 https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecodeanthropic&utm_campaign=rewrite 里的配置说明。
写代码的 agent 和审代码的 agent 分开,真正改变的是心理模型。我们不再把 Claude Code 的一句完成总结当成交付证明,而是要求它把交付暴露给一个没有参与实现的新上下文。代码最后能不能进仓库,仍然由测试、审查、权限、CI 和人来决定。这个边界越清楚,Claude Code 越像一个可靠的工程同事,而不是一个跑得很快但需要到处追着收尾的脚本。