打造 AI 的 Token 永动机
让 AI 持续稳定地工作,不在于囤积多少 API Key,而在于架构层面把「输入」和「输出」都兜住。本文记录我用 LiteLLM 搭建的一套 Token 流水线:多 provider 容灾保障输入不断,MCP 工具网关拓展输出质量,以及如何把任意本地能力转化为 MCP 服务喂给 Agent。
一、问题的起点:Token 为什么会断?
用 AI Agent 写代码、做研究的人,大概都经历过这种时刻——深夜灵感来了,敲下一段 prompt,然后看到一行红字:
litellm.exceptions.APIError: upstream service unavailable
单一 API 的脆弱性不用多说:速率限制、服务宕机、余额不足、区域封锁……任何一个都能让你的工作流戛然而止。
解决思路其实很简单:不要依赖任何单一入口。与其把命运交给一家服务商,不如用一个网关把多家聚合起来,一家挂了自动切到下一家——这就是 LiteLLM 的 fallback 机制。
但真正落地时,有几个细节值得认真对待。
二、第一层:多 provider 的 fallback 容灾
2.1 核心思路
以 DeepSeek 模型为例,同一个 deepseek-v4-pro,通过多条不同的路径获取:
对上游的 Agent 来说,它只需要请求 LiteLLM-Text-deepseek-v4-pro 这一个模型名。至于这个请求走哪条路到达真正的模型——那是 LiteLLM 的事。
2.2 model_list 配置
在 LiteLLM 的 config.yaml 中,每个 provider 通道都注册为一个独立的 model entry:
model_list:
- model_name: LiteLLM-Text-deepseek-v4-pro
litellm_params:
model: openai/deepseek-v4-pro
api_base: https://provider-a.example.com/v1
api_key: os.environ/PROVIDER_A_API_KEY
- model_name: LiteLLM-Text-deepseek-v4-pro-ProviderB
litellm_params:
model: openai/deepseek-v4-pro
api_base: https://provider-b.example.com/v1
api_key: os.environ/PROVIDER_B_API_KEY
- model_name: LiteLLM-Text-deepseek-v4-pro-ProviderC
litellm_params:
model: openrouter/deepseek/deepseek-v4-pro
api_key: os.environ/PROVIDER_C_API_KEY
命名规范采用 {网关}-{模态}-{模型}-{Provider} 的格式,既能一眼看出归属,也方便在 fallback 配置中引用。
2.3 fallback 链配置
有了多个 provider 通道后,在 router_settings.fallbacks 中定义优先级链:
router_settings:
routing_strategy: usage-based-routing
allowed_fails: 5
num_retries: 2
cooldown_time: 18000
fallbacks:
- LiteLLM-Text-deepseek-v4-pro:
- LiteLLM-Text-deepseek-v4-pro-ProviderB
- LiteLLM-Text-deepseek-v4-pro-ProviderC
- LiteLLM-Text-deepseek-v4-pro-ProviderD
- LiteLLM-Text-deepseek-v4-pro-ProviderE
- LiteLLM-Text-deepseek-v4-flash:
- LiteLLM-Text-deepseek-v4-flash-ProviderB
- LiteLLM-Text-deepseek-v4-flash-ProviderC
- LiteLLM-Text-deepseek-v4-flash-ProviderD
关键参数说明:
| 参数 | 典型值 | 含义 |
|---|---|---|
routing_strategy | usage-based-routing | 按用量权重分配请求,而非简单轮询 |
allowed_fails | 5 | 连续失败 N 次后才触发冷却 |
cooldown_time | 18000 | 冷却 5 小时(秒)后重新尝试该 provider |
num_retries | 2 | 每个 provider 重试 N 次后才走 fallback |
usage-based-routing 会优先把请求发往用量较低的 provider,避免某个通道因频率限制被过早触发冷却——这是一种更"省着用"的策略。
部署这套配置后,日常工作流最直观的变化是:几乎不再看到 API 报错。偶尔某个 provider 抽风,LiteLLM 在日志里默默地切到下一个通道,整个过程对上游 Agent 完全透明。
这就是第一层保障——Token 输入不断流。
三、第二层:MCP 工具网关——让 Token 烧得更有价值
Token 稳定供应只是第一步。更关键的问题是:Agent 拿着这些 Token 能干什么?
一个裸 LLM 只能聊天。但接入了工具的 Agent——能搜索论文、能操作文献库、能在 Jupyter 里跑代码、能操纵桌面——产出的价值完全不在一个量级。
这就是 MCP(Model Context Protocol)的意义。而 LiteLLM 从 v1.78.0 开始,不仅能代理 LLM 请求,还能同时承担 MCP Gateway 的角色:把所有 MCP Server 注册到 LiteLLM,然后本机所有 Agent 客户端共享同一套工具池。
3.1 架构一览
一个网关,同时承担 LLM 代理和 MCP 工具联邦两份职责,所有 Agent 客户端共享同一组工具——不需要每个 Agent 各自配置一遍。
3.2 mcp_servers 配置样例
来看两个典型的 MCP Server 接入方式,它们并列写在同一段 mcp_servers 配置中:
mcp_servers:
arxiv:
transport: stdio
command: uvx
args:
- "--with"
- "mcp[cli]>=1.10.1,<2.0.0"
- "arxiv-mcp-server"
allow_elicitation: false
taibu:
transport: stdio
command: npx
args:
- "-y"
- "taibu-mcp"
allow_elicitation: false
其中,arxiv-mcp-server 让 Agent 具备了搜索、下载、阅读 arXiv 论文的能力——Agent 可直接调用 arxiv_search_papers 和 arxiv_read_paper,而不必再手动打开浏览器检索。taibu-mcp 则是一个传统文化工具集(八字、紫微斗数、六爻、奇门遁甲等);接入后,查表推算类工作可完全自动化,Agent 能直接输出结构化的命盘分析。
3.3 工具名映射规则
MCP Server 注册到 LiteLLM 后,暴露给 Agent 的工具名遵循固定格式:
mcp__litellm__<server_name>_<tool_name>
例如 arxiv server 的 search_papers 工具,在 Agent 侧看到的名称是 mcp__litellm__arxiv_search_papers。
LiteLLM 的 MCP Server 名称不能包含连字符 -,因为它会和 MCP 工具名前缀分隔符冲突。用下划线替代:paper-search → paper_search。
3.4 从"写完"到"写好"
有了工具加持,Agent 的工作方式发生了质变。举个例子:
- 没工具时:你问 Agent "最近有什么关于 multi-agent 协作的论文?"——它只能凭训练数据里的记忆编造或拒绝回答。
- 有 arxiv 工具后:Agent 真的去搜 arXiv,下载 PDF,读摘要,然后告诉你真实的论文标题、作者、核心贡献。你甚至可以让它顺便把 BibTeX 导出来,直接入库 Zotero。
Token 还是那些 Token,但产出的信息密度完全不同。这就是"烧得更有价值"的含义。
四、第三层:把任意能力变成 MCP Server
前两层用的大多是社区现成的 MCP Server。但真正的灵活性在于:你可以把自己需要的任何工具包装成 MCP Server,然后 Agent 就能用上。
这一节以 PaddleOCR 为例,走通"本地部署 → MCP 封装 → LiteLLM 注册"的完整链路。
4.1 为什么选 OCR?
OCR(光学字符识别)是一个看似传统但 Agent 极度需要的能力。很多有价值的信息存在于截图、扫描件、PDF 图片中——Agent 如果不能"看懂"图片里的文字,就只能干瞪眼。
PaddleOCR 是百度开源的 OCR 引擎,中文识别效果一流。把它封装成 MCP Server 后,Agent 就获得了从任意图像中提取文字的能力。
4.2 部署 PaddleOCR MCP Server
社区已经有 paddleocr-mcp 封装好了 MCP 接口。关键是要处理好 GPU 依赖:
mcp_servers:
paddleocr:
transport: stdio
command: uvx
args:
- --find-links
- https://www.paddlepaddle.org.cn/packages/stable/cu130/paddlepaddle-gpu/
- --with
- paddlepaddle-gpu>=3.3.0,<3.4.0
- --from
- paddleocr-mcp
- paddleocr_mcp
- --model
- PP-OCRv6
- --ppocr_source
- local
- --device
- gpu:0
env:
PADDLEOCR_MCP_DEVICE: "gpu:0"
几个值得注意的点:
-
--find-links而非--index:PaddlePaddle 的 GPU 版本需要从特定源安装。用--find-links指定 wheel 地址比全局切换 PyPI 索引更精准,不会污染其他依赖的解析。 -
--device gpu:0:OCR 模型推理在 GPU 上比 CPU 快一个数量级。如果是 CPU 环境,改为cpu即可。 -
PP-OCRv6:这是目前最新的模型版本,中文识别准确率极高。
注册成功后,LiteLLM 暴露的工具名是 mcp__litellm__paddleocr_ocr——Agent 调用它就能提取图片中的文字。
4.3 拓展思路:什么都能变成 MCP
PaddleOCR 只是一个例子。这个模式的威力在于可复制性:
无论是本地 GPU 推理、传感器数据采集、还是你写的某个 Python 脚本,只要包装成 MCP Server 的标准接口(stdio 或 HTTP),它就能进入 Agent 的工具池。
核心代码量通常不超过 100 行。以 Python 为例,目前有两个主流选择——官方 MCP Python SDK v2 和 Prefect 的 FastMCP,两者 API 非常接近:
官方 SDK v2(MCPServer):
from mcp.server import MCPServer
mcp = MCPServer("my-tool")
@mcp.tool()
def my_function(param: str) -> str:
"""工具描述——Agent 会看到这段文字来判断何时调用"""
# 你的业务逻辑
return result
Prefect FastMCP:
from fastmcp import FastMCP
mcp = FastMCP("my-tool")
@mcp.tool
def my_function(param: str) -> str:
"""工具描述——Agent 会看到这段文字来判断何时调用"""
# 你的业务逻辑
return result
两者的核心原语(tool / resource / prompt / completion)几乎一致。参数和返回值的类型注解会被自动转为 JSON Schema,在调用前后进行 Pydantic 验证——类型不对的参数直接被拦截,返回值不符合声明也会报错。v1.x 时代还需要手动写 asyncio.run(stdio_server(...))、函数必须 async;无论是 v2 的 MCPServer 还是 FastMCP,样板代码都已经消失。
4.4 选型:官方 SDK v2 vs Prefect FastMCP
社区里更流行的其实是 Prefect 维护的独立 fastmcp 包(pip install fastmcp,from fastmcp import FastMCP),日均下载量过百万,v2 SDK 的设计受了它很大启发。两者的 API 现在非常接近,但定位不同:
| MCP SDK v2.x(官方) | FastMCP(Prefect) | |
|---|---|---|
| 定位 | 协议的标准实现 | 全栈 MCP 框架 |
| 能力 | Server + Client | Server + Client + 交互式 App(工具可返回表单/图表/表格) |
| TypeScript | 无 | 有官方 fastmcp-ts 对应包 |
| 治理 | Linux 基金会,紧跟协议 spec | Prefect 独立维护,发布节奏更快 |
| 适合 | 需要与 spec 严格对齐、希望零额外依赖 | 想用最少的代码获得最多的功能、需要交互式 UI |
- 表达能力
- 性能
- 成熟度
| 能力 | MCP SDK v2.x | FastMCP(Prefect) |
|---|---|---|
| 交互式 UI | — | ✅ @mcp.tool(app=True) + Prefab 100+ 组件 |
| 认证 | TokenVerifier 协议 + OAuth 2.1 资源服务器 | 5 种 provider + 开箱即用的 GitHub / Google / Auth0 / Keycloak 等 |
| 中间件 | OpenTelemetry 追踪(标记临时性) | 7 种命名中间件 + 类型化自定义钩子 |
| 服务器组合 | — | ✅ parent.mount(child) |
| OpenAPI 生成 | — | ✅ FastMCP.from_openapi(spec) |
| 依赖注入 | Resolve(fn) 注解 | guard pattern |
无公开 benchmark。FastMCP v4 底层就是 SDK v2(pyproject.toml 直接依赖 mcp),协议层优化两者共享。
| 方面 | MCP SDK v2.x | FastMCP(Prefect) |
|---|---|---|
| 协议热路径 | 与 FastMCP 相同 | 与 SDK v2 相同 |
| 框架层开销 | 几乎没有 | 中间件 + 认证 + 组合层有额外开销 |
| 补偿机制 | — | KeyValueResponseCacheStore(Redis)命中缓存;响应截断中间件 |
| 线程模型 | 同步 def handler 在工作线程池运行 | 同(基于 SDK v2) |
| 方面 | MCP SDK v2.x | FastMCP(Prefect) |
|---|---|---|
| 最新版本 | v2.0.0(stable) | v4.0.0b1(beta) |
| 协议层历史 | v1 中 28 个版本打磨 | 累计 3,834 commits |
| 发布节奏 | Linux 基金会治理,稳定优先 | Prefect 独立维护,迭代更快 |
| 官方声明 | Production / Stable | "Pin an exact version and expect sharp edges." |
两者不是替代关系——FastMCP v4 是 SDK v2 的超集框架。
简单工具暴露 → SDK v2 完全够用;需要认证 / 中间件 / 交互式 UI → FastMCP 更省时间。
五、三层的协同效应
把三层放在一起看,它们不是独立的模块,而是一套递进增强的体系:
| 层级 | 解决的问题 | 效果 |
|---|---|---|
| Provider 容灾 | Token 供应不稳定 | 多通道 fallback,输入不断流 |
| MCP 工具网关 | Agent 能力单一 | 共享工具池,token 产出价值密度提升 |
| 自定义 MCP | 通用工具无法覆盖特殊需求 | 任意本地能力转化为 Agent 工具,打造独特工作流 |
三层叠加后的工作流程:
整个过程:Token 输入稳定,工具能力丰富,输出质量立体。这就是"Token 永动机"的含义——不是无穷无尽的 Token,而是让每一枚 Token 都产出尽可能多的价值。
六、实际效果与一点体会
前面三层讲的是架构设计,这一节看看它们在生产环境中实际跑起来的效果。
6.1 Provider 容灾:故障自动切换
下图是 LiteLLM Playground 的请求日志截图。注意 01:10:57 这个时间点:

同一秒内,7 条 LLM 请求全部返回 Failure——涉及 Logs、Guardrails Monitor、Teams、Internal Users、Organizations 等多个后台模块。几乎可以断定是上游服务商发生了故障:LiteLLM 自身正常运行(MCP 类型的请求仍然成功),但所有依赖该 LLM provider 的查询全部失败。
关键是从 01:13:35 开始,所有请求恢复正常。LiteLLM 在约两分半钟内完成了故障检测 → 冷却触发 → fallback 切换的全过程,后续请求全部路由到了备用 provider,对上游 Agent 完全透明。
注:这个断网是另一个程序偶然切断了本机到互联网的连接. 故这个试验只能说明本工具具有保持会话, 断网重连的能力; 不能完全说明具有自动切换大模型服务商的能力. 几天前的下图能更好的说明同一个大模型 deepseek-v4-pro 可以在多个供应商之间, 在额度耗尽之后 "瞬时" 切换的能力:

你不需要手动换 API Key,不需要重启服务,甚至不需要注意到它发生过——这就是第一层容灾的实际表现。
6.2 自定义 MCP:从"看图"到"用图"
第二张截图展示了一条完整的自定义 MCP 工具链路:

具体流程是:Agent 调用 mcp__litellm__paddleocr_ocr(就是第四节部署的 PaddleOCR MCP Server)提取了第一张截图中的全部文字——包括时间戳、请求类型、状态、Session ID、费用等完整表格数据,置信度 97.68%。随后 Agent 将提取的文字作为上下文,自动分析了故障时间线、恢复窗口和费用差异。
这个流程展现了第三层"自定义 MCP"的核心价值:Agent 不再是只能聊天的对话机器人,而是一个能"看图 → 识文 → 分析 → 输出结论"的完整工作管道。 每一步依赖的工具,都是你自己部署、自己控制的本地服务。
6.3 一点体会
回看这套架构的搭建过程,最大的感受是:Agent 时代的生产力不取决于你用了哪个模型,而取决于你为它搭建了怎样的基础设施。 模型会迭代、API 会涨价、provider 会调整策略——但只要网关和工具链在,换一个模型对你的工作流几乎没有影响。

如果你也在搭建自己的 Agent 工作环境,希望这三层思路能给你一些参考。
