AI智能体记忆越用越长,推理引擎为何跟不上
你有没有想过,一个能帮你写代码、查资料、跑测试的AI智能体,为什么用着用着就变慢了?答案藏在一个很少被普通用户注意到的地方:对话记录。一个长期运行的AI智能体,比如帮你修Bug的编程助手,会不断积累历史,每次工具调用、每次推理、每次用户追问,都变成新的文字塞进上下文。几十轮下来,这段历史可能长达十几万个token。..
一个能帮你写代码、查资料、跑测试的AI智能体,怎么用着用着就慢下来了?这事很多人可能都碰到过。
原因藏在一个普通用户不太留意的地方:对话记录。长期跑着的智能体,比如帮你修Bug的编程助手,历史会一直堆下去。每回调用工具、每回推理、每回用户追问,都会变成新文字塞进上下文。几十轮之后,这段历史能长到十几万个token。模型不会主动把这些忘掉,它得全记着,因为哪一句话都可能在后面被再次用到。
可记住这件事,本身是要付代价的。
哈尔滨工业大学团队的一篇论文,讨论的正是这个麻烦:AI智能体的记忆越拖越长,跑它的推理引擎该怎么顶住这份压力。
**
先把问题说清楚:AI智能体为什么越聊越卡。
模型每生成一个新词,都得把此前说过的话回头再看一遍。这个回头的动作,叫注意力。
KV缓存*:模型处理每个历史词时会算出一组叫Key和Value的数字,存下来供后面复用,省得每次把全部历史重算一遍,这块存储就是KV缓存。
历史一长,KV缓存吃掉的显存就多,算注意力要扫的范围也跟着变大。论文开头点出的两个瓶颈正在这儿:显存装不下,算起来还慢。
学界其实早就看到了这个问题,给出的偷懒思路分四类。第一类是动态稀疏注意力,回答问题时只从历史里挑出一小部分看着相关的来算,剩下的先搁着,但完整历史仍然留在显存里,后面要用还能翻出来。第二类是KV淘汰,把不重要的记录直接从显存里删掉换空间,代价是删了就真找不回来了。第三类是KV压缩,把每段历史的信息压成更小的表示,占的地方少,内容还留着。第四类是KV量化,把数字精度降下来,比如从32位浮点数变成4位,用更粗的方式省空间。
四类办法脾气各不相同。动态稀疏要留着完整历史,另外还得配一份摘要索引;KV淘汰得持续更新一份谁重要谁不重要的评分;KV压缩要额外的重建逻辑;KV量化则要存一份量化参数。对于历史该长成什么样,它们的看法完全对不上。
于是工程上就有了一个很现实的问题:市面上的推理引擎,骨架通常只按某一类方法的思路搭。
论文举了几个例子。SPIN这个系统把整个流程做成建索引、挪到CPU、挑选、取回来、算注意力五步走的固定流水线。Vortex围绕分页这个概念来设计所有接口,什么操作都基于页面展开。Tangram则专门针对不同注意力头保留不同数量历史这种特殊情况做了优化。
这些设计各自解决了自己瞄准的问题,可换一种方法来跑,往往就水土不服。论文里提到,Quest靠查询动态选页面;H2O不光要动态选,还得一直维护一份持续累加的注意力分数表,并且真的把数据从显存里物理删除。假如推理引擎只为选页面这个动作设计了接口,H2O那种要持续记分、还要真删数据的逻辑,就没地方安放。
这有点像租了一套按单身公寓标准装修的房子,厨房小得只够放一个电磁炉。后来你想开个小饭馆,得支炒锅、放调料架、装抽油烟机,结果发现这些设备根本塞不进去。不是厨具不好,是房子从一开始就没按可能需要大改造来设计。真到了要扩建的时候,要么砸墙重装,要么干脆放弃,换一套毛坯房从头来。
论文的核心问题到这里就浮出来了:推理引擎的边界该划在哪儿?哪些东西归系统统一管,哪些东西放手让每个稀疏方法自己做主?
**把边界划在生命周期上**
研究团队给出的答案,是SparseEngine这套系统。
它的思路和前面那些引擎不太一样。前面提到的系统是先定好一套工作流程,比如索引、选择、注意力计算这样固定的三步,再要求所有方法套进这个流程。SparseEngine反过来,抓的是一个所有Transformer模型都逃不开的固定顺序:模型每一层先归一化、再算Q/K/V、算注意力、算前馈网络,这个顺序写死在模型结构里,不会因为换了稀疏方法就变。
在这个固定顺序的每个关键节点上,SparseEngine都开了一个口子,叫作生命周期钩子。
生命周期钩子*:模型执行到某个特定节点时(比如一层算完了、一个解码步骤结束了),允许外部代码插进来跑自定义逻辑的接口。
打个比方,一条流水线上有好几个固定工位,每个工位旁边都预留了一个插座。你可以在注意力计算前这个工位插上一台挑选重要历史的设备,也可以在这一步结束的工位插上一台清理不要数据的设备。流水线本身的顺序没变,每个工位能接什么外部设备,全由你自己定。要是不留这些插座,想加设备就得把流水线拆了重装,前面提到的其他引擎碰到的正是这个困境。
有了这些钩子,每个稀疏方法就能拥有自己专属的缓存管理器。
这个管理器管什么?管这个方法自己的数据怎么存、怎么更新、怎么释放。SnapKV在钩子里做的事,是看一眼最后几个词对历史的注意力分布,挑出重要的部分,把不重要的物理删除。H2O每步解码都要把累积分数更新一遍,再决定删谁。OmniKV更特别,它在某些层里先判断哪些历史重要,然后把这个判断结果传给后面的层直接复用,不用每层重新算一遍。
这些完全不同的操作逻辑,各自封装在缓存管理器里,互不干扰。把它们和实际注意力计算连起来的,是一个叫AttentionView的中间层。
AttentionView 是个视图机制,各方法自己管的那摊缓存数据,由它转成注意力计算模块能直接读的统一格式。换句话说,历史不管是稀疏挑选着存的、物理删掉之后存的、压缩过的还是量化过的,到真正算注意力那一步,交出去的都是同一种格式。跨境支付也是这个道理:各国货币背后的系统逻辑千差万别,最终清算时都要换算成同一种结算货币。
听着朴素,可论文给出的结果说明它确实能打。SparseEngine 最后支持了 15 种稀疏方法,分属四大类别,覆盖 14 种模型架构,分组查询注意力、多头潜在注意力、混合线性注意力这些技术路线都在其中。
聊天记录也能"续命":Chain Cache
光装得下各种方法还不够。论文提出了一个更贴近现实的场景:多轮对话的智能体,轮与轮之间靠什么接上?
按常理,和 AI 聊过好几轮,系统会动用一种叫前缀缓存的机制,把此前算过的部分拿来直接用,不必每轮从头算起。
前缀缓存指的是:新请求与先前处理过的请求开头一致时,直接复用已算好的结果,只把新增那部分算一遍。
对 Quest、OmniKV 这类"历史完整保留"的稀疏方法,这套机制天然合拍,历史本来就没被删,前缀当然还在。
麻烦出在 H2O、SnapKV 这类真删数据的做法上。上一轮聊完,系统已经把不重要的历史物理删掉了;新一轮对话到来,想复用缓存,却发现缓存里的内容跟"完整历史"对不上号。常规前缀缓存按"逐字匹配"设计,前提是历史完整连续,中间一旦被挖了个洞,匹配逻辑就失灵了。
研究团队为此拿出了 Chain Cache。
Chain Cache 是一种跨请求的缓存复用机制:某个方法即便已经把部分历史的 KV 数据物理删除,系统仍记得这段历史"在逻辑上"存在过的位置信息;新一轮对话进来,可以从保留下来的那部分历史接着算,整个对话不必重算。
关键是把"逻辑前缀"和"物理存储"分开看。逻辑前缀说的是这段对话在文字层面确实发生过,底层数据删没删,改变不了这个事实;物理存储则是实际占着显存的那部分数据。Chain Cache 留着逻辑前缀的匹配信息,哪怕物理上删掉大半,只要新对话仍沿着这个逻辑前缀往下讲,系统就认得出来,只算那些新增的、没算过的部分。
论文举的例子很直观:"The cat sat on the mat. It was warm." 这句话里,SnapKV 可能已经把"sat on"和"the mat"几个词的 KV 数据物理删了,可下一轮对话接上"Then it slept."时,系统依然认得出整段是同一个逻辑序列的延续,只给新来的"Then it slept."算 KV,前面的句子不用推倒重算。
就像在笔记本上记了整场会议纪要,事后发现中间几段废话没用,划掉了。笔记本封面的标题和页码没变,下次开会接着记,翻到正确那页往下写就行,不必从头把整本抄一遍。要是没有"认得逻辑位置"的本事,每次开会都得把划掉的部分补全重抄,页码才能对上,那才叫费工夫。
对依赖持续状态的方法,Chain Cache 尤其要紧:H2O 要一直累积注意力分数,SnapKV 在不同层删掉的词可能还不一样。少了这个机制,每轮新对话都得从零重建这些状态,先前的优化等于全部作废。
**
智能体的对话历史里,其实并非每一段都同等重要。
用户提的问题重要,模型自己的推理过程也重要;但工具调用返回的结果呢?一次搜索返回的网页全文,一次代码执行返回的报错日志,刚出现时也许很关键,可等 AI 把里面的有效信息提炼总结出来,这段原始长文本往往就没什么用了,留着纯粹占地方。
论文给出了一个叫可控前缀缓存裁剪的机制,应用方可以指定"历史里的哪一段区间"能被精简,以及精简到什么程度。
可控前缀缓存裁剪指的是:应用方划出一段历史区间、给出一个保留比例,系统按某种打分策略从这段区间里挑出最重要的部分留下,其余删掉,同时保证这段历史在"逻辑前缀匹配"上依然完整可用。
打分工具之一是 KVzip,它能判断一段历史里哪些词对后续生成真正有用。
论文做了个很实际的实验:在 SWE-bench Lite 这个真实代码修复任务集上,用 mini-SWE-agent 这个编程智能体跑测试。对所有工具调用结果一刀切、只留 20% 内容,任务完成率会掉。换个策略,延迟四轮再裁——新工具结果来了,只裁往前数第五轮的旧结果,最近四轮完整不动——完成率非但没降,反而到了 25.0%,比完全不裁的原始版本 23.7% 还高。
这个结果挺耐琢磨。它说明智能体干活时确实存在"最近的证据比老证据更有价值"的规律,老的工具调用结果往往已经完成使命,继续占显存没意义。整理手机相册也一样:要是规定"所有照片一律只留 20%",没准把昨天拍的重要截图也删了;改成"超过一周没翻看的旧截图可以清,最近几天的先留着",效果反而更好,因为更贴近人用相册的习惯。不做这种"延迟"区分,一刀切很容易误删正被频繁引用的信息,反过来拖累任务表现。
**
设计思路说了这么多,终归得看实际效果。
论文在两块不同的模型上做了测试:一块是 Qwen3-30B-A3B,参数规模 30B、激活参数只有 3B 的混合专家模型;另一块是 GLM-4.7-Flash,采用多头潜在注意力架构。测试场景是 12.8 万 token 的超长上下文输入。
解码吞吐量这个指标,说白了就是模型每秒能吐出多少词。SparseEngine配上SnapKV这类直接把历史数据物理删掉的做法,在两个模型上都跑到普通vLLM的近10倍。道理不复杂:数据一删,显存就空出来了,同一套硬件能扛更多并发请求,总产出自然往上走。而换成Quest、OmniKV这种"只挑不删"的动态稀疏方法,相同并发下吞吐量是普通vLLM的1.5到2.6倍。提升的来源不太一样——每次只算历史里的一小部分,省下的是算力,不是显存。
论文还做了一项公平性检验,专门挑那些和竞品系统设计思路高度对得上的方法来比。Quest恰好对应Vortex和HiSparse的设计初衷,SnapKV恰好对应Tangram的设计初衷。结果是:相同并发数下,SparseEngine跑Quest的吞吐量是Vortex的1.24倍、HiSparse的1.55倍;跑SnapKV则是Tangram的1.55倍。
这个结果挺有意思。SparseEngine支持的方法种类更多,可覆盖面广并没有换来深度上的让步。就算跑到对手最擅长的地盘上单挑,它照样不落下风。
质量上,论文在LongBench这两个长文本理解基准上,把SparseEngine实现的各个方法和原始论文的实现做了对比。横跨20项整体分数,平均差异只有0.17个百分点,方差也很小。这个数字说明,SparseEngine在追速度的同时,并没有明显牺牲原始方法该有的效果。前面提到的架构思路也在这里得到印证:给每个方法留出自由发挥的空间,不等于要把它的能力砍掉。
端到端的智能体任务测试也给出类似信号。在把GLM-4.7-Flash上跑的SWE-bench Lite对话轨迹完整重放的实验里,H2O方法达到2.02倍的端到端加速。另一个专门测系统效率的Gasai智能体轨迹上,SnapKV配合Chain Cache拿到了2.24倍的加速。
Q&A
Q1:SparseEngine是什么?A:这是哈尔滨工业大学团队提出的一套稀疏优先推理引擎,专为长上下文AI智能体打造。它通过生命周期钩子,让不同的KV缓存稀疏方法各自管理自己的数据表示和计算逻辑,同时共用调度、批处理、前缀缓存等基础设施,可支持15种不同的稀疏方法。
Q2:Chain Cache解决了什么问题?A:物理删除历史数据的稀疏方法(比如H2O、SnapKV)在多轮对话里没法复用前缀缓存,Chain Cache针对的就是这个。它让系统记住被删数据原本的逻辑位置,新一轮对话来时直接从保留的历史往下接,只算新增的部分,不必把整段对话从头重算。
Q3:使用SparseEngine会不会降低AI回答的质量?A:论文测试显示影响很小。在LongBench长文本基准上,SparseEngine实现的各个稀疏方法与原始论文实现相比,20项整体分数的平均差异只有0.17个百分点,说明加速并没有明显牺牲原有方法的任务表现。