Skip to content

fix(gateway): drop sampling params rejected by Claude 4.7+ upstreams - #517

Merged
qxcnm merged 1 commit into
qxcnm:mainfrom
tom062119:fix/claude-sampling-params
Oct 30, 2026
Merged

qxcnm merged 1 commit into
qxcnm:mainfrom
tom062119:fix/claude-sampling-params

Conversation

@tom062119

Copy link
Copy Markdown
Contributor

变更摘要

  • 聚合 API 转发请求体时,如果路由后的上游模型是 Claude 4.7 及之后的模型(opus/sonnet/haiku 4.7+,以及 fable、mythos),去掉 temperature、top_p、top_k。
  • 原因:这些模型对上述采样参数直接返回 400,Anthropic 原生 Messages API 和 OpenAI 兼容端点 /v1/chat/completions 都一样(temperature 小于 1 即报错)。OpenAI 风格客户端几乎都会带 temperature,所以把这些模型配成聚合上游后,带参数的请求全部失败。
  • Claude 4.6 及更早的模型、非 Claude 模型、非 JSON 请求体和其它字段都保持不变。判断依据是模型覆盖后的上游模型名,与上游地址和供应商类型无关,compatible、codex、claude 类型的聚合 API 都适用。

复现方式

  1. 新建一个 compatible 类型的聚合 API,地址填 https://api.anthropic.com/v1,使用 Anthropic API Key。
  2. 把任一文本模型的聚合路由上游模型设为 claude-haiku-5-5(换成 claude-sonnet-5-5 或 claude-opus-5-5 结果相同)。
  3. 通过网关发送:
{
  "model": "<platform-model>",
  "temperature": 0.2,
  "max_completion_tokens": 200,
  "messages": [{"role": "user", "content": "hello"}]
}

修复前:上游返回 400,报错 invalid_request_error: `temperature` is deprecated for this model,网关向客户端返回 502。同样的请求去掉 temperature 后返回 200。

修复后:带 temperature 0.2 的非流式请求和带 temperature 0.7 的流式工具调用请求都返回 200,tool_calls 正常。上游分别为 claude-haiku-5-5、claude-sonnet-5-5,均为真实调用验证。路由到 claude-opus-4-6 时保留 temperature,该模型仍接受这个参数。

改动范围

  • Frontend
  • Desktop / Tauri
  • Service
  • Gateway / Protocol Adapter
  • Docs / Governance
  • Workflow / Release

主要文件

  • crates/service/src/gateway/upstream/protocol/claude_sampling.rs(新增):识别 Claude 4.7+ 模型名,兼容 anthropic. 和 anthropic/ 前缀以及带日期的快照后缀,并去掉不受支持的采样参数;包含单元测试。
  • crates/service/src/gateway/upstream/protocol/aggregate_api.rs:在 rewrite_body_for_candidate_transport 完成模型覆盖后调用上述函数;新增候选转发回归测试。
  • crates/service/src/gateway/upstream/protocol/mod.rs:注册模块。

验证

  • pnpm -C apps run test
  • pnpm -C apps run build
  • pnpm -C apps run test:ui
  • cargo test --workspace
  • 其他本地验证已说明

已执行的实际验证:

cargo test --locked --release -p codexmanager-service --lib upstream::protocol
  31 passed; 0 failed(新增 5 项:版本识别,流式/非流式 Chat 带工具,Responses 请求体,
  路由后候选转发只对 Claude 4.7+ 生效,旧 Claude/非 Claude/非 JSON 不变)
cargo test --locked --release -p codexmanager-service --lib
  1986 passed; 0 failed; 8 ignored
rustfmt --check(改动文件)通过
在 Windows(stable-x86_64-pc-windows-gnu)上编译 release 并部署到实际网关:
  compatible 聚合 API -> https://api.anthropic.com/v1,claude-haiku-5-5
  带 temperature 0.2 的 Chat 非流式请求:200
  带 temperature 0.7 的流式工具调用请求:200,finish_reason=tool_calls

未执行的验证与原因:

pnpm 前端相关:本次没有改动前端。
cargo test --workspace:只改动了 service 内的网关协议模块,按仓库规范执行了 codexmanager-service 包的 lib 测试。

风险与影响面

  • 只影响路由到 Claude 4.7+ 模型的聚合请求,且只删除这些模型本来就会拒绝的三个字段;其它模型的请求体逐字节不变(有测试覆盖)。
  • 不涉及数据库迁移、鉴权和端点。
  • 未包含:Claude Opus 5.5 / Sonnet 5.5 不支持强制工具调用(tool_choice 为 required 或指定函数时返回 400),会改变请求语义,本 PR 不处理。claude 类型 Responses→Messages 桥接里的 thinking.budget_tokens 在 Claude 4.7+ 上同样会被拒绝,也可以另开 PR 处理。

备注

  • 已确认未包含敏感 token、cookie、API key。

🤖 Generated with Claude Code

Claude 4.7 and later return 400 for temperature/top_p/top_k on both the
Messages API and Anthropic's OpenAI-compatible endpoint, while OpenAI-style
clients send temperature routinely. Aggregate transport now removes those
fields once the routed upstream model is Claude 4.7+; older Claude and
non-Claude request bodies are left byte-for-byte unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@qxcnm
qxcnm merged commit d3c5978 into qxcnm:main Oct 30, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants