内容
# mcp-devils-advocate

**MCP 服务器,用于压力测试推理 — devil's advocate、premortem 分析、假设审计和 steelmanning 作为强制性结构协议。**
## 为什么
大型语言模型(LLMs)过于轻易地达成一致。当你询问模型你的计划是否良好时,它可能会给出一个礼貌的“是”,并附上三点建议。这个服务器通过将对抗性思维转化为模型无法捷径的协议来解决这个问题:它从不生成内容本身 — 它是一个状态机,强制客户端 LLM 完成每个阶段,并带有严格的规定(最小数量、类别、严重性评级、长度下限),验证每个提交内容并提供可行的错误信息,除非某个阶段真正完成,否则拒绝继续,并编译一份带有确定性评估的最终报告。结果是:真正的反驳而不是敷衍的回应,带有缓解义务的 premortem 分析,突出负载和未验证的假设审计,以及钢化对手实际上会支持的立场。
四种模式:
| 模式 | 协议 |
|---|---|
| `devils_advocate` | ≥3 反驳(分类,严重性 1–5,≥2 不同的类别)→ 每项严重性 ≥3 的反驳的诚实反驳(`holds` / `partially_holds` / `refuted`)→ 裁决 |
| `premortem` | 设置失败范围 → ≥4 个失败原因(可能性 × 影响)→ 每项评分 ≥9 的原因的具体缓解措施,带有剩余风险 → 裁决 |
| `assumptions` | ≥4 个假设(`load_bearing`,证据 `verified`/`partial`/`none`)→ 每个未验证的负载假设的廉价验证测试 → 裁决 |
| `steelman` | ≥3 个反对立场的最强论点 → 对每个论点的诚实 `concede` 或 `counter` 响应 → 裁决 |
## 工具
| 工具 | 参数 | 返回 |
|---|---|---|
| `start_review` | `claim: str`, `mode: str`, `context: str = ""` | 新的 `review_id`(例如 `rev-x9k2`)以及第一阶段的精确指令:项目格式、规则、最低要求 |
| `submit` | `review_id: str`, `items: list[dict]` | 批次的原子验证。`in_progress`(+ `missing` 列表),`phase_complete`(+ 下一阶段指令),或 `complete`。无效项目引发错误,列出每个问题;不会保存任何内容 |
| `get_verdict` | `review_id: str` | 仅当所有阶段都完成后:编译报告 — 主张,所有项目组织(反驳/缓解措施/测试/响应附加到其目标),聚合风险评分和具有文档化规则的评估 |
| `list_reviews` | — | 所有评论:id,主张片段,模式,状态,当前阶段,时间戳 |
| `abandon_review` | `review_id: str`, `reason: str` | 标记评论为废弃(保留记录,不再提交) |
### 评估规则(确定性)
| 模式 | 风险评分 | `claim refuted` | `claim needs revision` | `claim survives scrutiny` |
|---|---|---|---|---|
| `devils_advocate` | # 反驳在反驳后 `holds` | ≥2 次 hold,或任何严重性-5 的 hold | 正好 1 次 hold,或 ≥2 次部分 hold | 否则 |
| `premortem` | 平均可能性 × 影响(1–25) | 平均值 > 12 | 平均值 > 6,或任何缓解措施具有 `high` 剩余风险 | 否则 |
| `assumptions` | # 未验证的负载假设 | ≥2 个负载假设,证据为 `none` | 正好 1 个证据为 `none`,或 ≥2 个证据为 `partial` | 否则 |
| `steelman` | # 反对立场被让步 | 每个论点都被让步 | 让步 ≥ 反驳 | 反驳超过让步 |
## 工作原理
```mermaid
flowchart TD
S[start_review 主张 + 模式] --> M{模式}
M -->|devils_advocate| C["反驳<br/>≥3, ≥2 类别, 严重性 1–5"]
C --> D{任何严重性 ≥ 3?}
D -->|yes| R["反驳<br/>每个严重反驳"]
D -->|no| V
R --> V[所有阶段完成]
M -->|premortem| P1[设置: 失败范围] --> P2["失败原因<br/>≥4, 可能性 × 影响"]
P2 --> P3{任何分数 ≥ 9?}
P3 -->|yes| P4["缓解措施<br/>行动 + 剩余风险"] --> V
P3 -->|no| V
M -->|assumptions| A1["假设<br/>≥4, 负载 + 证据"]
A1 --> A2{未验证的负载?}
A2 -->|yes| A3["测试<br/>最便宜的验证"] --> V
A2 -->|no| V
M -->|steelman| T1["最强案例<br/>≥3 对方观点"]
T1 --> T2["响应<br/>让步或反驳每个"] --> V
V --> G["获取裁决<br/>报告 + 风险评分 + 评估"]
```
每次 `submit` 操作都会针对当前阶段进行原子验证;服务器仅在阶段要求满足时才继续,自动跳过没有目标的依赖阶段(例如,没有反驳达到严重性 3)。状态以 `~/.mcp-devils-advocate/` 目录下的一个 JSON 文件保存(可通过 `DEVILS_ADVOCATE_DIR` 环境变量覆盖)。
## 快速开始
```bash
pip install -e .
```
**Claude Desktop** — 添加到 `claude_desktop_config.json`:
```json
{
"mcpServers": {
"devils-advocate": {
"command": "python",
"args": ["/绝对路径/to/server.py"]
}
}
}
```
**Claude 代码**:
```bash
claude mcp add devils-advocate -- python /绝对路径/to/server.py
```
## 示例会话
> **用户:** 我们正在考虑用 Rust 重写后端。在我们提交之前,先进行 devil's advocate。
助手调用 `start_review(claim="我们应该用 Rust 重写后端", mode="devils_advocate")` 并收到:
```json
{
"review_id": "rev-k4d7",
"status": "active",
"instructions": {
"phase": "反驳",
"goal": "像 devil's advocate 一样攻击主张...",
"item_format": {
"text": "字符串,≥ 30 个字符 — 反驳,具体且可证伪",
"category": "以下之一:证据,激励,基准率,替代方案,二次订单,范围",
"severity": "整数 1-5 — 如果为真,对主张的损害程度(5 = 致命)"
},
"rules": [
"提交至少 3 个反驳(一次性提交所有反驳)。",
"使用至少 2 个不同的类别。",
"每个严重性 ≥3 的反驳必须在下一阶段被反驳 — 诚实地分配严重性。"
]
}
}
```
助手进行实际思考并调用 `submit`:
```json
submit("rev-k4d7", [
{"text": "完整重写工作系统失败或大大超过预期 — 增量迁移有更好的基准率。", "category": "基准率", "severity": 4},
{"text": "团队没有生产 Rust 经验;招聘和培训成本将恰好落在功能交付被冻结时。", "category": "证据", "severity": 4},
{"text": "性能分析显示瓶颈是数据库层,而不是 CPU — 重写优化的部分不是慢的。", "category": "替代方案", "severity": 5},
{"text": "推动重写的工程师是那些希望在简历上添加 Rust 的人 — 激励措施与商业案例不一致。", "category": "激励", "severity": 2}
])
```
服务器验证批次,标记阶段完成,并返回带有三个目标(严重性 ≥3 项)的 `rebuttals` 阶段。助手诚实地反驳每个目标:
```json
submit("rev-k4d7", [
{"index": 0, "verdict": "partially_holds", "justification": "总体正确,但我们可以将重写范围限定在两个无状态服务,首先实现一个增量迁移。"},
{"index": 1, "verdict": "holds", "justification": "没有诚实的反驳:团队中没有人交付过 Rust 项目,招聘市场在我们的地区很薄弱。"},
{"index": 2, "verdict": "holds", "justification": "性能数据是真实的 — p99 延迟存在于 Postgres 查询中。Rust 重写不会影响这一点。"}
])
```
所有阶段都完成后,`get_verdict("rev-k4d7")` 编译报告:
```json
{
"review_id": "rev-k4d7",
"claim": "我们应该用 Rust 重写后端",
"mode": "devils_advocate",
"risk_score": {"value": 2, "scale": "0-3 反驳在反驳后保持"},
"assessment": "主张被驳斥",
"assessment_reason": "3 个反驳中:2 次保持,1 次部分保持,0 次被驳斥;一个严重性-5 的反驳保持。规则:如果 ≥2 次保持或任何严重性-5 的保持,则驳斥; ..."
}
```
> **助手:** 主张没有经受审查。两个反驳保持,包括一个严重性-5 的反驳:我们的瓶颈是数据库,而不是 CPU,因此 Rust 重写攻击的问题不正确 — 而且我们没有 Rust 经验。建议:首先修复查询层;如果 CPU 成为瓶颈,迁移一个无状态服务作为试点。
## 开发
```bash
pip install -e ".[dev]"
python -m pytest
```
测试涵盖阶段转换、验证错误、所有四种模式直到裁决规则的完整流程,以及持久性 — 不需要安装 `mcp` 即可运行(`core.py` 是纯标准库)。
## 许可证
MIT