Files
2026-07-13 21:36:11 +08:00

16 KiB
Raw Permalink Blame History

name, description
name description
doubt-driven-development 对每一个非平凡决策,在它被采纳之前,都进行一次全新上下文的对抗性审查。当正确性比速度更重要时,当在陌生的代码中工作时,当风险较高(生产环境、安全敏感逻辑、不可逆操作)时,或任何时候一个自信的输出现在验证比以后调试更便宜时,请使用此方法。

怀疑驱动开发

概述

自信的答案不等于正确的答案。长时间的会话会累积上下文,在无人察觉的情况下悄然将假设变成"事实"。怀疑驱动开发是一种训练方法,在任何非平凡输出被采纳之前,引入一个持有全新上下文的审查者——其偏向是证伪,而非赞同。

这不是 /review/review 是对已完成产物给出定论。这是一种进行中的姿态:非平凡决策在纠错成本仍然很低时接受交叉审查。

何时使用

当一个决策满足以下至少一项条件时,它就是非平凡的:

  • 它引入或修改了分支逻辑
  • 它跨越了模块或服务边界
  • 它断言的某个属性是类型系统或编译器无法验证的(线程安全、幂等性、顺序、不变式)
  • 其正确性依赖于未来读者无法看到的上下文
  • 其影响范围是不可逆的(生产部署、数据迁移、公开 API 变更)

在以下场景中应用本技能:

  • 即将在不确定性下做出架构决策时
  • 即将提交非平凡代码时
  • 即将断言一个非显而易见的事实时("这是安全的"、"这能扩展"、"这符合规格"
  • 在不完全理解的代码中工作时

何时不使用:

  • 机械性操作(重命名、格式化、移动文件)
  • 遵循清晰明确的用户指令
  • 阅读或总结现有代码
  • 正确性显而易见的一行改动
  • 纯工具操作(运行测试、列出文件)
  • 用户明确要求速度优先于验证

如果你怀疑每一次按键,你将一事无成。本技能仅适用于上述定义的非平凡决策。

加载约束

本技能是为主会话编排器设计的,因为第 3 步(DOUBT,详见下文)可以生成一个持有全新上下文的审查者。

  • 不要将本技能添加到角色(persona)的 skills: 前置元数据(frontmatter)中。 遵循第 3 步的角色会生成另一个角色——这正是在 references/orchestration-patterns.md 中明确禁止的编排反模式("角色不能调用其他角色")。
  • 如果你发现自己在子代理上下文中应用本技能(在 Claude Code 中禁止嵌套子代理生成):更优的做法是向用户说明怀疑驱动模式无法在嵌套中运行,让主会话处理。仅作为最后手段,存在一种降级的自我质疑回退方案——将 ARTIFACT + CONTRACT 重写为一个新的自我提示,与先前的推理建立严格的心理分隔,然后执行步骤 1-5。但这不是全新上下文审查(你带着自己的上下文一起走),因此将结果标记为降级,并且在用户可触及时优先选择上报。

流程

应用本技能时复制此清单:

怀疑循环:
- [ ] 第 1 步:CLAIM(声明)——写出声明及其重要性
- [ ] 第 2 步:EXTRACT(提取)——隔离产物与契约,剥离推理过程
- [ ] 第 3 步:DOUBT(质疑)——以对抗性提示调用全新上下文审查者
- [ ] 第 4 步:RECONCILE(调和)——对照产物文本对每项发现进行分类
- [ ] 第 5 步:STOP(停止)——满足停止条件(琐碎发现、3 轮循环或用户覆盖)

第 1 步:CLAIM(声明)——呈现需要定论的内容

用两三行描述该决策:

CLAIM(声明):"新的缓存层在规格说明中描述的读密集型
              工作负载下是线程安全的。"
WHY THIS MATTERS(为何重要):此处的竞态条件会损坏用户数据,
                              且在 QA 中难以发现。

如果你无法将声明写得如此简洁,那你有的只是一种感觉,而非一个决策。在审视它之前先将其呈现出来。

第 2 步:EXTRACT(提取)——最小的可审查单元

一个持有全新上下文的审查者需要的是产物契约,而不是推导过程。

  • 代码:差异(diff)或函数——而不是整个文件
  • 决策:用 3-5 句话描述的提案加上它必须满足的约束条件
  • 断言:声明加上据称支持该声明的证据(与第 1 步的 CLAIM 块保持分离,后者是编排器正在审视的假设)

剥离你的推理过程。如果你交出结论,你得到的将是对你结论的确认。审查单元必须足够小,让审查者能在一次阅读中记住——如果是一个 500 行的 PR,请先分解。

第 3 步:DOUBT(质疑)——调用全新上下文审查者

审查者的提示必须是对抗性的。框架决定了答案。

对抗性审查。找出这个产物中有什么问题。
假设作者过于自信。查找:
- 未明言的假设
- 未处理的边界情况
- 隐藏的耦合或共享状态
- 契约可能被违反的方式
- 可能被破坏的现有约定
- 在意外输入下的失效模式

不要验证。不要总结。找出问题,或者明确说明在经过
彻底检查后你找不到任何问题。

ARTIFACT(产物):<粘贴产物>
CONTRACT(契约):<粘贴契约>

仅传递 ARTIFACT + CONTRACT。不要传递 CLAIM。 将你的结论交给审查者会使其偏向于赞同。审查者必须独立判断产物是否满足契约。

在 Claude Code 中,agents/ 目录下基于角色的审查者天生从隔离的上下文开始,可在本技能中使用——参见 agents/ 查看清单和按领域的匹配。

上述对抗性提示优先级高于角色(persona)的默认响应形态。code-reviewer 这样的角色被设计为生成兼顾优缺点的平衡裁决;而怀疑驱动开发只需要问题导向的输出。将对抗性提示逐字粘贴到调用中,使其覆盖角色的默认行为。如果某个角色的响应形态无法被干净地覆盖,则回退为使用通用子代理并附上对抗性提示。

跨模型升级

单一模型的审查者与原始作者共享盲区——一个更冷的、不同架构的模型可以发现这些盲区。怀疑驱动开发对于非平凡决策已是主动选择,因此在此范围内提供跨模型选项是技能价值的一部分,而非可选负担。

交互式会话:始终询问。绝不静默跳过。

第 1 步:询问用户

在上述第 3 步的单模型审查完成后,但在 RECONCILE 之前,暂停并询问:

"单模型审查已完成。是否需要跨模型的第二意见?选项:Gemini CLI、Codex CLI、手动外部审查(你粘贴到别处),或跳过。"

这个提问在每个交互式怀疑循环中都是强制性的——即使是对感觉风险较低的产物也是如此。由用户——而非代理——决定成本是否值得。代理的工作是将选择呈现出来。

第 2 步:如果用户选择了 CLI——先验证,再调用

  1. 检查工具是否在 PATH 中(which geminiwhich codex)。
  2. 在传递完整提示前测试其是否可用(gemini --version 或等效命令)——一个过时或损坏的二进制文件可能通过 which 检查,但在实际输入上会失败。
  3. 与用户确认确切的调用命令,包括必需的标志、认证信息和环境变量(例如 API 密钥)。不同实现的语法各异;切勿假设。
  4. 仅传递 ARTIFACT + CONTRACT + 对抗性提示。 不包含会话上下文,不包含 CLAIM。
  5. 注意 shell 转义。如果产物包含引号、$(...) 或反引号,优先使用标准输入(echo … | gemini)或 heredoc,而不是内联 -p "…"。如有疑问,请在运行前请用户确认调用命令。
  6. 将输出带入第 4 步(RECONCILE)。

切勿将产物内插到 shell 引号参数中。 代码、Markdown 和审查提示通常包含反引号、$(...) 和引号字符,这些字符要么会截断提示,要么会执行嵌入的 shell。将完整提示写入文件并通过标准输入管道传入。

示例形态(请根据你安装的工具验证标志——不同实现和版本的语法各不相同):

# 先将对抗性提示 + ARTIFACT + CONTRACT 写入一个临时文件。
# 然后通过标准输入管道传入,使产物中的 shell 元字符保持惰性。

# Codex(只读沙箱防止 CLI 写入你的工作区):
codex exec --sandbox read-only -C <repo-path> - < /tmp/doubt-prompt.md

# Gemini'--approval-mode plan' 为只读模式;'-p ""' 触发非交互
# 模式,提示从标准输入读取):
gemini --approval-mode plan -p "" < /tmp/doubt-prompt.md

只读沙箱是关键的细节:一个怀疑产物本身可能包含指令(有意或无意的提示注入),否则跨模型 CLI 可能会在工作区中执行这些指令。

第 3 步:如果 CLI 不可用或失败

明确地报告失败。提供选项:手动运行、尝试其他工具,或跳过。不要静默回退到单模型——用户应该知道跨模型未发生。

第 4 步:如果用户选择跳过

在输出中确认跳过("仅以单模型发现结果继续")并继续执行 RECONCILE。跳过是可以的;静默跳过则不行。

非交互式上下文CI、/loop、自动循环、定时任务):

  • 跨模型被跳过,且必须在输出中声明跳过:"跨模型已跳过:非交互式上下文。"
  • 未经用户明确授权,绝不调用外部 CLI——这是一项关键的安全属性。

跨模型审查增加了成本、延迟和工具脆弱性。代理在每个循环中呈现选择;由用户决定该产物是否值得采用。

第 4 步:RECONCILE(调和)——将发现结果纳入考量

审查者的输出是数据,而非最终裁决。你仍然是编排器。 在将每项发现分类之前,先对照产物文本重新阅读——不经审视地认可审查者与忽略它一样都是失败模式。

对于每项发现,按以下优先级顺序进行分类(最先匹配的类别为准):

  1. 契约误读——审查者指出的问题特别是因为你提供的 CONTRACT 不清晰或不完整造成的。先修复契约,在下一轮循环中重新分类。
  2. 有效 + 可操作——需要修改产物的真实问题。修改它,重新循环。
  3. 有效的权衡——问题是真实的,但修复成本超过了接受成本。明确记录该权衡,让用户看到。
  4. 噪音——审查者指出的问题实际上在审查者所缺乏的上下文下是正确的。记录下来,继续前进,并自问:如果将该上下文加入契约,是否能防止这个误报?

一个全新的审查者可能因为缺乏上下文而犯错。不要仅仅因为它"新"就一味听从。

第 5 步:STOP(停止)——有界循环,而非递归

在以下情况停止:

  • 下一轮迭代只返回琐碎的或已经考虑过的发现,或者
  • 已完成 3 轮循环(上报给用户,不要独自进行第四轮),或者
  • 用户明确说"发布它"

如果经过 3 轮循环后审查者仍然提出实质性问题,则该产物可能还没有准备好。将这一点呈现给用户——三轮未解决的循环本身就是关于产物的信息,而非继续循环的理由。

如果 3 轮循环"显然不够"因为产物太大:产物太大——返回第 2 步进行分解。不要提高循环上限。

常见合理化借口

合理化借口 现实
"我很自信,跳过怀疑步骤吧" 在新问题上,自信与正确性的相关性很差。确定感恰恰是盲区隐藏的时刻。
"生成一个审查者太贵了" 在生产环境中调试一个错误的提交更贵。检查是有界的;bug 是无界的。
"审查者只会挑刺" 只有在没有范围界定时才会如此。将提示限制为"会使产物在契约下失效的问题"。
"我最后用 /review 来做怀疑就行了" /review 是最终关卡。怀疑驱动开发在纠错成本低时及早发现错误方向。等到 PR 时就太晚了。
"如果每步都怀疑,我永远无法交付" 本技能适用于非平凡决策,而非每一次按键。重新阅读"何时不使用"部分。
"两个意见总比一个好" 当第二个意见上下文更少并产生噪音时则不然。调和,而非盲从。
"审查者不同意,所以我错了" 审查者缺乏你的上下文——分歧是信息,而非裁决。重新阅读产物,分类,然后做决定。
"跨模型总是更好" 跨模型能发现单一模型与自己共享的盲区,但它增加了成本和工具脆弱性。在每个交互式怀疑循环中提供此选项——由用户决定该产物是否值得采用。代理的工作是将选择呈现出来,而不是把关。
"用户同意过一次,所以我可以继续调用 CLI" 每次调用都是独立的授权行为。产物、提示和标志在多次调用之间都会变化——在每次运行前与用户重新确认确切的命令。

危险信号

  • 为一行重命名或格式化更改而生成全新上下文审查者
  • 未经重新阅读产物文本就将审查者输出视为权威
  • 循环超过 3 轮而未上报给用户
  • 以"这个好吗?"而非"找出问题"来引导审查者
  • 在高风险决策上面临时间压力时跳过怀疑
  • 在未更改的产物上重新生成全新上下文(你会得到相同的发现;你只是在拖延)
  • 怀疑表演(可检测信号):在两轮或更多轮审查者提出实质性发现的循环中,没有发现被归类为可操作。你是在确认,而不是在质疑。停止并上报。
  • 只在提交后才怀疑——那是 /review,不是怀疑驱动开发
  • 未经向用户确认工具是否存在、是否已配置以及是否接受该确切语法,就硬编码外部 CLI 调用
  • 在交互式怀疑循环中静默跳过跨模型审查。 即使不推荐使用,也必须让选择可见。跳过是可以的;静默跳过则不行。
  • 当外部 CLI 出错或缺失时静默回退——报告失败并让用户引导方向
  • 从审查者输入中剥离契约
  • 将 CLAIM 传递给审查者(偏向于赞同)

与其他技能的交互

  • code-review-and-quality / /review:互补。/review 是事后 PR 裁决;怀疑驱动开发是进行中的逐决策审查。两者都使用。
  • source-driven-developmentSDD 验证关于框架的事实是否与官方文档一致。怀疑驱动开发验证你对产物的推理。SDD 检查 API 是否存在;怀疑驱动开发检查你是否在契约下正确使用了它。
  • test-driven-development:TDD 的 RED 步骤是具体化的怀疑——一个失败的测试就是一次证伪尝试。当 TDD 适用时,那个失败的测试就是对行为性声明的怀疑步骤。
  • debugging-and-error-recovery:当审查者发现一个真实的失效模式时,进入调试技能进行定位和修复。
  • 仓库编排规则references/orchestration-patterns.md):本技能从主会话进行编排。一个角色调用另一个角色是反模式 B——参见上面的加载约束。

验证

应用怀疑驱动开发后:

  • 每个非平凡决策(按上述定义)在定论之前都被明确命名为一个 CLAIM
  • 每个非平凡产物至少经过一次全新上下文审查(TDD 的 RED 步骤产生的失败测试满足此条件,适用于行为性声明,参见与其他技能的交互部分)
  • 审查者收到的是 ARTIFACT + CONTRACT——而非 CLAIM,也非你的推理过程
  • 审查者的提示是对抗性的("找出问题"),而非验证性的("它好吗")
  • 发现结果按照优先级顺序对照产物文本进行分类(而非不经审视地认可):契约误读 / 可操作 / 权衡 / 噪音
  • 满足了停止条件(琐碎发现、3 轮循环或用户覆盖)
  • 在交互模式下,跨模型审查已明确向用户提供(无论产物风险大小),并且用户的回应已在输出中得到确认
  • 在非交互模式下,跨模型审查已跳过,且已声明跳过
  • 任何外部 CLI 调用之前都进行了 PATH 检查、可运行二进制测试、与用户确认语法,以及运行授权