内容
# 笛卡尔
> **怀疑,直到剩下确定的部分。**
[](https://github.com/pranjalbhatia710/descartes-mcp/actions/workflows/ci.yml)
> ### 🔭 姊妹项目: **[提问者](https://github.com/pranjalbhatia710/the-asker)** — *今天的AI回答,这个问题提问。*
> 提问者学习提出最尖锐的问题来理解一个主题;
> 笛卡尔学习怀疑,直到剩下确定的部分。两个半个想法:正确的问题胜过自信的答案。
> → **https://github.com/pranjalbhatia710/the-asker**
🪶 **[首页 →](https://pranjalbhatia710.github.io/descartes-mcp/)** · `descartes --epigraph` 获取来自他本人的短暂思考。
一个MCP服务器,在提示下,**怀疑计划中的每个决定,怀疑自己的怀疑,并回答它们——将每个答案建立在确凿的证据上**——迭代直到计划不再产生新的负荷承载怀疑。然后它返回一个改进的计划和*您需要做出的少数决定*。
目的:没有未经审查的假设到达工作,因此幻觉没有藏身之处。
---
## 循环
在提示下,笛卡尔运行递归的笛卡尔怀疑:
1. **草拟**计划/决定。
2. **怀疑**每个负荷承载的决定(11个怀疑算子之一)。
3. **怀疑怀疑** - 修剪琐碎和制造的怀疑。
4. **回答**每个幸存的怀疑 *仅基于确凿的证据*:
- 代码怀疑 → 从您传递的 `context` 中解决,
- 世界怀疑 → 通过 **Exa** (引用,置信度评分)解决,
- 不可根基的 → 标记为 **NEEDS_HUMAN**。
5. **怀疑答案** - 递归:每个已解决的答案本身都会被怀疑(问题背后的问题),产生下一层怀疑,受深度和全局怀疑预算限制。
6. **存入** - 每个根基的发现累积到一个 **知识库**,用于下一轮怀疑和最终计划。
7. **修订**计划,根据存活的内容,并 **重复**步骤2。
输出因此是一个 **怀疑树** (每个条目携带 `depth` + `parent`),而不是一个扁平列表,以及一个累积的 `knowledge_base`。
**停止规则:** 循环在 **没有新的负荷承载怀疑** 的时候停止,即收敛。它可能是第3次或第9次。**20是一个硬上限,从不作为目标**,递归受 `DESCARTES_MAX_DEPTH` (默认3)和 `DESCARTES_DOUBT_BUDGET` (默认64)限制。它从不制造怀疑来继续。
**根基规则:** 每个答案都与确凿的证据相符,或者成为您的问题。低置信度的Exa从不被断言。20轮自我回答的、无根基的怀疑将是20轮自信的幻觉——因此通过构造禁止。
---
## 两个引擎(自动选择)
| 如果您设置… | 笛卡尔运行… |
| --------------------- | -------------------------------------------------------------------------------------------- |
| `FIREWORKS_API_KEY` | 一个 **panel** 由不同的Fireworks模型家族组成。协议 = 解决;**分歧 = 真实的的不确定性** → 怀疑被升级。 |
| *无* (在支持MCP采样的客户端) | **Claude 独自** - 客户端自己的模型运行整个循环。 |
| `OPENROUTER_API_KEY` | 单模型“Claude 独自”通过OpenRouter(采样不可用时的备用)。 |
| *无密钥* | 一个 **确定性操作模板** 备用,因此它从不硬失败。 |
`EXA_API_KEY` 是独立的:设置它以根基世界怀疑任何模式。
### 没有密钥?它仍然有效 - 只有Claude
您 **不需要** 任何API密钥。在支持采样的MCP客户端(Claude Code)中,整个循环在 **客户端自己的Claude模型** 上运行 - 代码怀疑通过读取您传递的 `context` 解决,需要外部事实或人类决策的内容会返回给您。
即使采样不可用,笛卡尔 **不会猜测**。它不会通过关键词匹配伪造确认怀疑;它将每个负荷承载的怀疑作为 `needs_user` 中的问题呈现给您,并告诉您。因此,退化运行从不沉默。唯一规则:*没有证据的答案 - 否则,询问您。*
---
## 3步设置
```bash
# 1. 安装
git clone https://github.com/pranjalbhatia710/descartes-mcp && cd descartes-mcp
pip install -e .
# 2. (可选)携带您自己的密钥 - 仅复制名称,填写您的.env
cp .env.example .env # .env 被git忽略;从不提交
# 3. 运行它(stdio MCP服务器)
descartes # 或:descartes --selftest 以证明循环收敛
descartes --demo # 在终端中实时观察它怀疑
```
### 观察其工作
`descartes --demo` 运行一个脚本化的怀疑会话,并实时渲染它 - 一个旋转器,当它思考时,一个自我绘制的 **怀疑树** (◆ 顶级,↳ 递归),颜色编码的状态(✓ 确认 · ✗ 反驳 · ⚑ 为您),知识库填充,以及 `CONVERGED` 横幅。
在Claude Code内部,实际的 `doubt()` 工具向客户端报告 **MCP进度 + 日志通知**,因此您可以看到它在运行时的工作。它从不打印到stdout - 该通道是MCP协议。设置 `DESCARTES_VERBOSE=1` 还会在服务器的 **stderr** 日志中流式传输紧凑的进度。
### 添加到Claude Code
将以下内容添加到您的Claude Code MCP配置中(例如,`.mcp.json` 在您的项目中,或通过 `claude mcp add`)。密钥存储在您的shell / 配置环境变量中 - **从不提交文件**:
```json
{
"mcpServers": {
"descartes": {
"command": "descartes",
"args": [],
"env": {
"FIREWORKS_API_KEY": "${FIREWORKS_API_KEY}",
"EXA_API_KEY": "${EXA_API_KEY}",
"OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}"
}
}
}
}
```
然后要求Claude *“使用笛卡尔来怀疑这个计划”* 并传递相关文件作为上下文。
---
## 工具
### `doubt(prompt, context="", max_passes=20)`
运行上述循环。返回:
```jsonc
{
"passes_used": 4,
"converged": true,
"plan": "<改进的、怀疑强化的计划>",
"doubt_log": [
{ "id": 1, "pass": 1, "depth": 0, "parent": null,
"operator": "assumption", "doubt": "...", "kind": "code",
"status": "CONFIRMED|REFUTED|UNKNOWN|NEEDS_HUMAN",
"resolution": "...", "source": "..." }
],
"doubt_tree": [ { "depth": 0, "children": [ { "depth": 1, "children": [] } ] } ],
"knowledge_base": [
{ "claim": "...", "verdict": "CONFIRMED", "evidence": "...", "source": "...", "depth": 0 }
],
"needs_user": [ "<您需要做出的少数决定>" ],
"engine": "claude-sampling",
"note": "<普通英语:本次运行如何执行>",
"max_depth_reached": 2
}
```
`doubt_log` 是扁平记录(每个条目都带有 `depth` + `parent`);`doubt_tree` 是相同的数据嵌套;`knowledge_base` 是笛卡尔沿途根基的一切,它在不需要重新推导的基础上继续构建。
`needs_user` 是产品:它将 **笛卡尔自己解决的问题** 与 **它真正需要您的问题** 分开。保持简短 - 真正的阻塞问题。
### `ground(query)`
Exa深度搜索→引用,置信度评分的事实。在循环内部使用;可以直接调用。低置信度→`status: "UNKNOWN"`(从不断言)。
### `verdict(result)`
传递一个 `doubt()` 结果。返回 `{ proceed, blocking_questions }`。`proceed` 仅在计划以 **没有开放的负荷承载怀疑** 收敛时为真;否则,您会得到阻塞问题。
---
## 怀疑算子
每个怀疑都标记有一个算子(作为数据发送到 [`descartes/operators.py`](descartes/operators.py)):
`assumption` · `falsify` · `inversion` · `named_source` · `edge_case` ·
`quantify` · `root_cause` · `reversibility` · `second_order` · `define` ·
`deletion`
---
## 基准 - 怀疑有多好?
诚实的指标不是准确性(它跟踪您插入的任何模型)。它是:**计划的负荷承载假设有多少未被审查?** 在一个种子化的6个真实形状的计划的固定装置中带有 **19个手动标记的假设** ([`benchmark/coverage.py`](benchmark/coverage.py)):
| 方法 | 审查 | 基于证据的根基 | 向您提问 | **未审查的工作** |
|---|---|---|---|---|
| 计划原样 | 0(0%) | 0 | 0 | 19(**100%**) |
| **笛卡尔** | 19(100%) | 12 | 7 | 0(**0%**) |
未审查的假设到达工作从 **100% → 0%**。在19个表面中,笛卡尔自身根基 **12**,并为您提供仅 **7** 个真正需要人类介入的问题。这是保守的 *下限* - 确定性的,按照 [提问者](https://github.com/pranjalbhatia710/the-asker) 的合成下限。在精神上。真正的模型只会加宽差距,通过抓住标签遗漏的假设并递归更深入。
**收敛** ([`benchmark/bench.py`](benchmark/bench.py))- 它在 **一个通道没有新的怀疑** 时停止,并且失控的运行被限制:
| 场景 | 怀疑深度 | 通道 | 收敛 |
| --- | --- | --- | --- |
| 琐碎 | 0 | 1 | ✅ |
| 中等 | 3 | 4 | ✅ |
| 深入 | 11 | 12 | ✅ |
| 螺旋守卫 | 40 | **20(上限)** | ❌ 按设计 |
收敛恰好是 `depth + 1` 通道,从不超过20。两个基准都在CI上运行每个推送。
---
## 更大想法的组成部分 - 见提问者
笛卡尔有一个姊妹项目: **[提问者](https://github.com/pranjalbhatia710/the-asker)** - *“今天的AI回答,这个问题提问。”* 一个强化学习环境,智能体通过提问最尖锐的问题来理解任何主题,观察一组候选人减少到真相,尽可能少的问题,并击败只会猜测的前沿模型。
它们是两个半个想法:**正确的问题胜过自信的答案。** 猜测是幻觉的来源;这两个工具都用问题取代了它。
- **提问者** 提问,**理解** - 它仅凭奖励就学习哪些问题减少了不确定性。
- **笛卡尔** 怀疑,**确定** - 它质疑每个决定,然后递归质疑自己的答案,直到没有未经审查的内容。
将提问者指向一个主题,观察它学习提问。 将笛卡尔指向一个计划,观察它拒绝猜测。
→ **[github.com/pranjalbhatia710/the-asker](https://github.com/pranjalbhatia710/the-asker)**
---
## 开发和测试
```bash
pip install -e ".[dev]" # pytest + ruff
ruff check descartes/ tests/ benchmark/
pytest -q # 测试,无网络(所有后端都被模拟)
python -m benchmark.bench # 收敛基准(见上面的基准)
python -m benchmark.coverage # 覆盖基准(见上面的基准)
```
测试套件锁定了负荷承载的不变式:循环始终终止,从不超过20的硬上限,并在收敛时尽快添加新的怀疑,它递归(质疑自己的答案)受深度和节点预算限制,没有证据的断言(无法根基 → `NEEDS_HUMAN`,低置信度Exa → `UNKNOWN`),`needs_user` 恰好是 `NEEDS_HUMAN` 的怀疑,并且面板分歧升级到人类。`tests/test_regressions.py` 带有每个通过对抗性审计发现的错误守卫。CI(`.github/workflows/ci.yml`)运行lint + 测试 + 自我测试 + 两个基准测试,适用于Python 3.10-3.13。
## 安全
- **携带您自己的密钥。** 从环境变量读取(`os.environ.get`),从不存储,从不记录,从不提交。`.env` 被git忽略;`.env.example` 仅包含名称。
- 每个外部调用都被try/except + 超时 + 重试封装 - 一次失败从不杀死运行。
- Exa结果被缓存和定时,以便通道保持快速;面板大小在实时路径上被限制(`DESCARTES_PANEL_SIZE`)。
## 许可证
MIT - 见 [LICENSE](LICENSE)。