本文是《Ai大模型训练教程》系列实战篇,详解大模型API服务设计的四个关键:批处理(连续批处理/按token凑批)、KV Cache(会话缓存与前缀缓存、显存与命中率)、限流与配额(并发+TPM、预扣与结算)、多租户隔离(队列权重、缓存命名空间、专池与独占)。包含可落地参数、接口字段与排障思路,帮助推理服务稳定上线与规模化运营。
引言:为什么大模型 API 服务设计决定“能不能上线”
在“Ai大模型训练教程:从入门到实战落地的系统课程”里,训练只是起点,真正落地通常卡在推理服务:吞吐不够、延迟抖动、成本爆炸、不同客户互相影响、热点请求把集群打穿。
这篇聚焦大模型 API 服务设计的四个关键抓手:批处理(Batching)、KV Cache、限流(Rate Limit/Quota)、多租户隔离(Multi-tenancy Isolation)。目标不是泛泛而谈,而是给出能直接照做的设计步骤、接口字段建议、常见坑与排障思路。
一、服务整体架构:从 API 网关到推理执行器
一个可扩展的大模型推理服务通常拆成三层:
- 接入层(API Gateway):鉴权、配额、限流、日志、路由、协议转换(OpenAI 兼容 / 自定义)。
- 调度层(Scheduler/Router):将请求分配到具体模型实例或 GPU 节点,做批处理、队列控制、优先级、弹性扩缩。
- 执行层(Inference Worker):真正跑模型推理(vLLM/TGI/TensorRT-LLM/自研),实现 KV Cache 管理、prefill/decoding 流水化、流式输出。
建议从一开始就把“请求生命周期”定义清楚:
- request_id:全链路追踪
- tenant_id / user_id / api_key:多租户与计费
- model / version:模型路由与灰度
- input_tokens / output_tokens:容量与计费
- mode:stream / non-stream
- priority:交互请求与离线任务区分
二、批处理(Batching):吞吐提升的第一生产力
批处理的本质是把多个请求拼到一次 GPU 执行里,提高 GPU 利用率、摊薄 kernel launch 开销。但大模型推理有两段:
- Prefill(提示词阶段):输入长、计算密集
- Decode(逐 token 生成):每步小计算、需要频繁迭代
因此批处理也分两类:
2.1 静态批 vs 动态批:如何选
- 静态批(Static Batch):一次收齐 N 条再跑。实现简单,但会增加排队延迟,且不同长度 padding 浪费。
- 动态批(Dynamic Batch / Continuous Batching):持续把新请求插入运行中的批次(常见于 vLLM、TGI)。可以显著降低延迟并提高吞吐,是线上主流。
线上建议:优先采用支持 continuous batching 的推理引擎;如果你只能静态批,务必在接入层做“交互请求”与“离线任务”分流。
2.2 批处理的关键参数(可直接落地)
你需要在调度层定义这些参数,并提供“按模型可配置”的开关:
max_batch_size:单次最大并发请求数max_batch_tokens:单批次 token 上限(更有效)batch_wait_ms:最大等待时间(凑批窗口)max_concurrent_requests:单 worker 最大同时在途请求(含流式)scheduler_policy:FIFO / priority / shortest-remaining
推荐初始值(需要压测校准):
- 交互式聊天:
batch_wait_ms=2~10ms,max_batch_tokens优先控制 - 离线生成:
batch_wait_ms=20~100ms,允许更激进凑批
2.3 token 维度的批:为什么比按请求数更稳
只按请求数限制会遇到极端情况:一个请求 8k prompt,另一个 200 prompt,二者放一起可能把显存顶满。
更稳的做法:
- 预估每个请求的
prefill_tokens、max_new_tokens 维护一个批次累加器:
sum(prompt_tokens) + sum(active_decode_slots)不超过阈值
简化实现思路(调度层伪逻辑):
- 收到请求,计算
estimated_cost = prompt_tokens + alpha * max_new_tokens(alpha 可设 0.3~1) - 尝试塞进当前 batch:若
batch_cost + estimated_cost <= max_batch_tokens则加入 - 否则立即 flush 当前 batch 执行,并开新 batch
2.4 示例:API 层如何暴露“批处理友好”的字段
如果你提供非 OpenAI 的自定义 API,可以加一个建议字段:
latency_sla:low/normal/throughput
调度策略:
low:小窗口凑批,尽量低延迟throughput:更长窗口、更大 batch_tokens,提高吞吐降成本
三、KV Cache:降低重复计算与成本的核心资产
KV Cache(Key/Value Cache)用于保存注意力层的中间结果,使得 decode 阶段不必重复计算历史 token。对 API 服务来说,KV Cache 的关键不只是“开不开”,而是:
- 怎么复用(同一会话/相同前缀/多轮对话)
- 怎么管理显存(淘汰策略、碎片)
- 怎么隔离(不同租户不能互相“蹭 cache”泄露信息)
3.1 两类 KV Cache:会话级 vs 前缀复用
会话级(Session KV)
典型聊天:同一个 conversation_id,后续请求在同一 worker 上延续 KV。
落地要点:
- API 请求必须带
conversation_id或session_id - 调度层需要 sticky routing:尽量把同一 session 路由到同一 worker
- session 超时释放:例如 10~30 分钟无请求回收
前缀复用(Prefix Cache / Prompt Cache)
对“固定系统提示词 + 固定模板”的场景很有效,例如客服机器人、工具调用模板、RAG 的固定提示前缀。
落地要点:
- 对 prompt 做规范化(去多余空格、统一换行,避免 hash 不命中)
prefix_hash = hash(normalized_prefix_tokens)- 只缓存前缀段 KV,不缓存用户隐私段
重要安全原则:前缀缓存必须按租户维度做 key:(tenant_id, model_id, prefix_hash),防止跨租户命中。
3.2 显存管理:你会遇到的三个现实问题
- 显存不够:KV 随着上下文长度线性增长。
- 碎片化:动态 batch/持续插入删除会造成 KV 内存碎片,导致可用显存下降。
- 长上下文拖垮吞吐:某个 32k 上下文请求会让同 batch 其他请求 decode 变慢。
应对策略(可组合):
- 上限控制:限制
max_context_tokens,并对超限直接拒绝或降级(返回错误码与建议)。 - 分层队列:短上下文走交互池,长上下文走大上下文池(独立 worker/独立 GPU)。
- KV 淘汰策略:LRU + TTL,按 session 的最近访问回收。
- 分页/块管理:使用支持 paged attention 的引擎(如 vLLM)降低碎片影响。
3.3 KV Cache 命中率怎么衡量(必须上监控)
建议在 worker 暴露以下指标:
kv_cache_hit_rate_sessionkv_cache_hit_rate_prefixkv_cache_bytes_usedkv_cache_evictions_totalprefill_latency_msvsdecode_latency_per_token_ms
经验上:
- 会话型业务:session KV 命中显著降低 prefill 成本
- 模板化业务:prefix cache 能把系统提示 prefill 几乎“免费化”
四、限流:不只是防打爆,更是“公平与可预期”
大模型推理是稀缺资源(GPU)。限流要解决三件事:
- 防止单用户/单租户压垮集群
- 保证关键客户/关键业务的低延迟
- 与计费/配额一致,做到可解释
4.1 限流的四个维度:请求数不够,需要 token 维度
建议同时支持:
- RPS 限流:每秒请求数(粗粒度)
- 并发限流:同时在途请求数(对流式非常关键)
- TPM 限流:tokens per minute(最贴近成本)
- 上下文长度限流:max prompt tokens / max total tokens
如果只能选两个:优先 并发 + TPM。
4.2 令牌桶/漏桶怎么落地到 token 计量
TPM 的关键是:请求开始时你并不知道最终会生成多少 token。
可行做法:
- 进入队列前,先按
estimated_tokens = prompt_tokens + max_new_tokens进行“预扣”(reserve) - 流式生成过程中按实际输出 token 进行“结算修正”(settle)
- 请求取消/中断时,退还未使用的额度
接口建议:
- 请求体必须包含
max_new_tokens(或max_tokens) - 服务端返回 usage:
prompt_tokens,completion_tokens,total_tokens
4.3 分层限流:全局、租户、用户、API Key
推荐的限流层级:
- L1:集群全局保护(防雪崩)
- L2:租户级(多租户公平)
- L3:API Key / 用户级(防单点滥用)
- L4:模型级(某个昂贵模型单独限)
当触发限流时,返回要可操作:
- HTTP 429 +
Retry-After - body 给出
limit_type(tpm/concurrency/rps)、reset_time
4.4 排队与降级:比“直接拒绝”更友好
对于交互业务,排队太久会让用户体验崩溃;对于离线任务,排队是可以接受的。
建议:
- 交互:排队超过
queue_timeout_ms直接拒绝 - 离线:支持返回
job_id,转异步任务(回调/轮询) - 降级:优先降级到小模型、降低
max_new_tokens、关闭高成本采样参数
五、多租户隔离:性能、成本与安全要一起管
多租户隔离不仅是“不同客户互不影响”,还包括:
- 资源隔离(GPU/CPU/队列/并发)
- 数据隔离(日志、缓存、训练语料、提示词)
- 安全隔离(越权、提示注入后的信息泄露面)
- 成本隔离(精细计费、配额)
5.1 三种隔离模型:从共享到独占
方案 A:共享集群 + 逻辑隔离(最常见)
- 所有租户共享 worker
- 用限流、配额、优先级队列保证公平
优点:资源利用率高
缺点:尾延迟可能互相影响,需要更强的调度
方案 B:共享集群 + 租户专属队列/权重
- 每租户一个队列,调度按权重(Weighted Fair Queuing)
优点:公平性更好,可做 SLO
缺点:实现复杂
方案 C:租户独占实例(高端/强隔离)
- 给大客户独占 GPU 或独占一组 worker
优点:隔离最强,易承诺 SLO
缺点:成本高、资源碎片
实践建议:多数团队采用 A 起步,对大客户提供 C 作为增值。
5.2 必做:缓存与日志的租户边界
- Prefix Cache:必须加 tenant_id 作为命名空间
- Session KV:session_id 必须随机不可猜;并在服务端校验该 session 归属 tenant_id
- 日志/追踪:日志中敏感字段脱敏;不同租户的可观测数据分空间存储(例如不同 index/不同 project)
5.3 调度隔离:避免“邻居噪声”
邻居噪声(noisy neighbor)主要来自:
- 超长上下文请求
- 高并发流式连接占满 worker
- 离线批量任务持续压榨 GPU
应对组合拳:
- 租户级并发上限(streaming 连接数单独计数)
- 请求分级队列:interactive vs batch
- 长上下文专池:把
context_tokens > threshold的请求路由到单独的 worker pool - 优先级抢占(可选):高优先级请求可插队,但要设置插队比例上限避免饿死
5.4 计费与配额:统一到 token 账本
多租户服务强烈建议以 token 为最小计费单位:
- 记录:tenant_id / api_key / model_id / prompt_tokens / completion_tokens / latency
- 账本对齐限流:TPM 配额与计费口径一致
这样当客户抱怨“被限流”时,你可以给出清晰解释:过去 60 秒使用了多少 token、上限多少、何时恢复。
六、一个可落地的接口与内部字段清单(建议照抄再改)
6.1 外部 API 请求建议字段
model: 模型名messages或promptmax_new_tokenstemperature/top_pstream: boolconversation_id: 可选但建议latency_sla: low/normal/throughput(可选)
6.2 服务端内部必备字段(用于调度/隔离/计费)
request_idtenant_id,api_key_id,user_idpriorityprompt_tokens(预估+实际)reserved_tokens(预扣额度)queue_enter_ts,start_ts,first_token_ts,end_tsworker_id,gpu_id
6.3 核心 SLO 指标(强烈建议上看板)
P50/P95/P99:
time_to_first_token(TTFT)tokens_per_second(生成速率)end_to_end_latency
- 利用率:GPU utilization、显存占用
- 队列:queue depth、queue time
- 限流:429 数量、按 tenant 统计
- KV:命中率、淘汰次数、cache 使用量
七、常见故障与排障路径(线上最常用)
7.1 吞吐突然下降
排查顺序:
- 是否有长上下文请求暴增(看 prompt_tokens 分布)
- KV cache 是否碎片/命中下降导致 prefill 变慢
- batch_tokens 是否被配置得太小导致凑不起来批
- GPU 是否被其他进程抢占(节点级监控)
7.2 TTFT 变大但 TPS 正常
通常是:
- 队列排队变长(限流/并发太紧)
- prefill 阶段被拖慢(前缀没缓存、prompt 变长)
解决:
- 给交互流量更高优先级
- 提升 prefix cache 覆盖率(模板化规范)
- 降低 batch_wait_ms 或分离长上下文池
7.3 多租户互相影响(客户 A 说被客户 B 拖慢)
解决路径:
- 开租户队列 + 权重调度
- 租户并发上限与 TPM 上限
- 大客户独占池(付费方案)
结语:把“四件事”做成可配置、可观测、可解释
批处理决定你能跑多快,KV Cache 决定你能省多少,限流决定你能否稳定,多租户隔离决定你能否规模化商业化。建议从第一天就做到:
- 所有关键参数可按模型/租户配置
- 所有关键指标可观测(TTFT、TPS、队列、KV、限流)
- 所有拒绝/限流可解释(配额、重试时间、token 账本)
在后续“Ai大模型训练教程”的实战篇里,你可以在此基础上继续扩展:灰度发布、A/B 路由、多模型混部、RAG 缓存与工具调用的安全沙箱等,把推理服务真正做成可运营的产品能力。
Prev:模型量化实战:INT8/INT4、GPTQ、AWQ与精度-速度权衡