FastAPI + litellm 统一代理大模型 API:优雅实现成本监控与 Fallback 策略

1. 为什么需要统一代理?

现在的大模型 API 百花齐放。

OpenAI、DeepSeek、通义千问、文心一言……每个提供商都有自己的 SDK 和请求格式。如果你的应用需要调用多家模型,代码会变得杂乱无章,难以维护。

统一代理的核心思想是:用一个中间层屏蔽底层差异,让上游应用用一套标准接口访问所有模型。

它的好处很明显:

  • 接口统一:应用层只需关心 prompt,不用关心是哪个模型。
  • 故障转移:某个模型超时或报错,自动切换到备用模型。
  • 成本可观测:集中统计 token 消耗,方便核算费用。

下面介绍如何使用 FastAPIlitellm 快速搭建这样一个代理服务,并实现优雅的 fallback 和成本监控。

2. litellm 是什么?

简单说,litellm 是一个 Python 库,它把几十家大模型 API 的格式统一成了 OpenAI 的格式。

它的基本思想是:你只需要记住一个函数 completion(),传入 model 名称和 messages,它就能自动调用对应的 API。

例如:

import litellm

response = litellm.completion(
    model="openai/gpt-4",
    messages=[{"role": "user", "content": "Hello"}]
)

如果换成 DeepSeek,只需改 model 为 deepseek/deepseek-chat 并配置相应的环境变量。litellm 会自动处理鉴权和请求格式。

3. 整体架构设计

我们构建一个 FastAPI 应用,对外提供 /chat 接口。

内部流程如下:

  1. 接收请求(包含 prompt 和可选的模型列表)。
  2. 按优先级依次尝试模型,直到某个模型成功返回。
  3. 记录每次调用的 token 用量和成本。
  4. 返回最终结果给客户端。

我们可以这样理解:这是一个带有“断路器”和“计价器”的智能路由器。

4. 代码实现

4.1 环境准备

安装依赖:

pip install fastapi uvicorn litellm pydantic

设置环境变量(以 OpenAI 和 DeepSeek 为例):

export OPENAI_API_KEY="sk-xxx"
export DEEPSEEK_API_KEY="sk-yyy"

4.2 定义请求和响应模型

from pydantic import BaseModel
from typing import List, Optional

class ChatRequest(BaseModel):
    prompt: str
    models: List[str] = ["openai/gpt-4", "deepseek/deepseek-chat"]  # 按优先级排序
    temperature: Optional[float] = 0.7

class ChatResponse(BaseModel):
    text: str
    model_used: str
    total_cost: float

4.3 初始化成本跟踪

我们用一个全局列表来记录每次调用的成本(生产环境建议用数据库)。

import time
cost_records = []

def record_cost(model: str, tokens: int, cost: float):
    cost_records.append({
        "model": model,
        "tokens": tokens,
        "cost": cost,
        "timestamp": time.time()
    })

4.4 核心 Fallback 逻辑

这里是最关键的部分。我们写一个函数,依次尝试模型列表,直到成功。

import litellm
from fastapi import HTTPException

def call_with_fallback(models: List[str], prompt: str, temperature: float):
    last_exception = None
    for model in models:
        try:
            # 调用 litellm
            response = litellm.completion(
                model=model,
                messages=[{"role": "user", "content": prompt}],
                temperature=temperature
            )
            # 解析结果
            content = response.choices[0].message.content
            usage = response.usage
            prompt_tokens = usage.prompt_tokens
            completion_tokens = usage.completion_tokens
            total_tokens = usage.total_tokens

            # 计算成本(这里使用硬编码价格,实际应动态获取)
            # OpenAI gpt-4 约 $0.03/1k 输入,$0.06/1k 输出,这里简化处理
            cost = (prompt_tokens / 1000) * 0.03 + (completion_tokens / 1000) * 0.06

            # 记录成本
            record_cost(model, total_tokens, cost)

            return content, model, cost

        except Exception as e:
            last_exception = e
            continue  # 失败就尝试下一个模型

    # 所有模型都失败
    raise HTTPException(status_code=503, detail=f"All models failed: {last_exception}")

4.5 FastAPI 路由

from fastapi import FastAPI

app = FastAPI()

@app.post("/chat", response_model=ChatResponse)
async def chat_endpoint(request: ChatRequest):
    content, model_used, cost = call_with_fallback(
        models=request.models,
        prompt=request.prompt,
        temperature=request.temperature
    )
    return ChatResponse(
        text=content,
        model_used=model_used,
        total_cost=cost
    )

4.6 成本监控接口

我们再加一个接口,方便查看累计成本。

@app.get("/cost/stats")
async def get_cost_stats():
    if not cost_records:
        return {"total_cost": 0, "count": 0}
    total = sum(r["cost"] for r in cost_records)
    return {"total_cost": total, "count": len(cost_records)}

5. 更优雅的改进点

上面的代码已经可以工作,但还有几个可以“更优雅”的地方。

5.1 使用依赖注入共享记录

我们可以把 cost_records 封装成一个服务类,通过 FastAPI 的 Depends 注入,方便测试。

from fastapi import Depends

class CostService:
    def __init__(self):
        self.records = []

    def add(self, model, tokens, cost):
        self.records.append(...)

    def stats(self):
        ...

@app.post("/chat")
async def chat(request: ChatRequest, cost_service: CostService = Depends()):
    ...

5.2 动态获取价格

上面的代码硬编码了价格,不够灵活。我们可以从配置文件或数据库读取价格表。

PRICE_TABLE = {
    "openai/gpt-4": {"input": 0.03, "output": 0.06},
    "deepseek/deepseek-chat": {"input": 0.001, "output": 0.002},  # 假设数字
}

def calculate_cost(model, prompt_tokens, completion_tokens):
    prices = PRICE_TABLE.get(model, {"input": 0, "output": 0})
    return (prompt_tokens / 1000) * prices["input"] + (completion_tokens / 1000) * prices["output"]

5.3 异步调用提高并发

litellm 支持异步调用,使用 litellm.acompletion()。我们可以把 fallback 函数改为异步,提高并发能力。

async def call_with_fallback_async(models, prompt, temperature):
    for model in models:
        try:
            response = await litellm.acompletion(
                model=model,
                messages=[{"role": "user", "content": prompt}],
                temperature=temperature
            )
            # ... 处理
        except Exception:
            continue

然后在 FastAPI 路由中直接 await

6. 总结

通过 FastAPI 和 litellm,我们只用了不到 100 行代码就搭建了一个智能的模型代理网关。

它的核心价值在于:

  • 统一接口:应用层无需感知底层模型差异。
  • 自动故障转移:提升整体可用性。
  • 集中成本监控:方便预算控制和用量分析。

这套模式非常适合需要调用多个大模型、追求高可用和成本透明的场景。

希望这篇文章能帮助你构建自己的 AI 代理层。技术的魅力在于用简单的方式解决复杂的问题。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐