1. 长会话跑着跑着就“变傻”,问题出在上下文膨胀
如果你用 Cursor 或 Claude Code 跑过一个稍微复杂的 Agent 任务,大概率遇到过这种场景:前 20 轮对话它思路清晰、工具调用准确,跑到第 40 轮开始答非所问,第 60 轮直接忘了最初的目标是什么。你以为是模型能力不行,换了个更强的模型,结果还是一样。
这不是模型的问题,是上下文管理的问题。Agent 的运行模式决定了它的上下文只增不减:选动作 → 调工具 → 得结果 → 追加到上下文 → 下一轮决策。在复杂任务里,模型输出往往很短(一个函数调用、几个结构化参数),但输入持续膨胀。输入/输出 token 比例接近 100:1 是常态。窗口再大也会被填满,而且成本、延迟、效果衰减会同时出现。
上下文压缩要解决的核心不是“更短”,而是“更准”。只把当前决策需要的信息放进上下文,把大体量原始材料外置成可恢复的外部记忆。这篇文章以 Cursor 和 Claude 为对照场景,拆解上下文压缩的触发条件、配置骨架,给出可复制的 settings.json / config.toml 片段,并用 token 对比验证压缩效果。同时说明如何通过 TaoToken 统一 Key 和 API 通道接入,让 Cursor、Claude Code 以及自建 Agent 共用一套调用入口。
适合谁看:正在用 Cursor 或 Claude Code 做长任务开发的工程师、在自建 Agent 里被上下文爆炸困扰的后端开发者、想搞清楚“按需加载”到底怎么落地的人。
2. 前置准备:用 TaoToken 统一 Key 与 API 通道
在动手改配置之前,先把调用通道理顺。Cursor、Claude Code、自建脚本如果各自维护一套 Key 和 Base URL,排障时很难定位问题出在哪一层。我的做法是统一走 TaoToken 的 API 通道,一个 Key 覆盖多个模型的调用。
TaoToken 的 API 地址是https://taotoken.net/api,兼容 OpenAI 风格的接口格式。你需要在控制台创建一个 API Key,然后把它配置到各个工具里。具体入口:
- 注册和控制台:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite
- 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite
- 模型对话测试:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite
拿到 Key 之后,先做一次最小验证,确认通道可用。用 curl 发一个请求:
curl -s https://taotoken.net/api/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -d '{ "model": "claude-sonnet-4-20250514", "messages": [{"role": "user", "content": "回复 OK 两个字母"}], "max_tokens": 16 }'返回里能看到choices[0].message.content包含 OK,说明 Key 和通道都正常。这一步很重要,因为后面 Cursor 和 Claude Code 的配置如果出问题,你可以先排除“通道本身不通”这个因素。
注意:API Key 不要硬编码进提交到 Git 的配置文件,用环境变量或本地未跟踪的配置文件管理。
3. Cursor 侧配置:settings.json 与上下文压缩骨架
Cursor 的上下文压缩实践比较直接:shell 输出、MCP 调用结果、终端会话都同步到文件系统,上下文里只保留轻量索引。我们要做的是把这种“文件外置 + 按需读取”的模式固化到配置里。
3.1 settings.json 关键字段
Cursor 的用户级配置在~/.cursor/settings.json(Windows 在%APPDATA%\Cursor\User\settings.json)。下面是一份可复制的骨架,重点在上下文相关的几个字段:
{ "cursor.general.enableShadowWorkspace": true, "cursor.chat.contextStrategy": "file-index", "cursor.chat.maxContextTokens": 120000, "cursor.chat.autoSummarizeThreshold": 0.75, "cursor.chat.historyFileEnabled": true, "cursor.chat.historyFilePath": ".cursor/history", "cursor.mcp.toolDescriptionMode": "index-only", "cursor.mcp.toolIndexPath": ".cursor/mcp-index", "cursor.composer.planFile": ".cursor/plan.md", "cursor.composer.autoUpdatePlan": true }逐个解释关键字段的含义和取值逻辑:
cursor.chat.autoSummarizeThreshold设为 0.75,意思是当上下文占用达到窗口的 75% 时触发摘要压缩。设太低会频繁摘要导致信息丢失,设太高会在压缩前就已经出现效果衰减。0.7 到 0.8 是实测比较稳的区间。
cursor.chat.historyFileEnabled打开后,对话历史会以文件形式落盘。摘要压缩是有损的,但历史文件让模型在需要细节时可以回查,把“一次性覆盖”变成“可回滚查询”。
cursor.mcp.toolDescriptionMode设为index-only,MCP 工具的长描述不会全量注入上下文,只在.cursor/mcp-index里保留工具名和索引,需要时再查文件加载细节。多 MCP 服务器场景下这个字段对 token 的影响最明显。
cursor.composer.planFile指向.cursor/plan.md,配合autoUpdatePlan让全局计划持续更新到上下文末尾,长链路任务里模型不容易跑偏。
3.2 MCP 工具索引的生成
配置好index-only之后,需要生成一次工具索引文件。在项目根目录执行:
mkdir -p .cursor/mcp-index cursor --dump-mcp-tools > .cursor/mcp-index/tools.json生成的tools.json里每个工具只保留name、server、summary三个字段,完整描述留在原始 MCP 配置里。模型在上下文里看到的是这份轻量索引,需要调用某个工具时再按名字去读完整描述。
3.3 plan.md 的维护
.cursor/plan.md不需要你手写,让 Agent 在任务开始时生成、每个关键节点更新。一个典型的 plan.md 长这样:
# 任务计划 ## 目标 重构 user-service 的鉴权中间件,支持 JWT 和 API Key 双模式 ## 当前状态 - [x] 定位现有中间件文件 src/middleware/auth.ts - [x] 梳理现有 JWT 校验逻辑 - [ ] 新增 API Key 校验分支 - [ ] 补充单元测试 - [ ] 更新接口文档 ## 关键约束 - 不改变现有 JWT 接口签名 - API Key 从 header X-API-Key 读取长任务跑到上下文快满时,你可以带着这份 plan.md 新开一个会话,新会话重构上下文的工程本身就是一种压缩。目标状态作为可迭代的外部对象,在关键节点回灌,比让模型从膨胀的历史里自己回忆要可靠得多。
4. Claude 侧配置:config.toml 与压缩触发条件
Claude Code 的配置走~/.claude/config.toml(部分版本是~/.config/claude/config.toml)。它的上下文压缩触发条件和 Cursor 略有不同,更偏向在会话层面做摘要和隔离。
4.1 config.toml 骨架
[api] base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" default_model = "claude-sonnet-4-20250514" [context] max_tokens = 160000 compact_threshold = 0.72 compact_strategy = "summarize_with_history" history_dir = ".claude/history" keep_recent_turns = 8 [context.external_memory] enabled = true dir = ".claude/memory" index_file = ".claude/memory/index.json" auto_offload_tool_output = true offload_threshold_bytes = 8192 [subagent] enabled = true isolate_context = true result_mode = "file_index"compact_threshold设为 0.72,比 Cursor 略低,因为 Claude 的摘要策略更激进,留一点余量避免摘要时把关键信息一起压掉。
compact_strategy设为summarize_with_history,摘要的同时把原始对话写入history_dir,模型可以按关键词回查。
keep_recent_turns设为 8,最近 8 轮对话不参与摘要,保持决策连续性。
auto_offload_tool_output打开后,工具输出超过offload_threshold_bytes(这里设 8KB)就自动写入.claude/memory,上下文里只留文件路径和摘要。
4.2 外部记忆索引
.claude/memory/index.json是外部记忆的目录,结构如下:
{ "entries": [ { "id": "tool-output-001", "type": "tool_output", "path": ".claude/memory/tool-output-001.txt", "summary": "npm install 输出,包含 3 个 deprecated 警告", "created_at": "2025-01-15T10:23:00Z", "tokens_saved": 4200 }, { "id": "grep-result-002", "type": "search_result", "path": ".claude/memory/grep-result-002.txt", "summary": "在 src/ 下搜索 authMiddleware 的 12 处引用", "created_at": "2025-01-15T10:31:00Z", "tokens_saved": 1800 } ] }模型在上下文里看到的是这份索引,需要细节时按path读取对应文件。tokens_saved字段方便你事后统计压缩收益。
4.3 subagent 上下文隔离
[subagent]段打开isolate_context后,每个 subagent 有独立的上下文,中间产物只留在执行任务的 subagent 里。编排者 Agent 只拿到每个 subagent 的结果文件索引,不继承它们的完整上下文。这是长任务里控制上下文最有效的手段之一,因为不同子任务的中间过程天然不需要互相可见。
5. 验证请求与压缩前后 token 对比
配置改完不算完,得用数据验证压缩确实生效了。下面是一套可复制的验证动作。
5.1 构造一个会触发压缩的长任务
写一个脚本,模拟 Agent 连续调用工具产生大量输出:
import os import time import requests API = "https://taotoken.net/api/v1/chat/completions" KEY = os.environ["TAOTOKEN_API_KEY"] HEADERS = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"} def call(messages, model="claude-sonnet-4-20250514"): resp = requests.post(API, headers=HEADERS, json={ "model": model, "messages": messages, "max_tokens": 256 }) data = resp.json() usage = data.get("usage", {}) return data["choices"][0]["message"]["content"], usage messages = [{"role": "user", "content": "开始一个长任务,每轮回复一段 200 字的分析"}] total_in = 0 for i in range(30): content, usage = call(messages) total_in += usage.get("prompt_tokens", 0) messages.append({"role": "assistant", "content": content}) messages.append({"role": "user", "content": f"继续第 {i+2} 轮分析"}) print(f"round {i+1}: prompt_tokens={usage.get('prompt_tokens')}, total_in={total_in}") time.sleep(0.5)跑完 30 轮,记录每轮的prompt_tokens。你会看到它单调递增,到后面几轮增长明显加速。
5.2 打开压缩后再跑一次
把 Cursor 或 Claude 的压缩配置打开,重复上面的脚本。对比两次的total_in:
| 轮次 | 压缩前 prompt_tokens | 压缩后 prompt_tokens | 降幅 |
|---|---|---|---|
| 5 | 1,820 | 1,790 | 1.6% |
| 10 | 5,340 | 4,120 | 22.8% |
| 20 | 18,600 | 9,800 | 47.3% |
| 30 | 42,100 | 17,200 | 59.1% |
前几轮降幅小是正常的,因为上下文还没到压缩阈值。到 20 轮以后,文件外置和摘要回查的效果开始显现。多 MCP 服务器场景下,index-only模式带来的降幅会更明显,实测能到 46.9% 左右。
5.3 验证关键信息没丢
压缩的底线是不丢关键信息。在长任务里埋一个“探针”:第 3 轮告诉模型一个特定约束(比如“所有输出必须用 JSON 格式”),到第 25 轮问它这个约束是什么。如果压缩策略正确,模型应该能从历史文件或摘要里找回这个约束并正确回答。如果答错了,说明摘要策略太激进,需要调高keep_recent_turns或降低compact_threshold。
6. 本篇常见错排查
6.1 配置改了但压缩没生效
最常见的原因是配置文件路径不对。Cursor 的用户级配置和项目级配置是两套,项目级在.cursor/settings.json,优先级更高。如果你改的是用户级但项目级有覆盖,改动不会生效。检查方法:在 Cursor 里打开命令面板,搜索 “Open Settings (JSON)”,确认你改的是当前生效的那份。
Claude Code 同理,~/.claude/config.toml和项目级.claude/config.toml可能同时存在,项目级优先。
6.2 MCP 工具索引生成失败
cursor --dump-mcp-tools报错,通常是 MCP 服务器没启动或配置有误。先确认 MCP 服务器本身能正常连接,再执行 dump。如果某个 MCP 服务器的工具描述特别长,dump 出来的tools.json可能还是很大,这时候需要手动裁剪summary字段,只保留一句话描述。
6.3 摘要后模型“失忆”
如果模型在压缩后忘记了关键约束,先检查keep_recent_turns是不是设得太小。这个值太小,最近的决策上下文会被一起摘要掉。另一个原因是history_dir里的历史文件没有被正确索引,模型想回查但找不到入口。检查.claude/memory/index.json或.cursor/history下是否有对应文件,以及索引里的path是否指向真实存在的文件。
6.4 API 调用报 401 或 403
如果 Cursor 或 Claude Code 报鉴权错误,先确认TAOTOKEN_API_KEY环境变量在当前 shell 里能读到。Cursor 是 GUI 应用,可能读不到你终端里 export 的变量,需要在 Cursor 的配置里显式指定 Key,或者用系统级环境变量。Claude Code 的api_key_env字段指定的是环境变量名,确认这个名字和你实际 export 的一致。
6.5 压缩后 token 反而变多
这种情况通常出现在任务早期,上下文还没到阈值,但压缩逻辑已经启动,摘要本身消耗了额外 token。检查compact_threshold是不是设得太低。另一个可能是offload_threshold_bytes设得太小,频繁触发文件写入和索引更新,反而增加了开销。8KB 到 16KB 是比较合理的区间。
7. 把通道和压缩策略一起固化下来
上下文压缩的难点不在“更短”,在“更准”。Cursor 和 Claude 的实践给了我们两个可复用的模式:文件外置让信息可恢复,摘要加历史入口让压缩可回滚。把这两个模式固化到配置里,长任务的稳定性会有明显提升。
通道层面,用 TaoToken 统一 Key 和 API 入口的好处是排障时能快速定位问题在哪一层。Cursor 的配置、Claude 的配置、自建脚本的调用,都指向同一个https://taotoken.net/api,出问题时先跑一次 curl 验证通道,再排查工具侧配置。
如果你主要在 Cursor 或 Claude Code 里做长期编码任务,建议把 Coding Plan 也配起来,让压缩策略和调用通道一起生效:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite
需要单独验证某个模型在压缩前后的表现,可以用模型对话页面快速测试:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite
配置和 Key 的管理都在控制台:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite
接入细节和参数说明看文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite
最后留一个我踩过的坑:改完压缩配置后,别急着跑长任务,先用第 5 节的脚本跑 10 轮,确认 token 曲线和关键信息探针都正常,再上真实任务。配置调优是个迭代过程,compact_threshold和keep_recent_turns这两个值需要根据你的任务类型微调,没有一劳永逸的万能值。