08 - 上下文压缩策略
学习目标
本章聚焦 Hermes Agent 的上下文压缩实现。你将了解:
- 预飞行压缩为何在进入主循环前就执行
- 轨迹压缩如何用于训练下一代工具调用模型
- 对话中间 N turn 摘要策略
- 用户手动触发压缩的反馈机制
前置知识
本章涉及上下文压缩的通用原理,建议先阅读:
下文直接聚焦 Hermes 的具体实现。
项目实践
预飞行上下文压缩
Hermes 在进入主循环前,检测当前消息是否已超出模型上下文窗口:
if len(messages) > protect_first_n + protect_last_n + 1: tokens = estimate_request_tokens_rough(messages, system_prompt, tools) if compressor.should_compress(tokens): for _pass in range(3): messages, system_prompt = compress(...) if len(messages) >= _orig_len: break # 无法继续压缩为何预飞行? 通用指南中的压缩通常在 API 调用失败(context_window 错误)后触发。Hermes 选择提前检测,避免 API 调用失败导致的延迟和成本浪费。
适用场景:用户切换到小上下文模型时,历史对话可能已经超出新模型的窗口。预飞行压缩在 turn 开始前瘦身,确保 API 调用不会因超限而失败。
多策略压缩管线
Hermes 实现了多层次的压缩策略:
| 策略 | 位置 | 触发条件 | 目标 |
|---|---|---|---|
| 预飞行压缩 | 进入主循环前 | 检测 token 超限 | 防止 API 调用失败 |
| 对话压缩(conversation_compression) | 主循环中 | 中间 N turn | 摘要化历史对话 |
| 轨迹压缩(trajectory_compressor) | 训练 pipeline | 数据收集阶段 | 精简工具调用轨迹用于训练 |
| 手动压缩(manual_compression_feedback) | 用户触发 | 用户指令 | 按需压缩当前上下文 |
轨迹压缩(Trajectory Compression)
trajectory_compressor.py 专门用于压缩 Agent 的执行轨迹,目标是训练下一代工具调用模型:
- 保留完整的工具调用序列结构(调用顺序、参数名)
- 裁剪工具输出的内容(保留元数据,删除大段文本)
- 压缩后的轨迹更小,适合大规模训练数据收集
与普通对话压缩的区别:对话压缩服务于运行时的上下文窗口管理;轨迹压缩服务于离线训练的数据精简。
对话中间 N Turn 摘要
agent/conversation_compression.py 实现对话历史中的中间 N turn 摘要策略:
- 保留最近 N 轮对话的完整内容(tail 保护)
- 对更早的对话轮次进行 LLM 摘要
- 用户输入消息永久保留,不被摘要化
问题与规避
预飞行压缩误判
问题:粗糙的 token 估算可能高估或低估实际 token 数,导致不必要的压缩或遗漏超限。
对策:Hermes 使用 estimate_request_tokens_rough() 进行轻量估算。如果估算接近阈值,压缩器尝试压缩;如果压缩后长度未变化(无法压缩),放弃并让 API 调用自然失败或成功。
轨迹压缩丢失关键信息
问题:裁剪工具输出可能删除训练所需的关键细节(如代码错误的具体行号)。
对策:轨迹压缩保留工具调用的元数据(函数名、参数名、返回状态码),只裁剪内容体。对于关键工具(如代码执行),保留输出前 N 行。
设计取舍
预飞行压缩 vs 延迟压缩
| 方案 | 优势 | 代价 |
|---|---|---|
| 预飞行(Hermes) | API 调用不失败、用户体验连贯 | 可能多一次压缩开销 |
| 延迟(失败后) | 只在确实需要时压缩 | API 调用失败重试、延迟增加 |
Hermes 选择预飞行压缩,因为 API 调用失败的成本(额外延迟 + 可能的状态不一致)高于提前压缩的成本。
轨迹压缩的保留策略
| 方案 | 优势 | 代价 |
|---|---|---|
| 保留结构,裁剪内容 | 训练数据紧凑,保留调用序列 | 丢失输出细节 |
| 完整保留 | 训练数据完整 | token 消耗大、存储成本高 |
Hermes 选择保留结构裁剪内容,因为训练工具调用模型主要需要的是调用序列模式和参数结构,而非完整的工具输出内容。
参考来源
- 源码验证:
agent/context_compressor.py、trajectory_compressor.py、agent/conversation_compression.py、agent/manual_compression_feedback_feedback.py