通过LiteLLM代理将Claude Code路由到DeepSeek V4,用Haiku级成本完成探索性任务,仅对需要深度推理的工作才调用昂贵的主力模型,实现性价比最优的模型路由。
这是关于 model 路由和信任分层系列的一部分。这篇是无聊但能用的那半部分——没有 bug 追踪,只是一个在两台机器上干净运行了几个月的配置。
Claude Code 做一件事很擅长:谨慎的、限定范围的编辑,背后有真正的 plan-then-execute 循环支撑,以及你已经付费订阅的服务。不是每个任务都需要这样。探索性阅读、"总结一下这个目录"、草稿类用完即弃的工作——这些大多数不需要最有能力的模型盯着每一个 token。
解决方案是为这类工作准备一个更便宜的后端。问题是:Claude Code 只认 Anthropic 的 Messages API。它没有内置的"同一工具、不同模型"概念。所以问题是如何指向另一个地方而不放弃这个界面。
Trusted agent: claude — real Anthropic subscription, default session
Cheap agent: claude-cheap — same CLI, routed through a self-hosted proxy
Proxy: LiteLLM, translating Anthropic-format requests to
DeepSeek V4 (pro for Sonnet-tier calls, flash for Haiku-tier)
served through an OpenRouter API
Transport: a persistent SSH tunnel from a small VPS back to each machine
代理本身不是新东西。它和已经路由着另一条内容流水线的 LiteLLM 实例是同一个。真正的工作是把 Claude Code 接入它:一个 shell 函数加几个环境变量。
核心技巧——我花了几周才学会——是把 ANTHROPIC_BASE_URL 指向 LiteLLM 的 /v1/messages 端点,而不是 LiteLLM 也暴露的 OpenAI 兼容路径。Claude Code 只认 Anthropic 的 shape,所以 OpenAI 形状的端点会以看起来像客户端 bug 的方式失败,但实际上不是。一旦 LiteLLM 坐对端点并在底层做翻译,Claude Code 完全不知道它其实没在和 Anthropic 说话。
唯一值得提醒的一个 bug
Claude Code 的 Plan Mode 会给它的请求附加一个 context_management 参数。Anthropic 的 API 能处理它。其他大多数后端不认识这个参数,会以 400 拒绝整个请求——这看起来像是 Plan Mode 本身坏了,其实是下游模型从来没打算接受这个参数。
LiteLLM 配置里一行解决:
litellm_config.yaml
---
drop_params: true
这告诉 LiteLLM 静默剥离不支持的参数,而不是转发它们让后端拒绝调用。这样一来 Plan Mode 在哪个模型实际回答时都能正常工作。
两条命令,故意不对称
这部分比任何代理配置都值得复制:可信 agent 和便宜 agent 看起来不一样,是故意的。
claude——真家伙,全订阅,无包装。默认终端,默认 prompt。在这个 session 里犯错的代价最高,所以我不想要任何视觉噪音挡在我和它的操作之间。
claude-cheap——一个 shell 函数,掉进一个隔离的子 shell,给标签页重新命名加上独特标识和图标,退出时重置。不是美学问题:晚上 11 点在六个标签页之间切换,我要从结构上不可能把那个更便宜、更宽松的 session 和跑在我订阅上的那个搞混。贵的工具不给任何仪式感;便宜的工具要穿"戏服",因为搞反这个方向才是值得防备的失败模式。
# --- Cheap agent: DeepSeek via self-hosted LiteLLM proxy ---
claude-cheap() {
(
unset ANTHROPIC_API_KEY
export ANTHROPIC_BASE_URL=http://localhost:3456
export ANTHROPIC_AUTH_TOKEN=anything
export ANTHROPIC_MODEL=deepseek/deepseek-v4-pro
export ANTHROPIC_DEFAULT_SONNET_MODEL=deepseek/deepseek-v4-pro
export ANTHROPIC_DEFAULT_HAIKU_MODEL=deepseek/deepseek-v4-flash
export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
echo -ne "\033]0;🐋 DEEPSEEK-AGENT\007"
claude "$@"
echo -ne "\033]0;Terminal\007"
)
}
子 shell ( ... ) 是让这些导出用完即弃的原因——函数返回后它们不会泄漏到父 shell。ANTHROPIC_AUTH_TOKEN 设为一个假值,因为 LiteLLM 不检查它;它只需要有东西存在,这样 Claude Code 就不会拒绝启动。CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC 减少了回调 Anthropic 自有遥测端点的调用,因为这个 session 背后没有真正的 Anthropic 账号。
因为目标从来不是"让 Claude Code 更便宜"。它是一个 supervisor/executor 分离:订阅 session 做规划、review,任何我看到被搞坏会很恼火的事情。代理 session 处理量大、低风险的工作,它的输出在以同样方式被信任之前会经过 review。
和之前系列里为监控 agent 选云端模型而非本地模型的决策是同一形状——不是"哪个模型更聪明",而是"哪种失败模式我能接受,什么是最便宜的能达到标准的东西"。这里的轴是订阅成本而非设备端 vs 云端。底层问题是一样的:我愿意让什么东西出错,谁在盯着它出错。
还有一个纯本地变体:同样的两层模式,但便宜的那层完全跑在设备上而不是通过托管代理。这个遇到了工具调用格式不匹配的问题——那是另一个故事,我会单独写出来。