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

244 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: doubt-driven-development
description: 对每一个非平凡决策,在它被采纳之前,都进行一次全新上下文的对抗性审查。当正确性比速度更重要时,当在陌生的代码中工作时,当风险较高(生产环境、安全敏感逻辑、不可逆操作)时,或任何时候一个自信的输出现在验证比以后调试更便宜时,请使用此方法。
---
# 怀疑驱动开发
## 概述
自信的答案不等于正确的答案。长时间的会话会累积上下文,在无人察觉的情况下悄然将假设变成"事实"。怀疑驱动开发是一种训练方法,在任何非平凡输出被采纳之前,引入一个持有全新上下文的审查者——其偏向是**证伪**,而非赞同。
这不是 `/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 gemini``which codex`)。
2. 在传递完整提示前测试其是否可用(`gemini --version` 或等效命令)——一个过时或损坏的二进制文件可能通过 `which` 检查,但在实际输入上会失败。
3. 与用户确认确切的调用命令,包括必需的标志、认证信息和环境变量(例如 API 密钥)。不同实现的语法各异;切勿假设。
4. **仅传递 ARTIFACT + CONTRACT + 对抗性提示。** 不包含会话上下文,不包含 CLAIM。
5. 注意 shell 转义。如果产物包含引号、`$(...)` 或反引号,优先使用标准输入(`echo … | gemini`)或 heredoc,而不是内联 `-p "…"`。如有疑问,请在运行前请用户确认调用命令。
6. 将输出带入第 4 步(RECONCILE)。
**切勿将产物内插到 shell 引号参数中。** 代码、Markdown 和审查提示通常包含反引号、`$(...)` 和引号字符,这些字符要么会截断提示,要么会执行嵌入的 shell。将完整提示写入文件并通过标准输入管道传入。
示例形态(请根据你安装的工具验证标志——不同实现和版本的语法各不相同):
```bash
# 先将对抗性提示 + 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-development`**:SDD 验证*关于框架的事实*是否与官方文档一致。怀疑驱动开发验证*你对产物的推理*。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 检查、可运行二进制测试、与用户确认语法,以及运行授权