FastAPI 实战:构建企业级多模型 API 网关
背景
最近在做大模型 API 接入相关的项目,需要解决几个问题:
各厂商 API 格式不统一,切换成本高
需要统一鉴权、限流、日志
业务层不想关心底层是哪个模型
于是决定用 FastAPI 搭建一个 API 网关,统一封装对外暴露。
架构设计
整体架构:客户端 -> API 网关(FastAPI)-> 大模型厂商 API
网关核心职责:
协议转换:统一 OpenAI 格式,后端适配各厂商
负载均衡:多 Key 轮询,避免单 Key 限流
熔断降级:某厂商挂了自动切换
日志监控:记录调用量、延迟、成功率
核心代码
统一请求模型
from pydantic import BaseModel
from typing import Optional, List
class ChatMessage(BaseModel):
role: str
content: str
class ChatRequest(BaseModel):
model: str
messages: List[ChatMessage]
temperature: Optional[float] = 0.7
max_tokens: Optional[int] = 2048
多厂商路由
import httpx
from fastapi import FastAPI, HTTPException
app = FastAPI()
PROVIDERS = {
"deepseek-chat": {"base_url": "https://api.deepseek.com", "key": "sk-xxx"},
}
@app.post("/v1/chat/completions")
async def chat_completion(request: ChatRequest):
provider = PROVIDERS.get(request.model)
if not provider:
raise HTTPException(status_code=400, detail="Unsupported model")
async with httpx.AsyncClient() as client:
response = await client.post(
f"{provider['base_url']}/v1/chat/completions",
headers={"Authorization": f"Bearer {provider['key']}"},
json=request.dict(),
timeout=60.0
)
return response.json()
轮询负载均衡
from itertools import cycle
class KeyPool:
def __init__(self, keys: List[str]):
self.keys = cycle(keys)
def get_key(self):
return next(self.keys)
openai_keys = KeyPool(["sk-key1", "sk-key2", "sk-key3"])
熔断降级
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10),
retry_error_callback=lambda _: fallback_response()
)
async def call_with_fallback(provider, request):
pass
踩坑记录
流式响应 SSE
大模型 API 支持流式返回,FastAPI 需要特殊处理:
from fastapi.responses import StreamingResponse
@app.post("/v1/chat/completions")
async def chat_stream(request: ChatRequest):
async def generate():
async with httpx.AsyncClient() as client:
async with client.stream("POST", url, json=request.dict()) as response:
async for chunk in response.aiter_text():
yield f"data: {chunk}\n\n"
return StreamingResponse(generate(), media_type="text/event-stream")
坑点:httpx 的 stream 和 aiter_text 要注意编码,否则中文会乱码。
超时控制
大模型响应慢,默认 5 秒超时不够:
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(max_workers=4)
def log_async(*args):
executor.submit(write_log, *args)
timeout = httpx.Timeout(60.0, connect=10.0)
并发性能
FastAPI 默认用 async,但某些阻塞操作(如日志写入)会拖垮:
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(max_workers=4)
def log_async(*args):
executor.submit(write_log, *args)
部署
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
docker build -t api-gateway .
docker run -d -p 8000:8000 api-gateway
生产环境注意事项
这套架构已经在实际项目中跑了一段时间,几点经验:
Key 池管理:建议用 Redis 存储 Key 状态,避免单点故障
限流策略:按用户 + 按 Key 双重限流,防止被刷
日志采集:接入 Prometheus + Grafana,实时监控 QPS 和延迟
灰度发布:新模型接入时,先切 5% 流量观察稳定性
总结
| 统一接口 | Pydantic 模型 + FastAPI 路由,新增模型只需改配置 |
| 厂商适配 | 配置化路由表,一行代码接入新厂商 |
| 负载均衡 | Key 池轮询,多 Key 自动轮询 |
| 熔断降级 | tenacity 重试,失败自动切换备用 |
| 流式输出 | StreamingResponse + SSE,支持 SSE 流式返回 |
关于作者
独立开发者,专注后端架构与 AI 工程化。
做过多个大模型接入相关的项目,熟悉 DeepSeek、OpenAI、Claude 等主流厂商的 API 对接和性能优化。
有技术问题欢迎交流。

136

被折叠的 条评论
为什么被折叠?



