跳到主要内容

推理服务架构

本文用于整理大模型推理服务的整体工程架构。

推理服务的目标不是“把模型进程启动起来”,而是把模型变成一个稳定、可观测、可扩展、可治理的在线 API。

一个生产级 LLM 推理服务通常包含:

  • API Gateway。
  • 鉴权和限流。
  • OpenAI-compatible API。
  • prompt rendering。
  • tokenizer。
  • scheduler。
  • model worker。
  • GPU executor。
  • streaming response。
  • 多模型路由。
  • 多副本和负载均衡。
  • 日志、指标、审计和容量控制。

用一句话概括:

推理服务架构 = API 层 + 请求编排 + 调度层 + 模型执行层 + 观测治理层。

1. 整体请求链路

一个典型 Chat Completions 请求大致会经过下面这条链路:

Client
-> API Gateway
-> 鉴权 / 配额 / 限流
-> OpenAI-compatible API Handler
-> 请求校验和参数归一化
-> messages / tools / multimodal content 解析
-> chat template 渲染
-> tokenizer
-> scheduler 排队和组 batch
-> model worker
-> GPU executor
-> decode / sampling
-> streaming response / non-stream response
-> usage 统计 / 日志 / 指标 / 审计

这里最容易被低估的是中间几层。

HTTP 服务能接请求,不代表模型能稳定生成;模型能单请求生成,也不代表高并发下能控制 TTFT、ITL、p99、显存和成本。

2. 分层架构

生产系统里可以把推理服务拆成四层:

层级主要职责常见组件
接入层接收请求、鉴权、限流、协议转换API Gateway、Ingress、LB、Auth Service
API 层兼容接口、参数校验、prompt 渲染、token 统计OpenAI-compatible server、chat template、tokenizer
调度层排队、batch、路由、抢占、资源预算scheduler、router、queue、admission control
执行层加载模型、执行 prefill/decode、管理 KV Cachemodel worker、GPU executor、CUDA kernel、KV Cache manager

分层的意义是把职责拆开:

  • 接入层关注安全、租户、流量和协议。
  • API 层关注用户请求如何变成模型输入。
  • 调度层关注 GPU 资源如何被高效使用。
  • 执行层关注模型计算本身。

如果这些职责混在一个进程里,早期调试会简单,但生产阶段会很难定位问题。例如一次超时可能来自网关、排队、长 prompt、GPU OOM、KV Cache 紧张、流式连接断开或下游客户端取消。

3. API Gateway

API Gateway 是推理服务的第一道边界。

它通常负责:

  • TLS 终止。
  • 请求体大小限制。
  • 路由到不同服务或模型集群。
  • 租户、项目、用户维度的鉴权。
  • 粗粒度 QPS 限流。
  • 超时控制。
  • 黑白名单。
  • 请求 ID 注入。
  • 访问日志。

推理服务的网关不能只照搬普通 Web API 的策略。

LLM 请求的成本差异很大:一个 200 token 的问答和一个 100k token 的长文档总结,对 GPU、KV Cache、TTFT 和队列的压力完全不同。

所以接入层至少要能识别:

  • 请求路径,例如 /v1/chat/completions/v1/completions/v1/embeddings
  • 模型名。
  • 租户或 API key。
  • 请求体大小。
  • 是否 stream。
  • 估算 input token。
  • max_tokensmax_completion_tokens

网关适合做粗粒度保护,细粒度 token 预算和显存预算通常要交给 API 层或调度层。

4. 鉴权、配额和限流

LLM 限流不能只按请求数。

更合理的限流维度包括:

维度说明
requests per minute控制请求数量,适合防刷和基础配额
input tokens per minute控制 prefill 压力和 tokenizer 成本
output tokens per minute控制 decode 压力和账单风险
concurrent requests控制同时在跑的请求数
concurrent tokens控制当前系统里保留的上下文和 KV Cache 压力
max context length防止超长 prompt 拖垮队列
max output length防止长输出占住 decode batch

常见做法是分两段控制:

  1. 接入层先按 API key、租户和路径做粗限流。
  2. 调度层再按 token、KV Cache、队列长度和 GPU 状态做准入控制。

示例:

如果 input_tokens + max_output_tokens 超过租户预算:
直接拒绝或降级

如果当前 worker 的 KV Cache 使用率过高:
暂缓调度新长上下文请求

如果短请求队列被长请求阻塞:
分离队列或使用优先级调度

不要把所有限流都放在业务服务里。业务服务通常不知道模型 worker 的真实显存、batch 状态和 KV Cache 使用情况。

5. OpenAI-compatible API

很多推理框架会提供 OpenAI-compatible API,例如:

  • /v1/chat/completions
  • /v1/completions
  • /v1/embeddings
  • /v1/models

兼容 OpenAI API 的好处是生态接入简单:

  • SDK 可以复用。
  • LangChain、LlamaIndex、OpenAI SDK 等工具更容易接入。
  • 业务侧切换模型服务的成本更低。
  • 压测工具和网关规则更容易统一。

但“兼容”不等于“行为完全一致”。

需要重点确认:

  • messages 中多模态内容是否支持。
  • tools / tool_choice 是否支持。
  • response_format 是否支持。
  • stream_options.include_usage 是否支持。
  • logprobs 是否支持。
  • seed 是否可复现。
  • stop 的行为是否和预期一致。
  • 错误码和错误结构是否稳定。
  • usage 中 token 统计是否可信。

生产系统里最好把兼容性差异写进模型能力配置,而不是让业务代码靠试错判断。

6. 请求校验和参数归一化

API 层收到请求后,不能直接把原始 JSON 传给模型。

它需要先做校验和归一化:

  • 模型名是否存在。
  • 请求格式是否符合接口约定。
  • messages 是否为空。
  • role 顺序是否合法。
  • temperaturetop_ptop_k 是否在允许范围内。
  • max_tokens 是否超过服务上限。
  • stream 是否支持。
  • 工具定义大小是否超过限制。
  • 图片、音频等多模态输入是否符合模型能力。
  • stop 序列数量和长度是否受控。

归一化的目标是把不同客户端的输入变成内部统一结构。

例如:

外部请求
-> 校验
-> 默认值填充
-> 参数范围裁剪
-> 能力检查
-> 内部 GenerateRequest

这一步也适合生成 request id、trace id、租户 id、模型版本等上下文字段,后续日志和指标都应该带上这些信息。

7. Prompt Rendering

Chat API 传入的是结构化消息,但模型真正看到的是 token 序列。

中间需要经过 prompt rendering:

messages + tools + system prompt
-> chat template
-> prompt text
-> tokenizer
-> input ids

prompt rendering 要关注:

  • chat template 是否和模型训练格式一致。
  • system / user / assistant 边界是否正确。
  • tool calling 的格式是否正确。
  • thinking mode 或 reasoning token 是否需要特殊模板。
  • 多模态占位符是否正确插入。
  • stop token 和 special token 是否匹配。
  • 模板变更是否有版本记录。

很多“模型答非所问”“工具调用格式不对”“system prompt 不生效”的问题,本质不是模型能力问题,而是 template 或 special tokens 不匹配。

建议把 prompt rendering 作为可测试模块:

  • 给定固定 messages,输出固定 prompt。
  • 给定固定工具定义,输出固定工具描述。
  • 升级模型时对比新旧模板差异。
  • 日志里保留可审计的 prompt 版本和 token 数。

对应阅读:Chat Template

8. Tokenizer

Tokenizer 是推理服务中非常关键但容易被忽视的组件。

它影响:

  • 上下文是否超长。
  • input token 统计。
  • 计费。
  • 限流。
  • batch token 预算。
  • KV Cache 预算。
  • stop token 判断。
  • prefix cache 命中。

服务端必须使用和模型匹配的 tokenizer。

如果业务侧用一个 tokenizer 估算 token,服务端用另一个 tokenizer 实际执行,就会出现:

  • 业务侧以为没超长,服务端实际超长。
  • 限流和计费不准确。
  • RAG 截断位置不稳定。
  • prefix cache 命中率下降。
  • 压测数据和真实线上数据不一致。

生产服务通常会把 tokenizer 放在 API 层或 worker 附近。两种方式各有取舍:

位置优点风险
API 层 tokenizer方便提前校验、限流和计费CPU 压力可能集中在 API 层
worker 内 tokenizer和模型执行更贴近,版本更一致排队前难以准确知道 token 成本
双层 tokenizer接入层可估算,worker 可复核要保证版本一致,否则排障复杂

对应阅读:Tokenizer

9. Scheduler

Scheduler 是 LLM 推理服务和普通 Web 服务差异最大的部分之一。

普通 Web 服务常按请求调度;LLM 推理服务要按 token、batch、KV Cache 和阶段调度。

它需要处理:

  • 等待队列。
  • prefill batch。
  • decode batch。
  • continuous batching。
  • KV Cache block 分配。
  • 长短请求混排。
  • 优先级。
  • 取消请求。
  • 超时。
  • 抢占和恢复。
  • worker 负载感知。

一个请求进入 scheduler 后,通常会经历:

waiting
-> scheduled for prefill
-> running decode
-> finished / cancelled / failed

调度策略会直接影响:

  • TTFT。
  • ITL。
  • tokens/s。
  • GPU 利用率。
  • p95 / p99 延迟。
  • OOM 风险。
  • 短请求是否被长请求拖慢。

9.1 Prefill 和 Decode 分离

Prefill 和 decode 的资源特征不同:

阶段主要工作主要压力
Prefill处理完整输入 prompt算力、attention 计算、TTFT
Decode每步生成新 token显存带宽、KV Cache 读写、ITL

长 prompt 请求会占用大量 prefill 计算;长输出请求会长时间占用 decode batch 和 KV Cache。

好的 scheduler 不只是“谁先来谁先跑”,而是要平衡:

  • 短请求的响应速度。
  • 长请求的吞吐。
  • GPU 利用率。
  • KV Cache 剩余空间。
  • 租户优先级。

9.2 Admission Control

调度层还需要做准入控制。

即使 API 层校验通过,也不代表当前 GPU 有资源接收这个请求。

准入控制通常会检查:

  • 当前 waiting queue 长度。
  • running requests 数量。
  • 当前 batch token 数。
  • 可用 KV Cache block 数量。
  • 预计最大输出长度。
  • worker 是否健康。
  • 请求是否超过租户并发。

当资源不足时,可以选择:

  • 立即返回 429 / 503。
  • 进入等待队列。
  • 降低最大输出长度。
  • 路由到其他副本。
  • 对低优先级请求排队。
  • 对超长请求进入慢队列。

对应阅读:并发与批处理KV Cache

10. Model Worker

Model worker 是实际承载模型的服务进程。

它通常负责:

  • 加载模型权重。
  • 初始化 tokenizer 或 processor。
  • 初始化 CUDA / ROCm / XPU 运行时。
  • 管理 KV Cache。
  • 接收 scheduler 下发的 batch。
  • 执行 prefill 和 decode。
  • 返回 logits 或 token。
  • 管理 sampling。
  • 处理取消、异常和释放资源。

一个 worker 可以对应:

  • 单卡单模型。
  • 单卡多模型。
  • 多卡一个模型副本。
  • 多卡多个模型副本。
  • Tensor Parallel。
  • Pipeline Parallel。
  • Expert Parallel。

生产中更常见的是“一个 worker 进程绑定一组 GPU 和一个模型副本”,这样故障边界更清晰。

worker 的健康状态不能只看进程是否存活,还要看:

  • 模型是否加载完成。
  • GPU 是否可用。
  • 显存是否接近上限。
  • KV Cache 是否紧张。
  • batch 是否持续推进。
  • 请求是否大量超时。
  • CUDA error 是否出现。
  • tokens/s 是否异常下降。

11. GPU Executor

GPU executor 是真正执行模型计算的部分。

它通常包括:

  • attention kernel。
  • MLP kernel。
  • sampling kernel。
  • tensor parallel 通信。
  • CUDA graph。
  • KV Cache 读写。
  • quantization kernel。
  • 多模态 encoder 执行。

推理框架会尽量减少 CPU 和 GPU 之间的同步,让 GPU 连续执行 batch。

影响执行效率的因素包括:

  • 模型结构。
  • 权重精度。
  • KV Cache 精度。
  • batch token 数。
  • prompt 长度分布。
  • output 长度分布。
  • attention 实现。
  • 是否使用 CUDA graph。
  • 是否启用 FlashAttention / PagedAttention。
  • 多卡通信拓扑。

在排障时,不要只看 GPU utilization。

GPU 利用率高可能是正常高吞吐,也可能是长 prompt 把 prefill 打满;GPU 利用率低也不一定是模型慢,可能是 scheduler、tokenizer、网络、CPU 或客户端消费速度造成的。

12. Streaming Response

流式输出是 LLM 服务的核心体验之一。

常见实现是 SSE:

HTTP response
Content-Type: text/event-stream

data: {"choices":[{"delta":{"content":"你"}}]}
data: {"choices":[{"delta":{"content":"好"}}]}
data: [DONE]

流式输出要处理:

  • 第一个 token 尽快返回。
  • chunk 顺序稳定。
  • 客户端断开连接。
  • 用户取消生成。
  • 服务端超时。
  • 生成中途报错。
  • usage 是否在最后返回。
  • finish_reason 是否准确。
  • stop 序列是否截断。
  • tool call delta 如何拼接。

流式响应不一定减少总生成时间,但会显著改善用户体感。

生产系统要特别关注取消生成。

如果客户端已经断开,但 worker 还继续 decode,会浪费 GPU 和 KV Cache。API 层需要把取消信号传给 scheduler,scheduler 再释放对应请求的资源。

对应阅读:流式输出

13. 多模型路由

一个平台通常不只服务一个模型。

多模型路由要解决:

  • 模型名到后端集群的映射。
  • 模型版本管理。
  • 默认模型别名。
  • 多模态模型和文本模型区分。
  • embedding、rerank、chat、completion 不同任务路由。
  • 灰度版本路由。
  • 租户可用模型权限。
  • 不同模型的上下文长度和参数能力。

示例配置可以抽象成:

model: qwen3-32b
task: chat
context_length: 32768
backends:
- cluster-a / version-2026-04-18 / weight 90
- cluster-b / version-2026-04-18-canary / weight 10

路由层不要只转发模型名,还要携带模型能力:

  • 最大上下文。
  • 是否支持 tool calling。
  • 是否支持 vision。
  • 是否支持 JSON mode。
  • 是否支持 prefix cache。
  • 推荐默认推理参数。
  • tokenizer 版本。
  • chat template 版本。

这样 API 层才能在请求进入 worker 之前做正确校验。

14. 多副本和负载均衡

为了提高吞吐和可用性,生产服务通常会部署多个模型副本。

常见方式:

Router
-> Worker Replica 1
-> Worker Replica 2
-> Worker Replica 3

普通负载均衡常用 round-robin 或 least-connections,但 LLM worker 的负载不能只看连接数。

更合理的负载信号包括:

  • waiting queue 长度。
  • running requests 数量。
  • 当前 batch token 数。
  • GPU 显存使用率。
  • KV Cache 使用率。
  • prefix cache 命中情况。
  • 最近 TTFT / ITL。
  • worker 是否正在加载模型。
  • 是否有异常或重启。

14.1 Sticky Routing

某些场景需要粘性路由。

例如:

  • prefix cache 希望复用同一 worker 上的缓存。
  • 多轮对话使用同一上下文缓存。
  • 请求状态只存在某个 worker 内。

粘性路由可以提升缓存命中,但也会带来负载不均。

实践中可以按场景权衡:

  • 普通无状态请求:优先负载均衡。
  • 固定长前缀请求:考虑按 prefix hash 路由。
  • 会话型请求:考虑按 session id 路由。
  • 高优先级请求:优先路由到空闲 worker。

15. 推理服务与业务服务的边界

推理服务不应该承载所有业务逻辑。

更清晰的边界是:

模块应该负责不应该负责
业务服务用户流程、业务权限、RAG 编排、工具调用、结果后处理GPU 调度、KV Cache 管理、模型 batch
推理服务模型加载、prompt 到 token、调度、生成、流式返回、usage复杂业务规则、数据库事务、业务状态机

业务服务可以决定“为什么调用模型”和“拿结果做什么”;推理服务负责“如何高效稳定地生成”。

边界不清会导致几个问题:

  • 推理服务越来越像业务后端,升级模型时风险变大。
  • 业务服务不知道真实 GPU 状态,容易错误限流。
  • prompt、模型版本和工具 schema 难以审计。
  • 故障时分不清是业务编排问题还是模型执行问题。

建议用清晰协议连接两者:

业务服务
-> 组装 messages / tools / response_format
-> 调用推理服务
-> 接收 stream / final response / usage
-> 做业务后处理和持久化

推理服务返回的信息至少应包括:

  • request id。
  • model。
  • model version。
  • finish reason。
  • usage。
  • latency。
  • error code。

16. 部署形态

16.1 单机单副本

最简单的形态:

API Server + Scheduler + Worker + GPU

适合:

  • 本地开发。
  • 小流量内部服务。
  • 单模型验证。
  • 压测基线。

优点是简单;缺点是扩展性、隔离性和高可用较弱。

16.2 API 层和 Worker 分离

更常见的生产形态:

API Server
-> Router / Scheduler
-> Worker Pool

优点:

  • API 层可以水平扩展。
  • worker 可以独立扩缩容。
  • 不同模型可以放在不同 worker pool。
  • 模型加载失败不会直接拖垮接入层。
  • 调度策略可以集中管理。

16.3 多集群部署

大规模服务可能会按区域、租户或模型拆成多个集群:

Global Gateway
-> Region A Model Cluster
-> Region B Model Cluster
-> Dedicated Tenant Cluster

这种形态要额外关注:

  • 跨区域延迟。
  • 模型版本一致性。
  • 配额同步。
  • 日志归集。
  • 灰度和回滚。
  • 容灾切换。

17. 可观测性

推理服务必须具备完整观测能力。

建议至少记录这些指标:

指标说明
QPS请求量
input tokens/s输入 token 吞吐
output tokens/s输出 token 吞吐
TTFT从请求进入到首 token 返回
ITLtoken 间隔延迟
E2E latency端到端耗时
queue time排队时间
prefill timeprefill 耗时
decode timedecode 耗时
GPU memory usedGPU 显存使用
KV Cache usageKV Cache 使用率
batch sizebatch 中请求数或 token 数
running / waiting requests运行中和等待中请求
error rate错误率
cancel rate客户端取消比例
timeout rate超时比例

日志建议包含:

  • request id / trace id。
  • tenant / user / API key 哈希。
  • model / model version。
  • tokenizer version。
  • chat template version。
  • input tokens。
  • output tokens。
  • sampling params。
  • finish reason。
  • error code。
  • worker id。
  • latency breakdown。

注意不要在普通日志里直接记录敏感 prompt。需要记录时应做脱敏、采样和权限控制。

对应阅读:可观测性

18. 常见故障

18.1 API 层正常,首 token 很慢

常见原因:

  • prompt 太长,prefill 耗时高。
  • scheduler 队列积压。
  • 长请求和短请求混在同一队列。
  • tokenizer 在 CPU 侧成为瓶颈。
  • prefix cache 没有命中。
  • worker 正在高负载 decode。

排查重点:

  • queue time。
  • prefill time。
  • input tokens 分布。
  • waiting requests。
  • prefix cache hit rate。

18.2 QPS 不高,但 GPU 显存爆了

常见原因:

  • 少量超长上下文请求占满 KV Cache。
  • max_model_len 设置过大。
  • max_tokens 设置过大。
  • 多轮对话没有裁剪。
  • prefix cache 或 KV Cache 没有及时释放。

排查重点:

  • KV Cache usage。
  • input tokens / output tokens 分布。
  • running requests 的上下文长度。
  • OOM 前的 worker 日志。

18.3 流式输出中断

常见原因:

  • 客户端超时或断网。
  • 网关 idle timeout 太短。
  • SSE 被代理缓冲。
  • worker 中途异常。
  • API 层没有正确转发取消信号。

排查重点:

  • 客户端断开时间。
  • 网关日志。
  • API server error。
  • worker request state。
  • cancel rate。

18.4 多副本负载不均

常见原因:

  • 只按请求数轮询,没有看 token 和 KV Cache。
  • 粘性路由导致热点 worker。
  • 某些 worker prefix cache 命中高,被持续路由。
  • 长请求集中到少数副本。
  • worker 重启后冷启动,短期吞吐较低。

排查重点:

  • 每个 worker 的 running / waiting。
  • 每个 worker 的 input/output tokens/s。
  • 每个 worker 的 KV Cache 使用率。
  • 路由策略和权重。

19. 实践建议

设计推理服务时,可以按下面顺序检查:

  1. 明确支持哪些 API:chat、completion、embedding、rerank、多模态。
  2. 明确每个模型的能力配置:上下文长度、工具调用、JSON mode、多模态、tokenizer、template。
  3. 在 API 层做参数校验、默认值填充和能力检查。
  4. 按 token 预算和 KV Cache 预算做准入控制。
  5. 把长 prompt、长输出和普通短请求分开观察,必要时分队列。
  6. 路由层不要只看请求数,要看 worker 的队列、batch、显存和 KV Cache。
  7. 流式输出必须支持取消生成和资源释放。
  8. 日志里记录 request id、model version、token usage、latency breakdown 和 finish reason。
  9. 灰度发布时同时灰度模型权重、tokenizer、chat template 和推理参数。
  10. 压测要覆盖短输入短输出、长输入短输出、短输入长输出、长输入长输出。

20. 和其他概念的关系

  • Tokenizer:推理服务里的限流、计费、上下文裁剪和 usage 都依赖 tokenizer。
  • Chat Template:API 请求必须先渲染成模型训练时熟悉的 prompt 格式。
  • KV Cache:worker、scheduler 和 router 都需要感知 KV Cache 压力。
  • 并发与批处理:scheduler 负责把请求组织成 batch,并平衡吞吐和延迟。
  • 流式输出:streaming response 是推理服务对用户体验最直接的部分。
  • 容量与成本规划:容量不能只按 QPS 估算,要按 token、显存、KV Cache 和延迟目标估算。
  • 模型部署流程:推理服务架构决定模型上线、灰度、回滚和观测方式。

21. 总结

推理服务架构的核心问题是资源治理。

LLM 请求的成本不是固定的。输入长度、输出长度、并发、KV Cache、batch 调度、模型版本和流式连接都会影响服务稳定性。

一个可靠的推理服务需要同时回答四个问题:

谁可以调用?
请求应该路由到哪里?
当前 GPU 是否有资源接收?
生成过程是否可观测、可取消、可回滚?

模型进程只是执行层。真正面向生产的是从接入、鉴权、模板、tokenizer、调度、worker、流式响应到观测治理的一整套系统。