本文信息来源:dbreunig

减轻与避免上下文失效
接着我们之前的文章“How Long Contexts Fail”,让我们来看看有哪些方法可以减轻或完全避免这些失效。
但在此之前,让我们简要回顾一下长上下文可能失效的一些方式:
- 上下文中毒: 当幻觉或其他错误进入上下文,并被反复引用时发生。
- 上下文干扰: 当上下文变得过长,以至于模型过度关注上下文,而忽视了训练中学到的内容时发生。
- 上下文混淆: 当上下文中的多余信息被模型利用,从而生成低质量的回应时发生。
- 上下文冲突: 当你在上下文中积累的新信息和工具与提示中的其他信息发生冲突时。
这里的一切都与信息管理有关。上下文中的所有内容都会影响回复。我们回到了那句老编程格言:“ 垃圾进,垃圾出 。” 幸运的是,有很多方法可以应对上述问题。
上下文管理策略

RAG
检索增强生成(RAG)是指有选择地添加相关信息,以帮助 LLM 生成更好的回答。
关于 RAG 已经有大量的讨论,今天我们不会深入探讨,只想说:它依然非常活跃。
每当一个模型提升了上下文窗口的上限,就会引发一场新的“RAG 已死”争论。上一次的重要事件是 Llama 4 Scout 发布,带来了一个一千万 token 的窗口 。在这个规模下,人们真的很容易产生这样的想法:“算了,把所有东西都塞进去”,然后就收工。
但是,正如我们上次所说:如果你把上下文当作一个杂物抽屉来对待,这些杂物就会影响你的回答 。如果你想了解更多,这里有一个看起来很不错的新课程 。

工具装载
工具装载是指只选择与任务相关的工具定义添加到你的上下文中。
“Loadout”一词源自游戏领域,指的是在进入关卡、比赛或回合前,你所选择的特定技能、武器和装备组合。通常,你的装备组合会根据具体情境进行调整——包括角色、关卡、队友的构成以及你自己的技能水平。
在这里,我们借用这个词来描述为特定任务选择最相关工具的过程。
或许选择工具的最简单方法,就是将 RAG 应用于工具描述。这正是甘甜甜和孙启尧所做的,并在他们的论文《RAG MCP》中进行了详细说明。通过将工具描述存储在向量数据库中,他们能够根据输入提示选择最相关的工具。
在为 DeepSeek-v3 提示时,团队发现,当工具数量超过 30 个时,选择合适的工具变得至关重要。超过 30 个后,工具描述开始出现重叠,导致混淆。当工具数量超过 100 个时,模型几乎必然无法通过他们的测试。使用 RAG 技术将工具数量控制在 30 个以内,不仅显著缩短了提示长度,还使工具选择的准确率提升了多达 3 倍。
对于较小的模型,问题在我们达到 30 个工具之前就已经开始了。我们在上一篇文章中提到的一篇论文“Less is More”表明,Llama 3.1 8b 在提供 46 个工具时未能通过基准测试,但在仅提供 19 个工具时却成功了。问题在于上下文混淆, 而不是上下文窗口的限制。
为了解决这个问题,“Less is More”团队开发了一种使用 LLM 驱动的工具推荐器来动态选择工具的方法。LLM 被提示去推理“它‘认为’需要多少种、哪几类工具来回答用户的查询”。然后,这个输出会进行语义搜索(再次使用工具 RAG)以确定最终的工具配置。他们使用 Berkeley Function Calling Leaderboard 测试了这种方法,发现 Llama 3.1 8b 的性能提升了 44%。
《少即是多》论文指出,较小的上下文还有另外两个好处:降低功耗和提升速度,这在边缘运行时(即在手机或电脑上运行 LLM,而不是在专用服务器上)是至关重要的指标。即使他们的动态工具选择方法未能改善模型的结果,节省的功耗和提升的速度也值得付出努力,分别带来了 18%和 77%的节省。
值得庆幸的是,大多数代理的作用范围较小,只需要少量精心挑选的工具。但如果功能范围或集成数量需要扩展,一定要考虑你的装备配置。

上下文隔离
上下文隔离是将上下文隔离在各自专用的线程中,每个线程由一个或多个 LLMs 单独使用的行为。
当我们的上下文不太长且不包含无关内容时,我们会看到更好的结果。实现这一点的一种方法是将任务拆分为更小的、相互独立的工作——每个工作都有自己的上下文。
有许多例子采用了这种策略,但一个易于理解的相关介绍是 Anthropic 的博客文章,详细说明了他们的多代理研究系统 。他们写道:
搜索的本质是压缩:从庞大的语料中提炼出洞见。子代理通过在各自的上下文窗口中并行运行,探索问题的不同方面,然后将最重要的标记浓缩给主研究代理,从而促进压缩。每个子代理还提供了关注点分离——使用不同的工具、提示和探索路径——这减少了路径依赖,并使得调查能够全面且独立地进行。
研究非常适合这种设计模式。面对一个问题时,可以识别出几个子问题或探索领域,并使用多个代理分别进行提示。这不仅能加快信息收集和提炼的速度(如果有足够的计算资源),还可以防止每个上下文积累过多信息或与特定提示无关的信息,从而提供更高质量的结果:
我们的内部评估显示,多智能体研究系统在需要同时探索多个独立方向的广度优先查询中表现尤为出色。我们发现,在我们的内部研究评估中,以 Claude Opus 4 作为主代理、Claude Sonnet 4 作为子代理的多智能体系统,比单一的 Claude Opus 4 智能体性能高出 90.2%。例如,当被要求识别信息技术 S&P 500 指数公司所有董事会成员时,多智能体系统通过将任务分解给子代理找到了正确答案,而单一智能体系统则因缓慢的顺序搜索未能找到答案。
这种方法在工具配置方面也有帮助,因为代理设计者可以创建多个具有专属工具配置和使用说明的代理原型。
因此,代理构建者面临的挑战是寻找机会,将独立任务分配到不同的线程中。需要多个智能体共享上下文的问题并不特别适合这种策略。
如果你的代理领域适合并行化,一定要阅读完整的 Anthropic 文章 。它非常精彩。

上下文修剪
上下文修剪是指从上下文中移除无关或不再需要的信息的行为。
智能体在调用工具和整理文档的过程中会不断积累上下文。有时,值得停下来评估已整理的内容,并去除多余的部分。你可以将此任务交给你的主 LLM,也可以设计一个单独的、由 LLM 驱动的工具来审查和编辑上下文,或者选择一种更适合修剪任务的定制化方案。
上下文修剪有着(相对)较长的历史,因为在 ChatGPT 出现之前,上下文长度在自然语言处理(NLP)领域是一个更棘手的瓶颈。基于这一历史的当前修剪方法之一是 Provence,它是“一种高效且稳健的问答上下文修剪器”。
Provence 快速、准确、易于使用,而且体积相对较小——仅有 1.75 GB。你可以用几行代码调用它,例如:
from transformers import AutoModel
provence = AutoModel.from_pretrained("naver/provence-reranker-debertav3-v1", trust_remote_code=True)
# Read in a markdown version of the Wikipedia entry for Alameda, CA
with open('alameda_wiki.md', 'r', encoding='utf-8') as f:
alameda_wiki = f.read()
# Prune the article, given a question
question = 'What are my options for leaving Alameda?'
provence_output = provence.process(question, alameda_wiki)
Provence 将文章精简,删掉了 95% 的内容,只给我留下了这个相关的子集 。它做得非常到位。
可以使用 Provence 或类似的功能来筛减文档或整个上下文。此外,这种模式强烈支持将上下文的结构化 1 版本保存在字典或其他形式中,并在每次调用 LLM 之前从中组装出一个编译后的字符串。这种结构在修剪时会非常有用,使你能够确保主要指令和目标得以保留,而文档或历史部分则可以被修剪或摘要化。

上下文摘要
上下文摘要是将累积的上下文提炼成精简总结的行为。
上下文摘要最初作为应对较小上下文窗口的工具出现。当你的聊天会话接近超出最大上下文长度时,会生成一个摘要并开启一个新线程。Chatbot 用户会在 ChatGPT 或 Claude 中手动执行这一操作,请求机器人生成一个简短回顾,然后将其粘贴到新的会话中。
然而,随着上下文窗口的增加,智能体构建者发现,摘要的好处不仅仅在于保持在总上下文限制内。随着上下文的增长,它会变得分散注意力,并导致模型对训练中学到的内容依赖减少。我们称之为上下文干扰 。开发会玩宝可梦的 Gemini 智能体的团队发现,超过 100,000 个 token 就会触发这种行为:
虽然 Gemini 2.5 Pro 支持超过 100 万个 token 的上下文,但如何在智能体中有效利用它仍是一个新的研究前沿。在这种智能体设置中,观察到当上下文显著超过 10 万个 token 时,智能体倾向于重复其庞大历史中的动作,而不是综合生成新的计划。尽管这一现象只是轶事,但它突出了长上下文在检索与多步骤生成推理之间的重要区别。
总结你的上下文很容易做到,但对于任何特定的智能体来说,要做到完美却很难。了解哪些信息应该被保留,并将这些信息详细传递给由 LLM 驱动的压缩步骤,对智能体的构建者来说至关重要。值得将这一功能单独拆分为一个由 LLM 驱动的阶段或应用,这样可以收集评估数据,从而直接为这一任务提供信息并进行优化。

上下文卸载
上下文卸载是指将信息存储在 LLM 的上下文之外的行为,通常通过一个存储和管理数据的工具来实现。
这可能是我最喜欢的策略,仅仅因为它如此简单 ,以至于你都不相信它会奏效。
同样,Anthropic 对这一技术有很好的说明 ,其中详细介绍了他们的 “think” 工具,本质上就是一个草稿本:
使用 “think” 工具时,我们赋予 Claude 一个额外的思考步骤——配有自己专属的空间——作为获得最终答案的一部分…… 这在执行长链的工具调用或与用户进行长时间的多步骤对话时尤其有用。
我非常欣赏 Anthropic 发布的研究和其他文章,但我并不喜欢这个工具的名字。如果这个工具叫做 scratchpad,你会立刻明白它的功能。它是一个让模型记录笔记的地方,这些笔记不会干扰其上下文,并且可以在之后参考。名字“think”与“extended thinking”相冲突,而且不必要地将模型拟人化……不过我离题了。
拥有一个记录笔记和进展的空间确实有效 。Anthropic 展示了将“think”工具与特定领域的提示配合使用(在代理中你本来也会这么做)可以带来显著提升,在针对专业代理的基准测试中,性能最高可提升 54%。
Anthropic 确定了三种情境适合使用上下文卸载模式:
- 工具输出分析。当 Claude 需要在采取行动前仔细处理之前工具调用的输出,并且可能需要在方法上回溯时;
- 政策密集型环境。当 Claude 需要遵循详细的指导方针并验证合规性时;以及
- 顺序决策。当每个行动都建立在之前的行动之上且错误代价高昂时(通常出现在多步骤领域)。
上下文管理通常是构建代理中最困难的部分。正如 Karpathy 所说,将 LLM 编程为“ 恰到好处地打包上下文窗口 ”,并智能地部署工具、信息以及定期进行上下文维护,是代理设计者的核心工作。
上述所有策略的核心见解是, 上下文不是免费的 。上下文中的每一个 token 都会影响模型的行为,无论是积极还是消极。现代 LLMs 拥有庞大的上下文窗口,这是一种强大的能力,但这并不是在信息管理上马虎的借口。
当你构建下一个智能体或优化现有智能体时,问问自己:这个上下文中的每一部分都物有所值吗?如果不是,现在你有六种方法来修正它。