为什么上下文长度难以扩展
更长的上下文窗口听上去只是个简单的旋钮。其底层却在对抗一种增长快过文本本身的成本——以及一种被摊得越来越薄的注意力。
上下文窗口是一个语言模型一次能容纳多少文本——提示、文档、到目前为止的对话。更大显然更好:更大的空间意味着你可以把一整份报告、一大段代码库或一整段对话历史喂给模型,而不必删掉任何东西。那为什么不干脆把每个模型的窗口都做得巨大?因为在底层,长度并不是一个免费的参数。它对抗着让这些模型得以运作的那个核心机制,而其成本增长得比文本本身还快。本文要讲的,是为什么扩展上下文是真正困难的,而不仅仅是分配更多内存的事。
其实有两个问题叠在一起:一个成本问题,和一个质量问题。两个都得解决,而它们朝不同的方向拉扯。
让长度变得昂贵的那个机制
大多数现代语言模型都建立在注意力(attention)之上,正是这个机制让每个 token 去看其他 token,以判断什么是相关的。注意力是这些模型力量的来源:输入的每一片,原则上都能与其他每一片发生关联。
而那句话——每一片与其他每一片——也正是麻烦的源头。在注意力的标准形式里,工作量随 token 对的数目增长。把输入长度翻一倍,你并不是把工作量翻一倍;你大致是把它翻四倍,因为对的数目随长度的平方增长。这就是著名的注意力二次方成本,也是长上下文之所以昂贵的核心原因。
直觉很简单:如果你有 N 样东西,而每一样都必须考虑其他每一样,你就有大约 N 乘 N 量级的关系要去计算。把 N 放大十倍,关系就增长百倍。一个长十倍的窗口,处理起来的成本可能远不止十倍。在注意力中,长度不是一笔线性的开销。
计算问题之上的内存问题
成本不只关乎计算,也关乎内存。为了高效地处理、尤其是生成文本,模型会保留它已经见过的 token 的中间表示——一个常被称作键值缓存(key-value cache)的持续存储。这个缓存让模型不必为每一个新 token 都从头重新计算一切。
问题在于这个存储随上下文长度增长。窗口越长,模型就必须同时把越多的它保留在快速内存里。对极长的上下文而言,这个内存占用可能成为约束的瓶颈——你会先用光容纳上下文的空间,而不是先耗尽对算力的耐心。所以长上下文同时拉紧两种稀缺资源:把一切关联起来所需的计算,以及把一切保留下来所需的内存。设计长上下文系统,在很大程度上就是一场两线作战。
更安静的那个问题:注意力被摊薄
假设你付清了成本,把窗口做得巨大。第二个、更微妙的问题出现了,它关乎质量而非开销。注意力靠的是把焦点分散到整个输入上。当只有寥寥几样东西可供关注时,焦点是集中的。当有非常多时,那份焦点就得分散到所有这些之上,而真正相关的那几片,便可能淹没在一片无关之海里被稀释掉。
因此,一个长上下文反而可能让模型更难找到并用上那一个要紧的细节,即便那个细节技术上就在那里。信息在窗口里,但它在与窗口里的其他一切争夺注意力。一个更大的干草堆并不帮你找到那根针;它反而可能把针埋了起来。
这就是为什么一个拥有很长窗口的模型,并不会自动就把那个窗口用好。能放下一段长输入,和能在其上有效推理,是有真实区别的。前者关乎容量;后者关乎当有那么多东西要考虑时,注意力是否还能挑出真正重要的部分。
迷失在中间
这个质量问题有一个尤为出名的版本,就是模型倾向于根据信息坐落于长上下文中的哪个位置而不均匀地使用它。靠近长输入开头和结尾的材料,往往比埋在中间的材料被更可靠地用上。把关键事实放在一份长文档的正中央,模型可能就实际上把它忽略了,哪怕它读过。
这种模式——有时被描述为模型在其上下文的中段较弱——提醒我们一个长窗口并不是一份均匀、完美的记忆。它是一段注意力的跨度,有着自己强项与弱点的地理分布。知道这一点会改变你使用长上下文的方式:把最重要的材料放在模型注意力最强的位置,而不是假定每个位置都一样,是一个直接从底层行为推出的实用杠杆。
为什么不能光靠在更长的文本上训练
你也许会想,办法不就是干脆在很长的样本上训练模型、直到它学会处理它们吗。这有帮助,但它并不免费。在长序列上训练继承了同样的二次方成本,所以它昂贵的方式,恰恰就是使用长上下文昂贵的方式。而且一个主要在较短文本上训练出来的模型,当突然被喂以远比它在训练中见过的任何东西都长的输入时,可能无法优雅地泛化——它对位置和相关性的感知,会在熟悉的长度之外退化。因此扩展上下文不是一个一拨即开的开关;它是一种必须被刻意构建、并在训练和服务两端都付出代价的属性。
这个领域如何推动极限
因为障碍是真实的,所以围绕长上下文的许多工作都是在改变规则,而不是硬碰硬。这些方向即便不看数学也很符合直觉。
- 更便宜的注意力。 一大批研究致力于近似注意力,让它的成本随长度的增长更接近线性而非二次方,办法是避开完整的全对计算。用一点点精确去换大量的可扩展性,是反复出现的主题。
- 缩小内存占用。 压缩或节省键值缓存的技术,让更长的上下文能装进同样的内存,从内存这一侧攻击问题。
- 检索,而非把一切都装下。 与其把整个语料库塞进窗口,不如只取出相关的几片喂进去。这通过让实际的上下文保持很小,绕开了长度问题——正是检索增强(RAG)方案背后的策略。
每条路都要做一笔交易。更便宜的注意力放弃一些精确;压缩放弃一些保真;检索放弃了“一切同时在场”的保证。没有免费的午餐,只有不同的交易。
总结
上下文长度难以扩展,是因为这些模型背后的主导机制——注意力——的工作量随输入的平方增长,而为高效运行所需的键值缓存也随长度增长——所以更长的窗口比文本增长得更快地拉紧算力和内存。而即便你付清了这笔代价,更长的上下文也会把注意力摊得更薄、更不可靠地用上它的中段,所以装下更多文本,并不等同于在其上推理得很好。前沿的推进靠的是改变这笔交易——更便宜的注意力、更精简的内存,或只检索要紧的东西——每一种都拿某样东西去换取触达。一个更大的窗口从来不只是一个更大的数字;它是一场对抗复利式成本的战斗。
