Agent上下文压缩的"状态保真"取舍框架解读
摘要
在长任务 Agent 的工程化落地中,上下文管理是一个被长期低估的核心问题。随着 Agent 运行时间的增长,上下文窗口中不断累积系统提示词、用户指令、工具调用结果、中间推理过程和外部检索数据,最终导致 Token 成本飙升、模型注意力分散、关键信息被淹没,甚至触发上下文窗口溢出而中断执行。
本文基于对 Agent 上下文压缩策略的系统性研究,提出一种以"状态保真"为核心目标的三层压缩框架。该框架将上下文中的信息按性质划分为三个层级------聊天叙述层可摘要、执行状态层必须结构化、安全边界与外部标识层原样保留------并配套白名单机制与续跑验证策略,确保压缩后的上下文仍能支撑 Agent 做出正确的下一步决策。
与传统的"以节省 Token 为目标的压缩"不同,本文框架的核心主张是:上下文压缩的本质是状态保真(State Fidelity),而非文本缩短。压缩的评估标准不是 Token 减少率,而是压缩后 Agent 续跑时的决策正确率。
技术原理与核心方法
问题定义
设 Agent 的原始上下文为 C={c1,c2,...,cn}C = \{c_1, c_2, \ldots, c_n\}C={c1,c2,...,cn},其中每个元素 cic_ici 携带类型标签 type(ci)\text{type}(c_i)type(ci) 和内容 content(ci)content(c_i)content(ci)。压缩函数 fff 将原始上下文映射为压缩后的上下文 C′C'C′:
C′=f(C)C' = f(C)C′=f(C)
压缩函数需满足以下约束:
∀ci∈Skeep,f(ci)=ci(原样保留)\forall c_i \in S_{\text{keep}}, \quad f(c_i) = c_i \quad \text{(原样保留)}∀ci∈Skeep,f(ci)=ci(原样保留)
∀cj∈Sstructured,f(cj)=struct(cj)(结构化)\forall c_j \in S_{\text{structured}}, \quad f(c_j) = \text{struct}(c_j) \quad \text{(结构化)}∀cj∈Sstructured,f(cj)=struct(cj)(结构化)
∀ck∈Ssummary,f(ck)=summary(ck)(摘要化)\forall c_k \in S_{\text{summary}}, \quad f(c_k) = \text{summary}(c_k) \quad \text{(摘要化)}∀ck∈Ssummary,f(ck)=summary(ck)(摘要化)
其中 SkeepS_{\text{keep}}Skeep、SstructuredS_{\text{structured}}Sstructured、SsummaryS_{\text{summary}}Ssummary 分别对应三层分类的集合划分,且满足 Skeep∪Sstructured∪Ssummary=CS_{\text{keep}} \cup S_{\text{structured}} \cup S_{\text{summary}} = CSkeep∪Sstructured∪Ssummary=C。
三层压缩策略
第一层:聊天叙述层(Summary)
聊天叙述层包含用户与 Agent 之间的自然语言对话内容,如闲聊、背景说明、解释性文字等。这类信息的价值在于传递语义而非精确字符,因此适合使用 LLM 进行摘要压缩。
摘要策略应采用增量摘要(Incremental Summary)方式,仅对新增对话段进行摘要合并,而非每次从头重新摘要整个历史。这有助于减少语义漂移(Semantic Drift)并降低计算成本。
第二层:执行状态层(Structured)
执行状态层包含 Agent 的运行状态信息,如当前任务进度、已完成的子任务、工具调用参数与结果、中间计算结果等。这类信息对 Agent 的决策至关重要,但自然语言描述容易丢失关键字段。
推荐做法是将执行状态以结构化形式(如 JSON Schema)进行存储和流转。借助 OpenAI Structured Outputs 等受限解码(Constrained Decoding)机制,可以确保模型输出的状态信息严格符合预定义的 JSON Schema,从而避免关键字段丢失或格式错误。
第三层:安全边界与外部标识层(Verbatim)
安全边界与外部标识层包含绝对不能被修改或丢失的信息,包括:
- 用户指令中的目标和禁止项(含版本号、优先级)
- 工具返回的关键字段(订单号、文件路径、Trace ID、审批单号、数据库主键等)
- 失败路径记录(试过的方案、失败原因、未通过的测试)
- 证据和时效信息(RAG 检索原文片段、网页更新时间、外部数据查询时间)
这类信息需要逐字符原样保留,任何摘要或压缩都可能导致 Agent 做出错误决策。
白名单机制
白名单机制是三层压缩策略的工程实现核心。其形式化描述如下:
Skeep={ID,路径,金额,权限,测试失败信息,用户确认原话}S_{\text{keep}} = \{\text{ID}, \text{路径}, \text{金额}, \text{权限}, \text{测试失败信息}, \text{用户确认原话}\}Skeep={ID,路径,金额,权限,测试失败信息,用户确认原话}
Ssummary={解释性背景内容}S_{\text{summary}} = \{\text{解释性背景内容}\}Ssummary={解释性背景内容}
压缩算法的伪代码实现如下:
python
def compress_context(context: list[ContextItem]) -> CompressedContext:
"""
Agent上下文压缩主函数
参数:
context: 原始上下文列表,每个元素包含 type 和 content 字段
返回:
CompressedContext: 压缩后的上下文对象
"""
# 白名单集合:默认不压缩,逐字符原样保留
S_keep = {
'ID', '路径', '金额', '权限',
'测试失败信息', '用户确认原话'
}
# 摘要集合:进入摘要流程
S_summary = {'解释性背景内容'}
compressed_items = []
for item in context:
if item.type in S_keep:
# 第三层:原样保留,逐字符不差
compressed_items.append(Verbatim(item))
elif item.type == '执行状态':
# 第二层:结构化存储(如 JSON Schema)
compressed_items.append(Structured(structure(item)))
elif item.type in S_summary:
# 第一层:摘要压缩
compressed_items.append(Summary(summarize(item)))
else:
# 默认保守策略:保留原始内容
compressed_items.append(Verbatim(item))
# 目标需附加版本号与优先级信息
return CompressedContext(
items=compressed_items,
goal=GoalInfo(version=current_version,
priority=active_priority,
active_goal=current_goal)
)
验证策略
压缩是否合格的判定标准不是 Token 减少率,而是续跑能力:
Valid(C′)=Replay(C′)⇒{选对下一步,¬违反禁止项,复现关键证据}\text{Valid}(C') = \text{Replay}(C') \Rightarrow \{ \text{选对下一步}, \neg\text{违反禁止项}, \text{复现关键证据} \}Valid(C′)=Replay(C′)⇒{选对下一步,¬违反禁止项,复现关键证据}
具体评估三个维度:
- 动作正确性:压缩后的上下文能否让 Agent 选出正确的下一步动作
- 约束遵守性:Agent 是否违反了用户设定的禁止项
- 证据可复现性:Agent 能否复现关键证据和事实
只有当以上三个维度全部通过时,压缩才算合格。
对比分析
主流上下文压缩策略对比
下表从压缩方法、保真度、Token 节省率、实现复杂度、适用场景等维度对主流策略进行横向对比:
| 压缩策略 | 保真度 | Token 节省率 | 实现复杂度 | 适用场景 | 主要风险 |
|---|---|---|---|---|---|
| 截断/滑动窗口 | 低 | 高(50%-80%) | 低 | 硬 Token 预算保护 | 丢失关键历史信息 |
| 工具结果折叠 | 中 | 中(30%-50%) | 低 | 低成本初步策略 | 折叠后无法回溯细节 |
| 结构化摘要 | 中-高 | 中(40%-60%) | 中 | 长对话历史压缩 | 语义漂移、关键细节丢失 |
| 折叠与占位符 | 高 | 中(30%-50%) | 中 | 大文件/日志处理 | 需外部存储支持,延迟展开 |
| 剪枝(Pruning) | 低-中 | 高(50%-70%) | 中 | 去除明显冗余信息 | 不可逆,误删关键内容风险高 |
| 外部化与检索 | 高 | 高(60%-90%) | 高 | 超长上下文管理 | 检索延迟,需向量数据库 |
| 三层压缩(本文) | 高 | 中(40%-60%) | 中高 | 长任务 Agent 状态管理 | 分类准确性依赖类型标注质量 |
与现有工作的差异分析
| 对比维度 | 传统做法 | 本文框架 | 差异说明 |
|---|---|---|---|
| 压缩目标 | 节省 Token 成本 | 保证决策依据可靠性 | 目标函数不同,评估标准完全不同 |
| 信息分类 | 统一处理或简单截断 | 三层分类(摘要/结构化/原样) | 按信息性质差异化处理 |
| 失败记录 | 通常被压缩或删除 | 明确列为不可压缩层 | 失败路径价值不低于成功结果 |
| 验证方式 | 无明确验证机制 | 续跑验证(动作/约束/证据) | 提供可操作的评估方法论 |
| 状态管理 | 依赖模型"记住" | 结构化流转 + 白名单 | 从"记忆依赖"转向"工程保障" |
受限解码技术对比
本文框架中执行状态层依赖受限解码技术保证结构化输出质量,以下为业界主流实现对比:
| 实现方案 | 约束强度 | 延迟开销 | 递归结构支持 | 典型应用场景 |
|---|---|---|---|---|
| OpenAI Structured Outputs | 强(服务端受限解码) | 低 | 支持 | API 调用,生产环境 |
| Anthropic Structured Outputs | 强(服务端受限解码) | 低 | 支持 | API 调用,生产环境 |
| vLLM + XGrammar | 强(本地受限解码) | ~40μs/token | 支持 | 自托管推理,私有部署 |
| Outlines | 强(FSM 路线) | 较高(编译时间) | 有限 | 开发测试,简单 Schema |
| JSON Object Mode | 弱(仅格式保证) | 极低 | 不支持 | 简单结构化输出需求 |
工程实践要点
1. 目标管理需带版本号
Agent 的任务目标在长任务执行过程中可能发生演变。每次目标更新时必须附带版本号,明确目标的先后顺序和生效优先级。这确保压缩后 Agent 能准确判断当前应遵循哪个目标。
python
# 目标版本管理示例
class GoalManager:
def __init__(self):
self.goals = []
self.version = 0
def update_goal(self, goal_text: str, priority: int,
is_prohibition: bool = False) -> Goal:
"""更新目标并生成新版本"""
self.version += 1
goal = Goal(
id=f"goal_{self.version}",
content=goal_text,
priority=priority,
is_prohibition=is_prohibition,
version=self.version,
created_at=datetime.now()
)
self.goals.append(goal)
return goal
def get_active_goal(self) -> Goal:
"""获取当前生效目标(优先级最高且未废弃的版本)"""
active = [g for g in self.goals if not g.is_superseded]
return max(active, key=lambda g: g.priority) if active else None
2. 关键状态以结构化形式流转
借助受限解码机制(如 OpenAI 的 Structured Outputs),使模型输出严格符合预定义的 JSON Schema。关键状态(如工具调用参数、中间计算结果)不应以自然语言存储在上下文中,而应以结构化数据形式流转。
python
# 结构化状态定义示例(使用 Pydantic)
from pydantic import BaseModel, Field
from typing import Optional, List
class ToolCallResult(BaseModel):
"""工具调用结果的结构化表示"""
tool_name: str = Field(..., description="工具名称")
call_id: str = Field(..., description="调用唯一标识")
status: str = Field(..., description="执行状态: success/error")
result: Optional[dict] = Field(None, description="成功时的返回结果")
error_code: Optional[str] = Field(None, description="错误码(逐字符保留)")
timestamp: str = Field(..., description="执行时间戳")
class Config:
# 启用严格模式,确保输出符合 Schema
strict = True
class ExecutionState(BaseModel):
"""Agent 执行状态的结构化表示"""
state_id: str = Field(..., description="状态唯一标识")
current_task: str = Field(..., description="当前任务描述")
completed_steps: List[str] = Field(default_factory=list)
tool_results: List[ToolCallResult] = Field(default_factory=list)
failed_attempts: List[str] = Field(default_factory=list)
next_action: Optional[str] = Field(None, description="建议的下一步动作")
3. 压缩策略做成白名单机制
白名单机制的核心思想是"默认保守"------只有明确列入白名单的信息才被压缩,其余信息默认原样保留。这避免了"摘要写得漂亮但执行缺字段"的经典问题。
python
# 白名单压缩器实现
class WhitelistCompressor:
def __init__(self, whitelist: set[str], summarizer: Summarizer):
self.whitelist = whitelist # 可压缩的类型集合
self.summarizer = summarizer
def compress(self, context: Context) -> Context:
"""白名单压缩主流程"""
result = Context()
for item in context.items:
if item.type not in self.whitelist:
# 白名单外:原样保留(保守策略)
result.add_item(item.clone())
elif item.type == 'chat_narrative':
# 聊天叙述:摘要压缩
result.add_item(self.summarizer.summarize(item))
elif item.type == 'execution_state':
# 执行状态:结构化
result.add_item(self.structure(item))
# 其他类型默认保守保留
return result
4. 长间隔续跑需重新校验状态
对于暂停数天甚至更长时间后续跑的任务,旧状态可能已经过时(如外部数据已更新、权限已变更)。在恢复执行前必须对关键状态进行重新校验:
python
async def validate_stale_state(state: ExecutionState) -> bool:
"""校验过期状态的时效性"""
checks = [
validate_permissions(state.required_permissions),
validate_external_data_freshness(state.data_sources),
validate_goal_continuity(state.active_goal),
]
results = await asyncio.gather(*checks)
return all(results)
5. 失败记录的价值管理
失败路径(试过的方案、失败原因、未通过的测试、被拒的权限)在压缩时不应被简单丢弃。这些信息的价值不低于成功结果------它们帮助 Agent 避免重复走已证明走不通的路径,节省 Token 并提升用户体验。
建议将失败记录以结构化形式独立存储,压缩时保留其元数据(失败原因摘要 + 关键错误信息),而非完全删除。
局限性与客观评价
方法局限性
-
类型分类的准确性依赖:三层压缩策略的前提是能够准确判断每条上下文信息的类型归属。在实际工程中,自动分类的准确性直接影响压缩质量。当前框架未提供自动分类器的具体实现,分类准确性依赖外部标注或启发式规则的质量。
-
摘要质量的不可控性:第一层聊天叙述的摘要压缩依赖 LLM 的摘要能力。不同模型在摘要质量上存在差异,且摘要过程本身可能引入语义漂移(Semantic Drift),尤其对于长段对话的增量摘要场景。
-
缺乏量化评估:本文框架未提供正式的实验设计和量化评估指标(如 Token 减少率与决策正确率之间的帕累托前沿曲线)。验证方式主要依赖定性判断(续跑得动),缺乏大规模基准测试支撑。
-
静态白名单的灵活性不足:白名单机制采用静态集合定义可压缩信息类型,在面对新型工具返回格式或新兴应用场景时可能需要手动维护白名单,缺乏自适应能力。
假设的局限性
-
上下文元素可分类假设:框架假设上下文中的每个元素都可以被准确归类到三个层级之一。但在实际 Agent 运行中,某些信息可能同时具有多种性质(如一段对话既包含叙述又包含关键状态),分类边界可能模糊。
-
单 Agent 场景假设:框架主要针对单 Agent 场景设计。在多 Agent 协作场景中,上下文可能在多个 Agent 之间传递,压缩策略需要考虑跨 Agent 的上下文一致性问题。
-
压缩即时性假设:框架假设压缩操作可以在合理时间内完成,未考虑实时性要求极高的场景(如交互式对话系统中每轮响应时间需控制在毫秒级)。
潜在改进方向
-
自适应分类器:引入轻量级分类模型(如微调的小语言模型)自动判断上下文元素的类型归属,减少人工维护白名单的成本。
-
分层摘要优化:研究增量摘要的语义漂移抑制方法,如引入对比学习损失函数约束摘要的语义一致性。
-
多 Agent 扩展:将框架扩展至多 Agent 场景,设计跨 Agent 的上下文压缩协调协议,确保压缩后多 Agent 协作的一致性。
-
量化评估基准:构建标准化的 Agent 上下文压缩评估基准(Benchmark),包含不同任务类型的压缩前后对比数据,为策略选择提供数据支撑。
参考与延伸阅读
-
Anthropic. Effective Context Engineering for AI Agents. Anthropic 官方博客.
-
OpenAI. Structured Outputs. OpenAI Platform Documentation.
-
上下文工程全景研究. Agent 上下文工程:Token 管理、上下文压缩与分层记忆设计. CSDN 博客. 2026.
-
MorphLLM. Context Rot: Cross-Model Validation on 18 Frontier Models. 技术报告. 2026.
-
Mitchell Hashimoto. Harness Engineering. 2026.
-
Boris Cherny. Claude Code Session Management and 1M Context. Anthropic. 2026.
-
Paul Gauthier (Aider 创始人). Practical Context Window Management. 技术分享. 2026.
-
XGrammar Team. XGrammar-2: Adaptive Token Masking for Dynamic Structured Generation. 技术报告. 2026.
-
vLLM Team. Structured Outputs with XGrammar Backend. vLLM Documentation. 2026.
-
LangChain / LlamaIndex 官方文档. 上下文管理与检索增强生成(RAG)最佳实践.