|
| 1 | +# LiteLLM Gateway Spec |
| 2 | + |
| 3 | +> 本规范记录 `ai/gateway/litellm` 的路由与跨供应商兼容约定。修改 LiteLLM 配置、Claude Code 网关入口或模型 fallback 时必须先阅读。 |
| 4 | +
|
| 5 | +--- |
| 6 | + |
| 7 | +## Scenario: Claude Code GLM 429 Fallback 到 DeepSeek |
| 8 | + |
| 9 | +### 1. Scope / Trigger |
| 10 | + |
| 11 | +- Trigger: 修改 `ai/gateway/litellm/*.yaml` 中 Claude Code GLM 入口、DeepSeek 兜底别名、`router_settings.fallbacks`、`additional_drop_params` 或 `litellm_settings.modify_params`。 |
| 12 | +- Scope: `cc-glmplan-opus` / `cc-glmplan-haiku` 主路由优先使用智谱 GLM Coding Plan;GLM 返回 429 或 LiteLLM `RateLimitError` 后短重试,仍失败才 fallback 到 DeepSeek Anthropic 兼容端点。 |
| 13 | +- Design intent: 主路由尽量保留 Claude Code extended thinking;兜底路由优先保证请求不中断。 |
| 14 | + |
| 15 | +### 2. Signatures |
| 16 | + |
| 17 | +- Client-facing model names: |
| 18 | + - `cc-glmplan-opus` |
| 19 | + - `cc-glmplan-haiku` |
| 20 | + - `claude-code-deepseek-v4-pro` |
| 21 | + - `claude-code-deepseek-v4-flash` |
| 22 | +- Provider model mapping: |
| 23 | + - `cc-glmplan-*` -> `anthropic/GLM-5.1` |
| 24 | + - `claude-code-deepseek-v4-pro` -> `anthropic/deepseek-v4-pro[1m]` |
| 25 | + - `claude-code-deepseek-v4-flash` -> `anthropic/deepseek-v4-flash` |
| 26 | +- Router fallback contract: |
| 27 | + - `cc-glmplan-opus` -> `claude-code-deepseek-v4-pro` |
| 28 | + - `cc-glmplan-haiku` -> `claude-code-deepseek-v4-flash` |
| 29 | + |
| 30 | +### 3. Contracts |
| 31 | + |
| 32 | +- Required environment keys: |
| 33 | + - `Z_AI_ANTHROPIC_API_BASE`: 智谱 Anthropic 兼容端点。 |
| 34 | + - `Z_AI_API_KEY`: 智谱 Coding Plan 密钥。 |
| 35 | + - `DEEPSEEK_ANTHROPIC_API_BASE`: DeepSeek Anthropic 兼容端点。 |
| 36 | + - `DEEPSEEK_API_KEY`: DeepSeek 密钥。 |
| 37 | + - `LITELLM_MASTER_KEY`: LiteLLM 对外鉴权密钥。 |
| 38 | +- Fallback-only parameter policy: |
| 39 | + - DeepSeek 兜底别名必须显式丢弃 `thinking` 与 `reasoning_effort`。 |
| 40 | + - DeepSeek 官方 Claude Code 直连配置推荐 `CLAUDE_CODE_EFFORT_LEVEL=max`;在 Anthropic 兼容接口里,DeepSeek 的 effort 语义对应 `output_config.effort`,不是 OpenAI 兼容接口里的 `reasoning_effort`。 |
| 41 | + - 不得把 `output_config` 加入 DeepSeek 兜底别名的 `additional_drop_params`;当前只丢弃 `thinking` 与 `reasoning_effort`,避免误伤 DeepSeek 官方 Anthropic effort 参数。 |
| 42 | + - 丢弃 `thinking` 会让 DeepSeek 兜底不再显式请求 extended thinking;这是用 fallback 质量上限换取 GLM 429 后链路不中断。 |
| 43 | + - 丢弃范围只绑定到 DeepSeek 兜底别名;不得在 GLM 主路由上全局禁用 Claude Code thinking。 |
| 44 | + - 如果 `claude-code-deepseek-*` 被直接调用,也会应用同一丢弃策略;因此该别名应被视为 fallback/兼容专用入口。 |
| 45 | +- LiteLLM settings: |
| 46 | + - `drop_params: true` 用于丢弃上游不识别的普通参数。 |
| 47 | + - `modify_params: true` 用于允许 LiteLLM 修正 Anthropic tool/thinking 历史块兼容问题。 |
| 48 | + |
| 49 | +### 4. Validation & Error Matrix |
| 50 | + |
| 51 | +| Condition | Expected Behavior | |
| 52 | +|-----------|-------------------| |
| 53 | +| GLM 正常可用 | `cc-glmplan-*` 直接走 GLM,保留 Claude Code thinking 语义 | |
| 54 | +| GLM 返回 429 / `RateLimitError` | LiteLLM 先按 retry policy 短重试 | |
| 55 | +| GLM 短重试耗尽 | Router fallback 到对应 `claude-code-deepseek-*` | |
| 56 | +| DeepSeek 收到 `thinking` / `reasoning_effort` | 配置必须在兜底别名处提前丢弃这些参数 | |
| 57 | +| DeepSeek 收到 `output_config.effort` | 不应通过 `additional_drop_params` 丢弃;这是 DeepSeek Anthropic 兼容接口承接 `CLAUDE_CODE_EFFORT_LEVEL=max` 的官方字段 | |
| 58 | +| 历史消息缺少完整 `thinking_blocks` | `modify_params` 允许 LiteLLM 做兼容修正,避免 fallback 被 Anthropic 兼容端点拒绝 | |
| 59 | +| GLM 与 DeepSeek 都失败 | LiteLLM 将最终错误返回给 Claude Code,不伪装成功 | |
| 60 | + |
| 61 | +### 5. Good/Base/Bad Cases |
| 62 | + |
| 63 | +- Good: GLM 429 后切到 DeepSeek,DeepSeek 不接收 `thinking` / `reasoning_effort`,请求以普通非-thinking 模式继续完成。 |
| 64 | +- Good: DeepSeek 兜底别名不丢弃 `output_config.effort`;如果 Claude Code / LiteLLM 以 DeepSeek Anthropic 官方字段表达 effort,`CLAUDE_CODE_EFFORT_LEVEL=max` 仍有机会透传。 |
| 65 | +- Base: GLM 正常响应时不触发 fallback,不改变 Claude Code 对 GLM 主路由的 thinking 使用方式。 |
| 66 | +- Bad: 全局丢弃 `thinking`,导致 GLM 主路由也失去 Claude Code extended thinking 能力。 |
| 67 | +- Bad: DeepSeek 兜底别名保留 `thinking`,fallback 后报 `content[].thinking` / `thinking_blocks` 相关 `invalid_request_error`。 |
| 68 | +- Bad: 看到 DeepSeek 官方推荐 `CLAUDE_CODE_EFFORT_LEVEL=max` 后,把 fallback 别名改成保留 `thinking`;直连 DeepSeek 与跨供应商 fallback 的历史消息完整性不同,不能混为一谈。 |
| 69 | + |
| 70 | +### 6. Tests Required |
| 71 | + |
| 72 | +- Config parse: YAML 必须能被项目现有解析方式读取。 |
| 73 | +- Config sync: 如果 `newapi.yaml` 与 `litellm.local.yaml` 应保持一致,修改后需要确认两者没有非预期差异。 |
| 74 | +- Route contract: 检查 `router_settings.fallbacks` 仍指向专用 DeepSeek 兜底别名。 |
| 75 | +- Parameter contract: 检查 `additional_drop_params` 只出现在 DeepSeek 兜底别名或其它明确的兼容专用路由上。 |
| 76 | +- Runtime note: 真实 429 fallback 依赖上游额度、密钥和实时响应;本地配置验证不能证明线上额度恢复或供应商端协议行为。 |
| 77 | + |
| 78 | +### 7. Wrong vs Correct |
| 79 | + |
| 80 | +#### Wrong |
| 81 | + |
| 82 | +```yaml |
| 83 | +litellm_settings: |
| 84 | + drop_params: true |
| 85 | + |
| 86 | +model_list: |
| 87 | + - model_name: "cc-glmplan-opus" |
| 88 | + litellm_params: |
| 89 | + model: "anthropic/GLM-5.1" |
| 90 | + - model_name: "claude-code-deepseek-v4-pro" |
| 91 | + litellm_params: |
| 92 | + model: "anthropic/deepseek-v4-pro[1m]" |
| 93 | +``` |
| 94 | +
|
| 95 | +问题:DeepSeek 兜底仍可能收到 Claude Code extended thinking 参数;跨供应商 fallback 时,历史消息缺少完整 `thinking_blocks` 会触发 `invalid_request_error`。 |
| 96 | + |
| 97 | +#### Correct |
| 98 | + |
| 99 | +```yaml |
| 100 | +model_list: |
| 101 | + - model_name: "claude-code-deepseek-v4-pro" |
| 102 | + litellm_params: |
| 103 | + model: "anthropic/deepseek-v4-pro[1m]" |
| 104 | + additional_drop_params: |
| 105 | + - reasoning_effort |
| 106 | + - thinking |
| 107 | +
|
| 108 | +litellm_settings: |
| 109 | + drop_params: true |
| 110 | + modify_params: true |
| 111 | +``` |
| 112 | + |
| 113 | +理由:DeepSeek 兜底别名是降级链路专用入口,优先保证 GLM 429 后可用;主 GLM 路由仍保留 Claude Code extended thinking。 |
| 114 | + |
| 115 | +#### DeepSeek effort vs thinking |
| 116 | + |
| 117 | +```yaml |
| 118 | +model_list: |
| 119 | + - model_name: "claude-code-deepseek-v4-pro" |
| 120 | + litellm_params: |
| 121 | + model: "anthropic/deepseek-v4-pro[1m]" |
| 122 | + additional_drop_params: |
| 123 | + - reasoning_effort |
| 124 | + - thinking |
| 125 | + # 不要加入 output_config;DeepSeek Anthropic 兼容接口用它承接 effort。 |
| 126 | +``` |
| 127 | + |
| 128 | +结论:`CLAUDE_CODE_EFFORT_LEVEL=max` 是 DeepSeek 官方 Claude Code 直连推荐配置;在 DeepSeek Anthropic 兼容接口里,effort 对应 `output_config.effort`。兜底配置丢弃 `reasoning_effort` 主要影响 OpenAI 风格参数,丢弃 `thinking` 则会关闭显式 extended thinking。该取舍只应用于跨供应商 fallback,因为 GLM 生成的历史 `thinking` 块不一定满足 DeepSeek/Anthropic 兼容端点对完整 thinking 历史的校验。 |
| 129 | + |
| 130 | +#### Deferred option: two-stage DeepSeek fallback |
| 131 | + |
| 132 | +```yaml |
| 133 | +router_settings: |
| 134 | + fallbacks: |
| 135 | + - cc-glmplan-opus: |
| 136 | + - claude-code-deepseek-v4-pro |
| 137 | + - claude-code-deepseek-v4-pro-safe |
| 138 | +``` |
| 139 | + |
| 140 | +说明:可以先尝试完整 DeepSeek 路由,再 fallback 到丢弃 `thinking` / `reasoning_effort` 的 safe 路由,以尽量保留 DeepSeek 官方 thinking 能力。但 LiteLLM YAML 不能按 DeepSeek 返回的精确错误文本改写同一请求后重放;两级路由会增加配置复杂度和一次失败重试延迟。当前策略选择直接让 DeepSeek 兜底路由进入 safe 模式,优先保证 GLM 429 后 Claude Code 不被中断。 |
0 commit comments