|
| 1 | +# brainstorm: DeepSeek 兜底 thinking 参数策略 |
| 2 | + |
| 3 | +## Goal |
| 4 | + |
| 5 | +厘清并收敛 `claude-code-deepseek-*` 兜底别名是否还需要在 `additional_drop_params` 中丢弃 `thinking` / `reasoning_effort`。目标是让 Claude Code 的 Anthropic `/v1/messages` fallback 保留 DeepSeek thinking 能力,同时避免 Chat/Responses 或 OpenAI 兼容路径把不兼容参数传给 DeepSeek。 |
| 6 | + |
| 7 | +## What I already know |
| 8 | + |
| 9 | +* 用户质疑 `ai/gateway/litellm/litellm.local.yaml` 中 `claude-code-deepseek-v4-pro` 仍配置 `additional_drop_params: [reasoning_effort, thinking]`。 |
| 10 | +* 当前 sanitizer 已不再禁用 top-level `thinking`,并且只清理无签名/不完整的历史 thinking block;带 `signature` 的 `thinking` 与带 `data` 的 `redacted_thinking` 会保留。 |
| 11 | +* 运行态源码显示原生 Anthropic messages 路径只对 `additional_drop_params` 中的 dotted nested path 做删除;普通字段名 `thinking` / `reasoning_effort` 主要影响 Chat/Responses / OpenAI 兼容参数转换路径。 |
| 12 | +* DeepSeek Anthropic 兼容接口可接受 top-level `thinking: {"type": "adaptive"}` 与 `output_config.effort`,真实 smoke 已验证 `/v1/messages` fallback 返回 200。 |
| 13 | +* 用户已选择 Approach B:移除 `claude-code-deepseek-*` 的 `additional_drop_params`,把该别名定位为 Claude Code Anthropic messages 专用兜底入口。 |
| 14 | + |
| 15 | +## Assumptions (temporary) |
| 16 | + |
| 17 | +* Claude Code 主路径是原生 Anthropic `/v1/messages?beta=true`,不是 OpenAI chat/completions。 |
| 18 | +* `claude-code-deepseek-*` 不承担 Chat/Responses 保守兼容职责;如果未来需要,应新增独立 safe 路由。 |
| 19 | + |
| 20 | +## Open Questions |
| 21 | + |
| 22 | +* 无。 |
| 23 | + |
| 24 | +## Requirements (evolving) |
| 25 | + |
| 26 | +* 明确 `additional_drop_params` 在 Anthropic messages 与 Chat/Responses 路径中的真实影响范围。 |
| 27 | +* 保持 GLM 429 fallback 到 DeepSeek 的 `/v1/messages` 链路可用。 |
| 28 | +* 避免再次引入 `thinking: disabled` 与 effort 冲突。 |
| 29 | +* 文档必须区分 “top-level current thinking 参数” 与 “历史 content thinking block”。 |
| 30 | +* `claude-code-deepseek-*` 不得通过 `additional_drop_params` 丢弃 `thinking` / `reasoning_effort`。 |
| 31 | + |
| 32 | +## Acceptance Criteria (evolving) |
| 33 | + |
| 34 | +* [x] 选定并记录 `claude-code-deepseek-*` 是否保留 `additional_drop_params` 的策略。 |
| 35 | +* [x] 如果修改 YAML,`newapi.yaml` 与 `litellm.local.yaml` 保持预期一致。 |
| 36 | +* [x] `/v1/messages?beta=true` fallback 仍返回 200。 |
| 37 | +* [x] sanitizer 日志中 top-level `thinking` 不被降级,signed thinking 不被误删。 |
| 38 | +* [x] 文档与 Trellis spec 同步记录最终策略。 |
| 39 | + |
| 40 | +## Definition of Done (team quality bar) |
| 41 | + |
| 42 | +* Tests added/updated (unit/integration where appropriate) |
| 43 | +* Lint / typecheck / CI green |
| 44 | +* Docs/notes updated if behavior changes |
| 45 | +* Rollout/rollback considered if risky |
| 46 | + |
| 47 | +## Out of Scope (explicit) |
| 48 | + |
| 49 | +* 不在本任务中重写 LiteLLM Router fallback 机制。 |
| 50 | +* 不新增外部代理或替换 DeepSeek Anthropic 上游。 |
| 51 | +* 不处理 `.codex/config.toml` 与 `.shrimp-data/` 这些已有未提交工作区改动。 |
| 52 | + |
| 53 | +## Research Notes |
| 54 | + |
| 55 | +### Code inspection |
| 56 | + |
| 57 | +* `ai/gateway/litellm/litellm.local.yaml` 与 `ai/gateway/litellm/newapi.yaml` 的 DeepSeek 兜底别名仍配置 `additional_drop_params: [reasoning_effort, thinking]`。 |
| 58 | +* LiteLLM 容器内 `llm_http_handler.py` 的 Anthropic messages path 只从 `additional_drop_params` 中取 dotted nested path 并对 `anthropic_messages_optional_request_params` 做删除,普通字段名不会删除原生 messages 的 top-level `thinking`。 |
| 59 | +* LiteLLM `utils.py` 中 `_should_drop_param` 会让普通字段名 drop 作用于 OpenAI 兼容参数映射路径。 |
| 60 | + |
| 61 | +### Feasible approaches |
| 62 | + |
| 63 | +**Approach A: 保守保留 drop(当前状态)** |
| 64 | + |
| 65 | +* How it works: 保留 `additional_drop_params: [reasoning_effort, thinking]`,原生 `/v1/messages` 依靠 sanitizer 保留 top-level thinking;Chat/Responses 继续丢弃这两个参数。 |
| 66 | +* Pros: 对非 Claude Code 路径更保守,减少未知兼容风险。 |
| 67 | +* Cons: 配置语义容易误导,名字叫 Claude Code 但 Responses 路径会失去 thinking。 |
| 68 | + |
| 69 | +**Approach B: 移除 drop(推荐,如果该别名只给 Claude Code 用)** |
| 70 | + |
| 71 | +* How it works: 从 `claude-code-deepseek-*` 别名移除 `additional_drop_params`,让 DeepSeek Anthropic 兼容接口接收当前 thinking/effort;历史 content block 仍由 sanitizer 清理。 |
| 72 | +* Pros: 语义最一致,DeepSeek thinking 能力不被配置层静默拿掉。 |
| 73 | +* Cons: 如果有人直接用该别名走 Chat/Responses,可能重新暴露 provider 参数兼容问题。 |
| 74 | + |
| 75 | +**Approach C: 拆路由** |
| 76 | + |
| 77 | +* How it works: `claude-code-deepseek-*` 移除 drop,新增 `deepseek-compat-safe-*` 之类路由给 Chat/Responses 保守 drop。 |
| 78 | +* Pros: 能力与兼容边界最清晰。 |
| 79 | +* Cons: 配置更复杂,fallback 规则和文档都要增加维护成本。 |
| 80 | + |
| 81 | +## Technical Notes |
| 82 | + |
| 83 | +* 相关文件: |
| 84 | + * `ai/gateway/litellm/litellm.local.yaml` |
| 85 | + * `ai/gateway/litellm/newapi.yaml` |
| 86 | + * `ai/gateway/litellm/callbacks/deepseek_thinking_sanitizer_core.py` |
| 87 | + * `.trellis/spec/infra/litellm-gateway.md` |
| 88 | + * `ai/gateway/litellm/litellm.md` |
| 89 | +* Context7 查询 LiteLLM 文档未直接返回 `additional_drop_params` 专门章节;以运行容器源码为准。 |
| 90 | + |
| 91 | +## Decision (ADR-lite) |
| 92 | + |
| 93 | +**Context**: `claude-code-deepseek-*` 是 GLM 429 后的 Claude Code Anthropic messages 兜底入口。上轮保留 `additional_drop_params: [thinking, reasoning_effort]` 是为了 Chat/Responses 路径保守兼容,但会让配置语义变成“Claude Code 兜底仍静默丢弃 thinking/effort”。 |
| 94 | + |
| 95 | +**Decision**: 采用 Approach B,移除 `claude-code-deepseek-*` 的 `additional_drop_params`。Claude Code 兜底路由保留当前 top-level `thinking`、`reasoning_effort` 与 `output_config.effort`;历史 content thinking 兼容仍由 sanitizer 处理。 |
| 96 | + |
| 97 | +**Consequences**: Claude Code fallback 保留 DeepSeek thinking / effort 能力;如果未来要支持 Chat/Responses 的保守 DeepSeek 兼容,应新增独立 safe 路由,而不是复用 `claude-code-deepseek-*`。 |
0 commit comments