推理服务架构
本文用于整理大模型推理服务的整体工程架构。
推理服务的目标不是“把模型进程启动起来”,而是把模型变成一个稳定、可观测、可扩展、可治理的在线 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 Cache | model 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_tokens或max_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 |
常见做法是分两段控制:
- 接入层先按 API key、租户和路径做粗限流。
- 调度层再按 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 顺序是否合法。
temperature、top_p、top_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。
- 进入等待队列。
- 降低最大输出长度。
- 路由到其他副本。
- 对低优先级请求排队。
- 对超长请求进入慢队列。
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 返回 |
| ITL | token 间隔延迟 |
| E2E latency | 端到端耗时 |
| queue time | 排队时间 |
| prefill time | prefill 耗时 |
| decode time | decode 耗时 |
| GPU memory used | GPU 显存使用 |
| KV Cache usage | KV Cache 使用率 |
| batch size | batch 中请求数或 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. 实践建议
设计推理服务时,可以按下面顺序检查:
- 明确支持哪些 API:chat、completion、embedding、rerank、多模态。
- 明确每个模型的能力配置:上下文长度、工具调用、JSON mode、多模态、tokenizer、template。
- 在 API 层做参数校验、默认值填充和能力检查。
- 按 token 预算和 KV Cache 预算做准入控制。
- 把长 prompt、长输出和普通短请求分开观察,必要时分队列。
- 路由层不要只看请求数,要看 worker 的队列、batch、显存和 KV Cache。
- 流式输出必须支持取消生成和资源释放。
- 日志里记录 request id、model version、token usage、latency breakdown 和 finish reason。
- 灰度发布时同时灰度模型权重、tokenizer、chat template 和推理参数。
- 压测要覆盖短输入短输出、长输入短输出、短输入长输出、长输入长输出。
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、流式响应到观测治理的一整套系统。