# 投机执行子系统完全解析

投机执行是 Claude Code 中最激进的性能优化子系统——它在用户还没打字时就预测下一条指令并开始执行，猜对了延迟归零，猜错了静默丢弃。这套系统借鉴了 CPU 投机执行的思想，用一个用户空间的 Copy-on-Write 覆盖文件系统实现安全的"先做再说"。本章将深入解析提示词预测、COW 路径重写、边界系统、管道化预测链的完整机制。

> **源码位置**：`src/services/PromptSuggestion/`（目录内含 `promptSuggestion.ts`、`speculation.ts` 等文件）

> 💡 **通俗理解**：投机执行就像快递公司在你下单前就把你**可能会买**的商品发到附近仓库——根据你的购物历史赌你接下来会买什么，赌对了下单秒到，赌错了悄悄退回，你完全无感。关键词是"赌"——这不是确定性的提前准备，而是在不确定性下押注。（类似亚马逊的 anticipatory shipping 专利。）

> 🌍 **行业背景**：在 AI 编码工具领域，投机执行是一种前沿但尚未普及的优化策略。**GitHub Copilot** 的投机发生在补全层面——它在你打字时预测下一行代码，但不涉及文件系统操作的预执行。**Cursor** 的 Tab 补全也是轻量级预测，不执行工具调用。**Aider** 和 **Windsurf** 没有投机执行机制，每轮都是用户触发后才开始。Claude Code 的投机执行在应用层实现了完整的"预测 → 执行 → 回滚"循环，包括文件系统隔离，这在 AI 编码工具中确实是较少见的设计。但需要注意，"投机执行"本身是 CPU 架构（如 Intel Tomasulo 算法、分支预测）和数据库（乐观并发控制 OCC）中的经典概念，Claude Code 的创新在于**将这些思想移植到 AI Agent 的工具调用场景**，并用用户空间 COW 解决了回滚问题。

---

## 概述

投机执行（Speculation）是 Claude Code 最激进的性能优化——在用户还没打字的时候，系统就已经预测了你要说什么，并且开始执行那条指令。如果预测对了，延迟降为零。如果预测错了，静默丢弃。

这个系统借鉴了 CPU 投机执行的思想，但增加了一个更复杂的挑战：CPU 只需要回滚寄存器状态，而 Claude Code 的投机需要回滚**文件系统写入**。解决方案是一个用户空间的 Copy-on-Write 覆盖文件系统。

---

> **[图表预留 3.2-A]**：时序图 — AI 响应完成 → 建议生成 → 投机执行 → 用户接受/拒绝的完整时间线，标注 CacheSafeParams 复用点

> **[图表预留 3.2-B]**：架构图 — Copy-on-Write overlay 文件系统的读写路径（overlay → main 的路径重写逻辑）

---

## 1. 系统入口与启用条件

### 1.1 Prompt Suggestion 的启用链

提示词预测是投机执行的前置步骤。`promptSuggestion.ts:37-93` 定义了五层启用检查，以及一个日志记录步骤：

```
1. env CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION (true/false 覆盖一切)
2. GrowthBook gate: tengu_chomp_inflection (默认 false)
3. 非交互模式（print mode / piped input / SDK）→ 禁用
4. Swarm teammate → 禁用（只有 leader 显示建议）
5. settings.promptSuggestionEnabled !== false
---
6. 记录 tengu_prompt_suggestion_init 分析事件（注意：这不是一层"检查"）
```

> **澄清**：步骤 6 是一个分析事件的日志记录，不是启用/禁用的判定条件——它不会导致功能被启用或禁用，而是一个副作用操作。因此严格来说，启用链是**五层检查 + 一个日志记录**，而非"六层检查"。我们在此如实区分，避免给读者留下凑数的印象。

每一步检查都记录了禁用的原因（`source: 'env' | 'growthbook' | 'non_interactive' | 'swarm_teammate' | 'setting'`），这意味着 Anthropic 可以精确追踪每种禁用场景的分布。

### 1.2 Speculation 的启用检查

`speculation.ts:337-343`：

```typescript
export function isSpeculationEnabled(): boolean {
  const enabled =
    process.env.USER_TYPE === 'ant' &&
    (getGlobalConfig().speculationEnabled ?? true)
  return enabled
}
```

投机执行目前是 **ant-only**——只有 Anthropic 内部用户可用。但它通过 `getGlobalConfig().speculationEnabled` 支持配置开关，默认为 `true`。

## 2. 提示词预测（Prompt Suggestion）

### 2.1 生成流程

AI 响应完成后，`executePromptSuggestion()`（`promptSuggestion.ts:184-200+`）启动：

```
1. 检查 querySource === 'repl_main_thread'（只在主线程运行）
2. 创建 AbortController + CacheSafeParams
3. tryGenerateSuggestion():
   a. 至少 2 轮 assistant 消息后才生成（assistantTurnCount < 2 → 跳过）
   b. 最后一条 assistant 消息不是 API 错误
   c. 父请求缓存足够大（见 §2.2）
   d. 无 pending 权限请求、无 elicitation、非 plan 模式、无 rate limit
   e. generateSuggestion() → runForkedAgent()
   f. shouldFilterSuggestion() 过滤不合适的建议
```

### 2.2 CacheSafeParams 与缓存复用

这是投机执行的**经济基础**。

`CacheSafeParams` 确保分叉 Agent 的请求与父请求共享 prompt cache。不能改变的参数包括：system prompt、tools 列表、model、messages 前缀、effortValue、maxOutputTokens。

`promptSuggestion.ts:152-156` 的 `getParentCacheSuppressReason()` 会检查父请求是否有足够的缓存 token——如果未缓存的 token 超过 10,000，则抑制建议生成（因为 fork 需要重新处理这些 token，成本太高）。

**PR #18143 的教训**（源码注释见 `promptSuggestion.ts:313-314`）：一次尝试用 `effort:'low'` 降低建议生成成本，但因为修改了 effort 参数（影响 thinking budget_tokens），导致缓存命中率从 92.7% 降至 61%，引起 45 倍的缓存写入量激增。这证明了 Anthropic API 的 prompt cache 键包含了比预期更多的参数。

### 2.3 建议抑制条件

`getSuggestionSuppressReason()`（`promptSuggestion.ts:107-119`）定义了五种抑制场景：

| 条件 | 原因 |
|------|------|
| 功能未启用 | `'disabled'` |
| 有 pending 权限请求 | `'pending_permission'` |
| 有 elicitation 队列 | `'elicitation_active'` |
| 在 plan 模式 | `'plan_mode'` |
| 外部用户被限流 | `'rate_limit'` |

## 2.4 SUGGESTION_PROMPT：预测器的核心提示词

**源码位置**：`src/services/PromptSuggestion/promptSuggestion.ts`，第 258–287 行

提示词预测系统的核心是一个名为 `SUGGESTION_PROMPT` 的常量，它定义了预测 AI 分叉实例的**完整行为规范**。这是该子系统中最值得单独解析的设计文档：

```
[SUGGESTION MODE: Suggest what the user might naturally type next into Claude Code.]

FIRST: Look at the user's recent messages and original request.

Your job is to predict what THEY would type - not what you think they should do.

THE TEST: Would they think "I was just about to type that"?

EXAMPLES:
User asked "fix the bug and run tests", bug is fixed → "run the tests"
After code written → "try it out"
Claude offers options → suggest the one the user would likely pick, based on conversation
Claude asks to continue → "yes" or "go ahead"
Task complete, obvious follow-up → "commit this" or "push it"
After error or misunderstanding → silence (let them assess/correct)

Be specific: "run the tests" beats "continue".

NEVER SUGGEST:
- Evaluative ("looks good", "thanks")
- Questions ("what about...?")
- Claude-voice ("Let me...", "I'll...", "Here's...")
- New ideas they didn't ask about
- Multiple sentences

Stay silent if the next step isn't obvious from what the user said.

Format: 2-12 words, match the user's style. Or nothing.

Reply with ONLY the suggestion, no quotes or explanation.
```

**中文分析**：这段 29 行的提示词是整个投机执行子系统的**认知模型的凝结**，每一行都是精心权衡的设计决策：

**1. 核心测试标准："Would they think 'I was just about to type that'?"**

这一行是整个提示词最重要的指导原则。它把"预测用户输入"这个抽象问题，转化为一个具体的心理模型测试：**站在用户的视角，判断这个建议是否让他们感到"正是我想说的"**。这不是"AI 认为用户应该说什么"，而是"用户自己会自然地说什么"——两者有本质区别。前者是 AI 的主观判断，后者是对用户意图的客观预测。

**2. 禁止清单的设计逻辑**

`NEVER SUGGEST` 中的四条禁令揭示了 Anthropic 在实验中发现的常见失败模式：
- "Evaluative"（如"looks good"）：用户不会夸 AI，这是 AI 的语气；
- "Questions"（如"what about...?"）：用户的下一条消息是指令，不是问题；
- "Claude-voice"（如"Let me..."）：这是 AI 说话的方式，不是用户说话的方式——这个禁令防止模型"入戏太深"，把自己的角色和用户的角色搞混；
- "New ideas they didn't ask about"：预测是保守的，不是创意的。

**3. "Stay silent"的设计**

`Stay silent if the next step isn't obvious`——提示词明确允许输出空字符串。这是一个少见但重要的设计：大多数生成任务要求模型"必须输出某些东西"，而这个提示词要求模型在不确定时**主动保持沉默**。对应源码第 284–285 行的`Format: ... Or nothing`。

**4. 格式约束：2–12 词**

输出格式是精确量化的（2–12 words），而不是模糊的"简短"。这直接连接到 `shouldFilterSuggestion()` 函数（第 354–455 行）中的硬过滤规则：`too_few_words`（< 2 词，除非是单词白名单）和 `too_many_words`（> 12 词）。提示词的格式要求和过滤器的数值完全吻合——**提示词和过滤代码是同一个设计的两个实现层次**。

**5. 示例的作用**

提示词中的六个 `EXAMPLES` 不只是说明，更是**行为模板**：它们覆盖了最常见的对话场景（任务完成、代码刚写好、Claude 提供选项、Claude 请求继续、任务完成后的跟进、错误/误解后保持沉默）。模型在预测时可以把当前对话状态匹配到这些模板，降低了生成质量的方差。

**技术注**（源码第 289–292 行）：`SUGGESTION_PROMPT` 虽然被存在两个变体键（`user_intent` 和 `stated_intent`）下，但两个键的值完全相同——`const SUGGESTION_PROMPTS = { user_intent: SUGGESTION_PROMPT, stated_intent: SUGGESTION_PROMPT }`。这说明"两个变体"的 A/B 测试设计框架已经建立，但实际的内容分化尚未实施。这是一个典型的"预留扩展点但当前合并"的工程决策——保持接口的灵活性，避免过早优化。

## 3. 投机执行核心

### 3.1 启动

`startSpeculation()`（`speculation.ts:402-715`）是投机的主入口。流程：

1. 终止现有投机（`abortSpeculation()`）
2. 生成 UUID-8 作为投机 ID
3. 创建 overlay 目录：`~/.claude/tmp/speculation/<PID>/<UUID>/`
4. 设置 AppState.speculation 为 active 状态
5. 调用 `runForkedAgent()` 开始执行

关键参数：
- `maxTurns: 20`（`MAX_SPECULATION_TURNS`）
- `maxMessages: 100`（`MAX_SPECULATION_MESSAGES`）
- `querySource: 'speculation'`
- `requireCanUseTool: true`（所有工具必须经过 canUseTool 检查）

### 3.2 Copy-on-Write 覆盖文件系统

> 📚 **设计灵感与实现差异**：COW（Copy-on-Write）是**操作系统**课程的核心概念——Linux 的 `fork()` 系统调用正是通过 COW 实现父子进程的内存隔离：子进程共享父进程的页表，只在写入时才复制对应的内存页。Claude Code 借鉴了这一思想，在用户空间（而非内核态）实现了文件级 COW。
>
> 但需要明确指出实现差异：
> - **与 OverlayFS 的区别**：Linux OverlayFS 的合并（merge）是内核在文件访问时**透明完成**的，不存在显式的"复制回主目录"调用。Claude Code 的 `copyOverlayToMain()` 更接近一个**暂存区 + 提交**模型——类似 Git 的 staging area → commit 的关系，需要显式地逐文件复制回主目录。overlay 目录的作用不是 OverlayFS 意义上的 upper layer，而是一个用于隔离写入的临时暂存区。
> - **与重排序缓冲区（ROB）的区别**：CPU 的 ROB 是一个精密的硬件机制，负责保证指令的按序提交，涉及寄存器重命名、精确异常处理和指令间依赖检测。Claude Code 的 overlay 目录没有这些语义——overlay 内多个文件的写入之间没有顺序追踪，也没有依赖检测。更准确地说，overlay 是一个**简化的事务暂存区**：commit 时批量写回主目录，abort 时整体丢弃。
>
> 💡 **通俗理解**：可以把 overlay 目录想象成草稿纸——你在草稿纸上演算，确认答案正确后再誊抄到正式本上，如果算错了直接撕掉草稿纸。

这是投机系统中一个实用的工程设计。`canUseTool` 回调（`speculation.ts:461-632`）实现了路径重写逻辑：

**写操作（Edit/Write/NotebookEdit）**：

```
1. 检查权限模式（acceptEdits/bypassPermissions 才允许）
2. 计算 relative path = relative(cwd, filePath)
3. 如果 path 在 cwd 外 → 拒绝
4. 如果文件未在 overlay 中 → 复制原文件到 overlay（COW 语义）
5. 重写 input 中的 file_path 到 overlay 路径
6. 记录到 writtenPathsRef
```

**读操作（Read/Glob/Grep/ToolSearch/LSP/TaskGet/TaskList）**：

```
1. 如果文件已被投机写入 → 重写 path 到 overlay（读取投机版本）
2. 否则 → 不重写（读取原版）
3. 无 path 的读操作（如 Glob 默认 CWD）→ 直接允许
```

**Bash 命令**：

```
1. 调用 checkReadOnlyConstraints() 检查命令是否只读
2. 只读命令 → 允许
3. 非只读命令 → 记录 boundary（type: 'bash', command），中止投机
```

**其他所有工具** → 拒绝并记录 boundary（type: 'denied_tool'）。

### 3.3 四种边界（Boundary）

当投机遇到无法处理的操作时，记录边界并停止：

| 类型 | 触发条件 | 记录内容 |
|------|---------|---------|
| `bash` | 非只读 bash 命令 | command（截断 200 字符） |
| `edit` | 非 acceptEdits 模式下的文件编辑 | toolName + filePath |
| `denied_tool` | 不在白名单中的工具 | toolName + detail（截断 200 字符） |
| `complete` | 投机正常完成（20 轮或模型停止） | outputTokens |

### 3.4 消息注入预处理

`prepareMessagesForInjection()`（`speculation.ts:203-271`）在投机消息被注入主会话前做清理：

1. **去除 thinking/redacted_thinking block** — 投机的思考过程不应注入
2. **去除失败的 tool_use + tool_result 对** — 只保留成功的工具调用
3. **去除 interrupt 消息** — 投机中止产生的中断消息不应出现
4. **去除空白内容消息** — API 拒绝全空格的 text block（400 错误）

### 3.5 接受投机

`acceptSpeculation()`（`speculation.ts:717-800`）：

```
1. 获取 overlayPath 和 writtenPaths
2. 调用 copyOverlayToMain() — 将 overlay 文件复制回主目录
3. 删除 overlay 目录
4. 计算 timeSavedMs = min(acceptedAt, boundary.completedAt) - startTime
5. 累加到 speculationSessionTimeSavedMs
6. 记录到 transcript（speculation-accept 类型）
7. 返回 { messages, boundary, timeSavedMs }
```

`timeSavedMs` 的计算用 `min(acceptedAt, completedAt)` 而非单纯 `completedAt - startTime`——因为如果用户在投机完成前就接受了建议（投机还在运行），节省的时间是用户等待时间，不是投机执行时间。

### 3.6 拒绝/中止投机

`abortSpeculation()`（`speculation.ts:802-833`）：

```
1. 记录 abort_reason: 'user_typed'
2. 调用 abort() 终止 forkedAgent
3. 删除 overlay 目录
4. 重置 AppState.speculation 为 IDLE
```

## 4. 管道化（Pipeline）

> 📚 **课程关联**：管道化预测链直接对应**计算机体系结构**中的"指令流水线（Instruction Pipeline）"概念——当前指令执行时，下一条指令已在译码，再下一条已在取指。Claude Code 的 Pipeline 是：当前投机执行时，下一条建议已在生成。这也是**数据库**课程中"预取（Prefetch）"策略的体现——基于时间局部性假设，提前加载即将需要的数据。

`generatePipelinedSuggestion()`（`speculation.ts:345-399`）：

投机完成后，系统立即开始生成**下一条**建议。流程：

1. 构造 augmentedContext = 原始消息 + 投机用户消息 + 投机响应消息
2. 创建新的 CacheSafeParams（基于 augmented context）
3. 调用 `generateSuggestion()` 预测用户在接受当前投机后会输入什么
4. 结果存入 `pipelinedSuggestion`

如果用户接受了当前投机，管道化建议立刻变成下一轮建议——不需要等新的预测。这形成了一个**预测链**：预测 → 投机 → 管道化预测 → 用户接受 → 管道化建议变为新建议 → 新投机…

## 5. 反馈与可观测性

### 5.1 ant-only 反馈消息

`createSpeculationFeedbackMessage()`（`speculation.ts:273-308`）在投机被接受后向 ant 用户显示：

```
[ANT-ONLY] Speculated 5 tool uses · 1,234 tokens · +3.2s saved (12.5s this session)
```

### 5.2 分析事件

每次投机（无论接受/拒绝/错误）都记录 `tengu_speculation` 事件，维度：

- `speculation_id`：8 字符 UUID
- `outcome`：accepted / aborted / error
- `duration_ms`：投机持续时间
- `suggestion_length`：建议文本长度
- `tools_executed`：成功执行的工具数
- `completed`：是否正常完成
- `boundary_type/tool/detail`：边界信息
- `time_saved_ms`：节省时间（仅 accepted）
- `is_pipelined`：是否是管道化投机

### 5.3 Transcript 持久化

接受的投机被写入 transcript 文件（`speculation.ts:784-797`），格式：

```json
{"type":"speculation-accept","timestamp":"2026-04-02T...","timeSavedMs":3200}
```

文件权限 `0o600`——只有当前用户可读写。

## 6. 安全分析

### 6.1 文件系统隔离

- **写入隔离**：所有写入重定向到 overlay 目录
- **路径越界保护**：`relative(cwd, filePath)` 如果是绝对路径或以 `..` 开头，写入被拒绝
- **权限检查**：写入工具需要 `acceptEdits` 或 `bypassPermissions` 模式
- **bash 隔离**：只允许只读命令（通过 `checkReadOnlyConstraints()` 验证）

> ⚠️ **安全薄弱环节：`checkReadOnlyConstraints()` 的可靠性**
>
> 判断一个 bash 命令是否"只读"在一般情况下是**不可判定问题**。考虑以下例子：
> - `cat file | python -c "import os; os.remove('foo')"` — 表面上像只读（`cat`），实际通过管道执行了文件删除
> - `curl https://example.com/script.sh | sh` — `curl` 本身是只读的，但管道后的 `sh` 可以执行任意操作
> - `$(rm -rf /)` 嵌套在任何看似无害的命令中
>
> 源码中没有暴露 `checkReadOnlyConstraints()` 的完整实现策略——它可能是基于命令白名单（只允许 `cat`/`ls`/`grep` 等已知只读命令）、黑名单（排除 `rm`/`mv`/`write` 等已知写入命令），还是基于更复杂的命令解析（AST 分析），我们无法确定。但无论哪种策略，都存在假阴性（漏判非只读命令为只读）的风险。
>
> 这是投机执行安全模型中**最脆弱的一环**：COW overlay 只隔离了通过 Claude Code 工具层进行的文件写入，而 bash 命令可以绕过工具层直接操作文件系统。如果 `checkReadOnlyConstraints()` 误判一个写入命令为只读，该写入会直接作用于主目录而非 overlay，且无法回滚。在投机执行的语境下（猜错了应该无副作用），这种误判的后果尤为严重。

### 6.2 泄漏风险

- overlay 目录在 `~/.claude/tmp/speculation/<PID>/<UUID>/`，如果进程崩溃，overlay 可能残留
- `safeRemoveOverlay()` 使用 `maxRetries: 3, retryDelay: 100` 做最佳努力清理
- PID 子目录意味着不同进程的 overlay 不会冲突

### 6.3 一致性风险

- 投机读取 overlay 写入的文件版本——但如果外部进程同时修改了主目录的文件，投机看到的是旧版本
- 没有文件锁机制——COW 是"乐观"策略
- 接受时的 `copyOverlayToMain()` 是逐文件复制，不是原子操作——中途崩溃可能导致部分更新

## 7. 性能特征

| 指标 | 值 | 来源 |
|------|---|------|
| 最大投机轮数 | 20 | `MAX_SPECULATION_TURNS` (speculation.ts:58) |
| 最大消息数 | 100 | `MAX_SPECULATION_MESSAGES` (speculation.ts:59) |
| 缓存抑制阈值 | 10,000 未缓存 token | `getParentCacheSuppressReason()` |
| overlay 清理重试 | 3 次，间隔 100ms | `safeRemoveOverlay()` (speculation.ts:72-78) |
| 边界命令截断 | 200 字符 | `getBoundaryDetail()` (speculation.ts:188) |

## 8. GrowthBook Gates

| Gate | 功能 |
|------|------|
| `tengu_chomp_inflection` | Prompt Suggestion 启用（默认 false） |
| ant-only | Speculation 启用（无 GrowthBook gate，硬编码 USER_TYPE 检查） |

## 9. 设计取舍与评价

**优秀**：
1. COW overlay 用 `mkdir + copyFile + 路径字符串替换` 实现了用户空间的文件写入隔离——方案简单直接，不依赖内核级文件系统支持
2. CacheSafeParams 复用让建议生成几乎免费
3. 管道化形成预测链，可以在当前投机执行的同时预生成下一条建议（但注意：多级管道化受限于预测准确率的指数衰减——如果单步准确率为 60%，三级管道化的联合准确率仅约 21.6%，因此超过两级的管道化可能是净负收益）
4. 边界系统干净地处理了"投机到此为止"的语义
5. 每次投机都有完整的分析事件，ROI 可精确计算

**代价**：
1. ant-only 限制意味着外部用户无法享受这项优化
2. 精确字符串匹配意味着轻微的措辞变化（如加标点）会浪费整个投机
3. 非原子的 overlay→main 复制有部分更新风险
4. 20 轮 × API 调用 = 一次错误预测的成本可能相当高
5. overlay 的路径重写逻辑只处理 `file_path`/`path`/`notebook_path`——如果工具用其他字段传递路径，重写会失败

### 9.1 缺失的效果数据

> **诚实声明**：截至本文写作时，没有公开的投机执行命中率、成本模型或 ROI 数据。这是本章分析的一个重大局限。

我们能从源码的可观测性设计**反推** Anthropic 在追踪哪些指标：
- `time_saved_ms` 字段 → 他们在量化节省的用户等待时间
- `is_pipelined` 字段 → 他们在评估管道化的增量价值
- `tools_executed` 字段 → 他们在追踪每次投机的实际工作量
- `boundary_type` 字段 → 他们在分析投机被中止的原因分布

但这些遥测字段只说明 Anthropic **在收集**这些数据，并不告诉我们结果是什么。没有数据，我们无法回答几个关键问题：

1. **预测命中率是多少？** 如果命中率低于 50%，投机执行可能是净负收益（浪费的 API 调用 > 节省的等待时间）
2. **一次错误预测的成本是多少？** 假设平均每轮消耗 500 tokens，20 轮上限意味着最坏情况消耗 10,000 tokens
3. **ant-only 状态持续至今意味着什么？** 一个"最激进的性能优化"在发布后仍然是 internal-only，可能的原因包括：(a) 预测准确率还不够高，(b) 成本/收益比还没有达标，(c) 安全模型还需要加固，(d) 纯粹是产品节奏的选择。无论哪种原因，这一事实本身就说明 Anthropic 对该特性的外部推广仍持谨慎态度

**这为什么重要**：读者在评估是否要在自己的系统中借鉴投机执行模式时，需要知道它是"一个聪明但尚未证明的实验"还是"一个已经验证有效的杀手特性"。没有效果数据，我们倾向于将其定位为前者——一个设计思路值得学习、但 ROI 尚待验证的实验性优化。

### 9.2 精确匹配 vs 语义匹配：一个核心设计权衡

投机执行的接受判定使用**精确字符串匹配**——用户输入必须与预测文本完全一致，投机结果才会被采纳。这意味着即使用户意图完全相同，只要措辞略有不同（多一个标点、换一种表述），整个投机就会被丢弃。

为什么不用语义匹配（如 embedding 相似度 > 0.95）？这里存在一个深层权衡：

**精确匹配的优势**：
- **安全性高**：不会出现"语义相似但意图微妙不同"的误接受（如"删除测试文件" vs "删除测试数据"）
- **实现简单**：字符串比较是 O(n) 操作，不需要额外的模型调用或 embedding 计算
- **可预测**：用户和开发者都能明确理解匹配规则

**精确匹配的代价**：
- **命中率受限**：预测措辞正确但用户表述略有不同时，白白浪费了全部投机计算
- **对自然语言不友好**：自然语言的表述方式天然多样，精确匹配与这一特性相悖

**语义匹配的潜在风险**：
- 需要额外的推理成本（embedding 计算或模型调用）来判断相似度
- 相似度阈值的设定本身就是一个难题——0.95 可能漏掉合理变体，0.85 可能误接受不同意图
- 在涉及文件系统写入的场景下，误接受的后果比误拒绝严重得多

从工程角度看，选择精确匹配是一种**保守但安全**的策略，符合投机执行"猜错了不能有副作用"的核心约束。但这也意味着命中率存在天花板——即使预测模型完美预测了用户意图，只要用户的措辞有任何差异，投机就会失败。这可能是该特性仍在 ant-only 阶段的原因之一。

## 10. 可复用设计模式

1. **用户空间 COW 覆盖**：用 `mkdir + copyFile + 路径重写` 实现写入隔离，不需要内核级文件系统支持
   - *适用场景*：文件数量少、单用户、对原子性要求不高的场景
   - *反模式*：高并发写入、大文件场景、需要目录级操作（创建/删除目录）的场景——此时应考虑 Docker overlay2 或 ZFS snapshot 等内核级方案
2. **Cache-safe forking**：任何"侧任务"都通过保持缓存参数不变来共享父请求的投资
   - *适用场景*：API 提供 prompt cache 且缓存键包含请求参数的场景
   - *反模式*：侧任务需要不同的 model/effort/tools 配置时，强行保持参数不变会限制侧任务的质量
3. **Boundary-based speculation**：不是"全部成功或全部失败"，而是"尽可能多做，遇到边界就停"
   - *适用场景*：操作序列中各步骤的副作用可独立回滚的场景
   - *反模式*：步骤之间存在强依赖（如 A 的输出是 B 的输入）时，部分执行可能产生不一致状态
4. **Pipeline prediction chain**：投机完成后立即预测下一步，提前准备下一条建议
   - *适用场景*：单步预测准确率较高（> 50%）的场景
   - *反模式*：准确率低于 50% 时管道化是净负收益——每增加一级管道化，联合准确率指数衰减，浪费的计算资源迅速超过节省的等待时间

---

