1. 长程 Agent 的上下文困境为什么 2026 年顶会都在盯这件事如果你最近在跑一个需要几十步甚至上百步才能完成任务的 Agent大概率遇到过这种情况前 20 步表现堪称完美工具调用准确、推理链条清晰但到了第 40 步之后它开始忘记最初的目标重复调用同一个工具或者干脆把之前已经确认过的中间结论推翻重来。这不是模型变笨了而是上下文管理出了问题。长程 AgentLong-Horizon Agent指的是那些需要跨越大量交互轮次、持续维护状态、在多个子任务之间保持连贯性的智能体。它和那种一问一答的短任务 Agent 有本质区别——短任务里你把所有信息塞进一次 prompt 就够了长任务里上下文会随着每一步的工具返回、观察结果、中间推理不断膨胀很快就会撞上模型的上下文窗口上限或者即使没撞上也会因为信息密度被稀释而导致注意力涣散。ICLR 和 ICML 这类会议近两年关于 Agent 的投稿量暴涨其中相当一部分工作都指向同一个核心问题如何在有限的上下文预算下让 Agent 在长程任务中保持记忆的完整性、推理的连贯性和决策的一致性。围绕这个问题的解法大致分成了几条技术路线我把它拆成下面这张表方便你先建立一个全局认知技术路线核心思路典型代表方向主要代价上下文压缩把历史信息压缩成更短的表示摘要式记忆、隐状态压缩信息有损可能丢关键细节检索增强记忆把历史存到外部按需检索向量库、结构化记忆检索质量决定上限延迟增加分层记忆架构短期/长期/永久分层管理多级缓存、记忆固化架构复杂层间同步难状态外置与重放把状态放到环境里按需重建检查点、轨迹重放重建成本高依赖环境可复现注意力与位置优化不改内容改信息摆放方式位置编码、注意力掩码受模型底层能力限制这张表不是让你选一个而是让你意识到长程上下文管理从来不是单一技术能解决的它是一套组合拳。下面我会逐条拆开讲每一条都配上我实际跑 Agent 项目时踩过的坑和验证过的做法。先说一个反直觉的结论上下文窗口变大并不等于长程问题被解决了。现在动辄 128K、200K 甚至更长的窗口很多人第一反应是那我全塞进去不就行了。实测下来当有效信息被淹没在几万 token 的噪声里时模型的召回率会明显下降尤其是那些出现在上下文中段的关键约束最容易被忽略。这就是所谓的lost in the middle现象。所以窗口大只是给了你更多预算怎么花这个预算才是真本事。2. 上下文压缩摘要、隐状态与选择性遗忘的取舍2.1 摘要式记忆为什么容易越摘越糊最直觉的做法是让模型定期把历史对话总结成一段摘要然后用摘要替换原始历史。这个思路在早期 Agent 项目里非常流行实现也简单每 N 轮触发一次总结把之前的消息列表压缩成一条 system 或 assistant 消息。但我实测下来纯摘要式记忆有个致命问题摘要会丢失那些当时看起来不重要、后面却关键的细节。比如 Agent 在第 5 步随口确认了一个参数用户偏好用 JSON 格式输出总结时这句话很可能被合并成确认了输出偏好等到第 60 步真正要生成输出时具体是 JSON 还是 YAML 已经无从考证。解决办法是分层摘要不要把所有历史压成一段而是保留一个关键事实清单key facts ledger这个清单只增不减专门记录那些不可逆的决策和约束。摘要负责压缩叙事性内容清单负责锁定硬约束。两者分开维护互不干扰。# 关键事实清单的维护逻辑伪代码 class KeyFactsLedger: def __init__(self): self.facts [] # 不可逆决策、硬约束、用户明确指令 def maybe_add(self, message, llm): # 只提取约束类信息不提取叙事 prompt f从以下内容中提取不可逆的决策或硬约束没有则返回空\n{message} extracted llm(prompt) if extracted and extracted not in self.facts: self.facts.append(extracted) def render(self): return 【必须遵守的事实】\n \n.join(f- {f} for f in self.facts)这个清单在每次构造 prompt 时都完整带上因为它通常很短几十条也就几百 token但它是长程任务不跑偏的底线。2.2 隐状态压缩把历史编码进向量而不是文字另一条路是不用文字摘要而是把历史信息编码成连续的隐状态向量比如通过一个专门的压缩模块把多轮对话映射成固定长度的表示。这类方法在论文里很漂亮理论上信息损失更小因为它不受自然语言的离散瓶颈限制。但工程上要小心隐状态压缩对训练和推理的一致性要求极高。你训练时用的压缩器和推理时用的如果不是同一套或者模型版本有细微差异压缩出来的向量分布就会漂移导致 Agent 行为不稳定。我在一个项目里用过类似方案训练环境跑得好好的换到线上推理后 Agent 开始出现莫名其妙的工具选择排查了两天才定位到是压缩器版本不一致。所以如果你要走这条路务必把压缩器和主模型绑定版本管理任何一方升级都要重新验证长程任务的表现不能只看短任务的指标。2.3 选择性遗忘主动丢弃比被动压缩更有效还有一个容易被忽视的角度不是所有历史都值得保留。工具返回的大段原始数据比如一次网页抓取的完整 HTML、失败的尝试、已经被证伪的中间结论这些留着只会污染上下文。我的做法是给每条消息打一个保留价值标签分三档必须保留用户指令、关键事实、最终结论条件保留中间推理如果后续可能被引用、工具调用的参数可丢弃原始工具返回的大段文本、失败尝试的详细过程、重复的确认信息可丢弃的内容在进入下一轮之前就被替换成一句极简的占位说明比如第 12 步抓取了页面提取到 3 个候选链接详见检查点。真正的原始数据存到外部需要时再取。这样上下文里留下的都是高密度信息模型的注意力不会被浪费。提示选择性遗忘的阈值不要设得太激进。我一开始把条件保留也大量丢弃结果 Agent 在需要回溯推理链时频繁要求重新执行已经做过的步骤反而更慢。后来把中间推理的保留窗口设为最近 15 步效果明显好转。3. 检索增强记忆向量库不是万能药结构化才是关键3.1 纯向量检索在 Agent 场景下的三个硬伤说到外部记忆很多人第一反应就是上向量数据库把每轮对话 embed 一下存进去需要时做相似度检索。这个方案在知识问答场景很成熟但直接搬到长程 Agent 上会暴露三个问题。第一Agent 的记忆查询往往不是语义相似而是结构化定位。比如 Agent 想回忆我第 30 步调用那个 API 时用的超时参数是多少这是一个精确的字段查询不是找语义相近的段落。向量检索很可能返回一堆语义相关但字段不对的内容。第二时间顺序在 Agent 记忆里至关重要。向量检索默认是忽略时序的但 Agent 经常需要最近一次上一次成功的那次这类带时序的查询纯相似度排序满足不了。第三检索结果的噪声会直接误导决策。知识问答里检索错一条顶多答案不准Agent 里检索错一条可能导致它基于错误记忆做出不可逆的操作。3.2 结构化记忆表把 Agent 的记忆当数据库来设计我的做法是把 Agent 记忆拆成几张结构化的表向量检索只作为其中一张表的补充手段记忆表存储内容查询方式更新时机事实表关键约束、用户偏好精确匹配 标签过滤实时写入动作表每步工具调用及结果摘要时序查询 状态过滤每步写入实体表任务中出现的对象及其属性主键查询实体首次出现时语义表非结构化的观察、推理向量检索批量写入关键在于动作表。它记录了 Agent 每一步做了什么、结果如何、状态是什么。当 Agent 需要回溯时它查的是这张表而不是去翻原始对话。这张表天然带时序天然结构化查询又快又准。# 动作表的典型结构 action_record { step: 30, action: call_api, params: {endpoint: /v1/search, timeout: 30, retry: 2}, result_summary: 返回 5 条结果已提取标题, status: success, timestamp: 2026-01-15T10:23:00Z }有了这张表Agent 在第 60 步想知道之前那个 API 超时设的多少直接按 action 类型查最近一条成功记录就行根本不需要向量检索。3.3 检索时机比检索质量更影响整体表现很多人把精力全花在提升检索准确率上但我实测发现什么时候触发检索对长程任务的影响更大。如果 Agent 每一步都去检索一遍记忆不仅慢还会引入大量无关信息干扰当前决策。我的策略是事件驱动检索只在特定事件发生时触发记忆查询比如即将执行一个不可逆操作前查有没有相关约束连续两次工具调用失败后查历史上类似情况怎么处理的进入一个新的子任务时查这个子任务相关的实体和事实模型自己显式请求回忆时这样检索次数大幅下降但每次检索都是有针对性的信噪比高得多。4. 分层记忆架构短期、长期、永久三层怎么落地4.1 三层的职责边界必须清晰Agent 记忆分层是老生常谈但很多实现失败在层与层之间的职责没划清。我见过一个项目短期记忆和长期记忆都在存对话历史结果两边数据不一致Agent 时而记得时而忘记排查起来极其痛苦。我的划分标准是这样的短期记忆工作记忆当前子任务的上下文容量小比如最近 10-20 步全量保留任务切换时清空或归档。长期记忆跨子任务的任务级状态包括关键事实、已完成步骤、待办事项容量中等结构化存储全程可查。永久记忆跨任务的知识比如用户长期偏好、领域常识、历史成功模式容量大需要显式写入和检索。三层的读写规则要明确短期记忆每步都写长期记忆在子任务边界写永久记忆只在明确确认有价值时写。读的时候短期记忆直接进 prompt长期记忆按需检索永久记忆通过检索或预加载。4.2 层间同步最容易出 bug 的地方层间同步是分层架构的命门。举个真实例子Agent 在短期记忆里确认了用户要求输出中文但这条信息没有及时同步到长期记忆结果子任务切换后短期记忆被清空Agent 又开始输出英文。我的解法是关键事实双写任何被标记为关键事实的信息在写入短期记忆的同时立即同步写入长期记忆的事实表。这样即使短期记忆被清空长期记忆里还有备份。同步是同步操作不搞异步避免时序问题。def write_memory(content, level, is_key_factFalse): if level short: short_term.append(content) if is_key_fact: long_term.facts.append(content) # 双写 elif level long: long_term.append(content) elif level permanent: permanent.append(content)4.3 记忆固化什么时候把短期升级为长期不是所有短期记忆都值得升级为长期。升级太频繁长期记忆会被噪声淹没升级太少关键信息会随短期记忆一起丢失。我用的判断标准是**跨子任务相关性**如果一条信息在当前子任务结束后下一个子任务还可能用到就升级。具体来说满足以下任一条件就升级是用户明确指令或约束是某个实体的关键属性比如这个 API 的 rate limit 是 100/min是已经确认的中间结论后续推理会依赖是失败教训避免重复踩坑这套标准跑下来长期记忆的增长是可控的不会爆炸。5. 状态外置与轨迹重放把记忆交给环境而不是模型5.1 为什么让模型记住一切是错误的方向前面讲的都是怎么帮模型更好地记住东西但还有一条完全相反的思路干脆不让模型记把状态放到环境里需要时重建。这个思路的洞察是模型记忆本质上是不可靠的与其花大力气优化记忆不如把状态外置到确定性的存储里模型只负责决策不负责记忆。每一步的状态都持久化模型需要什么就现查现用。这在工程上有个巨大好处可复现、可调试。当 Agent 出错时你可以精确地回到某一步查看当时的状态重放决策过程。而如果状态全在模型的上下文里出错后你只能看到一团模糊的历史很难定位。5.2 检查点设计存什么、多久存一次状态外置的核心是检查点checkpoint。检查点要存的东西包括当前任务目标原始指令已完成步骤的摘要列表当前环境状态文件、数据库、外部系统的快照或引用待办事项关键事实清单存频率上我的经验是每个不可逆操作后必存其他步骤按固定间隔存。不可逆操作包括写文件、发请求、修改数据库等这些一旦执行就无法回退必须在执行前存一个检查点执行后再存一个这样出问题能精确回滚。def execute_with_checkpoint(action): save_checkpoint(fbefore_{action.id}) result action.run() save_checkpoint(fafter_{action.id}, resultresult) return result5.3 轨迹重放调试长程 Agent 的杀手锏轨迹重放是状态外置带来的最大红利。当 Agent 在长程任务中出错你可以找到出错的那一步加载它之前的检查点用相同的输入重放这一步对比实际输出和期望输出定位是记忆问题、推理问题还是工具问题我靠这套方法定位过好几个隐蔽 bug比如某个工具在特定参数下返回格式不一致导致 Agent 后续解析失败。如果没有重放能力这种问题在长程任务里几乎不可能复现和定位。注意轨迹重放要求环境是可复现的。如果 Agent 依赖的外部系统状态会变比如实时数据重放时要么用快照要么接受一定的不确定性。设计时要把可复现作为环境的一个硬指标。6. 注意力与位置优化不改内容改摆放方式6.1 信息摆放位置对长程表现的影响前面讲的都是怎么改内容但还有一类方法不改内容只改信息在上下文里的摆放方式。这背后的原理是模型对上下文不同位置的注意力分布是不均匀的开头和结尾的召回率通常高于中间。所以一个简单但有效的技巧是把最关键的约束放在上下文的开头和结尾各一份。开头放一份让模型一开始就建立约束意识结尾放一份让模型在生成前最后确认。中间放详细的历史和推理。这个首尾呼应的做法我在多个长程任务上验证过能明显降低 Agent 违反约束的概率。6.2 注意力掩码与位置编码的工程应用更进阶的做法是用注意力掩码或位置编码来引导模型关注特定区域。比如给关键事实打上特殊的位置标记让模型的位置编码能区分这是约束和这是普通历史。但这类方法对模型底层有要求不是所有模型都支持自定义注意力模式。如果你用的是闭源 API基本没法改如果是开源模型自己部署可以尝试。我的建议是先用简单的位置摆放技巧收益不够再考虑改底层因为改底层的维护成本很高模型一升级可能就失效。6.3 上下文预算分配给每类信息定配额最后一个实操性很强的技巧是给上下文预算定配额。不要让它自然增长到满而是提前分配系统指令和约束10%关键事实清单10%最近 N 步详细历史40%检索到的相关记忆20%当前任务描述和待办20%每类信息超出配额就触发压缩或丢弃。这样能保证上下文里各类信息都有位置不会出现某一类比如工具返回把其他类挤没的情况。配额比例可以根据任务特点调整但一定要有配额这个概念否则上下文管理就是失控的。7. 我在长程 Agent 项目里踩过的几个真实坑7.1 摘要触发时机不对导致关键信息丢失早期我用固定轮次触发摘要每 20 轮总结一次。结果有一次 Agent 在第 18 轮确认了一个关键参数第 20 轮总结时这个参数被合并进了一句模糊的描述第 40 轮需要用时已经找不回来了。后来改成事件触发 轮次兜底关键事实随时写入清单不依赖摘要摘要只在上下文接近预算上限时触发且摘要时明确要求保留所有数字、标识符和约束。这个改动之后关键信息丢失的问题基本消失。7.2 检索增强引入的错误记忆有一次 Agent 在检索历史时检索到了一条语义相似但实际属于另一个任务的记忆导致它把两个任务的约束混在一起行为变得莫名其妙。排查后发现是向量库没有做任务隔离所有任务的记忆混在一个索引里。修复方法是给记忆加任务命名空间检索时强制过滤当前任务。同时给每条记忆加上时间戳和任务 ID检索结果按相关性和时效性综合排序而不是只看相似度。7.3 分层记忆的同步延迟前面提过层间同步的问题我实际遇到的是异步同步导致的延迟。当时为了性能长期记忆的写入用了异步队列结果 Agent 在写入后立即读取读到的还是旧数据。这种 bug 特别隐蔽因为大部分时候队列处理很快偶尔慢一次就出问题。改成同步写入后性能确实下降了一点但稳定性大幅提升。在记忆这种基础能力上稳定性优先于性能这是我用血泪换来的教训。7.4 上下文配额被工具返回撑爆有一次接了一个返回数据量很大的工具每次调用返回几千 token几步下来上下文就被撑满了导致关键事实被挤出去。后来给工具返回单独设了配额超出部分自动截断并存入外部存储上下文里只留摘要和引用。这个改动让 Agent 在长任务里的稳定性上了一个台阶。8. 面向 2026 的技术趋势与选型建议从 ICLR、ICML 近期的投稿方向看长程 Agent 上下文管理有几个明显的趋势。一是记忆的结构化程度越来越高纯向量的方案在退潮混合结构化存储成为主流。二是状态外置和可复现性被提到前所未有的高度因为长程任务的调试需求太强烈了。三是上下文管理开始和推理过程耦合不再是独立的预处理步骤而是嵌入到 Agent 的每一步决策里。选型上我的建议是按任务长度分档20 步以内选择性遗忘 关键事实清单就够了不用上复杂架构。20 到 100 步分层记忆 结构化动作表 事件驱动检索这套组合能覆盖大部分场景。100 步以上必须上状态外置和检查点否则调试和维护成本会失控。最后分享一个我一直在用的自检清单每次 Agent 长程任务出问题我就按这个顺序排查先看关键事实清单是否完整再看动作表是否有断档然后看检索是否引入了错误记忆最后看上下文配额是否被某一类信息撑爆。按这个顺序走八成问题能在十分钟内定位。这套方法不是从论文里抄的是实打实跑项目跑出来的。顶会论文给的是方向真正落地还得靠这些脏活累活的细节。
