长任务跑到一半上下文就满了,这是每个做 Agent 的人都会撞上的墙。这节比较三种处理方式。
可复现前提: 测试任务为平均 40 轮的代码修改会话,20 个样本,脚本 bench/context。
三种策略
A. 滑动窗口。 只保留最近 N 轮。实现最简单,但会丢掉任务目标——跑到后期 Agent 忘了自己在干嘛。
B. 摘要压缩。 超过阈值时把早期对话压成摘要。保留了目标,但摘要会丢细节,比如具体的文件路径和错误信息。
C. 分层保留。 我们最终用的方案:
- 永久保留:任务目标、约束、状态清单
- 压缩保留:已完成步骤的结论(每步一行)
- 滚动丢弃:工具调用的原始输出
实测
| 策略 | 任务完成率 | 平均 token | 平均成本 |
|---|---|---|---|
| 全保留(基线) | 71%(超窗口失败) | 92K | ¥1.42 |
| A 滑动窗口 | 58% | 31K | ¥0.48 |
| B 摘要压缩 | 79% | 44K | ¥0.71 |
| C 分层保留 | 91% | 38K | ¥0.59 |
分层保留同时赢了完成率和成本,因为它丢弃的是真正没用的东西——工具的原始 JSON 输出在结论产生后就没有价值了。
实现要点
PERMANENT = {"goal", "constraints", "state"}
COMPRESSIBLE = {"step_result"}
DISPOSABLE = {"tool_raw_output"}
def compact(messages, budget):
kept = [m for m in messages if m.kind in PERMANENT]
for m in reversed(messages):
if m.kind in DISPOSABLE:
continue
if tokens(kept) + tokens(m) > budget:
break
kept.append(m)
return sorted(kept, key=lambda m: m.seq)丢弃要从最旧的原始输出开始,而不是从最旧的消息开始。
评论与复现反馈 0
还没有人评论。复现之后回来说一声,对作者很有价值。