长程 agent 把显存撑爆以后:哈工大 SparseEngine 为什么要从零重建推理引擎
哈工大开源 SparseEngine:长程 agent 的 KV cache 撑爆后,用稀疏优先推理引擎与 Chain Cache 接上被驱逐的记忆。
一个 AI agent 连续工作一个小时,它的"记忆"放在哪里?
很多人会说,放在上下文里。
这个回答没错,但是只说了一半。
上下文是文字,真正占用显卡内存的,是模型为这些文字算出来的一份中间结果,叫做 KV cache。
对话短的时候,它不起眼。
对话一长,它就会把显存撑爆。
最近,哈尔滨工业大学的团队开源了一个推理引擎 SparseEngine,论文编号 arXiv:2609.39068。
它要解决的,正是这个问题:长程 agent 的 KV cache 装不下时,怎么办。
它的答案是稀疏注意力。
但是,稀疏注意力并不是新东西,学界已经提出了很多种算法。
为什么还要专门做一个新引擎,而不是把这些算法装进现成的 vLLM 一类引擎?
今天就用大白话,把这件事讲清楚。
一、KV cache 是什么
先说一般原理。(这一节是大模型推理的通用知识,不是 SparseEngine 的发布内容。)
大模型生成文字,是一个 token 一个 token 往外蹦的。
每生成一个新 token,模型都要回头看一遍前面所有的 token,决定"现在该说什么"。
这个"回头看"的动作,就是注意力(attention)。
问题来了:如果每一步都把前面所有内容从头算一遍,计算量会非常大。
所以,推理引擎会把前面每个 token 算好的两份中间结果----Key 和 Value----存起来,下一步直接拿来用。
这份存下来的东西,就叫 KV cache。
打个比方。
KV cache 就像做数学题时的草稿纸。
前面算过的步骤写在纸上,后面要用时扫一眼就行,不用重算。
但是草稿纸有一个特点:题目越长,用掉的纸越多。
KV cache 的大小,大致和上下文长度成正比。
普通聊天,几轮就结束,草稿纸够用。
长程 agent 就不一样了。
二、长程 agent 的麻烦
所谓长程 agent,就是那种要跑几十轮、上百轮才能完成任务的智能体。
比如,SparseEngine 面向的场景里,提到了 BrowseComp 和 Terminal-Bench 这类长交互任务。
前者需要在网上反复搜索、翻页,才能找到一个难找的答案;后者需要在命令行里一步步操作,完成一个工程任务。(对这两个基准的描述是一般性介绍。)
我们设想一个场景(这是假设,用来说明问题):一个 agent 在做网页检索任务,每一轮都要把搜索结果、网页正文、自己的思考过程放进上下文。
第 1 轮,上下文几千个 token。
第 30 轮,可能已经十几万个 token。
每多一轮,草稿纸就厚一层。
而显卡内存是固定的,不会跟着变大。
总有一刻,KV cache 放不下了。
这时,引擎只有几个选择:拒绝新请求、减少同时服务的请求数,或者把一部分 KV 扔掉。
扔掉的动作,英文叫 eviction(驱逐)。
驱逐听起来很简单,但是扔掉哪些、扔掉以后怎么办,都是问题。
三、稀疏注意力:只看重要的那几页
稀疏注意力的思路,来自一个朴素的观察。(这一节同样是一般原理。)
模型回头看前文的时候,并不是每个 token 都同样重要。
一篇几万字的网页里,和当前问题真正相关的,可能只有几段。
既然如此,能不能只看重要的部分,忽略其他部分?
这就是稀疏注意力:不再对所有旧 token 一视同仁,而是挑出一部分来算,或者干脆把不重要的 KV 清理出去。
打个比方,普通注意力像是每做一步,都把整本草稿纸从头翻一遍;稀疏注意力像是只翻那几页做了标记的。
这样做,省显存,也省计算。
学界围绕这个思路,提出了各种各样的方法。
SparseEngine 支持其中 4 个族、共 15 种稀疏注意力算法。(具体是哪 15 种、怎么分族,请看论文和项目仓库,本文不逐一列举。)
既然算法有这么多,为什么在实际的服务系统里不常见?
四、为什么进不了 vLLM 一类的引擎
要回答这个问题,得先说说 vLLM 这类引擎是怎么管理 KV cache 的。(以下是一般原理。)
现在主流的开源推理引擎,大多借鉴了操作系统的内存分页思想。
KV cache 被切成固定大小的块,叫做"页"。
每个请求需要多少,就分配多少页,用一张表记下"第几个 token 的 KV 在哪一页"。
这个设计很成功,它解决了显存碎片的问题,让一张显卡能同时服务更多请求。
但是,它有一个隐含的前提:每个 token 的 KV 都老老实实存在页里,注意力计算时,按顺序把这些页全部读一遍。
这就是"dense(稠密)"的意思。
整套系统----内存分配、调度、批处理、缓存复用----都是围绕这个前提设计的。
稀疏注意力恰恰要打破这个前提。
它要求引擎能做这些事:挑出一部分 token 来算,扔掉另一部分;扔掉以后,页表里留下空洞;不同的算法,挑选和丢弃的规则还各不相同。
在一个以"全部存、全部读"为中心的系统里,做这些事,就像在一栋按整层出租设计的写字楼里,突然要按工位出租。
不是做不到,但是水电、门禁、物业管理都要跟着改,每加一种出租方式,就要再打一轮补丁。(这里冲突点的归纳和比喻是我的推断,论文的具体分析请看原文。)
这大概就是很多稀疏注意力算法停留在论文和实验代码里,很难进入生产服务的原因。(这是我的推断。)
SparseEngine 的做法是:不在稠密引擎上打补丁,而是从零开始,按"稀疏优先"重新设计服务层。
也就是说,从一开始就假设 KV 会被挑选、会被驱逐,再在这个假设上搭内存管理和调度。
五、Chain Cache:扔掉的东西,下一轮还要用
稀疏优先的引擎,会主动驱逐 KV。
但是 agent 的工作是多轮的。
这一轮扔掉的内容,下一轮可能又需要了。
举个例子(假设场景):agent 在第 5 轮读过一份文档,第 12 轮时这份文档的 KV 已经被驱逐,到了第 20 轮,它又需要引用文档里的一段话。
这时候怎么办?
最笨的办法,是把前面所有内容重新算一遍,相当于草稿纸丢了,整道题重做。
对长程 agent 来说,这个代价很大,因为前文可能已经有十几万个 token。(这是按一般原理的推断。)
SparseEngine 用一个叫 Chain Cache 的机制处理这个问题:在 KV 被驱逐以后,跨多轮把它恢复回来。
它具体怎样记录和恢复,公开报道没有展开,有兴趣的话可以读论文。
但是它解决的问题很清楚:驱逐不再是"一次性的永久丢失",多轮对话之间可以接上。
六、Controllable Prefix-Cache Pruning:删旧历史,又不想丢前缀
第二个机制,名字比较长,叫 Controllable Prefix-Cache Pruning,直译是"可控的前缀缓存修剪"。
要理解它,先说 prefix cache(前缀缓存)。(以下是一般原理。)
很多请求的开头是一样的:同样的系统提示、同样的工具说明、同样的前几轮对话。
既然开头一样,就没必要每次都重新算,算一次,存起来,后面的请求直接复用。
这就是前缀缓存。
agent 特别依赖它,因为每一轮请求,都带着前面所有轮的历史,前缀高度重合。
但是前缀缓存有一个脾气:它是从头开始逐个 token 比对的。
只要中间有一处不一样,从那里往后的缓存全部作废。
现在矛盾来了。
长程 agent 上下文太长,自然想删掉一些旧历史,腾出空间。
可是,如果从对话中间删掉一段,新请求的 token 序列就和缓存里的不一致了。
结果是:显存省下来了,前缀缓存却失效了,后面的内容得重算。(这一段对冲突的描述,是按一般原理的推断。)
Controllable Prefix-Cache Pruning 要解决的,就是这个两难:在删除旧历史的同时,保住前缀匹配。
至于名字里的"可控",我的理解是,删什么、怎么删,可以按需要控制,而不是一刀切。(这是我根据名字的推测,请以论文为准。)
把两个机制放在一起看,思路是一致的。
Chain Cache 管的是"扔掉以后还能找回来"。
Prefix-Cache Pruning 管的是"删掉一部分,不连累其他部分"。
两者都是为了让"驱逐"和"多轮复用"这两件事,在长程 agent 里不再互相打架。
七、效果怎么样
下面这些数字,都是论文称的结果。
(1)在发生 KV 驱逐的情况下,吞吐量提升超过 10 倍。
(2)同样的并发数下,解码速度比 vLLM 快超过 2.5 倍。
(3)端到端的任务执行,快了超过 2 倍,并且推理准确度没有下降。
这些数字看上去很亮眼,但是读的时候要注意几点。
第一,它们都是论文作者自己的测量,目前我没有看到第三方的独立复现。
第二,每个数字都有前提条件。比如"超过 10 倍"是在 KV 驱逐场景下,"超过 2.5 倍"是在同等并发、只看解码阶段。具体用了什么模型、什么硬件、和哪个版本的 vLLM 对比,要看论文原文。
第三,"准确度不降"也是论文的说法,适用于论文测试的任务和设置,换一个场景未必一样。(这三点提醒是我的看法。)
做一个简单的换算,帮助理解端到端 2 倍是什么意思。(以下是我自己算的,场景是假设的。)
假设一个长程任务原来要跑 60 分钟,端到端快 2 倍,就是 30 分钟左右。
如果一个团队每天要跑 100 个这样的任务,那就是从 100 个小时,降到大约 50 个小时的机器时间。
当然,前提是你的任务和论文的测试条件相近。
八、对普通开发者意味着什么
我觉得,这个项目最值得注意的,不是某一个具体数字,而是它提出的问题。(这一节是我的观点。)
过去两年,推理引擎的主要优化目标,是"短对话、大批量":一个问题,一段回答,尽量同时服务更多人。
agent 的工作方式不一样。
它一次任务要跑很多轮,上下文越积越长,KV cache 成了最先撑不住的地方。
当负载的形状变了,原来围绕稠密注意力设计的系统,就未必是最合适的。
SparseEngine 的选择是:与其在旧房子上不断加盖,不如按新的用途重新盖一栋。
这条路对不对,还需要时间和更多人的使用来检验。
但是它是开源的,代码在 GitHub 上,论文在 arXiv 上,任何人都可以去读、去跑、去验证。
如果你在自己部署模型跑 agent,经常遇到显存不够、上下文被截断的问题,可以关注一下这个项目。
需要提醒的是,它来自学术团队,在生产环境里的稳定性、对各种模型和硬件的支持程度,目前公开信息不多,上线之前最好自己测一测。(这是我的推断和建议。)
总结
用一句话概括。
长程 agent 会把 KV cache 撑爆,稀疏注意力是解法之一,但它很难塞进以稠密分页内存为中心的现有引擎,所以哈工大的 SparseEngine 选择从零开始,按稀疏优先重建服务层,并用 Chain Cache 和可控的前缀缓存修剪,处理"驱逐以后怎么接上"的问题。
论文称效果显著,但这些数字值得你亲自验证。
(完)
来源:arXiv:2609.39068;GitHub CURRENTF/SparseEngine;aicoder.com 报道(2026-10-10)。性能数字均为论文自述;换算与机制理解处为作者推断,正文已标明。