一个 Agent 运行得足够久,上下文窗口一定会被填满。罪魁祸首通常是工具结果:一次文档抓取或查询返回,就可能占几千个 token;而之后每一轮对话,这些 token 都会被原样重发一遍。 最直接的想法是把最旧的消息丢掉。这对普通聊天有效,但对 Agent 是致命的——最旧的消息往往就是任务本身。问题不在于“丢多少”,而在于“哪些部分可以重建”。 把历史消息按可重建性分成四类,代价完全不同: 第一类:绝不丢弃——任务本身。系统提示词和最初的用户请求。失去它们,Agent 就会在完成别的任务。这类消息根本不该进入压缩路径。 第二类:绝不丢弃——不可逆事实。“退款已发起”“邮件已发送”“工单 4471 已创建”。丢掉这些,Agent 就可能重复执行一次操作。它们不是聊天记录,应该进入结构化状态,而不是留在消息列表里。 第三类:可压缩——推理过程。针对已完成步骤的中间思考。结论有价值,反复斟酌的过程没有。 第四类:可丢弃或外置——批量工具结果。六个回合前 Agent 读过的 4000 token 文档。这类数据占了绝大部分窗口压力,却几乎不贡献价值。 代码实现可以这样: ```typescript export type Retention = "pin" | "state" | "compact" | "evict"; export function classify(m: Msg): Retention { if (m.role === "system" || m.meta?.isOriginalTask) return "pin"; if (m.meta?.effect === "irreversible") return "state"; if (m.role === "tool" && (m.tokens ?? 0) > 500) return "evict"; return "compact"; } ``` 在写入时打标签,而不是在压缩时事后猜测,这才是可靠的关键。当一个有副作用的工具返回结果时,立刻标记它——分类器应该读一个布尔标志,而不是解析字符串。 对工具结果,删除正文但保留元数据。这样既能释放窗口空间,又不丢失可追溯的关键信息。

打开网易新闻 查看精彩图片