在第七篇“推理落地篇”中,前序章节已经解决了模型怎么跑得快、显存怎么省的问题。但模型跑起来只是第一步,要让它真正成为业务系统中的一个标准化组件,你必须回答两个工程问题:
- 如何让前端、后端、第三方服务用统一的协议调用你的模型?
- 当你同时维护多个模型(不同版本、不同用途、不同规格)时,如何避免配置地狱和调用混乱?
这就是大模型 API 服务化的核心命题。本节聚焦当前事实上的行业标准——OpenAI 兼容接口,并给出多模型管理的实用方案。与 1.4 节工程层的推理服务框架相呼应,这一节会把前面的 vLLM、TGI 等推理引擎,真正“包装”成生产可用的 HTTP 服务。
一、为什么需要“服务化”?
裸推理引擎(直接 Python 脚本加载模型)只适合实验阶段。生产环境有截然不同的需求:
- 多客户端接入:Web 应用、移动端、内部脚本、第三方 API 都要调用,不能每接入一个就改一次调用方式。
- 认证与计费:谁在调用?调了多少 Token?必须可追踪、可计量。
- 负载均衡与弹性伸缩:流量高峰时自动扩容,低谷时回收资源,不能让 GPU 空转烧钱。
- 版本管理与灰度发布:新模型上线不能直接全量替换,需要逐步放量验证。
因此,“服务化”就是在推理引擎外面加一层标准 HTTP API 网关,把上述能力全部统一封装。
二、OpenAI 兼容接口:事实上的行业协议
1. 为什么是 OpenAI 的格式?
OpenAI 的 Chat Completions API(/v1/chat/completions)已经成为大模型 API 的“HTTP 协议”。原因很现实:
- 生态绑定:绝大多数 LLM 应用框架(LangChain、LlamaIndex、AutoGen)和客户端工具,都内置了对 OpenAI API 格式的支持。
- 开发者习惯:调过 ChatGPT API 的人,只需要改
base_url和model参数,就能无缝切换到你的自建模型。 - 社区推动:vLLM、TGI、Ollama、LocalAI 等几乎所有推理框架,都原生支持或通过插件提供 OpenAI 兼容接口。
这意味着,你只需要部署一个兼容 OpenAI 格式的 API 端点,就能让几乎所有现成的 LLM 工具链直接对接你的私有模型。
2. 核心接口:/v1/chat/completions
这是当前最主流的对话式接口。一个典型的请求如下:
POST /v1/chat/completions
{
"model": "qwen2-72b",
"messages": [
{"role": "system", "content": "你是一个有用的助手"},
{"role": "user", "content": "你好,请解释一下量子纠缠"}
],
"temperature": 0.7,
"max_tokens": 1024,
"stream": true
}
响应(非流式)结构:
{
"id": "chatcmpl-xxx",
"object": "chat.completion",
"created": 1715000000,
"model": "qwen2-72b",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "量子纠缠是..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 20,
"completion_tokens": 150,
"total_tokens": 170
}
}
你需要实现的关键能力:
messages数组解析:支持 system / user / assistant / tool 等角色,并能正确拼成推理引擎所需的 prompt 格式(不同模型的 chat template 不同,需自动转换)。stream流式输出:当stream=true时,返回 Server-Sent Events(SSE)格式的增量 Token,实现打字机效果。这是用户体验的关键。- 常用参数支持:
temperature(随机性)、top_p(核采样)、max_tokens(最大生成长度)、stop(停止词)、frequency_penalty/presence_penalty(重复惩罚)等。不一定全部实现,但至少要正确解析并传递给推理引擎。
3. 其他常用兼容接口
| 接口 | 用途 |
|------|------|
| /v1/models | 列出当前可用的模型列表 |
| /v1/completions | 旧式纯文本补全接口(部分场景仍在使用) |
| /v1/embeddings | 文本向量化接口(用于 RAG 的检索端) |
如果你的服务还需要支持 Function Calling(工具调用),则需要实现 /v1/chat/completions 中的 tools 和 tool_choice 参数,并正确处理模型返回的 tool_calls 结构。这在 1.3 节的能力边界和 24.3 节的 Agent 实现中都有涉及。
三、多模型管理:从“一个模型”到“模型广场”
当你的业务跑起来后,很快会面临这样的局面:
- A/B 测试:新模型和旧模型同时在线,对比效果;
- 场景隔离:客服模型用 7B,代码模型用 34B,翻译模型用特定微调版;
- 租户隔离:不同客户或部门使用不同的模型或资源配额;
- 滚动升级:新版本模型部署时,不能中断正在服务的请求。
这时,一个清晰的多模型管理方案就至关重要。
1. 模型注册与路由
核心思想:每个模型(或模型版本)有一个唯一标识符(model name),API 网关根据请求中的 model 字段,将流量路由到对应的推理后端。
推荐架构:
用户请求 → API 网关(Nginx / Envoy / 自建路由)
↓
模型路由器(解析 model 字段)
↓
┌──────────┼──────────┐
↓ ↓ ↓
模型实例组A 模型实例组B 模型实例组C
(qwen2-7b) (qwen2-72b) (code-llama)
实现要点:
- 路由表:维护一个配置(可以是数据库或 YAML 文件),记录
model_name → 后端地址的映射。例如:
models:
- name: "gpt-3.5-turbo" # 对外展示的名称
backend: "http://10.0.1.10:8000/v1" # 实际推理服务地址
- name: "gpt-4"
backend: "http://10.0.1.11:8000/v1"
- name: "my-finetuned-7b"
backend: "http://10.0.1.20:8001/v1"
- 动态切换:当新模型上线时,只需更新路由表,无需重启网关。
2. 负载均衡与健康检查
同一模型可能有多个推理实例(多张 GPU 或多台机器)。路由器需要具备:
- 轮询 / 最少连接:将请求均匀分配到各实例。
- 健康检查:定期探活(如
GET /health),自动剔除故障节点。 - 会话保持(可选):对于需要上下文缓存的场景,将同一会话路由到同一实例,可提升 KV-cache 命中率。
3. 资源隔离与配额管理
多租户场景下,必须防止一个用户打爆所有资源。常用方案:
- 并发限制:基于用户 API-key 或 IP,限制同时处理的请求数。
- 速率限制(Rate Limiting):基于 Token 消耗量或请求次数,实施 QPM(每分钟查询数)/ TPM(每分钟 Token 数)配额。
- 优先级队列:VIP 用户的请求进入高优先级队列,保证延迟。
4. 使用 LiteLLM 或自建网关
目前业界有两种落地路径:
路径一:直接使用现成方案
LiteLLM Proxy 是目前最成熟的开源方案之一,它:
- 完全兼容 OpenAI API 格式;
- 支持接入 100+ 种 LLM 提供商(包括自部署的 vLLM、TGI 后端);
- 内置负载均衡、速率限制、花费追踪、日志记录;
- 一个
docker-compose up即可启动。
典型配置示例(litellm_config.yaml):
model_list:
- model_name: gpt-3.5-turbo
litellm_params:
model: openai/my-fake-gpt
api_base: http://localhost:8000/v1
api_key: sk-dummy
- model_name: gpt-4
litellm_params:
model: huggingface/meta-llama/Llama-3-8b
api_base: http://localhost:8001/v1
路径二:自建轻量网关
如果需要深度定制(如自定义认证、审计、日志格式),可以基于 Flask / FastAPI + 异步 HTTP 客户端自建。核心逻辑不到 500 行代码:
from fastapi import FastAPI, Request, HTTPException
import httpx
import yaml
app = FastAPI()
with open("routes.yaml") as f:
route_table = yaml.safe_load(f)
async def get_backend(model_name):
for m in route_table["models"]:
if m["name"] == model_name:
return m["backend"]
raise HTTPException(404, "Model not found")
@app.post("/v1/chat/completions")
async def chat_completions(request: Request):
body = await request.json()
model = body.get("model")
backend = await get_backend(model)
async with httpx.AsyncClient() as client:
# 透传请求头(如 Authorization)
headers = {"Authorization": request.headers.get("Authorization")}
resp = await client.post(f"{backend}/chat/completions", json=body, headers=headers)
return resp.json()
这样,前端调用 http://your-gateway/v1/chat/completions,传入任意 model 名称,网关自动路由到对应后端。
四、实用避坑指南
1. Token 计数与计费
OpenAI API 返回的 usage 字段是计费基础。自建服务必须准确计算 prompt_tokens 和 completion_tokens。这要求:
- 使用与推理引擎相同的 Tokenizer 离线计数,或在推理引擎返回时附带 token 统计。
- 注意计费模型设计:是按实际 Token 消耗,还是包月套餐?不同模型可能使用不同的计费系数。
2. 流式输出的网关处理
当 stream=true 时,推理后端返回 SSE 事件流。网关需要做流式透传,不能等待所有数据到齐再返回,否则客户端会白屏数秒。FastAPI 的 StreamingResponse 可以轻松实现。
3. 请求/响应格式兼容性
不是所有开源模型都能 100% 复刻 OpenAI 的响应格式。例如,某些模型的 finish_reason 可能不是 "stop" 而是 "eos_token",需要在网关层做规范化转换。
4. 安全措施
自建 API 服务暴露在公网时,至少要做好:
- API 密钥认证:简单但有效,配合 HTTPS 加密传输;
- 请求体大小限制:防止恶意长 prompt 刷爆显存;
- 敏感词过滤:在输出端做一层安全扫描(可用单独的 NLP 模型或正则)。
五、小结
大模型 API 服务化的核心,就是把推理引擎的能力通过标准 HTTP 协议暴露出来,让业务系统可以像调用云服务一样调用私有模型。
- OpenAI 兼容接口已成为事实标准,是实现生态对接的最短路径;
- 多模型管理的本质是一个带路由功能的 API 网关,负责将不同 model 名称映射到不同后端实例,并提供负载均衡、速率限制和安全管控;
- 使用 LiteLLM 等现成方案可以快速搭建,自建网关则适合需要深度定制的场景。
这样一层包装完成后,你的模型就不再是一个“实验脚本”,而是可以与整个 LLM 应用开发生态无缝集成的标准化服务。在下一节 24.1 中,我们将进入应用开发的第一线——提示工程,看如何通过精心设计的 Prompt,让这个标准化服务输出更高质量的结果。