LLM API 设计
LLM 应用的 API 层是连接前端/客户端与模型服务的桥梁。与传统的 REST API 不同,LLM API 需要处理流式传输、Token 计费、多模型代理等特殊需求。OpenAI 的 Chat Completions API 已经成为事实标准,几乎所有主流模型服务商和推理框架都兼容这一协议。
OpenAI 兼容协议
OpenAI 的 POST /v1/chat/completions 接口定义了 LLM 调用的标准格式。请求体包含 model(模型名)、messages(消息数组,每条有 role 和 content)、temperature、max_tokens 等参数。响应包含 choices(生成结果)、usage(Token 消耗统计)。
import openai
client = openai.OpenAI(
base_url="http://localhost:11434/v1", # Ollama 兼容端点
api_key="not-needed"
)
response = client.chat.completions.create(
model="llama3",
messages=[
{"role": "system", "content": "你是一个有帮助的助手。"},
{"role": "user", "content": "解释什么是向量数据库"}
],
temperature=0.7,
max_tokens=1000
)
print(response.choices[0].message.content)
print(f"Token 用量: {response.usage}")协议兼容的价值在于生态复用。vLLM、Ollama、TGI 等推理框架都实现了 OpenAI 兼容的 API,意味着用 OpenAI SDK 写的应用可以无缝切换到本地模型,只需修改 base_url。LangChain、LlamaIndex 等框架也基于这个协议封装了通用的 Model I/O 层。
工具调用(Function Calling)通过 tools 参数定义可用函数,模型返回 tool_calls 指示程序执行函数,程序将结果通过 tool role 消息返回,模型基于结果继续生成。这套机制已经被 Anthropic、Google 等厂商采纳,成为跨平台的工具调用标准。
流式传输
LLM 生成响应需要数秒到数十秒,如果等待完整响应再返回,用户体验很差。流式传输(Streaming)将响应拆分为多个 chunk 逐步返回,前端可以实时渲染"打字机效果"。
Server-Sent Events (SSE) 是实现流式传输的标准协议。客户端发送 stream: true 参数,服务端保持 HTTP 连接开放,逐个 token 发送数据块,每个 chunk 格式为 data: {json}\n\n,最后的 data: [DONE]\n\n 标记传输结束。
# 服务端 SSE 实现
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import openai
app = FastAPI()
@app.post("/api/chat")
async def chat(request: ChatRequest):
client = openai.OpenAI()
stream = client.chat.completions.create(
model="gpt-4o",
messages=request.messages,
stream=True
)
def generate():
for chunk in stream:
if chunk.choices[0].delta.content:
yield f"data: {chunk.model_dump_json()}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(
generate(),
media_type="text/event-stream",
headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"}
)流式传输的工程细节值得注意。Nginx 等反向代理默认会缓冲响应,需要设置 X-Accel-Buffering: no 禁用缓冲。超时设置要足够长(通常 60-120 秒),因为 LLM 生成长响应需要时间。工具调用的流式处理更复杂——模型可能在流式输出中间突然切换到工具调用模式,需要解析部分 JSON 来判断是否包含 tool_calls 字段。
Token 计费
Token 是 LLM API 的计费单位。输入 Token 和输出 Token 的单价不同,输出通常贵 2-3 倍(因为生成比理解计算量更大)。GPT-4o 的输入约 $2.50/1M tokens,输出约 $10/1M tokens(2026 年价格持续下降中)。
计费的关键是准确统计 Token 用量。tiktoken 是 OpenAI 官方的 Token 计数库,支持不同模型的编码器(cl100k_base 用于 GPT-4,o200k_base 用于 GPT-4o)。对于 OpenAI 兼容的 API,响应中的 usage 字段提供了精确的 Token 统计。
import tiktoken
encoding = tiktoken.encoding_for_model("gpt-4o")
text = "这是一个测试文本"
tokens = encoding.encode(text)
print(f"Token 数量: {len(tokens)}")成本控制是 LLM 应用的运维重点。常见策略包括:限制单次请求的 max_tokens(防止无限生成)、设置用户/项目的日/月预算上限、使用更小的模型处理简单任务、缓存重复请求的结果。LiteLLM 等网关工具内置了预算管理和成本追踪功能。
API 版本管理
LLM API 的版本管理比传统 API 更复杂,因为模型本身在不断更新。GPT-4 到 GPT-4o 到 GPT-5,每个新版本的行为可能不同,但 API 接口保持兼容。最佳实践是在请求中指定具体的模型版本(如 gpt-4o-2024-08-06),而不是使用别名(如 gpt-4o),这样即使模型提供商更新了默认指向,你的应用行为也不会变化。
模型切换是版本管理的常见场景。从 GPT-4 切换到 Claude 或本地模型时,虽然 API 协议兼容,但行为差异(输出风格、工具调用格式、安全策略)可能导致问题。渐进式切换策略是先让 5% 流量走新模型,观察质量指标(准确率、延迟、成本),确认无问题后逐步扩大。
API 网关
多模型场景下,API 网关负责统一入口、路由请求、管理认证。LiteLLM 是最流行的开源 LLM 网关,它封装了 100+ 模型提供商的 API 差异,对外暴露统一的 OpenAI 兼容接口。
# LiteLLM 配置示例
model_list:
- model_name: gpt-4o
litellm_params:
model: openai/gpt-4o
api_key: os.environ/OPENAI_API_KEY
- model_name: gpt-4o
litellm_params:
model: anthropic/claude-sonnet-4-20250514
api_key: os.environ/ANTHROPIC_API_KEY
router_settings:
routing_strategy: usage-based-routing-v2
allowed_fails: 3
cooldown_time: 60网关的负载均衡策略包括轮询(round-robin)、最少延迟优先(least-latency)、成本优先(cheapest)、用量均衡(usage-based)。对于高可用场景,同一个模型名可以配置多个提供商(如 OpenAI 和 Azure OpenAI),网关在主提供商失败时自动切换到备用。
限流是 API 网关的核心功能。LLM 提供商通常有 RPM(每分钟请求数)和 TPM(每分钟 Token 数)限制,网关需要在应用侧实现请求队列和速率控制,防止突发流量触发提供商的限流。用户级别的限流则需要按 API Key 追踪用量,超出配额时返回 429 状态码。