校外生活模拟器3
118.60M · 2026-02-11
如果你在做 AI 应用开发,大概率遇到过这些问题:
这些问题的本质是:你的应用直接耦合了某个具体的模型 API。
解决方案很简单——在你的应用和模型之间加一层网关,统一接口、自动路由、故障转移。
直接上代码,Python + FastAPI,能跑的那种。
import os
import time
import httpx
import asyncio
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
app = FastAPI(title="AI API Gateway")
# 模型配置:按优先级排列
MODEL_PROVIDERS = [
{
"name": "deepseek",
"base_url": "https://api.deepseek.com/v1",
"api_key": os.getenv("DEEPSEEK_API_KEY", ""),
"model": "deepseek-chat",
"timeout": 30,
"max_retries": 2,
},
{
"name": "openai",
"base_url": "https://api.openai.com/v1",
"api_key": os.getenv("OPENAI_API_KEY", ""),
"model": "gpt-4o-mini",
"timeout": 30,
"max_retries": 1,
},
{
"name": "anthropic",
"base_url": "https://api.anthropic.com/v1",
"api_key": os.getenv("ANTHROPIC_API_KEY", ""),
"model": "claude-3-5-sonnet-20241022",
"timeout": 30,
"max_retries": 1,
},
]
# 健康状态追踪
provider_health = {p["name"]: {"healthy": True, "last_fail": 0} for p in MODEL_PROVIDERS}
COOLDOWN_SECONDS = 60 # 故障冷却时间
async def call_provider(provider: dict, messages: list) -> dict:
"""调用单个模型供应商"""
headers = {
"Authorization": f"Bearer {provider['api_key']}",
"Content-Type": "application/json",
}
# Anthropic 的 API 格式略有不同
if provider["name"] == "anthropic":
headers = {
"x-api-key": provider["api_key"],
"anthropic-version": "2023-06-01",
"Content-Type": "application/json",
}
payload = {
"model": provider["model"],
"max_tokens": 4096,
"messages": messages,
}
url = f"{provider['base_url']}/messages"
else:
payload = {
"model": provider["model"],
"messages": messages,
"max_tokens": 4096,
}
url = f"{provider['base_url']}/chat/completions"
async with httpx.AsyncClient(timeout=provider["timeout"]) as client:
resp = await client.post(url, json=payload, headers=headers)
resp.raise_for_status()
return resp.json()
def normalize_response(provider_name: str, raw: dict) -> dict:
"""统一不同供应商的响应格式"""
if provider_name == "anthropic":
content = raw.get("content", [{}])[0].get("text", "")
model = raw.get("model", "")
else:
content = raw["choices"][0]["message"]["content"]
model = raw.get("model", "")
return {
"content": content,
"model": model,
"provider": provider_name,
}
@app.post("/v1/chat")
async def chat(request: Request):
"""统一聊天接口——自动路由到可用的模型"""
body = await request.json()
messages = body.get("messages", [])
preferred = body.get("provider", None) # 可选:指定供应商
errors = []
for provider in MODEL_PROVIDERS:
name = provider["name"]
health = provider_health[name]
# 跳过指定供应商以外的
if preferred and name != preferred:
continue
# 跳过冷却中的供应商
if not health["healthy"] and time.time() - health["last_fail"] < COOLDOWN_SECONDS:
continue
try:
raw = await call_provider(provider, messages)
provider_health[name]["healthy"] = True
return JSONResponse(normalize_response(name, raw))
except Exception as e:
provider_health[name] = {"healthy": False, "last_fail": time.time()}
errors.append(f"{name}: {str(e)}")
continue
return JSONResponse(
{"error": "All providers failed", "details": errors},
status_code=503,
)
@app.get("/health")
async def health():
"""查看各供应商健康状态"""
return {name: info for name, info in provider_health.items()}
pip install fastapi uvicorn httpx
export DEEPSEEK_API_KEY="sk-xxx"
export OPENAI_API_KEY="sk-xxx"
export ANTHROPIC_API_KEY="sk-xxx"
uvicorn gateway:app --port 8000
# 自动路由(优先 DeepSeek,失败自动切换)
curl -X POST
-H "Content-Type: application/json"
-d '{"messages": [{"role": "user", "content": "你好"}]}'
# 指定供应商
curl -X POST
-H "Content-Type: application/json"
-d '{"messages": [{"role": "user", "content": "你好"}], "provider": "openai"}'
# 查看健康状态
curl
MODEL_PROVIDERS 数组的顺序就是优先级。DeepSeek 排第一是因为性价比最高,OpenAI 和 Claude 作为备用。
某个供应商报错后,标记为"不健康"并进入 60 秒冷却期。在此期间跳过该供应商,直接尝试下一个。冷却结束后自动恢复。
不管后端用的是哪个模型,返回格式都是统一的 {content, model, provider},调用方完全不需要关心底层用的是谁。
这个 100 行版本是最小可用版。生产环境中你可能还需要:
| 功能 | 说明 |
|---|---|
| 流式响应 | SSE 支持,实现打字机效果 |
| 请求日志 | 记录每次请求的模型、耗时、token 数 |
| 成本追踪 | 按 token 计费,统计各模型花费 |
| 负载均衡 | 多个 API Key 轮询,避免单 Key 限流 |
| 缓存层 | 相同请求命中缓存,省钱又快 |
| 鉴权 | 给网关加 API Key,防止滥用 |
如果你不想自己造轮子,市面上也有现成的模型聚合方案:
搭一个 AI API 网关并不难,核心就三件事:统一接口、自动路由、故障转移。
100 行代码就能解决 90% 的场景。剩下的 10%(流式、缓存、监控),要么自己加,要么用现成的聚合平台。
重点是:别让你的应用跟任何一个模型供应商绑死。今天 DeepSeek 最强,明天可能是别人。保持灵活,才能永远用上最好的。
觉得有用?点个赞收个藏,这是我继续写的最大动力。有问题评论区见。