Agent 跑得慢,可能不是模型的问题:一篇论文挖出了 Tokenization 这个隐藏瓶颈
一个常见场景:Coding agent 调一个工具,返回一小段结果,然后它把整段对话历史——可能已经几万 token 了——重新提交一遍。盯着屏幕等第一个 token 吐出来,总觉得哪里不对劲。
不是错觉。最近一篇 arXiv 论文直接点明了这个问题。Zhenyu Zhang 和 Zhichao Cao 提交的 TokTier,标题叫「Exact Stateful Tokenization for Agentic LLM Serving」,核心意思很直接:现在大部分 LLM serving 的前端,每次请求都在重新做一遍完整分词,这对 Agent 负载来说越来越不能忍。
论文给出了一个数据:他们分析了两个 Agent 生态的 153,951 次调用,中位数每次调用只追加大约 1.4K 个字符。但就是这点追加,让整个对话上下文被重新 tokenize 一遍。只有 1.0%-3.6% 的调用是真正从头开始的——绝大多数都是长上下文加一个小尾巴。在 prompt 缓存命中率已经高达 94.1% 的 fleet 里,tokenization 居然占了首 token 延迟的 64%——缓存命中了,但卡在分词上。
TokTier 的方案不算复杂,但踩的点很准。它做了一件事:记住上一次分词的状态,增量修复。对于续写请求,它只重新 tokenize 追加位置附近的一个小窗口,然后做一个稳定边界检查,确认拼接后的 token ID 跟全文重 tokenize 完全一致。如果检查不通过,就扩大窗口或者 fallback 到完整 re-tokenize。对于不能复用前缀的请求,它在 GPU 上跑完整的分词(regex pre-tokenization + BPE),而不是交给 CPU 慢慢算。
结果很硬。增量修复模式下,100K 到 3M 字符的上下文,每次只花 0.5-1.1 ms,比 HuggingFace tokenizers 快 437 倍,比目前最强的缓存方案 Gigatoken(完全预热后)还快 2.1 倍。GPU 完整分词模式,1M 字符的请求编码只需 0.87 ms,比 HF 快 491 倍,比已发表的最快 CPU 方法快 23.4 倍。
放到实际 serving 里看效果:集成到 vLLM 后,中位首 token 延迟下降了 16%-34%,P99 下降了 23%。在 50 ms P99 的目标下,4 个修复核加 1 块 GPU 能撑住 1,821 请求/秒,而 16 核的无状态前端 40 请求/秒就饱和了——差了 45 倍。
论文也做了大量验证:覆盖 17 个 tokenizer 家族、1.5×10¹⁰ 次分割检查、12.4 TB 真实文本语料、93,000+ 回放的 Agent 步骤,零偏差。他们还用了一个采样影子验证器在线检查流量,防止增量逻辑悄悄出错。
对跑 Agent 的人来说,这个结果的意思是:以 coding agent、research agent 这类需要反复提交长上下文的负载为例,瓶颈可能不在模型推理,甚至不在 KV cache 命中率,而在连缓存都没考虑的前端分词上。这不是什么 fancy 的模型架构改进,但对 serving 成本的感受是最直接的——少等、少算、少浪费 GPU 在等待 tokenization 上。
TokTier 目前还是一篇论文,没有看到开源发布。但这个方向已经足够清楚了:Agent 的 serving 栈,不能再拿传统的无状态 serving 硬套了。从 KV cache、调度到 tokenization,每一层都在重新适配 Agent 的交互模式。自己搭 Agent serving 的话,现在就可以检查一下——前端是不是每次都在全文重 tokenize?如果是,那可能已经踩到这个坑里了,只是还没意识到它叫啥。