![]()
你有没有想过一件事:为什么ChatGPT这类模型思考得越久,反而会变得越贵、越慢?
这不是一个技术八卦,而是一个真实存在的工程困境。2024年之后,"让模型多想一会儿"成了提升AI表现的杀手锏,业内管这个叫**测试时扩展**。
> 测试时扩展:不改变模型本身,只是在回答问题时给它更多思考时间和计算资源,从而提升答案质量的方法。最简单的版本就是让模型像人一样,先在心里琢磨一会儿再开口。
道理很直白:一道数学题,模型多想几步,正确率就会上去。但这里藏着一个陷阱,模型每多想一个词,就要把之前所有想过的内容全部重新看一遍。这就是所谓的**全注意力机制**。
> 全注意力机制:模型生成每一个新词时,都要回顾此前生成的所有内容,计算量随着文本长度增长而线性甚至更快增长。
这意味着,如果你让模型思考一千个词,它需要处理的信息量是思考一百个词的十倍不止。等它想到十万个词的时候,计算成本已经高到离谱,慢到你可能等到天荒地老。
这就是斯坦福大学、华盛顿大学、Prime Intellect等机构联合发表的这篇论文要解决的问题。他们发现了一件很有意思的事:模型在长时间推理的过程中,其实并不需要死死记住中间的每一个细节。
被遗忘的中间步骤
先说一个直觉判断。假设你在心算一道复杂算式,比如"((42+84)×4)-5"。你算出42加84等于126之后,还需要记得"42"和"84"这两个数字本身吗?
不需要。
一旦这一步算完,只有结果126才重要,过程可以彻底忘掉。
研究者把这个直觉放进了真实模型里验证。他们用Qwen3-1.7B模型跑一道数学竞赛题(AIME25),然后把模型在生成每个新词时,对之前所有词的**注意力概率**画了出来。
> 注意力概率:模型在生成新内容时,给之前每个词分配的"关注度",数值越高说明模型越依赖这个词。
结果很清楚地显示出一个"U形"曲线:开头几个词(也就是系统指令和题目本身,论文里叫**前缀**)拿到了极高的关注度,最近生成的几百到一千个词也拿到了很高关注度,但中间那一大段,注意力几乎趋近于零。
> 前缀:对话开始时的系统指令和用户提出的问题,包含任务要求、可用工具等关键信息。
这个发现有点像你在看一本厚厚的推理小说。开头交代的案情背景(谁死了、现场有什么线索)你会一直记着,最近读的这几页情节你也记得清楚,但中间那些侦探绕来绕去的推理过程,一旦你翻过去,其实大部分细节你根本记不住,也不需要记住,因为最终真相只取决于开头设的谜题和最后的结论。如果作者非要你记住每一页的每一句话才能读懂结局,那这本书基本没法读下去。
模型的"前缀"之所以重要,还有一个隐藏原因。前几个词往往扮演着**注意力汇聚点**的角色。
> 注意力汇聚点:模型会把多余的关注度"倾倒"到序列最开头的几个词上,即使这些词本身没有实际内容,这是一种模型内部的机制性现象。
这也解释了为什么开头那个标志"开始思考"的特殊符号(比如``)也会一直拿到很高关注度,因为它持续提醒着模型"你现在处于推理状态"。
前缀滑动:一个只留头尾的记忆策略
既然中间大段内容不重要,那能不能干脆把它们从内存里删掉?
这正是论文提出的核心方法,**前缀滑动**。
它的思路简单到有点朴素:推理过程中,模型只保留最开始的前缀,加上最近生成的一段固定长度的窗口,中间的内容一律丢弃。
> 前缀滑动:一种让语言模型在长推理过程中只保留任务前缀和最近若干词的注意力窗口,从而将每一步生成的计算成本控制在恒定水平的方法。
举个具体数字。假如系统指令是40个词,用户问题是60个词,前缀总共就是100个词。再设定一个4096词的滑动窗口,那么无论模型思考了一万个词还是一百万个词,它任何时刻需要处理的内容都不会超过4196个词。
这就带来一个关键效果:生成第一个词和生成第一亿个词,成本完全一样。
这一点值得多说两句,因为它直接决定了这个方法的意义。如果没有这个恒定成本的设计,模型思考得越久就越贵,这就形成了一个天然的"思考惩罚",逼着工程师人为砍断模型的思考长度,哪怕问题本身需要更长的推理。而恒定成本意味着,理论上模型可以思考几周甚至几个月,只要问题足够重要,值得投入这么多算力。
这就好比你搬家打包行李。如果每装一件新东西都要把之前打包好的所有箱子重新检查一遍确认位置对不对,那搬家效率会随着东西越来越多而急剧下降,搬到最后可能一天都搬不完一间屋子。但如果你规定行李箱只有固定几个格子,装满了就把最早放进去的东西挪出来(除非是你一开始就打算随身带着的证件和钱包),那么不管你要打包多少东西,每次收纳的动作耗时都差不多。前缀滑动本质上就是给模型的"记忆行李箱"设定了固定容量,证件和钱包(前缀)永远带在身上,其他东西按照先进先出的规则轮换。
那如果模型本来就是用全注意力训练出来的,突然改成这种"选择性遗忘"的方式,它还认得路吗?
研究者做了实验验证,答案是认得。他们在Qwen3-1.7B上直接套用前缀滑动,不做任何额外训练,在三个基准测试上(AIME25竞赛数学、GPQA博士级科学问答、MATH500数学题)都做到了和全注意力相当的准确率,但速度快了3倍。
具体来看下面这张实验结果表格里的数字:
| 窗口大小 | AIME25准确率 | GPQA准确率 | MATH500准确率 | 32K长度下每秒生成词数 |
| 2048 | 27.7% | 35.9% | 89.8% | 8973 |
| 4096 | 33.9% | 37.0% | 91.5% | 5479 |
| 8192 | **35.8%** | 38.0% | 91.4% | 3291 |
| 16384 | 35.3% | **38.2%** | **91.5%** | 2441 |
| 全注意力(对照组) | 34.2% | 37.6% | 91.7% | 1477 |
注意最后一列,同样是处理32000个词长度的推理,前缀滑动在窗口8192时每秒能生成3291个词,而全注意力只能生成1477个。窗口2048时更是达到每秒8973个词,速度提升超过6倍,而准确率还没有明显掉队。
位置编码怎么处理:接着编还是重新编
这里有个技术细节值得展开讲一下。模型知道一个词在句子里的位置,靠的是一种叫**位置编码**的机制。
> 位置编码:让模型区分"这是第几个词"的一套数学编号系统,常见实现方式叫RoPE(旋转位置编码)。
当滑动窗口往前推进、老词被踢出去之后,剩下的词的位置编号是应该保持原样继续往后编,还是重新从头编号?
论文测试了两种方案。一种叫"继续编号",就是词的位置标签不变,即使它前面的邻居已经被删掉了;另一种叫"重置编号",每次滑动之后都给剩下的词重新分配从0开始的位置标签。
直觉上"重置编号"似乎更干净,但实际操作起来复杂得多,而且计算成本更高,因为已经算好的表示要重新套上新的位置标签才能复用。研究者对比后发现,两种方案在准确率上差别很小,于是选择了更省事的"继续编号"方案。
训练阶段怎么用:让强化学习跑得更远
如果说前缀滑动在不训练的情况下已经能省电又保效果,那把它用进训练过程,尤其是强化学习,又能带来什么?
先解释一下背景。目前主流的强化学习训练方式叫**GRPO**,它需要模型自己生成一段完整的推理轨迹,然后根据这段轨迹的对错去调整参数。
> GRPO:一种强化学习算法,通过让模型生成多条推理路径并比较优劣来更新模型参数,常用于训练推理能力。
问题是,如果模型生成的推理轨迹动辄十万甚至几十万个词,那训练时反向传播梯度就会因为内存不够而直接崩掉。
行业里常见的做法是,直接把超长的生成结果掐断丢弃,不参与训练。这就好比一个学生辛辛苦苦写了一整篇论文,老师却因为纸张太厚懒得批改,直接扔进垃圾桶,只批改简短的作业。学生付出的努力全都白费,而且长论文往往对应着更难的问题,恰恰是最需要反馈的那部分被浪费掉了。
论文提出用前缀滑动来解决这个矛盾。既然推理阶段只需要保留前缀和滑动窗口,那反向传播时也只需要传回最后一段窗口内容加上少量上文,而不是整个几十万词的轨迹。
具体的做法论文里叫**截断反向传播**。
> 截断反向传播:只对推理轨迹的最后一小段计算梯度,前面的内容仅作为上下文参与前向计算,不参与梯度更新的训练技巧。
举个例子,模型生成了十万个词,滑动窗口大小是2048。训练时只需要把最后8192个词传给训练器,其中前6144个词只当作背景context,真正计算损失、更新参数的只有最后2048个词。这样虽然只反向传播了一小部分,但因为这部分是用四倍窗口大小的上下文精确算出来的,梯度依然足够准确。
研究者做了个KL散度实验来验证这个"只传一部分"到底靠不靠谱。
> KL散度:衡量两个概率分布之间差异程度的指标,数值越小说明两个分布越接近,这里用来检验生成器和训练器算出来的概率是否一致。
实验结果显示,如果只传回和滑动窗口一样大的内容(2K),KL散度超过0.1,说明生成器和训练器算出来的结果对不上号;但只要多传两倍(4K),误差就大幅下降;传四倍(8K)时误差已经很低,和传八倍(16K)差不多。所以研究者最终选定了"四倍窗口"这个折中方案。
在真实的强化学习实验里,前缀滑动交出的成绩是这样的:在同样限定8192个词的内存预算下,用前缀滑动训练的模型,能够生成长达十万词的推理链,而全注意力模型被死死限制在8192词以内。前者的奖励曲线明显更高更稳定,说明允许模型"想得更久"确实换来了更好的表现。
和其他"省内存"方案的正面对比
前缀滑动不是唯一试图解决这个问题的思路。论文专门拿出了三种常见替代方案做对比,逐一分析它们的短板。
第一种叫**last k**,简单粗暴,每隔一段时间就把除了最后k个词以外的所有内容全部删掉,只留最近的一小截接着往下写。
> last k:当推理长度超过阈值时,只保留最近k个词,删除更早的所有内容的一种上下文管理策略。
这个方法的问题在于,被保留的这k个词其实要被处理两遍:第一次是生成的时候,第二次是删除旧内容之后重新构建上下文时。而且如果k设得太小,一些本该有用的近期信息也会被误删,模型可能得重新把删掉的内容想一遍才能继续,等于做了无用功。
这就像你每写几页笔记就把本子撕掉重开一本,只带走最后一页接着写。看似轻装上阵,实际上那最后一页的内容你要先抄一遍才能继续,而且前面几页里那些你还没来得及记住的关键点,可能就这么弄丢了,回头还得重新推导一次。
第二种叫**总结法**,让模型定期把当前所有内容压缩成一段摘要,然后拿着这段摘要重新开始一轮新的上下文。
这个方法看起来更聪明,因为摘要理论上能提炼出真正重要的信息。但论文的实验发现了一个很扎心的问题:模型经常会写完摘要之后,压根不参考自己刚写的摘要,而是直接重新从头推导一遍。论文里给了一个具体案例,一道关于梯形内切圆的几何题,模型在摘要里已经写好了"r等于12加6乘根号3,s等于12减6乘根号3"这个关键结论,但换了一轮上下文之后,它完全无视这段摘要,又老老实实从头把整个推导过程做了一遍。
这暴露了一个更深层的问题:模型嘴上说着"参考之前的推理",实际决策时到底有没有真的用上这些信息,很难验证。这和此前学术界讨论的"思维链是否真实反映模型内部推理过程"是同一类担忧。
第三种叫单纯的**滑动窗口**,也就是前缀滑动去掉前缀部分之后剩下的版本,只保留最近的固定窗口,完全不管最初的任务说明。
这个方法的问题最直观:模型很容易忘记自己到底在解决什么问题,或者手头有哪些工具可以用。就好比你参加一场持续几小时的会议,会议记录本却只能记最近十分钟的内容,那开场时老板交代的核心目标,你早忘得一干二净了,会开到最后完全跑题都不知道。
四种方法放在一起测试AIME25的结果非常直观:前缀滑动在准确率和速度的平衡上明显胜出,纯滑动窗口的准确率很快就趴在低位不再上升,last k和总结法虽然也能达到不错的准确率,但因为需要重复处理词或者额外生成摘要的开销,效率上天然吃亏。
这个方法也不是万能的
论文很坦诚地列出了几个前缀滑动目前解决不了的问题,这一点值得单独说说,因为这才是真正体现研究严谨度的地方。
第一个坑出现在代码生成任务上。在LiveCodeBench这个编程测试里,前缀滑动需要把窗口开到16384才能追上全注意力的表现,用小窗口就会明显掉分。研究者深挖之后发现,问题出在模型写代码的习惯上:它经常先写一个函数框架,然后用大段注释在里面"碎碎念"式地推理好几千个词,等它想明白继续写代码的时候,最初的函数定义已经被滑出窗口之外了,模型自己都不记得开头写了什么。
这就像你在装修房子,先在墙上画好水电线路图,然后你花了大半天时间站在旁边琢磨接下来怎么走线,思考的时间太长,等你终于想清楚要回去看线路图的时候,发现图纸已经被工人不小心撤走了。不是线路图不重要,而是你的"记忆窗口"没能覆盖到你思考的这么长时间。
第二个局限是,对于本来就很短的任务,前缀滑动几乎没有加速效果。论文用了一个医疗问答测试(HealthBench)来验证,这类任务平均只需要2086个词就能回答完,如果滑动窗口设成2048,那模型基本用不上滑动机制,速度和全注意力几乎一样。这也提醒我们,任何优化方法都有它的适用边界,不是所有场景都能从中受益。
第三个问题出现在需要模型读取外部内容的场景,比如网页、文件。如果这些外部内容的长度超过了滑动窗口大小,模型天然就没办法完整读进去,甚至可能因为新读入的大段内容把原本重要的信息挤出窗口。这类问题在多轮对话里同样存在,未来的用户指令要不要放进前缀里,还是任由滑动窗口把它冲刷掉,目前还没有定论。
从更大的视角看这件事
论文里还专门讨论了一个更宏观的分类框架,把各种处理长文本的方法分成**有界方法**和**无界方法**两类。
> 有界方法:每生成一个新词的成本,无论文本多长,最终都会趋于一个固定上限的技术路线。
> 无界方法:即便计算复杂度已经优化到低于平方级别,每生成一个新词的成本依然会随文本变长而持续增加的技术路线。
全注意力属于典型的无界方法。RNN、状态空间模型(比如业内熟知的Mamba架构)这些新兴架构则属于有界方法,但它们的硬伤是必须从头训练全新的模型架构,没法直接套用在市面上已经训练好的模型身上。
前缀滑动的特别之处在于,它既是有界的,又能直接套用在现有模型上不需要重新训练,同时还能选择性地用于强化学习训练阶段进一步提升效果。这种"两头都占"的定位,恰恰是这篇论文最实际的价值所在。
写在后面
读完这篇论文,最触动我的其实不是前缀滑动这个方法本身有多精妙,而是那张注意力分布图带来的冲击感。
我们习惯性地以为,模型"思考"是一个连贯的、每一步都依赖前面所有铺垫的过程,就像人类写论文时前后逻辑环环相扣。但这张图赤裸裸地展示出,模型的注意力其实是"两头沉、中间空"的哑铃形状。中间那一大段推理过程,在模型自己看来,重要性几乎为零。
这其实是对"思维链"这个概念的一次悄悄的祛魅。我们一直假设模型是在"认真地一步步推导",但如果它自己都不太回头看这些中间步骤,那这些步骤到底是真实的推理,还是仅仅是一种"表演给自己看"的输出格式?论文提到的另一篇工作标题就叫《推理模型不总是说出它们真实所想》,这两件事放在一起看,让人忍不住重新思考:所谓的"长思考",究竟有多少比例是真正的计算,又有多少只是一种自我强化的仪式感?
还有一个细节我觉得值得单独拎出来,代码生成任务上前缀滑动栽的那个跟头。模型用大段注释"碎碎念"式地思考,这其实暴露了一种很人性化的行为模式,边写边想,想到哪写到哪,而不是先想清楚再动笔。如果未来要让这类方法更普适,可能真正需要解决的不是内存管理技巧,而是训练模型养成"结论先行、过程后补"的思维习惯,这或许比调大窗口更根本。
Q&A
Q1:前缀滑动是什么?
A:前缀滑动是一种让语言模型在长推理时只保留任务前缀(系统指令和问题)以及最近若干词的方法,中间的推理内容会被丢弃,从而让每生成一个新词的计算成本保持恒定,不随推理长度增长。
Q2:前缀滑动需要重新训练模型才能用吗?
A:不需要。论文证明前缀滑动可以直接套用在已经训练好的模型上,无需任何额外训练就能实现3倍加速且保持准确率,同时它也可以选择性地用于强化学习训练阶段进一步提升效果。
Q3:前缀滑动在哪些任务上表现不好?
A:在需要模型长时间读写代码并用大段注释推理的任务(如LiveCodeBench)上,前缀滑动需要更大的窗口才能匹配全注意力效果;对于本身推理很短的任务,加速效果也很有限。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.