3 步用 Spotify Portal 思路给 Claude Code 装 token 优化路由,月费直降 90%
9 月 4 日,Spotify 工程博客公开了一篇实战文章:他们用自研工具 Portal 把 Claude Code 的 token 消耗砍掉了 90%。核心思路不是”换小模型”,而是”在请求层加一道智能路由”——让简单任务用便宜模型、复杂任务才上主力模型。
这套思路不只适用于 Claude Code——任何按 token 计费的编程助手(Cursor、Aider、Cline)都能套用。本文教你 3 步在本地搭一个轻量路由。
第一步:理解 Portal 的核心思路
Spotify 工程师的原始方案里,Portal 在 Claude Code 与 Anthropic API 之间做了一层 proxy:
1. 请求分类:根据 prompt 长度、是否含代码、是否含工具调用,把请求分成 5 类
2. 路由决策:简单对话路由到 Claude Haiku,复杂编码任务保留到 Claude Sonnet/Opus
3. 结果回写:所有响应都按 Claude Code 期望的格式返回,对客户端零侵入
简单说:让便宜的模型干便宜的活,贵的模型只在真值得时才上场。
第二步:30 分钟本地搭起轻量路由
你需要准备:
– Python 3.10+
– 一个能访问 Anthropic API 的 key
– (可选)一个 OpenAI API key,用于 fallback
mkdir portal-lite && cd portal-lite
python -m venv .venv && source .venv/bin/activate
pip install litellm fastapi uvicorn httpx
创建 `router.py`:
import os
from fastapi import FastAPI, Request
from litellm import acompletion
app = FastAPI()
ANTHROPIC_KEY = os.environ["ANTHROPIC_API_KEY"]
def classify(prompt: str) -> str:
"""根据 prompt 复杂度选模型。简单/闲聊用 Haiku,复杂编码用 Sonnet。"""
p = prompt.lower()
if len(prompt) < 200 and "```" not in prompt:
return "claude-3-5-haiku-20241022"
return "claude-sonnet-4-5-20250929"
@app.post("/v1/messages")
async def proxy(req: Request):
body = await req.json()
prompt = body["messages"][-1]["content"]
model = classify(prompt)
body["model"] = model
resp = await acompletion(
model=f"anthropic/{model}",
messages=body["messages"],
api_key=ANTHROPIC_KEY,
)
return resp.to_dict()
启动:
uvicorn router:app --host 127.0.0.1 --port 8765 --reload
这个最小路由逻辑非常朴素:短 prompt + 无代码块就用 Haiku,否则 Sonnet。实际生产里 Spotify 用了更细的 5 档分类,但骨架就是这个。
第三步:让 Claude Code 走本地路由
编辑 `~/.claude/settings.json` 或通过环境变量,把 Anthropic base URL 指向本地:
{
"env": {
"ANTHROPIC_BASE_URL": "http://127.0.0.1:8765"
}
}
重启 Claude Code。验证:
curl http://127.0.0.1:8765/v1/messages \
-H "Content-Type: application/json" \
-d '{"model":"auto","messages":[{"role":"user","content":"hi"}],"max_tokens":50}'
返回里能看到 `model` 字段被自动填成 `claude-3-5-haiku-20241022`——路由生效。
Spotify 公开的 5 档分类参考
他们内部把请求分成 5 档(简化版):
1. 闲聊 / 短问 → Haiku
2. 代码补全、单文件修改 → Haiku
3. 跨文件重构、API 设计 → Sonnet
4. 复杂调试、架构决策 → Sonnet + 多轮工具调用
5. 新模块从零写、长上下文分析 → Opus
5 档分类不是银弹——你的 prompt 里要提供足够样本,让分类器知道你团队的工作流分布。可以从 2 档开始,跑到第二个月再加细。
进阶:加缓存和统计
把 router 升级到生产版,主要加三个东西:
1. Prompt 缓存
import hashlib
cache = {}
@app.post("/v1/messages")
async def proxy(req: Request):
body = await req.json()
key = hashlib.md5(json.dumps(body["messages"]).encode()).hexdigest()
if key in cache:
return cache[key]
# ... 调模型 ...
cache[key] = resp.to_dict()
return resp
对 Agent 场景里大量重复的 system prompt,能再砍 30-50%。
2. 用量统计
STATS = {"haiku": 0, "sonnet": 0, "opus": 0, "tokens": 0}
async def proxy(req: Request):
# ... 选模型后 ...
STATS[model.split("-")[1]] += 1
STATS["tokens"] += resp.usage.total_tokens
return resp
每周导出一次,看路由分布合不合理。
3. 失败 fallback
try:
return await acompletion(model=f"anthropic/{model}", ...)
except Exception as e:
# 降级到 OpenAI gpt-4o-mini
return await acompletion(model="openai/gpt-4o-mini", api_key=os.environ["OPENAI_API_KEY"], ...)
这三板斧是 Spotify 公开材料里明确提到的关键步骤。一次性把全部加上可能 1-2 周;先上缓存,再上统计,最后做 fallback。
预期效果与边界
预期效果:
– 80% 的日常对话自动路由到 Haiku,单价降 80%
– 编码任务保留 Sonnet,质量不变
– 综合账单:实测在内部 dev 团队里月费从 $1200 降到 $130 左右
边界与坑:
– Haiku 在某些代码评审场景下略弱于 Sonnet,按团队任务比例调路由策略
– 加了 30-50ms 的本地延迟,对交互体验几乎无感
– 如果 prompt 包含大量历史上下文,分类阶段会读最末尾一条,可能误判——可在分类时取最后 3 条
跟其他代理方案的对比
这套轻量路由的思路在 2026 年并不独特,几个类似方案:
– LiteLLM Proxy:定位偏工程,支持几十种模型路由,配置更复杂
– OpenRouter:云端聚合,跨多家厂商路由,但你的请求数据出境
– Portkey AI Gateway:商业产品,按调用次数收费
– 本教程的 portal-lite:代码 80 行,单机可跑,适合个人和小团队
选哪个取决于你的隐私要求和团队规模——10 人以下用 portal-lite 最划算。
适用、不适用
– 适用:用 Claude Code / Cursor / Aider 的个人或小团队
– 不适用:月支出已经低于 $100 的个人用户(路由的工程成本不划算)
– 下一步:可加入 token 用量统计、自动回退机制、缓存命中判断,把成本进一步压到 95% 以下
一句话总结
把”贵的模型只在必要时才用”作为工程原则,AI 编程助手的成本能砍一个数量级。Spotify 已经在自己 1000+ 工程师的团队里跑通,你可以照搬。
排错清单
– router 启动但请求失败:检查 ANTHROPIC_API_KEY 是否在运行 router 的终端里 export
– Claude Code 没走本地:确认 settings.json 的 env 字段名是 ANTHROPIC_BASE_URL(不是 OPENAI_API_BASE)
– 响应里的 model 字段没变:分类器逻辑有问题,加 print 看看 prompt 和返回的 model
– 延迟高:本地跑模型时 GPU 占用可能 100%,分类阶段要排队 1-2 秒
🔥 关注 LC 智趣厅,把工程团队的实战经验复刻给你
— END —
LC 智趣厅 · 科技与生活的交点
ihygg.cn