← 返回列表

阅读 —下载 —

LLM / Agent 推理链路延迟优化

核心问题:如何减少不必要的计算、重复计算以及串行等待,从而降低 Agent 整条推理链路的延迟。

优化主线:减少计算 × 减少等待 × 复用计算。


一、这是一个什么问题?

1.1 Agent 请求不是一次 LLM 调用

生产环境中的 Agent 请求,通常是一条完整的推理链路:

用户请求
   ↓
意图识别 / Router
   ↓
RAG 检索
   ↓
LLM 推理
   ↓
Tool / MCP 调用
   ↓
LLM 再次推理
   ↓
最终回答

尤其是在 Agent 场景中,一次请求可能触发:

  • 多次 LLM 调用;
  • 多次 Tool / MCP 调用;
  • 多轮“推理 → 调工具 → 再推理”的循环。

1.2 用户感受到的是整条链路的累计延迟

总延迟
≈
LLM 推理
+ RAG
+ Tool / MCP
+ Agent 编排
+ 网络通信
+ 排队等待

因此,优化时不能只盯着单次模型调用,而要观察整条链路中:

  • 哪些计算是不必要的;
  • 哪些计算被重复执行了;
  • 哪些步骤本来可以并行,却仍然串行等待。

1.3 优化目标

减少不必要的计算、重复计算以及串行等待,降低 Agent 端到端延迟。


二、从哪些方面解决?

整体可以拆成三个方向:

LLM / Agent 推理链路延迟优化总览

图 1:Agent 推理链路的典型执行路径,以及“减少计算、减少等待、复用计算”三类优化杠杆。

优化方向 核心目标 常见手段 重点关注指标
减少计算 让每一步少算、少调用 规则、小模型、限制 Step、裁剪 Context LLM Calls、Input Tokens、Steps
减少等待 缩短关键路径 Tool 并行、RAG 并行、流式输出 Critical Path、TTFT、P95
复用计算 相同结果不要重算 Tool Cache、RAG Cache、Prefix / KV Cache Cache Hit Rate、Prefill Time

2.1 减少计算量

核心思想:

调用次数 × 输入 Token 数。

能少计算,就不要让模型计算。

2.1.1 减少 LLM 调用和 Agent Step

例如,原本需要经过多次 LLM 调用:

Router LLM
   ↓
Query Rewrite LLM
   ↓
Reranker LLM
	 ↓
Agent LLM
   ↓
Tool
   ↓
Agent LLM

如果能通过规则、小模型或者一次规划解决,就可以减少不必要的 LLM 调用。

同时要控制 Agent 的:

  • 推理 Step;
  • Tool Call 次数;
  • 无意义循环;
  • 重复推理。

因为每增加一次:

LLM → Tool → LLM

都会增加额外延迟。

2.1.2 减少输入 Token

LLM 每次推理都需要处理输入 Context,因此 Prompt 越长,Prefill 的计算量通常越大。

生产环境常见的 Context 裁剪方式:

Tool Schema
    ↓
只保留相关 Tool

Conversation
    ↓
摘要 / 截断

RAG
    ↓
控制 TopK + 去重TopN

Prompt
    ↓
精简固定指令

本质上就是:

让模型每次少读一些东西。

2.2 减少等待时间

有些延迟并不是“计算慢”,而是因为系统在串行等待。

2.2.1 Tool 并行

串行执行:

Tool A
 ↓
Tool B
 ↓
Tool C

如果三个 Tool 互相没有依赖关系,就可以改成并行:

        ┌→ Tool A ─┐
Agent ──┼→ Tool B ─┼→ 汇总
        └→ Tool C ─┘

目标是缩短关键路径,而不是简单把多个节点放进同一个执行阶段。

2.2.2 RAG 并行

同样,在 RAG 中:

Vector Search
Keyword Search

如果没有依赖关系,也可以并行执行。

2.2.3 适用判断

适合并行的任务通常满足:

  • 输入相互独立;
  • 执行过程不依赖其他任务的结果;
  • 最终只在下游统一汇总。

因此,生产系统经常会把:

没有依赖关系的任务从串行改成并行。

这类优化对 Agent 特别重要,因为 Agent 本身就是一个由多个步骤组成的执行链。

2.3 复用已经计算过的结果

核心思想:

相同的东西不要重复计算。

最常见的是缓存。整体可以沿这条链路理解:

Prefill → KV Cache → Prefix Cache → Decode

其中,“提高缓存命中率”主要是在提高 Prefix Cache / KV Cache 的复用率,从而减少重复 Prefill 计算。

2.3.1 Prefill 与 Decode 是大模型生成的两个阶段

Prefill、Decode 与 Prefix Cache 原理

图 2:Prefill 生成并写入 K/V,Decode 逐 Token 生成;Prefix Cache 跨请求复用相同前缀的 K/V,减少重复 Prefill。

用一个具体例子理解。

假设用户问:

北京今天的天气怎么样?

模型最终回答:

北京今天晴,最高温度……

虽然用户只问了一句话,但实际送给模型的 Prompt 还包含 System Prompt、Tool Schema 和用户问题:

System Prompt:
你是一个天气助手,请简洁回答。

Tool:
weather(city)

User:
北京今天的天气怎么样?

假设整个 Prompt 经过 Tokenizer 后一共有 100 个 Token。

2.3.2 Prefill:一次性处理输入

Prefill 会把整个输入 Prompt 一次性送进 Transformer:

100 Tokens
    ↓
Embedding
    ↓
Transformer Layer 1
    ↓
Transformer Layer 2
    ↓
...
Transformer Layer N
    ↓
得到每个 Token 对应的 K / V

可以简单理解为:

Token 1 ─┐
Token 2 ─┤
Token 3 ─┤
...      ├──→ Transformer ──→ KV Cache
Token 99 ┤
Token 100┘

最终得到:

KV Cache:

Token 1   → K1   V1
Token 2   → K2   V2
Token 3   → K3   V3
...
Token 100 → K100 V100

同时,模型根据最后位置的信息预测第一个输出 Token:

下一个 Token = “北”

因此:

Prefill 的核心是一次性处理整个输入 Prompt,并建立 KV Cache。

2.3.3 Decode:逐 Token 生成

现在模型已经处理完 100 个输入 Token,并得到对应的 KV Cache:

K1  V1
K2  V2
...
K100 V100

接下来进入 Decode。模型生成第一个 Token:

“北”

此时不需要重新计算前面的 100 个 Token,只需要处理新 Token:

“北”
 ↓
Transformer
 ↓
K101 V101
 ↓
结合之前的 KV Cache
 ↓
预测下一个 Token

KV Cache 继续增长:

K1   V1
K2   V2
...
K100 V100
K101 V101

然后依次生成:

北 → 京 → 今 → 天 → 晴 → ...

每一步 Decode 都只计算新 Token,并复用之前所有 Token 的 KV Cache。

2.3.4 Prefill 与 Decode 的差异

阶段 处理方式 输入规模 主要特征 常见瓶颈
Prefill 一次性处理整个 Prompt 通常很大 可并行计算 Compute-bound
Decode 每次生成一个 Token 单步很小 存在串行依赖 Memory-bound

Decode 必须知道前一个 Token,才能继续生成下一个 Token:

第 1 次 Decode → 北
第 2 次 Decode → 京
第 3 次 Decode → 今
第 4 次 Decode → 天
第 5 次 Decode → 晴

所以:

Decode 的计算量相对较小,但每一步都需要访问 KV Cache,并且存在逐 Token 的串行依赖。

2.3.5 KV Cache 是什么?

Transformer 每一层都会产生:

  • K(Key);
  • V(Value)。

在生成过程中,后面的 Token 会不断使用之前 Token 的 K/V。

例如,模型第一次处理:

A B C D E

会产生:

K/V(A)
K/V(B)
K/V(C)
K/V(D)
K/V(E)

后面生成 F 时,不需要重新计算 A ~ E 的 K/V。

这就是 KV Cache。

KV Cache 解决的问题是:同一次生成过程内,历史 Token 的 K/V 不要重复计算。

2.3.6 Prefix Cache 优化哪里?

假设 Agent 每次请求前面都有一大段完全一样的内容:

System Prompt
Agent Instructions
Tool Definitions
MCP Tools
业务规则

只有最后的用户问题不同。

第一次请求:

10,000 Token
    ↓
完整 Prefill
    ↓
计算 K/V
    ↓
写入 Prefix Cache

第二次请求:

相同的 10,000 Token
       ↓
命中 Prefix Cache
       ↓
直接复用之前的 K/V
       ↓
不再重复 Prefill 这 10,000 Token

所以,有缓存和没有缓存的路径可以对比为:

没有 Prefix Cache:

10,000 Token
     ↓
完整 Prefill
     ↓
Decode

有 Prefix Cache:

10,000 Token
     ↓
直接复用 Prefix KV
     ↓
只处理新增 Token
     ↓
Decode

Prefix Cache 主要减少的是重复的 Prefill 计算,从而降低 TTFT(Time To First Token)和推理成本。

2.3.7 为什么要固定 Prefix?

假设 Prompt 原来的组织方式不断变化:

System
用户信息
Tool
History
当前问题

那么不同请求可能是:

请求 A:
System + 用户信息A + Tool + ...

请求 B:
System + 用户信息B + Tool + ...

动态内容插在前面,会导致 Prefix 很快发生变化,缓存难以命中。

更合理的组织方式是:

System Prompt
固定 Rules
固定 Tool Schema
固定 MCP Schema
----------------
动态 History
动态 Context
用户 Query

原则是:

稳定、重复的内容放前面;动态变化的内容放后面。

这样不同请求之间可以拥有更长的共同 Prefix:

请求 A
████████████████████░░░░░

请求 B
████████████████████░░░░░

请求 C
████████████████████░░░░░
        ↑
    相同 Prefix

共同 Prefix 越长,Prefix Cache 命中概率越高。

2.3.8 KV Cache 与 Prefix Cache 的区别

KV Cache:

KV Cache
    ↓
保存已经计算过的 Token K/V
    ↓
主要用于同一次生成过程

Prefix Cache:

Prefix Cache
    ↓
发现不同请求存在相同 Prefix
    ↓
复用这个 Prefix 对应的 KV Cache

因此:

Prefix Cache 是 KV Cache 的一种跨请求复用机制。

面试或总结时可以说:

Prefix Cache 主要优化 Prefill,不是优化 Decode 本身。Decode 仍然需要逐 Token 生成,只是它可以直接利用已经缓存的 Prefix KV,因此整体请求延迟下降。

2.3.9 本节结论

Prefill 是一次性把 Prompt 处理完并建立 KV Cache;Decode 是基于已有 KV Cache,一个 Token 一个 Token 地生成;Prefix Cache 则是在不同请求之间复用相同 Prefix 已经计算好的 KV,从而避免重复 Prefill。


三、结合一个企业 Agent 场景

假设我们有一个企业智能助手,用户问:

帮我查询一下张三最近一个月的订单情况,并分析一下有没有异常。

3.1 原始执行链路

用户请求
   ↓
意图识别 LLM
   ↓
Query 改写 LLM
   ↓
Agent LLM
   ↓
查询用户 Tool
   ↓
查询订单 Tool
   ↓
Agent LLM
   ↓
异常分析
   ↓
最终回答

这条链路主要存在四个问题。

3.2 问题与优化

问题 1:LLM 调用太多

可以把简单的意图识别交给 Router / 小模型,减少一次大模型调用。

问题 2:Tool 串行

如果“用户信息”和“订单信息”没有依赖关系:

用户信息 Tool ──┐
                ├→ 汇总 → Agent
订单信息 Tool ──┘

就可以直接并行执行。

问题 3:Tool 太多

如果 MCP Server 有 100 个 Tool,不应该全部放进 Agent Context。

可以先做语义路由:

用户问题
   ↓
Semantic Tool Routing
   ↓
筛选相关 Tool
   ↓
Agent

只把真正需要的 Tool Schema 放进去。

问题 4:Prompt 重复

Agent 每次都有大量固定内容:

System Prompt
Agent Rules
Tool Schema
MCP Metadata

可以让这些内容保持稳定并形成 Prefix:

固定 Prefix
      ↓
Prefix Cache
      ↓
复用 KV Cache

用户问题 / 实时订单数据
      ↓
动态部分

3.3 优化后的链路

                 用户请求
                    ↓
             Rule / 小模型 Router
                    ↓
              Tool Semantic Routing
                    ↓
        ┌───────────┴───────────┐
        ↓                       ↓
   用户信息 Tool             订单 Tool
        └───────────┬───────────┘
                    ↓
              Agent LLM
          ↑
     Prefix / KV Cache
          ↑
  System / Rules / Tool Schema
                    ↓
                最终回答

3.4 全文总结

减少计算
  → 少调用 LLM、少 Token、少 Agent Step

减少等待
  → RAG / Tool 并行

复用计算
  → Tool Cache、RAG Cache、Prefix / KV Cache

这三个方向基本就是理解生产级 Agent 推理延迟优化的主线。