深度解析:Claude Code 的 /compact 命令是如何优化上下文的

作者
  • avatar
    姓名
    Nino
    职业
    Senior Tech Editor

随着 Claude Code 等基于 LLM 的命令行工具成为开发者工作流的核心,如何管理上下文窗口(Context Window)和 API 成本成为了一个关键挑战。Claude Code 将整个对话历史以 JSONL 文件的形式本地存储在 ~/.claude/projects/ 目录下。如果不进行干预,你发送的每一条后续消息都会将完整的历史记录附加并发送到 Anthropic 的服务器,这会导致延迟增加和 Token 消耗激增。为了解决这个问题,Claude Code 引入了 /compact 命令。

在本教程中,我们将对运行 /compact 时发生的情况进行深度取证分析。我们将使用代理工具拦截流量,并编写 Python 脚本来衡量 Token 的缩减效果。如果你正在寻求稳定、高速且支持 Claude 3.5 Sonnet 或 DeepSeek-V3 等模型的企业级 API 访问,建议关注 n1n.ai

实验环境搭建:深度检测工具

为了观察底层发生的情况,我们需要拦截 Claude CLI 与 Anthropic API 之间的加密 HTTPS 流量。我们将使用 mitmproxy 进行拦截,使用 jq 处理 JSON,并使用 tiktoken 进行 Token 估算。

首先,安装必要的工具:

brew install mitmproxy
brew install jq
pip install tiktoken

运行 mitmproxy 一次以生成必要的 SSL 证书:

mitmproxy
# 启动后按 q 退出

证书会生成在 ~/.mitmproxy/ 路径下。我们必须配置 Claude Code 信任此本地证书颁发机构,否则它会拒绝代理连接。

第一步:建立基准

为实验创建一个新目录,并配置环境变量以通过代理路由流量:

mkdir ~/compact-experiment && cd ~/compact-experiment

export HTTPS_PROXY=http://127.0.0.1:8080
export HTTP_PROXY=http://127.0.0.1:8080
export NODE_EXTRA_CA_CERTS=~/.mitmproxy/mitmproxy-ca-cert.pem

claude

在另一个终端中,启动 mitmproxy 并通过按 f 设置过滤条件为 api.anthropic.com,以便只观察与 Anthropic 服务器的通信。

为了构建一个真实的上下文,我连续运行了 10 个 Prompt 来构建一个 Python FastAPI 服务器。这包括添加 Pydantic 验证、使用 slowapi 进行速率限制、编写单元测试、异常处理和中间件。到第 10 个 Prompt 时,对话历史已经相当庞大。

第二步:分析本地存储(压缩前)

Claude Code 会维护本地状态。你可以在家目录中找到 JSONL 历史记录。让我们在执行压缩前检查文件的大小和结构。

ls ~/.claude/projects/
cp ~/.claude/projects/<项目文件夹>/*.jsonl ~/compact-experiment/pre-compact.jsonl

# 检查行数和文件大小
wc -l pre-compact.jsonl
ls -lh pre-compact.jsonl

在该文件中,一条典型的用户消息如下所示:

{
  "uuid": "msg_01XK...",
  "type": "human",
  "message": {
    "role": "user",
    "content": "Add rate limiting using slowapi..."
  },
  "timestamp": "2025-01-17T10:23:45.123Z",
  "sessionId": "sess_abc123..."
}

此时,pre-compact.jsonl 文件大小约为 38 KB。然而,发送到 API 的实际请求 Payload 会更大,因为它包含了系统提示词(System Prompt)和格式化元数据。

第三步:测量 API Payload

使用 Python 脚本,我们可以计算 mitmproxy 捕获的最后一次请求的 Token 数量。虽然 Anthropic 使用私有分词器,但 tiktoken(使用 cl100k_base 编码)为 Claude 3.5 Sonnet 或 DeepSeek-V3 等现代 LLM 提供了非常接近的估算。在 n1n.ai 平台上,这种 Token 优化直接关系到用户的成本控制。

# count_tokens.py
import json, os, sys, tiktoken

enc = tiktoken.get_encoding("cl100k_base")
filepath = sys.argv[1]

with open(filepath) as f:
    messages = json.load(f).get("messages", [])

tokens = sum(len(enc.encode(m.get("content", ""))) for m in messages)

print(f"消息数: {len(messages)}")
print(f"Token 数: {tokens}")
print(f"字节大小: {os.path.getsize(filepath)}")

对压缩前的请求运行此脚本的结果为:

  • 消息数: 21
  • Token 数: 14,280
  • 字节大小: 41,847

第四步:执行 /compact 命令

现在,在 Claude Code CLI 中运行该命令:

/compact

等待几秒钟,Claude 会确认压缩完成。让我们看看更新后的本地 JSONL 文件。

cp ~/.claude/projects/<项目文件夹>/*.jsonl ~/compact-experiment/post-compact.jsonl

有趣的是,本地文件的大小反而增加了(从 38 KB 增加到 41 KB)。这证明了压缩并不会从你的本地机器上删除历史记录。相反,它附加了一个 compact_boundary(压缩边界)文档。

第五步:压缩边界的解剖

使用 grepjq,我们可以检查这个边界条目:

grep -i "compact_boundary" post-compact.jsonl | jq .

该 JSON 对象中的关键字段包括:

  • subtype: compact_boundary —— 这告诉 CLI 从哪里开始生成摘要。
  • compactMetadata.preTokens: 37418 —— 记录了在此检查点之前处理的总 Token 数。
  • logicalParentUuid: 将此边界链接到最后一条完整的消息。

第六步:压缩后的效率提升

为了观察实际收益,我发送了最后一条消息:"Add a /metrics endpoint"。然后分析 mitmproxy 捕获的新请求 Payload。

指标压缩前 (Pre)压缩后 (Post)缩减比例
消息数量21386%
Token 数量14,2801,82087.3%
Payload 大小41.8 KB6.2 KB85.1%

通过运行 /compact,现在的系统提示词中包含了一个对前 21 条消息的简明摘要。只有边界之后的新消息才会作为 messages 数组中的独立条目发送。这意味着在 n1n.ai 等 API 聚合平台上,你的单次请求成本将大幅下降。

技术见解与专业建议

1. 上下文丢失(权衡取舍)

压缩是有损的(Lossy)。虽然它保留了代码的状态和对话的总体逻辑,但它会丢失细粒度的细节。如果你要求模型“记住我在第 3 条消息中建议的那个变量名”,在执行 /compact 后,如果该细节未被视为摘要的重点,模型可能会遗忘。

2. 何时使用压缩

  • 任务切换:当你完成“身份验证”模块并开始开发“数据库”模块时,请运行 /compact
  • 延迟增加:如果模型响应变慢,说明上下文窗口可能接近饱和。
  • 调试阶段避开:在积极调试特定错误时,应避免压缩,因为模型需要完整的堆栈跟踪和之前的尝试记录来定位根本原因。

3. 企业级扩展性

对于使用 Claude Code 的大规模团队,上下文的累积会导致巨大的开销。通过使用 n1n.ai 这样的聚合器,你可以监控不同模型(如 Claude 3.5 Sonnet 和 DeepSeek-V3)的使用情况,确保你的上下文管理策略真正起到了节省成本的作用。

总结

Claude Code 的 /compact 命令是上下文管理的一个强大工具。它利用“本地优先”的存储策略确保完整历史的安全,同时使用摘要“检查点”保持 API 交互的高速和低成本。通过减少约 85% 的 Payload,它有效地重置了长对话的“重力”,让开发循环更加顺畅。

n1n.ai 获取免费 API 密钥。