---
title: "令牌预算"
description: "200K 上下文窗口不是全部。理解 Claude Code 如何管理 token 预算：动态计算、近似 vs 精确计数、分层压缩策略和缓存优化。"
keywords: ["Token 预算", "上下文窗口", "token 计算", "压缩策略"]
---

## 核心约束：200K 不是全部

Claude 的上下文窗口为 200K tokens（部分模型支持 1M），但实际可用于对话的空间远小于此：

```
上下文窗口（200K）
├── 系统提示词（~15-25K）
├── 工具定义（~10-20K，含 MCP 工具）
├── 用户上下文（CLAUDE.md、git status 等）
├── 输出预留（AI 响应的空间）
└── 剩余：对话历史空间（随对话增长而缩小）
```

**设计挑战**：对话历史不断增长，可用空间持续缩小。系统必须在"保留足够的上下文让 AI 理解对话"和"不超出 token 限制"之间持续平衡。

### 上下文窗口的动态解析

上下文窗口大小不是硬编码的。系统按优先级从多个来源解析：

1. 用户环境变量覆盖（强制指定）
2. 模型名后缀标记（如 `[1m]` 表示 1M 窗口）
3. 模型自身的能力声明
4. 特定 beta 功能的支持情况
5. 兜底值：200K

这种分层解析意味着同一个系统可以适配不同模型和不同配置，而不需要为每种情况写特殊逻辑。

## Token 计数：近似 vs 精确

Token 计数是所有预算决策的基础。系统采用两级策略：

### 近似估算（毫秒级）

基于一个简单的经验公式：大约每 4 个字节 ≈ 1 个 token。对不同内容类型有调整：
- **JSON/JSONL**：更密集，每 2 字节 ≈ 1 token
- **图片/文档**：固定估算值（基于尺寸上限的保守估计）
- **普通文本**：每 4 字节 ≈ 1 token

### 精确计数（需要 API 调用）

使用 Anthropic 的 token 计数端点。不同 Provider 的支持程度不同：

| Provider 类别 | 精确计数支持 | 注意事项 |
|---------------|-------------|----------|
| Anthropic 直连 | 原生支持 | 最准确 |
| 云平台（Bedrock/Vertex） | 各自的 SDK 接口 | 需要额外依赖 |
| 第三方兼容（OpenAI/Gemini/Grok） | 不支持 | 退回近似估算 |

### 为什么需要两级策略

近似估算用于**热路径**——每轮 agentic loop 都需要判断"是否需要压缩"，这个检查必须足够快。精确计数用于**关键决策点**——压缩前后对比、费用计算等需要准确数字的场景。

**设计权衡**：近似估算可能偏差 10-20%，这意味着自动压缩的触发时机可能略有提前或延后。但这个偏差是可以接受的——提前压缩只多花一点 token，延后压缩最多触发一次 API 错误然后紧急压缩。

## 分层压缩策略

系统不是等到"满了才压缩"，而是采用了由轻到重的分层策略：

### 第一层：工具结果截断

单个工具的输出有硬性上限（通常 100K 字符）。超长的命令输出、文件内容在写入消息前就被截断。

这是最轻量的"压缩"——只是防止单个工具结果占用过多空间。

### 第二层：微压缩（Micro-Compact）

在触发全量压缩之前，系统先尝试只压缩旧的工具调用结果：

- 超过一定时间的工具结果被替换为简短占位符
- 图片/文档结果替换为 `[image]` / `[document]` 文本
- 每次替换释放 token，可能推迟全量压缩的触发

**设计考量**：为什么不直接全量压缩？因为全量压缩需要调用 AI 生成摘要，成本高且耗时。微压缩是确定性操作（简单替换），几乎零成本，可以频繁执行。

### 第三层：自动压缩（Auto-Compact）

当对话接近 token 上限时，系统用 AI 自身来总结之前的对话：

1. **剥离非必要内容**：图片、文档附件被替换为文本标记
2. **生成摘要**：通过一个独立的 agent 调用生成对话摘要
3. **重建上下文**：用摘要替代原始对话，同时重新注入关键信息（最近操作的文件、活跃的计划等）

**设计考量**：压缩后会重新读取最近操作的 5 个文件。这是因为在实际使用中，AI 最可能需要的就是刚刚操作过的文件——重新读取它们比让 AI 再次搜索更高效。

### 压缩的安全阀

- **连续失败上限**：连续 3 次压缩失败后停止尝试（断路器模式）
- **压缩来源的查询不触发压缩**：防止压缩本身触发无限递归
- **手动压缩**：用户可以随时通过 `/compact` 主动触发

## 缓存感知的压缩设计

压缩操作本身需要调用 API 生成摘要——这是整个会话中最昂贵的操作之一。系统通过**复用主线程的缓存前缀**来优化：

系统 prompt + 工具定义 + 上下文消息通常不变，这部分可以通过 API 的 prompt cache 机制缓存。压缩时的摘要请求复用了这些缓存，使得缓存命中率从接近 0% 提升到接近 100%。

**设计洞察**：这不是一个独立的优化——它是整个缓存策略的一部分。系统 prompt 的组装策略（"不变内容在前"）和压缩时的缓存复用，都是为了最大化 prompt cache 的命中率。

## 输出 Token 的 Slot 优化

一个容易被忽视但影响深远的优化：AI 输出的 token 上限默认只设为 8K，而不是模型支持的最大值（32K 或 64K）。

**为什么**？因为 API 服务端按 `max_tokens` 参数预留推理容量（slot）。99% 的请求实际输出不到 5K tokens，但如果所有请求都预留 32K 的 slot，会导致严重的容量浪费。

降到 8K 后，不到 1% 的请求会被截断——这些请求自动获得一次高上限的干净重试。

**设计哲学**：用 1% 的请求多一次重试的代价，换取 99% 请求的更快响应。这是一个典型的"优化常见路径，用重试处理边缘情况"的设计模式。

## 选择性压缩

除了全量压缩，用户还可以选择只压缩对话的某一部分：

- **压缩早期内容**（保留最近对话）：适用于"开头说了很多背景，但后面只需要关注最近操作"的场景
- **压缩近期内容**（保留早期对话）：适用于"早期的架构决策很重要，但最近的工具调用结果不需要"的场景

两种方向对缓存有不同的影响——保留前缀（早期内容）可以维持 prompt cache，修改前缀则破坏缓存。

## 接下来

- **上下文压缩** — 深入了解压缩的触发条件和摘要生成机制
- **项目记忆** — 理解跨会话的记忆持久化设计
- **穷鬼模式** — 了解如何减少 token 消耗
