3 步用 Spotify Portal 思路给 Claude Code 装 token 优化路由,月费直降 90%

· 小白基础技术分享

9 月 4 日,Spotify 工程博客公开了一篇实战文章:他们用自研工具 Portal 把 Claude Code 的 token 消耗砍掉了 90%。核心思路不是”换小模型”,而是”在请求层加一道智能路由”——让简单任务用便宜模型、复杂任务才上主力模型。

3 步用 Spotify Portal 思路给 Claude Code 装 token 优化路由,月封面

这套思路不只适用于 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

Scroll to Top
微信公众号:LC智趣厅

扫码关注微信公众号
LC智趣厅