多智能体调用外部工具时,GPU KV Cache 常常像合租房的冰箱:等外卖的同伴把半个冰箱占满,急着开火的人反而塞不进去,速度被拖垮。北航、北大、阿里的 Tokencake 给出了一套“先搬走闲人行李、再给关键房客留格子”的玩法,在典型基准下把延迟干到了 vLLM 的 53% 左右,还把 GPU 内存利用率抬高了 16.9%。

Tokencake 论文配图封面与核心结论

原理速写(5 分钟看懂 Tokencake)

  1. 先把业务画成图:Tokencake 的前端 API 把多智能体逻辑拆成有向图(节点是智能体或工具,边是消息流),调度器据此感知谁关键、谁可等。

前端 API 将 RAG/多智能体流程转成可优化的图

  1. 时间调度器:等外部调用时先“腾冰箱”:遇到长时间函数/工具调用,先把该智能体的 KV Cache 卸到 CPU,估算返回时间后再预测性地搬回 GPU,只有预期收益大于传输成本才执行。

时间调度器决定何时卸载/回迁 KV Cache 时间调度与空间调度的协作关系

  1. 空间调度器:GPU 分两块:一块共享池给所有智能体,另一块预留池只给优先级高的(优先级来自“历史用量 + 业务重要度”的混合评分,动态重算)。

GPU KV Cache 的共享池与预留池动态分区

  1. 两项减摩擦小技巧:CPU 侧做块缓冲(不立刻还给 OS,后续卸载直接复用,延迟从接近秒级稳到亚毫秒),GPU 侧渐进预留(提前几个调度周期拆小单预留内存,避免一次性卡住)。

CPU 块缓冲与渐进预留降低分配抖动

  1. 效果数据:在 Code-Writer、Deep-Research 等多智能体基准(请求来自 ShareGPT、AgentCode,泊松流量)下,1 QPS 高负载时端到端延迟比 vLLM 至少低 47%,GPU KV Cache 利用率最高多出 16.9%。

实验场景与请求生成流程 高负载下延迟曲线更平滑,Tokencake 领先 vLLM GPU KV Cache 利用率曲线 更多对比图:Tokencake(SunCake)在多负载下的优势

实战步骤(照着做就能跑)

  • Step 1:把业务画成节点图
    先列出智能体/工具节点、消息通路、预期最长外部调用时长,把“谁不能被挤掉”写清楚。图越清晰,后面预留池越好配。

  • Step 2:在推理循环里接入“等外部调用就卸载”逻辑
    下面是一个极简模拟(Python 3.10+,纯标准库),演示如何在外部调用超过阈值时把 KV Cache 先搬去 CPU,返回前再搬回:

# tokencake_demo.py
import asyncio, random, time

GPU_BUDGET = 2  # 模拟 GPU 只够放两个 KV Cache
kv_pool = {}

async def external_call(agent: str) -> None:
    await asyncio.sleep(random.uniform(0.8, 1.5))

def offload(agent: str):
    kv_pool.pop(agent, None)
    print(f"[{time.time():.2f}] offload {agent} -> CPU")

def load(agent: str):
    if len(kv_pool) >= GPU_BUDGET:
        victim = next(iter(kv_pool))
        offload(victim)
    kv_pool[agent] = "on-gpu"
    print(f"[{time.time():.2f}] load {agent} -> GPU")

async def run_agent(agent: str):
    load(agent)
    print(f"[{time.time():.2f}] {agent} start tool call")
    offload(agent)           # 工具调用期间先挪走
    await external_call(agent)
    load(agent)              # 预测调用结束前搬回
    print(f"[{time.time():.2f}] {agent} resume decode")

async def main():
    await asyncio.gather(*(run_agent(f\"agent-{i}\") for i in range(3)))

asyncio.run(main())

期望输出示例(可直接运行 python3 tokencake_demo.py):

[... ] load agent-0 -> GPU
[... ] agent-0 start tool call
[... ] offload agent-0 -> CPU
[... ] load agent-1 -> GPU
[... ] ...
  • Step 3:给关键智能体配预留池比例
    如果某个规划/审核类智能体对全局质量最关键,就给它预留固定比例 GPU 块,其余走共享池。用“历史最大 KV 占用 + 业务权重”算出 0~1 的混合分数,再按分数分配配额。

  • Step 4:压测观测点
    关注三件事:外部调用的真实耗时分布(预测模型需要它),GPU/CPU KV 占用曲线是否抖动(如果抖,调高预留池或放宽渐进预留步长),以及是否出现“搬来搬去反而更慢”(传输成本大于收益时要禁止卸载)。

常见坑与对策

  • 预测偏差:外部调用抖动大时先用保守阈值(只卸载超过 P95 耗时的调用),否则会频繁搬运。
  • CPU 内存被吃爆:做块缓冲时加上上限,超过就直接丢回 OS,避免长尾请求把内存顶满。
  • GPU 分区震荡:total_reserve_ratio 不要随使用率频繁跳动,可设“高/低水位 + 缓慢调节因子”。
  • 批量分配卡顿:渐进预留的步长太大也会堵;改成多周期、小份额预留。
  • 指标只看吞吐忽略延迟:多智能体场景延迟更关键,监控里分开记录“外部调用等待”“回迁时间”“解码时间”。

总结与下一步

  • Tokencake 用“时间卸载 + 空间预留”两板斧解决多智能体的 KV Cache 争抢问题,让外部调用期间的闲置缓存不再浪费 GPU。
  • CPU 块缓冲 + 渐进预留把内存分配的抖动压到亚毫秒级,是它比常规实现更平滑的关键。
  • 实测在高负载(1 QPS)下,端到端延迟比 vLLM 至少低 47%,GPU 利用率最高多出 16.9%。

下一步可做:

  1. 把你现有的多智能体流程画成节点图,标出最长外部调用节点并设卸载阈值。
  2. 给最关键的 1~2 个智能体设预留池比例,观察延迟曲线是否变平。
  3. 参考原论文(https://arxiv.org/pdf/2510.18586)进一步把预测模型和阈值调优到业务场景。