Lazy loaded image
Agent丨大模型长上下文场景下,如何进行上下文压缩与优化?
字数 7055阅读时长 18 分钟
2026-4-20
type
Post
status
Published
date
Apr 20, 2026
slug
agent14
summary
tags
Agent
category
icon
password
在 Agent、RAG、AI Coding 这类系统里,长上下文不是“模型窗口越大越好”的问题,而是“如何把有限注意力分配给真正重要的信息”的问题。Anthropic 在 Claude API 文档里也明确指出:随着 token 数增长,准确率和召回会退化,长上下文会出现 context rot;因此,管理上下文内容和拥有大窗口一样重要。(Claude Platform) 经典论文《Lost in the Middle》也验证了一个常见现象:关键信息放在长上下文中间时,模型使用效果会明显下降。(ACL 论文集)
本文从 Claude Code、OpenCode、OpenClaw 这类成熟 Agent 的公开文档、配置与 issue 出发,结合 RAG 的检索压缩、对话压缩、工具结果裁剪、记忆沉淀、上下文预算等技术,系统讲清楚:大模型长上下文场景下,应该如何做上下文压缩与优化。

一、先定义问题:上下文不是记忆,而是模型当前能看到的工作区

在 Agent 系统里,“上下文”通常由几类内容组成:
OpenClaw 文档对 context 的定义很清晰:context 是每次 run 发送给模型的所有内容,包括系统提示词、会话历史、工具调用结果、附件等;它和 memory 不同,memory 可以存在磁盘上,context 是模型当前窗口内可见的内容。(OpenClaw)
Claude Code 的 context window 文档也指出,会话启动前就可能加载 CLAUDE.md、auto memory、MCP 工具名、skill 描述等;随着工作进行,每次文件读取、工具结果、hook 触发内容都会继续占用上下文。(Claude Code)
因此,长上下文优化的核心不是“把更多内容塞进去”,而是:
在每一轮模型调用前,动态决定:哪些内容必须原文保留,哪些内容可以摘要,哪些内容可以检索,哪些内容应该丢弃,哪些内容应该沉淀到长期记忆。

二、成熟 Agent 是怎么做的?

1. Claude Code:自动压缩、手动压缩、子 Agent 隔离、Skills 按需加载

Claude Code 的公开文档展示了几个很关键的设计点。
第一,Claude Code 会在上下文接近限制时使用 auto-compaction,把历史对话压缩成结构化摘要;/compact 则允许用户手动压缩,并指定“重点保留什么”。Claude Code 文档还建议用 /usage 观察 token 使用,用 /clear 在无关任务间清空上下文。(Claude Code)
第二,Claude Code 会区分不同内容在 compaction 后是否自动恢复。例如系统提示词、项目根目录 CLAUDE.md、auto memory 会重新注入;路径级规则、子目录 CLAUDE.md 只有在再次读取匹配文件时才会重新加载;skill body 重新注入但有 token 上限。(Claude Code)
第三,Claude Code 鼓励用 subagent 隔离高噪声操作。比如跑测试、抓日志、查外部文档,这些操作会产生大量输出;放到子 Agent 的独立上下文里执行,只把摘要返回主会话,可以显著减少主上下文污染。(Claude Code)
第四,Claude Code 建议把通用但低频的长指令从 CLAUDE.md 移到 Skills,因为 CLAUDE.md 会在会话启动时进入上下文,而 Skills 是按需加载。文档甚至建议把 CLAUDE.md 控制在 200 行以内。(Claude Code)
这说明 Claude Code 的上下文策略不是单点摘要,而是一套组合拳:
启动上下文瘦身 + 工具输出预处理 + 子 Agent 隔离 + 手动/自动压缩 + 长期记忆重注入。

2. OpenCode:compaction.auto、prune、reserved 三个核心旋钮

OpenCode 的配置文档提供了一个非常简洁的上下文压缩接口:
其中 auto 表示上下文满时自动压缩,prune 表示移除旧工具输出以节省 token,reserved 表示为压缩过程预留 token 缓冲,避免等到窗口满了才发现已经没有空间生成摘要。(OpenCode)
OpenCode 的实践也暴露了一个重要问题:如果 Agent 或 subagent 工作流里上下文增长过快,哪怕开启 auto-compaction,也可能仍然遇到 context_length_exceeded,尤其是在多 Agent、多工具、多轮调用中。(GitHub)
另一个典型 issue 指出,超大的 AGENTS.md / CLAUDE.md / CONTEXT.md 如果每轮都完整注入系统提示词,会在任务开始前就消耗大量上下文,甚至导致第一轮直接触发 compaction loop。该 issue 建议:大文件不要直接注入,而是插入短提示,让 Agent 在需要时用 read 工具按需读取。(GitHub)
这给我们的启发是:
自动压缩不能替代上下文入口控制。项目指令、工具定义、长文档、日志文件,都应该有尺寸上限、按需加载和压缩策略。

3. OpenClaw:上下文可观测、保留工具调用配对、memory flush、可插拔压缩器

OpenClaw 文档里对上下文工程的拆解更偏平台化。它提供 /status/context list/context detail/context map/usage tokens 等命令,用于观察当前上下文来源和大小。(OpenClaw)
OpenClaw 的 compaction 机制有几个关键点:
  • 旧消息会被摘要成 compact entry;
  • 摘要会写回 session transcript;
  • 近期消息保留原文;
  • 切分历史时会保证 assistant tool call 和对应 toolResult 不被拆散;
  • 完整历史仍保存在磁盘,compaction 只改变下一轮模型看到的内容。(OpenClaw)
OpenClaw 还支持自动压缩、手动 /compact、指定压缩模型、identifier preservation、active transcript byte guard、successor transcript、memory flush、可插拔 compaction provider 等配置。(OpenClaw)
它的配置 schema 里也能看到更细粒度的设计:contextPruning 支持工具结果裁剪;compaction 支持 reserveTokenskeepRecentTokensmaxHistoryShareidentifierPolicymemoryFlushtruncateAfterCompactionmaxActiveTranscriptBytesnotifyUser 等参数。(GitHub)
不过 OpenClaw 的 issue 也很好地暴露了压缩系统的复杂性。例如有 issue 指出,compaction 如果把文件读取状态当成普通叙事历史压缩掉,会导致 Agent 反复重读同一批关键文件,浪费 token 并造成状态不一致。(GitHub) 另一个 issue 指出,tool call 和 tool result 如果在压缩边界处理不好,会出现 orphan toolResult,导致 API 请求失败。(GitHub) 还有安全 issue 指出,如果 identifier preservation 策略无差别保留 API key、token、URL 等 opaque identifier,就可能让敏感信息穿越多轮 compaction 并被外传。(GitHub)
这说明一个成熟的 compaction 系统必须同时考虑:
压缩质量、工具轨迹一致性、运行状态保留、敏感信息脱敏、失败回退、可观测性。

三、上下文压缩的 6 层架构

真正可靠的长上下文优化,不应该只靠“把历史总结一下”。建议把系统拆成 6 层:

第 1 层:输入入口控制

入口控制要解决的是:什么内容一开始就不应该进入上下文。
常见策略:
• 超大 AGENTS.md、CLAUDE.md、CONTEXT.md 不全文注入,只注入目录、摘要和读取提示。 • 大型日志、测试输出、grep 结果必须先过滤。 • MCP 工具过多时,只注入工具名或延迟加载 schema。 • 专项流程放到 Skills,而不是塞进全局项目指令。 • 子目录规则按路径触发,而不是全局注入。
Claude Code 成本文档也建议用 hooks 预处理大日志,比如测试命令只返回失败片段;并建议禁用不用的 MCP server,因为工具定义本身也会占用上下文。(Claude Code)

第 2 层:Token 预算分账

不要让上下文自然增长,应该主动预算。
一个实用预算模型:
例如 128K 上下文窗口可以这样分配:
区域
建议比例
说明
System / Tool Schema
10% - 20%
固定成本,尽量缓存和瘦身
当前任务与用户请求
5% - 10%
必须原文保留
最近对话尾部
15% - 25%
保留最近 N 轮,避免摘要丢细节
RAG / 代码片段
20% - 35%
只放当前任务相关内容
历史摘要 / Memory
10% - 20%
结构化摘要,而非全量历史
输出预留
10% - 20%
避免模型无法完整回答或无法生成压缩摘要
OpenCode 的 reserved 参数、OpenClaw 的 reserveTokens / keepRecentTokens / reserveTokensFloor,本质上都是为了给后续生成、压缩、恢复留空间。(OpenCode) (GitHub)

第 3 层:轻量裁剪 pruning

Pruning 不是 summarization。它通常不调用 LLM,只做确定性裁剪。
适合 pruning 的内容:
• 旧工具输出 • 过长 stdout / stderr • 重复日志 • 编译成功的完整输出 • 旧搜索结果 • 已被结构化记录的中间观察
OpenCode 将 prune 设计成 compaction 配置的一部分,默认用于移除旧工具输出。(OpenCode) OpenClaw 文档也明确区分 compaction 和 pruning:compaction 摘要旧对话并保存到 transcript;pruning 则更轻量,主要裁剪工具结果。(OpenClaw)

第 4 层:语义压缩 compaction

Compaction 要解决的是:历史有价值,但不能原文保留。
一个好的压缩摘要不应该是“聊天记录摘要”,而应该是“任务接力文档”。
推荐结构:
Claude Cookbook 给出的自动压缩流程也是类似模式:监控 token,超过阈值时请求摘要,清空历史,只保留摘要,然后继续任务。(Claude Platform) Claude API 的 server-side compaction 则是在接近阈值时检测、生成 summary、创建 compaction block 并继续响应。(Claude Platform)

第 5 层:长期记忆 memory offload

上下文压缩之后最怕丢两类信息:
• 决策类信息:为什么这么改、不能这么做的原因、用户偏好。 • 运行状态类信息:哪些文件已读、哪些测试已跑、哪些任务已完成。
所以压缩前要做 memory flush:把长期有价值的信息写入外部存储,再在后续轮次按需检索回来。OpenClaw 文档提到,compaction 前可以运行 silent memory flush,把 durable notes 写到磁盘,避免上下文丢失。(OpenClaw)
但 memory 不能无脑塞回上下文。正确做法是:

第 6 层:RAG 压缩与重排

RAG 场景下,长上下文优化更复杂,因为 retrieved docs 本身就是大头。
推荐管线:
LlamaIndex 的 node postprocessor 文档里提供了 LLM rerank、相似度过滤、LongContextReorder 等后处理思路;LongContextReorder 的目标就是在需要较大 top-k 时调整节点顺序,缓解长上下文中间位置利用率差的问题。(Developer Documentation) (Developer Documentation)
LLMLingua / LongLLMLingua 则代表了另一条路线:用较小模型或压缩模型对 prompt 做细粒度压缩,保留关键语义信息,减少推理成本。Microsoft Research 对 LLMLingua 的介绍提到,它会识别并移除 prompt 中不重要的 token,让闭源 LLM 使用压缩后的 prompt 推理。(微软) LongLLMLingua 在 RAG 中强调 reranking、fine-grained prompt compression、subsequence recovery,以改善大段检索内容里的关键信息感知。(LlamaIndex)

四、参考实现:一个可落地的 Context Engine

下面代码不是某个项目的逐字源码,而是综合 Claude Code / OpenCode / OpenClaw 的公开设计后,抽象出来的工程实现骨架。

1. 上下文元素建模

这里的关键点是:不要把上下文看成字符串数组,而要看成带元数据的资源池。

2. Token 预算器

这里的 outputReserve 很重要。很多系统的 compaction 失败,不是因为没有摘要能力,而是因为已经把窗口塞满了,模型连生成摘要的空间都没有。

3. 构建上下文包:先 pin,再 recent,再 RAG,再 memory

注意最后的 repairToolPairs。OpenClaw issue 里出现过 orphan toolResult 问题,本质就是压缩边界破坏了 tool_call / tool_result 的合法结构。(GitHub)

4. 保护 tool call / tool result 配对

对 Agent 来说,工具轨迹是状态机,不是普通文本。压缩时必须保证合法性。

5. 对话 compaction 摘要 Prompt

这里特别加入了敏感信息脱敏,因为 compaction 很容易把 secret “持久化”。OpenClaw 的安全 issue 就指出,如果压缩摘要无差别保留 token、API key 等 opaque identifier,可能形成 read → compaction → web_fetch 的泄漏链。(GitHub)

6. 工具输出裁剪

Claude Code 文档中的 hook 示例也是类似思想:不要把 10000 行日志交给模型,而是在模型看到之前就过滤出失败片段。(Claude Code)

7. RAG 上下文压缩:高召回、强重排、句子级抽取

生产系统里可以把 lexicalRelevance 换成 cross-encoder、LLM reranker、LLMLingua、句子级 embedding compressor。这里的关键原则是:RAG 不要把 chunk 原样塞进上下文,而是先压缩到和当前 query 相关的证据句。

五、不同场景下应该怎么选策略?

场景 1:AI Coding Agent

优先级:
项目规则瘦身:CLAUDE.md / AGENTS.md 只放核心规则。文件按需读取:不要启动时扫描全仓。LSP / symbol search 替代 grep + read 大量文件。测试输出只保留失败片段。子 Agent 隔离探索、日志、文档检索。每个阶段主动 /compact 或自动压缩。把架构决策写入 memory / docs,而不是依赖聊天历史。
Claude Code 文档也建议用 LSP 提供精确符号导航,减少不必要的文件读取;并建议把高输出任务交给 subagents。(Claude Code)

场景 2:RAG 问答

优先级:
chunk 设计:父子分块、句子窗口、标题路径元数据。高召回检索:先取较大 top-k。rerank:用 cross-encoder 或 LLM rerank 降到 top-n。context compression:只保留和 query 相关的句子。reorder:把最高价值证据放在开头和结尾,降低 lost-in-the-middle 风险。引用链保留:压缩后仍保留 doc_id、page、section、chunk_id。

场景 3:长会话客服 / 办公 Agent

优先级:
会话摘要滚动更新。用户偏好写入长期记忆。当前工单状态原文保留。历史工单只保留决策和结论。工具结果只保留业务字段,不保留原始 JSON。每次压缩后做一致性检查:用户诉求、待办、承诺、截止时间是否还在。

场景 4:多 Agent 协作

优先级:
每个 Agent 独立上下文窗口。Agent 间只传递 contract,不传递完整聊天历史。主 Agent 保存全局任务状态。子 Agent 返回结构化报告。长任务使用 checkpoint,而不是无限延长单会话。
Claude Code 文档提到,subagent 会运行在独立上下文窗口中,只把结果返回主会话;但如果很多 subagent 都返回详细结果,仍然会消耗主上下文。(Claude Code)

六、上下文压缩最容易踩的坑

1. 摘要过度抽象,丢掉可执行细节

坏摘要:
已经修复了登录问题,下一步继续测试。
好摘要:
已修改 src/auth/login.tsvalidatePassword(),增加空密码校验;pnpm test auth 仍失败,失败用例是 should reject expired token,原因疑似 TokenService.now() mock 未生效;下一步检查 tests/auth/token.spec.ts

2. 压缩时丢掉操作状态

例如:
哪些文件读过?
哪些命令跑过?
哪些测试失败?
哪些任务已完成?
这些不是普通历史,而是 Agent 的运行状态。OpenClaw 的相关 issue 就指出,compaction 如果不保留文件读取状态,会导致 Agent 反复重读文件并造成状态不一致。(GitHub)

3. 工具调用边界被破坏

对支持 tool calling 的模型来说,tool call / tool result 是协议结构。压缩时不能只删 assistant 消息或只删 tool result。OpenClaw 的 orphan toolResult issue 就是这个问题的典型案例。(GitHub)

4. Secret 被摘要持久化

压缩摘要经常比原始上下文活得更久。如果 API key、token、password 进入摘要,就可能跨轮次、跨会话、跨工具传播。OpenClaw 安全 issue 已经把这类风险描述为 read → compaction → web_fetch 的泄漏链。(GitHub)
建议所有 compaction 前后都跑一层脱敏:

5. 等到 95% 甚至 100% 才压缩

这很危险,因为压缩本身需要输入空间和输出空间。OpenClaw 有 issue 提到,在慢速本地模型上,compaction 触发不稳定或超时会导致长期运行会话不可用。(GitHub)
更稳妥的设计:
• 70%:开始 warning。 • 80%:先 pruning。 • 85%:memory flush。 • 90%:compaction。 • provider overflow:压缩后 retry。

七、评估指标:怎么判断压缩做得好不好?

不要只看 token 减少比例。上下文压缩要同时看质量和成本。
指标
说明
Compression Ratio
压缩前后 token 比例
Task Success Rate
压缩后任务能否继续完成
State Retention
文件、决策、待办、测试状态是否保留
Citation Retention
RAG 证据引用是否仍可追溯
Tool Validity
tool call / tool result 是否协议合法
Secret Leakage Rate
摘要中是否残留敏感信息
Re-read Rate
压缩后是否反复读取同一文件
User Correction Rate
压缩后用户纠正次数是否增加
Latency / Cost
每轮推理成本和耗时是否下降
ACON 这类研究也在强调,长程 Agent 的上下文压缩不能只压 token,还要保持 task success;其论文报告在多个 Agent benchmark 上降低峰值 token 使用的同时保持任务成功。

八、推荐的生产级方案

最终,一个生产级长上下文系统可以这样设计:
最小可行版本:
• 每轮统计 token。 • 工具输出做 head/tail + error extraction。 • 历史超过 80% 时摘要旧消息。 • 保留最近 N 轮原文。 • 摘要结构化。 • 压缩前做 secret redaction。 • RAG 检索结果先 rerank 再抽取关键句。 • 大项目指令按需读取,不启动时全文注入。
进阶版本:
• 独立 Context Engine。 • 每类上下文有预算和优先级。 • 支持 pluggable compressor。 • 支持 memory flush 和 memory search。 • 支持 tool pair repair。 • 支持压缩质量审计。 • 支持可观测命令,如 /context list/context map/usage。 • 支持多 Agent 独立上下文和结构化 handoff。

九、结论

长上下文优化的本质不是“压缩文本”,而是“管理模型的工作记忆”。
一套好的上下文压缩系统,需要同时做到:
• 少放:入口处限制无关内容。 • 晚放:按需加载规则、技能、文件、工具 schema。 • 精放:RAG 先 rerank,再句子级压缩。 • 稳放:当前任务、最近尾部、工具状态原文保留。 • 会忘:旧日志、重复输出、无关历史大胆裁剪。 • 会记:关键决策、长期偏好、运行状态写入 memory。 • 可恢复:压缩摘要像任务交接文档,而不是聊天总结。 • 可观测:知道 token 花在哪里,知道压缩丢了什么。
Claude Code、OpenCode、OpenClaw 的实践都指向同一个结论:**长上下文能力越强,越需要上下文工程。**模型窗口变大只是在扩大“可用内存”,而上下文压缩与优化才是在做“操作系统级内存管理”。
回到首页