---
title: "react - 上下文压缩（compression）"
---


在智能体（Agent）的长期运行中，上下文窗口（Context Window）的限制是开发者面临的最大挑战。随着对话轮次的增加，Token 消耗不仅会带来高昂的成本，更会导致模型因为信息过载而变得迟钝甚至失忆。

Solon AI 通过 `ContextCompressionInterceptor` 拦截器与多维摘要策略，为智能体提供了类似人类的"长短期记忆"管理机制。

### 1、 核心组件：ContextCompressionInterceptor

`ContextCompressionInterceptor` 实现 `ReActInterceptor`，挂载在 ReAct 推理流程上，负责在**推理开始前**（`onReasonStart`）监控工作记忆（Working Memory）的规模；当服务端因上下文超限（PTL, Prompt-Too-Long）返回错误触发重试时，还会在 **`onReasonRetry`** 中执行**强制收紧**模式。

触发时机与工作原理

- 双维度触发：**消息数量**（非初心消息数 > `maxMessages × messageTriggerFactor`）或 **Token 数**（估算值 > `contextLength × maxContextLengthRatio`，默认 75%）任一超过阈值即触发压缩。
- 执行策略：调用配置的 SummarizationStrategy 对判定为"过期"的消息段进行加工（LLM 摘要 / 关键信息提取 / 向量归档 / 滚动压缩）。
- 注入摘要：将加工后的摘要消息（统一带 `META_COMPRESSED` 标记）重新注入上下文头部，并物理移除原始明细。
- 强制模式（PTL）：`onReasonRetry` 检测到 Prompt-Too-Long 错误时，按失败次数逐级收紧预算（0.8 → 0.6 → 0.4 → 0.25），在保证返回可用的同时尽量少丢历史。

核心保护机制（压缩不会"拆家"）

- **初心链保护**：标记为 `META_FIRST` 的消息（system prompt、用户原始问题）永不参与压缩与删除。
- **Tool-use 原子对保护**：`Assistant(with tool_calls)` ↔ `ToolMessage` 的调用-结果配对不会被拆散；截断点落在工具结果上时会向前回溯到源头调用。
- **孤立结果清理**：压缩后无配对源头的 `ToolMessage` / Observation 会被自动移除，避免 LLM 感知到错位消息。
- **保留窗口下限**：`minReservedMessages`（默认按 Token 预算动态推导，区间 [3, 20]）保证 Token 维度过度截断时至少保留最近几轮交互。
- **单条消息硬上限**：`perMessageCap`（默认自动推导）对超大的单条消息（如工具读取超大文件）做头尾截断，防止单条顶爆请求。
- **压缩效果监控**：压缩后消息数仍 ≥ 原始 90% 时输出告警，提示调大 `maxMessages` 或调整 `minReservedMessages`。

构造器与关键配置

```java
// 双参构造：maxMessages + 策略（maxContextRatio 默认 0.75）
new ContextCompressionInterceptor(int maxMessages, CompressionStrategy strategy)

// 三参构造：显式指定上下文窗口使用比例（(0,1]）
new ContextCompressionInterceptor(int maxMessages, double maxContextRatio, CompressionStrategy strategy)

// 四参构造：额外指定摘要重试次数
new ContextCompressionInterceptor(int maxMessages, double maxContextRatio, int maxRetries, CompressionStrategy strategy)

// 无参构造：maxMessages 默认 15
new ContextCompressionInterceptor()

// 链式配置（均提供 setter）
.setMaxMessages(int)          // 消息数阈值（下限 10）
.setMessageTriggerFactor(1.5) // 触发滞后系数（≥1.0，调高可避免临界抖动）
.setMaxContextLengthRatio(0.8)// Token 阈值 = contextLength × 该比例
.setDefaultContextLength(128_000L) // 模型未提供 contextLength 时的回退值
.setMinReservedMessages(8)    // 保留窗口消息数下限（显式覆盖）
.setPerMessageCap(8000)       // 单条消息 Token 硬上限
.setMaxRetries(3)             // 策略生成摘要的重试次数
```

Token 阈值始终以**模型配置的 `contextLength`** 为准（`finalTokenThreshold`），模型未配置时回退到 `defaultContextLength`（默认 128k）。拦截器内部用 GPT-4o 编码器（jtokkit）估算 Token，对主流模型偏差 < 5%。

### 2、 内置摘要策略全家桶

Solon AI 提供了四个开箱即用的策略（构造器均为无参，模型实例由拦截器在运行时传入），满足从"简单压缩"到"无限续航"的不同业务场景。

#### A. 基础语义压缩 (LLMCompressionStrategy)

- 职能：调用轻量级模型对过期的对话段落进行一次性概括。
- 场景：通用场景，对历史细节要求不高。
- 特点：精简、准确，自带视觉标记（`--- [执行进度总结] ---`）；内置 PTL 自动重试，待压缩历史过大时逐步收窄范围后重试（最多 3 次）。
- 可定制：`systemInstruction(...)` 链式替换默认系统指令。

#### B. 关键信息看板 (KeyInfoExtractionStrategy)

- 职能：作为"信息审计专家"，只提取事实、参数、结论和已验证的失败尝试。
- 场景：垂直领域任务（如 SQL 生成、自动化运维），需要防止核心参数丢失。
- 特点：过滤掉冗长的思考过程，只保留"硬干货"，输出为 Markdown 列表（`--- [已确认的关键信息] ---`）。
- 可定制：`systemInstruction(...)` 链式替换默认提取协议。

#### C. 层级滚动摘要 (HierarchicalCompressionStrategy)

- 职能：将"旧摘要"与"新消息"递归合并。(Summary_N-1 + History_New) -> Summary_N。
- 场景：超长任务流。
- 特点：支持无限续航。旧摘要通过 Trace 的 `agent:summary:hierarchical` 槽位持久保留，记忆链条永不断裂。
- 工程细节：`maxSummaryLength` 默认 500 Token（按 Token 计量截断）；单次压缩最多调用模型 3 次，遇 PTL 时执行两段式降级（先合并较旧分块，再以中间摘要合并较新分块）；所有分块成功后才提交新摘要，避免中间状态污染。

#### D. 冷记忆归档 (VectorStoreCompressionStrategy)

- 职能：将原始明细**同步**存入向量数据库（`RepositoryStorable`），仅在上下文中留下一个"检索锚点"。
- 场景：合规审计、需要回溯原始细节的复杂推理。
- 特点：物理存盘 + **内置取回工具**。该策略同时是 `AbsTalent` 子类，注册为 Talent 后注入 `recall_history` 工具（按 sessionId 过滤，带白名单防注入校验），Agent 看到 `--- [历史细节已归档] ---` 标记即可主动调用回溯，具备"翻阅档案"的能力。

### 3. 级联编排：CompositeCompressionStrategy

在生产环境下，单一策略往往不够。你可以通过 `CompositeCompressionStrategy` 将多个策略串联起来，构建多层级记忆体系。

- 执行语义：**按添加顺序逐个执行**所有子策略，各策略输出以 Markdown 分割线（`---`）拼接为一条摘要消息；子策略的 metadata 合并（`putIfAbsent`，先策略优先）；合并结果统一强制标记 `META_COMPRESSED`。
- 容错：单个子策略抛异常不影响其它策略，被吞掉并记录错误日志。

最佳实践建议顺序：

- 先通过 VectorStore 存盘（保证原始数据不丢）。
- 再通过 KeyInfo 提纯（保证硬核数据在看板上）。
- 最后通过 Hierarchical 压缩（保证全局进度不丢失）。

### 4、 快速上手

以下示例展示了如何为 ReAct 智能体配置一个"永不失忆"的记忆模型：

```java
// 1. 选择并组合策略（策略类均为无参构造，chatModel 由拦截器运行时注入）
VectorStoreCompressionStrategy vectorStoreCompression = new VectorStoreCompressionStrategy(vectorRepo);

CompressionStrategy myStrategy = new CompositeCompressionStrategy()
 .addStrategy(vectorStoreCompression) // 冷归档
 .addStrategy(new KeyInfoExtractionStrategy()) // 事实看板
 .addStrategy(new HierarchicalCompressionStrategy()); // 滚动摘要

// 2. 注入拦截器（消息超过 15 条，或 Token 超过模型 contextLength 的 75% 时触发）
ContextCompressionInterceptor memoryGuard = new ContextCompressionInterceptor(15, myStrategy);
memoryGuard.setDefaultContextLength(128_000L);

// 3. 构建 Agent
Agent agent = ReActAgent.of(chatModel)
 .defaultInterceptorAdd(memoryGuard) // 挂载记忆守卫
 .defaultTalentAdd(vectorStoreCompression) // 注册 recall_history 取回工具
 .build();

```

### 5、压缩参数配置参考

Token 阈值由模型 `contextLength × maxContextLengthRatio` 推导，因此配置重点是**消息数阈值**与**上下文窗口比例**，而非绝对值。

| 模型上下文窗口 | maxMessages 建议 | maxContextLengthRatio | 适用场景与策略建议 |
| --- | --- | --- | --- |
| 20k | 10 - 15 | 0.7 - 0.8 | 紧凑型： 必须频繁触发压缩。由于容量有限，需严格控制工作内存，建议配合 perMessageCap 防止单条大消息顶爆。 |
| 100k | 30 - 40 | 0.75（默认） | 均衡型： 能够容纳较长的代码段或多轮 ReAct 思考。75% 是目前大多数模型保持高召回率（Recall）的黄金线。 |
| 200k | 50 - 60 | 0.75 - 0.85 | 扩展型： 适合复杂任务编排。利用长上下文减少摘要频率，保持原始 Tool Call 链路的完整性。 |
| 1m (100万) | 100 - 150 | 0.85 - 0.9 | 海量型： 此时 Token 比例更多是为了控制成本和响应延迟。大窗口下建议调高 messageTriggerFactor（如 1.5）降低触发频率。 |

> 说明：`maxMessages` 有下限保护（`Math.max(10, v)`），设置过小会被钳到 10；`messageTriggerFactor` 默认 1.0（无滞后），触发阈值 = `maxMessages × factor`，压缩后保留窗口仍收敛到 `maxMessages`。

重要提醒

- 摘要窗口越大，有助于 llm 理解上下文；但是，上下文的 token 也会越大（越费钱）
- 摘要窗口太小，llm 不好施展拳脚（还可能处处受制。比如：读取的文件，很快就被压缩了）
- 若未配置任何策略（构造器传 null），压缩退化为"零成本物理裁剪"：过期消息直接丢弃，同时自动执行原子序列追溯，保留最后一个完整的工具调用组，避免上下文错位。
- 策略生成摘要失败（LLM 调用异常 / 返回"无显著进度" / 摘要超预算）时返回 null，拦截器会保留已有旧摘要（`META_COMPRESSED` 标记消息）兜底，不会静默丢状态。
- 每次压缩都会向流式接收端推送 `ContextSizeEvent`（消息数、Token 数、压缩前后对比），前端可据此展示"上下文规模"与"记忆压缩"状态。
- 静态上下文（system prompt + tools 定义）会标记边界，配合模型 Prompt Caching（cache_control / prompt_cache_key）自动获得缓存收益，压缩不会破坏可缓存块的结构完整性。
