首页 / 文章

更大的上下文窗口无法解决你的智能体问题:注意力预算与缓存机制

上下文窗口的作用类似于注意力预算。了解“Lost in the Middle”机制,以及何时该使用压缩、滑动窗口、压缩处理或提示词缓存。

发布者:REACTAPP.TOP阅读约 11 分钟2427 词

来源: A Bigger Context Window Won’t Fix Your Agent

提供商可以宣称拥有百万令牌的上下文窗口,但模型实际使用的量通常会远少于此。NVIDIA的RULER基准测试用于检测模型在何种长度下仍能保持良好性能。在其测试的17个模型中,Yi-34B和GPT-4(1106预览版)在宣称的20万令牌中实际可靠使用长度约为3.2万令牌,在宣称的128万令牌中则约为6.4万令牌。性能最差的模型在远低于宣传数值的情况下就出现性能下降。超过这个限度后,所宣称的容量只不过是价格表上的数字而已,并非真正的实际能力。

在多个地方都能看到同样的根本性缺陷。某个智能体会忘记第一轮时做出的架构决策;RAG系统虽找到了正确的文档,但依然给出错误答案;自动会话总结则恰好遗漏了你需要的配置行。人们通常的第一反应是增加模型容量,但对于这类智能体而言这并无用处,因为容量从来都不是问题所在。真正的问题在于模型如何将注意力分配到已填满该容量的所有信息中。

简短版

上下文窗口并非统一内存,而是一种具有注意力预算的资源,这种预算会在达到令牌限制之前就已耗尽。位于上下文开头或末尾的内容比中间的内容更易被利用,以至于当模型收到嵌入在提示语中间的文档时,其回答质量可能还不如没有收到任何文档时的情况。一个具体的例子是:如果智能体在同一个提示语中同时接收到冗长的工具日志、一堆检索到的内容片段以及相关指令,它往往会优先处理边缘的内容,而忽略其余部分。

有三种工具负责管理这一注意力预算,每种工具会以不同的方式造成损失:

  • 提示压缩会删除信息量较低的令牌。它在参考基准测试中表现良好,但在独立复现实验中,对于编号、精确字符串和代码片段等结构化内容却会出现问题。
  • 滑动窗口与压缩用于控制会话长度。前者会丢弃最旧的轮次,后者则用摘要替换它们,两者的数据损失程度不同。
  • 提示词缓存可在不丢失信息的前提下将输入成本降低约90%,前提是各次调用之间的前缀必须完全一致。
  • 问题在于:压缩和压缩处理都会破坏缓存,而且通过缓存节省的成本往往超过压缩带来的节省。用错误的工具解决错误的问题会导致隐蔽的生产故障,事后诊断起来十分困难。

    上下文是一种预算,而非存储空间

    首先介绍两个术语。标记是模型处理的文本单位,大约相当于四个字符或英文单词长度的四分之三。上下文窗口则是指单次调用中可处理的最大标记数量,它更多取决于注意力矩阵在单次遍历中的最大尺寸,而非日常意义上的内存大小。

    安德烈·卡帕西将上下文工程描述为一种技巧,其核心是在模型作为处理器的背景下,为“窗口”填充下一步所需的确切内容,而该“窗口”则相当于模型的工作内存。这一类比虽有用,但仅涵盖了其中一半内容。另一半则是注意力预算的问题。Anthropic针对智能体上下文工程的指导认为,上下文是一种收益递减的有限资源,每新增一个标记都会消耗有限的注意力资源。这属于数学问题而非诗意表达:注意力对的数量呈二次方增长,因此一千个标记大约对应一百万种关系,而十万个标记则对应十亿种关系。

    因此,即便只是为了预防万一而添加背景信息,也绝非免费之事。多提供的几个少样本示例、完整的对话历史记录,或是用二十个工具定义替代五个定义,这些都需要从与关键事实相同的资源池中获取。在架构评审中的第一个问题不应该是可用令牌的数量,而应是预算的哪一部分真正用于实现目标。

    U形曲线

    Liu及其同事(斯坦福大学和伯克利大学,2023年)对多文档问答任务的准确率进行了测量,发现呈现出U形曲线。当相关段落位于开头或结尾时,答案的可靠性最高;而处于中间位置时则最不可靠。人们很快便使用了“位于中间的答案可靠性最低”这一说法,其普及速度远超任何公认的解释。

    真正令人担忧的是一个次要现象:当提示词中包含二三十份文档时,那些位于文本中间位置的正确答案得分反而低于完全不提供任何文档时的基准得分。在错误的位置提供正确的证据,反而可能让系统的表现比什么都不给更差。

    为何会出现这种情况:尚未明确

    多年过去,关于其成因仍没有共识,几种解释并存:

    • 这是训练数据导致的异常现象,因为作者往往将关键信息放在开头或结尾;
    • 与位置编码和因果掩码的运作方式有关;
    • 源于初始化阶段的解码器结构,早在训练开始之前就已存在;
    • 是模型在预训练过程中为平衡各种记忆需求而产生的适应性调整。

    每种问题都需要不同的解决方案:额外的训练数据、不同的注意力掩码、注意力校准,或是重新排序的提示词。将它们合并为单一简洁的解释可能会造成误导。

    哪些问题已解决,哪些尚未解决

    用“问题是否已经解决”来表述会带来误解。简单的事实检索在很大程度上已得到解决:当前的先进模型能够在极长的信息海中找到明确表述的任何目标。而多步骤推理尚未解决。整合多份文档或编辑大型代码库中的代码,与查找单一事实是不同的任务;已发布的长时间上下文编码评估结果显示,对于同一模型和任务类型,随着输入长度的增加,成功率会急剧下降。

    也有证据表明该曲线并非普遍适用。Chroma的Context Rot研究测试了18种前沿模型,结果发现在所有模型中,经过打乱且逻辑上不连贯的“草堆”都比有序的“草堆”表现更好,而且其实验也未能重现一致的位置优势。合理的结论是存在多种退化机制,“Lost in the Middle”仅是其中之一。

    一句话就让得分从27%升至98%

    Anthropic报告了一个关于Claude 2.1在“大海捞针”测试中的典型案例。在该测试中,模型的准确率仅为27%,直到在模型回复的开头添加了一行指令,要求其从上下文中选出最相关的句子。此后准确率上升到了98%。并没有新增任何功能,只是指令的位置发生了变化。由于仅进行了一次评估,且使用的是同一个模型版本和同一类任务,因此应将其视为一个示例,而非适用于所有提示的通用规则。

    机制:注意力沉降点

    序列中的早期标记无论是否有实际内容,都会占据过大的注意力份额。其原因在于数学原理——Softmax函数使得注意力权重之和为1,因此即使没有合适的对象,模型也必须将全部注意力分配给某个地方。放弃分配并非选项,于是这些早期位置便成了注意力的“倾倒地”,这类现象被称为注意力沉降点。

    MIT的一个团队(Xiao及其同事)将这一特性转化为一种工具。他们的研究发现,当第一个标记被从缓存中移除时,简单的滑动窗口就会崩溃。仅将最初的少数几个标记固定为“固定汇点”,就能在处理数百万个标记的流时保持生成过程的稳定性,其运行速度比重新计算每个窗口快22.2倍。常见的总结往往忽略了一个限制:这种方法不会占用任何实际内存。虽然旧标记会消失,但输出依然流畅,而那些滑出窗口的标记则永远丢失。稳定性与内存使用量是两回事。

    因此,实际建议是将关键指令放在注意力最强的位置,通常是在序列末尾,并根据自身的实验环境进行测试。这一方法并非适用于所有情况:一些研究表明,在序列中间出现的汇点,与其被保护不如被抑制更有效,且不同模型的表现也有所不同。

    压缩、窗口与紧缩

    想象一个装不下所有东西的行李箱。你可以丢掉不太重要的物品,只打包最新的内容,或者写下哪些东西被留在了家里。每种选择都会失去不同的东西。

    即时压缩

    LLMLingua系列模型会借助一个小型辅助模型来评估每个标记的“意外性”,从而剔除信息量较低的标记。其效果相当显著:LLMLingua的压缩率可达20倍;而具备查询感知功能的LongLLMLingua在NaturalQuestions任务上的表现提升了21.4%,且仅使用了四分之一的标记数量。这是两种不同的版本,而非单一结果。

    独立复制使得情况更加复杂。有一项针对参考存储库提交的研究指出,未压缩的提示词表现明显优于压缩后的版本,这与论文结论相反。另一项关于该领域压缩技术的研究则发现,由于压缩会破坏编号和精确字符串,导致片段计数精度大幅下降。这并不意味着压缩技术完全失效,只是其可靠性存在争议且取决于数据类型——叙述性文本对压缩的容忍度较高,而带编号的段落、标识符、代码及数字则无法承受压缩。

    管理会话的三种方式

    • 滑动窗口法。采用简单的先进先出机制:保留最近的k条消息或N个标记,丢弃其余内容。这种方法在计算上无需额外成本,但信息损失严重,第一轮的决策到第五轮就可能被忽略,模型还可能提出与之矛盾的内容。
  • 压缩处理。用摘要替换较旧的对话内容。风险在于过度简化的摘要会丢失日后才会显现重要性的细节。不同工具的阈值差异很大,但普遍的建议是在存储容量达到70%至75%时触发压缩,而非95%,因为没有剩余空间的模型生成的摘要质量会更差。
  • 外部内存。在MemGPT模式下,数据存储在窗口之外,模型在需要时通过函数调用将其调取。数据不会永久丢失,但每次调取都会带来延迟并增加一次模型调用次数,而且模型必须先判断某个事实是否值得获取,而这本身就容易出错。该机制适用于那些需要按需检索的事实,比如用户偏好或之前的决策,而不宜用于所有数据。
  • 陷阱:压缩会破坏缓存折扣机制

    通过即时缓存,服务提供商会记住您提示语中不变的起始部分,之后再次读取时仅按常规费率的一小部分收费。底层的KV缓存会存储先前标记的计算结果,这样模型就无需重复处理这些内容。

    这种折扣机制的代价在于僵化性:每次调用时前缀必须完全一致。这就排除了在开头使用动态时间戳、在指令前添加随机会话ID或在使用JSON字典时重新排序键值的可能性。所有可变内容都必须放在易变的尾部。那些使用高效生产代理的团队将缓存命中率视为最重要的系统指标,因为命中与未命中的成本差距可达十倍之多。

    此时陷阱便关闭了。由于每次调用时丢弃的标记取决于当前问题,压缩功能会重新生成提示词,因此每个请求都会导致缓存未命中。虽然这样能节省约60%的标记使用量,但却会失去90%的折扣优势,而且这种情况发生的频率比团队们设想的还要高。

    营销材料中流传着一则轶事,称在采用压缩技术后,每月的账单从约42,000美元降到了2,100美元,但并未提及具体公司、日期或方法。无法确定该对比是否已计入因缓存未命中而产生的额外成本,而这恰恰是决定此类结果能否重复出现的变量。

    周一的计划

    这份清单并不能替代使用自身数据进行的测试。它的作用是避免最常见的错误,即在未尝试更便宜、更安全的方案之前就直接采用压缩技术或更长的处理时间窗口。

    1. 对任务进行分类。是简单的信息检索,还是需要在长上下文中进行多步骤推理?这决定了位置偏差的严重程度。
    2. 确认关键指令的位置。如果它被埋在提示语的中间,就将其移到末尾后再进行测试。只需修改一句话,这是目前唯一可行的方法。
    3. 验证前缀的稳定性。如果每次调用时系统提示语仅有单个字节的不同,缓存就毫无作用,因此必须先解决这个问题。在评估中,这一点被提及的频率远低于模型选择,但它却可能对结果产生更大影响。
  • 在选择工具之前先明确问题所在。如果出现成本增加的问题,说明需要在压缩前检查缓存;若长时间使用后质量下降,则表明应在70%到75%的压缩比例时停止操作。如果某些具体信息被遗忘,那就需要考虑是否使用滑动窗口机制或外部存储,这取决于这些信息是否需要按需调取。
  • 如果仍要使用压缩功能,务必在自己的数据上对其进行测试,尤其是那些包含精确数字、标识符和代码的数据,因为现有公开的结果往往无法在这些数据上得到相同的效果。
  • 核心要点

    更大的窗口并不能解决代理程序的问题,因为它只是增加了本就不缺容量的资源的存储空间。

    • 窗口实际上是一种注意力预算而非存储空间,每多添加一个标记都会占用原本用于处理重要信息的资源。
  • 关于“中间迷失”问题的讨论存在错误前提:事实检索主要依赖前沿模型来完成,而针对长上下文的多步骤推理能力仍明显不足。
  • 位置信息是你最容易获取的优化手段,因此在投入更多昂贵资源之前应先检查这一点。
  • 压缩技术在独立测试中已被证实存在缺陷,尤其是对于那些需要完整保留的内容。
  • 从成本角度而言,缓存与压缩的效果会相互抵消,因此应先计算两者的节省幅度。
  • 日常工作中真正的变化在于设计评审时问题的提问顺序。首先应询问上下文包含什么以及每个元素的位置,之后再考虑其规模大小。如果颠倒顺序,就会因为过大的视野范围而让重要信息在更宽的范围内被忽视。有一条简单的经验法则:先检查位置,再考虑稳定性,接着是体积,最后才处理压缩问题。