智能体在执行长任务时突然忘记最初的目标,用户明明在第一轮就说了要求,到了第十轮它却完全不认账;或者一个多步骤任务执行到一半,Agent开始重复之前已经做过的动作。这类问题十有八九不是模型变笨了,而是上下文窗口溢出,早期的关键信息被挤出了模型可见的范围。本文围绕这个故障展开,从定位到修复给出完整思路。

先搞清楚:上下文溢出到底是怎么发生的
大语言模型每次推理时,能看到的只有当前请求里携带的全部token,包括系统提示词、对话历史、工具调用记录和工具返回结果。这个总量受限于模型的最大上下文长度,比如8K、32K或者128K。一旦拼接后的内容超过上限,常见处理方式有两种:一种是直接报错,请求被拒绝;另一种更隐蔽,由框架自动做截断,把最早的消息丢掉,只保留最近的部分。
第二种情况最坑,因为它不报错。表面上Agent还在正常工作,实际上它已经丢失了任务的关键前提。比如一个数据分析智能体,用户在开头说明了数据口径和输出格式要求,中间调用了十几次工具,每次工具返回几百行结果。等窗口装不下了,框架悄悄丢弃了开头那几条消息,Agent自然就开始自由发挥,输出格式全乱了。
还有一个容易忽视的因素:token消耗的大头往往不是对话本身,而是工具返回结果。一次网页搜索可能返回三千token,一次代码执行日志可能有五千token,几轮下来窗口就被填满了。定位时可以先统计各类内容的token占比,用tiktoken之类的工具对消息分段计数,很快就能找到膨胀源头。
三种主流修复方案对比与实现
第一种方案是滑动窗口,实现最简单:维护一个消息队列,只保留最近N条消息或者最近M个token。它的优点是逻辑清晰、延迟极低,缺点是硬截断,被丢弃的信息就真的没了。适合任务目标在每一轮都会被重申的场景,比如客服多轮问答。
第二种方案是摘要压缩,也是目前Agent框架里最常用的做法。当历史消息超过阈值时,调用模型把早期对话压缩成一段摘要,替换原始消息。关键技巧在于分层保留:系统提示词和任务目标永远不压缩,中间对话压缩成摘要,最近几轮保持原文,因为模型对近距离内容的依赖最强。实现思路大致如下:
def build_context(messages, max_tokens, summarizer):
# 第一层:系统提示词与任务目标,永不压缩
system_msgs = [m for m in messages if m["role"] == "system"]
# 第二层:保留最近K轮原文
recent = messages[-K:]
# 第三层:更早的消息压缩为摘要
old = messages[:-K]
summary = summarizer.summarize(old)
return system_msgs + [{"role": "system", "content": f"历史摘要:{summary}"}] + recent
第三种方案是向量检索召回,把历史消息和中间结果写入向量数据库,每轮推理前根据当前问题检索最相关的几条注入上下文。这种方式理论上能支撑无限长的任务历史,代价是引入了检索环节,可能召回不相关内容,而且任务的全局目标不适合靠检索获取,它应该常驻在提示词里而不是等被检索到。
实践中这三种方案经常组合使用:滑动窗口控制最近对话,摘要压缩处理中程历史,向量库存放大体积的工具结果。单一方案都有明显短板,组合使用才能兼顾成本、延迟和信息完整性。
工程细节:容易被忽略的几个坑
第一个坑是工具输出不裁剪。很多开发者把工具的完整返回直接塞进消息历史,比如把整个文件内容、整页搜索结果都存下来。正确做法是工具返回时就做裁剪,只保留结构化关键字段,原文可以存到外部存储,历史里只放引用ID,需要时再通过检索取回。这一个改动往往能把上下文占用降低一半以上。
第二个坑是摘要时机选择。不要等到窗口快满了才触发压缩,那时压缩本身也面临超限风险,而且一次性压缩大量历史会丢失细节。更好的策略是设置水位线,比如占用达到70%时就启动增量压缩,每次只压缩最早的一小段,平滑地腾出空间。
第三个坑是压缩时的信息保真。摘要提示词里要明确要求保留任务目标、关键约束、已完成的步骤和重要决策结论,而不是泛泛地总结。可以在摘要后加一步校验:让模型回答当前任务目标是什么,如果答不上来说明摘要丢了关键信息,需要回退重新压缩。示例提示词结构:
SUMMARY_PROMPT = """请将以下对话历史压缩为摘要,必须保留:
1. 用户的原始任务目标
2. 明确的约束条件(格式、风格、禁止事项)
3. 已完成的步骤及关键结果
4. 未完成的待办事项
只输出摘要内容,不要解释。
对话历史:
{history}"""
最后一点,日志与监控不能少。给每次请求记录token占用曲线,设置告警阈值,当上下文增长速度异常时能及时发现,比事后排查为什么Agent失忆要省力得多。把这些机制组合起来,上下文溢出导致的遗忘问题基本可以得到根治。