# 6.4 上下文窗口优化策略

## 6.4.1 Token 估计与上下文预算管理

精准的 Token 估计是上下文预算管理的基础。

### Token 计数策略

在实际应用中，Token 计数通常采用混合策略：

* **精确计数**：使用上次 API 调用返回的 `input_tokens` 值作为基准
* **粗估计**：对于新增文本，可先用“字符数 / 经验系数”做粗估，但中文、代码、JSON 和不同 tokenizer 的差异很大；图像、音频、PDF 等多模态输入应以供应商 token counting API 或模型文档为准
* **输出预留**：按任务期望输出、模型 `max_tokens` 和上下文窗口保留缓冲，避免填满窗口导致截断或停止
* **跨版本迁移注意**：截至 2026-05-17，Anthropic 官方价格页说明 Claude Opus 4.7 使用新 tokenizer，同一固定文本最多可能多消耗 35% tokens。从旧版本切换到新 tokenizer 时，需重新校准估算、`max_tokens` 与压缩触发阈值。

### 上下文窗口分辨率优先级

当需要动态确定模型上下文窗口大小时，系统通常采用优先级链：

1. **模型后缀标记**（如 `[1m]` 表示 1M Token）
2. **模型能力查询**（通过 API 或本地模型卡获取）
3. **测试版 HTTP 头**（某些 API 在响应头中返回支持的窗口大小）
4. **环境变量**（应用级配置）
5. **默认值**（通常 200K Token）

### 预算分配

为不同组成部分预先分配 Token 预算：

| 组成部分    | 典型预算占比 | 说明     |
| ------- | ------ | ------ |
| 系统提示词   | 5-15%  | 尽量精简   |
| 知识/检索内容 | 30-50% | 核心信息区  |
| 对话历史    | 20-30% | 动态调整   |
| 输出预留    | 15-25% | 确保足够空间 |

*注：以上占比为常见起点，实际分配需结合任务类型、模型上下文长度、工具调用开销与期望输出长度进行调整。*

![Token 预算堆叠图](/files/7mUkTQbdb9vnUwVjkKIR)

图 6-5：Token 预算堆叠图

### 动态调整

根据任务特点动态调整分配：

* 知识密集任务：增加检索内容预算
* 多轮对话任务：增加历史预算
* 长文生成任务：增加输出预留

## 6.4.2 系统提示词优化

系统提示词是最稳定的上下文部分，应该优化到最精简。

### 精简策略

**删除冗余**

* 移除重复说明
* 合并相似指令
* 使用简洁表达

**结构化表达**

* 使用列表替代段落
* 使用表格组织规则
* 采用编号便于引用

**模板复用**

* 将通用部分模板化
* 动态部分参数化
* 条件加载可选内容

### 提示词压缩技术

**人工精简**

最直接有效，逐字审查每句话的必要性。

**LLM 辅助压缩**

让模型帮助精简：

```
请将以下系统提示词压缩到 500 Token 以内，保持所有关键指令：
[原始提示词]
```

**符号化表达**

用简洁符号替代冗长说明：

```
原文：如果用户没有明确指定格式，请使用 Markdown 格式输出
精简：默认格式=Markdown
```

## 6.4.3 检索内容优化

检索内容往往占用大量上下文，是优化重点。

### 精准检索

* 提高检索精度，减少无关结果
* 使用重排序过滤低相关内容
* 根据置信度阈值截断结果

### 检索后压缩

对检索结果进行二次压缩：

* 提取与查询相关的片段
* 生成针对性摘要
* 合并重复信息

### 渐进式检索

按需检索，而非一次全部加载：

1. 先用少量关键信息回答
2. 如果需要更多细节再补充检索
3. 避免预防性的大量检索

## 6.4.4 格式优化

格式选择影响 Token 效率。

### 结构化格式对比

| 格式       | Token 效率 | 可读性 | 适用场景  |
| -------- | -------- | --- | ----- |
| 纯文本      | 高        | 一般  | 连续内容  |
| Markdown | 中        | 好   | 结构化文档 |
| JSON     | 低        | 中   | 数据交换  |
| XML      | 最低       | 高   | 明确边界  |

### 格式优化建议

* 非必要不使用嵌套结构
* 属性名尽量简短
* 避免冗长的 key 名称
* 考虑自定义简洁格式

## 6.4.5 KV 缓存压缩技术

在不减少模型能力的前提下，压缩 KV 缓存体积是实现更长上下文的关键路径。

### 多头隐式注意力（MLA）

DeepSeek-V2/V3 采用的 **多头隐式注意力（Multi-head Latent Attention）** 将 KV 缓存压缩到极致：

* 原始 KV 缓存占用：以 Llama-3.1-405B 为例，单个 Token 需要约 516KB 的 KV 缓存
* MLA 压缩后：每个 Token 的 KV 缓存仅需约 70KB，压缩比约 7 倍
* **实现原理**：将 KV 映射到低维隐向量，再按需扩展到多个查询头，既保留了多头注意力的表达能力，又大幅降低显存需求

### 分组查询注意力（GQA/MQA）

**GQA（Grouped Query Attention）** 和 **MQA（Multi-Query Attention）**：多个查询头共享一个或几个 KV 头组，线性降低 KV 缓存体积。

* GQA：8 个查询头共享 1 个 KV 头，KV 缓存减少约 8 倍
* MQA（极端情况）：所有查询头共享单个 KV 头，缓存最小化但精度可能下降
* **权衡**：在精度损失与缓存收益间找到最优点，通常 GQA 是最佳选择

### KV 缓存量化

将 KV 缓存从 FP32 或 BF16 量化到 INT4 或 FP8：

* **INT4 量化**：降低位宽同时保留关键信息，从 BF16/FP16 量化到 INT4 理论上可将 KV 缓存显存需求降至约 1/4，有效上下文长度可放大约 4 倍
* **实现策略**：对 KV 进行分段量化，采用动态范围缩放，降低量化误差
* **成本**：推理时需额外的反量化开销，但总体 Token 吞吐仍能提升

## 6.4.6 缓存与复用

减少重复内容的传输和计算。

### 提示词缓存与基础设施级缓存

许多模型支持 Prompt 缓存机制，这是优化成本和延迟的最有效手段之一。此外，基础设施层面的 KV 缓存共享技术为系统级优化提供了新机遇。

**经济学原理**：

* **存活时间（TTL）**：缓存通常有较短的生命周期，每次缓存命中都会刷新该计时；Anthropic 当前提供 5 分钟（默认）与 1 小时（extended，`ttl: 3600`）两档，长时程 Agent 会话推荐使用 1 小时档。
* **成本不对称性**：写入缓存（计算 KV Cache 并存入高速显存）通常比常规输入 Token 更贵（可能有 25% 溢价（5 分钟默认 TTL 写入约 1.25x 基价；1 小时 extended TTL 写入约 2x 基价）），但在随后的请求中读取缓存却能获得极大的折扣（如高达 90% 的降价）。频繁且连续的交互能够极大地放大这种收益。

**基础设施级缓存：Radix Attention（SGLang）**

**Radix Attention** 在系统级别实现全局 KV 缓存共享，超越单个会话的限制：

* **全局基数树**：维护所有历史 KV 缓存的全局 Radix 树，每个节点代表一个 Token 序列的 KV 缓存切片
* **前缀匹配与重用**：新请求到达时，系统自动检测其前缀是否在树中存在。若存在完全匹配的前缀（如相同的系统提示词 + RAG 文档），新请求可直接跳过 Prefill，仅执行 Decode 阶段
* **应用场景**：系统提示词和 RAG 文档在多个请求间高度重复时，收益最大。客服、内部知识库等场景可能获得较高命中率，但具体比例必须用线上流量验证。

**KV 缓存感知路由（KV-Cache-Aware Affinity Routing）**

API 网关在接收请求时计算请求前缀的哈希，将其路由到缓存该前缀的 GPU 节点，避免冷启动：

* **哈希映射**：对请求的系统提示词 + 前 k 个用户消息计算哈希
* **节点亲和性**：根据哈希值选择已缓存该前缀的节点，若无则选择最近空闲的节点
* **成本效益**：对于高重复的前缀（RAG 文档、系统提示词），可显著降低 Prefill 计算；具体节省比例取决于请求重复度、缓存生命周期和调度实现。

**架构级最佳实践**：

为最大化缓存命中率，系统设计需要严格保持“前缀一致性”。

* **使用消息，而非修改系统提示词**：绝对不要将会变化的上下文（如当前时间、随时更新的文件状态）写入系统提示词（System Prompt）。正确的做法是保持系统提示词绝对冻结，并使用特定的标记形式将动态数据放入最新的用户消息中。
* **延迟加载工具**：不要在中途动态添加或删除可用工具，这会改变前缀并使得迄今为止的全部缓存由于错位而失效。最佳做法是：始终将所有可用工具的轻量级“存根（Stubs，只包含名称和基础描述）”组装给模型，当模型尝试并确实需要调用时，再通过主动的检索工具获取该工具的完整参数要求，并将其作为附加消息传入。
* **跨模式保持工具稳定**：如果系统拥有诸如“计划模式”与“执行模式”，不要在模式切换时尝试通过增删工具列表来加以限制。应保持全量的工具定义始终不变，仅仅通过添加一条普通的前置消息来指示模型改变其行为（如“你现在进入了计划模式，请只读而不要使用修改源代码的任何动作”）。

### 各场景的缓存收益分析

不同应用场景中，前缀缓存的收益差异显著：

* **复杂系统提示词**：智能体、客服机器人和 RAG 管道通常携带数千 Token 的系统提示词，每次请求完全一致。前缀缓存可跳过这些 Token 的 Prefill 计算，TTFT 降幅需通过压测确认
* **代码补全与生成**：需要将当前文件的数千行代码作为共享上下文，前缀缓存可避免对未修改的代码行重复计算
* **文档摘要与问答**：文档内容在多次提问中保持不变，仅用户问题变化。将文档放在提示词前部、问题放在末尾，即可最大化缓存复用
* **多轮对话**：聊天模板在每轮中回传所有历史消息，前缀缓存的收益随对话轮次递增——第 N 轮对话可复用前 N-1 轮的所有 KV 缓存

设计上下文时应始终考虑缓存特性：将频繁变化的内容（如用户输入、最新检索结果）放在提示词末尾，将稳定内容（如系统提示词、工具定义）放在前部。这一原则不仅适用于单轮请求，在多轮对话和智能体工作流中同样关键。

### 预计算

对于频繁使用的内容预先计算：

* 预生成摘要并存储
* 检索结果预处理
* 通用模板预填充

## 6.4.7 监控与调优

### 监控指标

* Token 使用分布：各部分占比
* 使用效率：有效信息/总 Token
* 边界情况：接近上限的频率
* 成本追踪：Token 费用趋势

### 持续优化

1. 建立基准线
2. 识别最大消耗点
3. 针对性优化
4. 验证效果
5. 持续监控

上下文优化是一个持续的过程，需要在效果和效率之间找到最佳平衡点。

## 6.4.8 长任务场景的高级压缩策略

对于执行跨越数十分钟到数小时的长期任务（如大规模代码迁移或全面的研究项目），需要专门的技术来解决上下文窗口限制。以下介绍两种核心技术：

### 紧凑化技术

Compaction 是一种在上下文接近窗口限制时，将对话内容进行摘要，并以摘要重新初始化新上下文窗口的实践。

**核心思路**：高保真地提炼上下文窗口的内容，使智能体能够以最小的性能损失继续工作。

**实现要点**：

* 将消息历史传递给模型进行总结和压缩
* 保留架构决策、未解决的问题和实现细节
* 丢弃冗余的工具输出或消息
* 用压缩后的上下文加上最近访问的文件继续工作

**分叉操作与缓存复用**： 在执行压缩任务本身时，一个关键的优化设计是将压缩请求作为当前会话的“分叉（Fork操作）”。即在压缩请求中，**绝对完整地复用** 原会话那一长串稳定的系统提示词、知识库和全部的工具定义作为前缀，仅将对话消息部分替换为原消息副本以及“请总结上述对话”的指令消息。由于系统环境前缀通常占据了会话绝大比例的内容空间且完全一致，这种分叉形式能够 100% 命中先前的缓存，使得处理数万 Token 的基础设施开销变得极为廉价。

**压缩的艺术**：关键在于选择保留什么与丢弃什么。过于激进的压缩可能导致丢失细微但关键的上下文信息。

> **最佳实践**：从最大化召回（recall）开始，确保压缩提示词捕获了跟踪中的每一条相关信息，然后迭代改进精度以消除多余内容。

### 结构化笔记

结构化笔记是一种 Agent 定期将笔记持久化到上下文窗口外部存储的技术。这些笔记在后续需要时被拉回上下文窗口。

**工作方式**：

* 智能体创建待办事项列表或维护 `NOTES.md` 文件
* 用于跟踪复杂任务的进展
* 保持关键上下文和依赖关系，否则这些信息会在大量工具调用中丢失

**实际案例（思路说明）**：在长时间交互任务中，智能体可以通过持续维护结构化笔记来跟踪关键状态（例如计数器、已完成步骤与下一步目标）。当上下文被重置后，读取笔记即可恢复工作状态并继续执行。

**选择策略的指南**：

| 技术                     | 适用场景          |
| ---------------------- | ------------- |
| Compaction             | 需要大量来回交互的任务   |
| Structured Note-taking | 有明确里程碑的迭代开发   |
| 子智能体架构                 | 需要并行探索的复杂研究分析 |

## 6.4.9 压缩前的记忆刷写与检查点

在长时程智能体任务中，压缩是不可避免的有损操作。为降低信息损失，生产级系统通常在压缩前执行 **记忆刷写（Memory Flush）**，并建立 **压缩检查点（Compaction Checkpoint）** 以支持任务恢复。

### 记忆刷写

当上下文占用接近窗口限制的某个阈值（如 75%）时，系统在执行压缩前先触发一次记忆刷写：将需要长期保留的关键信息（决策、偏好、待办事项）写入外部持久化存储（如本地 Markdown 文件或数据库），确保这些信息不会在压缩过程中丢失。

```
上下文接近阈值 → 刷写关键记忆到外部存储 → 执行有损压缩 → 继续工作
```

这种“先存后压”的策略已被多个生产级智能体采用。其核心配置通常包括：刷写触发阈值、写入目标路径、以及哪些类型的信息需要优先保留。

将这三者串起来看，核心不是“上下文满了就压缩”，而是先判断能否继续保留原窗口，再决定是否先刷写记忆并建立检查点：

```mermaid
flowchart TD
    A["上下文占用持续上升"] --> B{"是否接近安全阈值?"}
    B -- "否" --> C["继续执行并监控预算"]
    B -- "是" --> D{"近期信息是否仍高频被引用?"}
    D -- "是" --> E["延后压缩\n优先裁剪旧工具输出"]
    D -- "否" --> F["刷写长期记忆\n决策 / 待办 / 偏好 / 活跃文件"]
    F --> G["创建压缩检查点\n摘要 + 结构化状态 + 文件索引"]
    G --> H["执行有损压缩"]
    H --> I{"压缩后还能安全恢复任务?"}
    I -- "是" --> J["加载检查点摘要并继续工作"]
    I -- "否" --> K["回退到最近检查点\n补充关键上下文后重试"]
    E --> C
```

图 6-6：压缩、记忆刷写与检查点决策流

### 压缩检查点

对于可能运行数小时的任务，仅靠压缩摘要可能不足以恢复完整的工作状态。压缩检查点在每次压缩时额外保存：

* **压缩摘要**：对话历史的精简版本
* **结构化状态**：当前的任务进度、待办清单、已完成步骤
* **活跃文件列表**：最近读写的文件路径和关键片段

当任务需要恢复时（如会话中断后重启），系统可以从最近的检查点加载状态，而不是从零开始。这种机制对于跨越多次压缩的超长任务尤为关键。

### 工具输出的分层裁剪

长时程任务中，工具执行结果（如编译日志、API 响应）会随时间大量积累。分层裁剪策略按时间衰减处理这些输出：

| 时间距离    | 裁剪策略      | 示例                    |
| ------- | --------- | --------------------- |
| 最近 3 轮  | 完整保留      | 最新的命令输出全文             |
| 4-10 轮前 | 软裁剪（保留首尾） | 前 1500 字符 + 后 1500 字符 |
| 10 轮以前  | 硬清空       | `[旧工具结果已清空]` 占位符      |

这种裁剪只作用于传递给模型的上下文，磁盘上的完整执行结果不受影响，后续仍可通过检索访问。结合提示词缓存的 TTL 机制，系统还可以在缓存过期后自动触发裁剪，降低重新缓存的成本。

## 6.4.10 智能体上下文缩减策略（案例思路）

在一些生产级智能体的开发中，为了应对超长任务和复杂工具调用，常会演化出一些专门的上下文缩减策略。

（关于相关思路的进一步讨论，请参见 [13.5 案例分析：全自主智能体架构（示意）](/context_engineering_guide/di-si-bu-fen-gong-cheng-shi-zhan-yu-wei-lai-yan-jin/13_cases/13.5_generalist_agent.md)）

### 1. 双重工具结果

将工具执行结果分为“完整版”和“紧凑版”两种形式...

### 2. 陈旧结果压缩

随着对话进行，早期结果被替换为摘要...

### 3. 基于结构的轨迹摘要

即便使用摘要，也强制使用结构化 Schema...


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yeasy.gitbook.io/context_engineering_guide/di-er-bu-fen-he-xin-ji-shu-yu-ce-le/06_compress/6.4_window_optimization.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
