[Bug]: Bedrock Claude Opus 5.5 returns plain text for response_format json_schema because json_tool_call can’t be forced

在 LiteLLM 通过 Bedrock 调用 Claude Opus 5.5、并请求 response_format 为 json_schema 时,返回 200 但内容是纯文本而非 JSON,通常是因为 Bedrock 上 Opus 5.5 无法强制 tool_choice ,合成的 json_

快速结论:在 LiteLLM 通过 Bedrock 调用 Claude Opus 5.5、并请求 response_format 为 json_schema 时,返回 200 但内容是纯文本而非 JSON,通常是因为 Bedrock 上 Opus 5.5 无法强制 tool_choice,合成的 json_tool_call 工具只能以非强制方式下发,模型在短问题下直接跳过工具作答。优先排查结构化输出在这种模型/通道组合下是否真正走通了可用路径,而不是返回 HTTP 状态码。

适用环境:LiteLLM 通过代理调用 Bedrock 上的 us.anthropic.claude-opus-5-5;测试通道包括 Converse、invoke、/v1/chat/completions、/v1/responses、/v1/messages 及流式请求;LiteLLM 版本为 main 的 59db39626f(1.104.0 dev)以及 PyPI 1.102.1。Issue 中未提及其他操作系统或 Python 版本等信息。

最快修复方案:升级到包含 #49703 的 LiteLLM 版本。该修复对 Bedrock 上的 Opus 5.5 发送原生结构化输出,如果 Bedrock 拒绝,则回退到 json 工具方式重试。

注意事项:Issue 中说明 Bedrock 在 Opus 5.5 上会拒绝严格工具(strict tool use)和 output_config.format,因此不能靠简单地启用强制 tool_choice 解决;修复依赖 #49703 中的回退逻辑,升级后应在自己的通道(Converse/invoke/responses/messages、流式)上分别验证,因为原报告显示多个入口均受影响。

问题场景

用户在本地启动 LiteLLM 代理(配置中定义 bedrock/us.anthropic.claude-opus-5-5、bedrock/invoke/...、bedrock/converse/... 等模型),通过 curl 向 /v1/chat/completions 等接口发送带 response_format(type: json_schema,schema 名为 City)的请求,并设置 max_tokens: 4096。请求真实打到 Bedrock,期望拿到形如 {"name": "Paris", "country": "France"} 的 JSON,但 Opus 5.5 返回的是 "Paris"、"Paris." 之类的纯文本,HTTP 状态为 200。同配置下的 opus-5(强制工具,对照组)5/5 返回 JSON。

报错原文

[Bug]: Bedrock Claude Opus 5.5 returns plain text for response_format json_schema because json_tool_call can't be forced

实际现象为 200 响应但内容不是 JSON,例如:

"Paris"
"Paris."

原因分析

可能原因:Opus 5.5 在 Bedrock 上不能接受强制 tool_choice,LiteLLM 为 json_schema 合成的 json_tool_call 工具只能以 toolChoice: auto 的非强制方式下发,且该工具描述只有工具名本身。Issue 中的对照实验显示,直接 boto3 Converse 调用时,工具描述为 json_tool_call 时模型 0/5 调用该工具;而把描述改成 “Always respond by calling this tool. Its input is your final answer; do not reply in plain text.” 后达到 5/5。说明在短问题上,缺少明确引导时模型会跳过工具、直接用纯文本作答。

Issue 还指出,迁移指南建议使用 auto 配合严格工具或结构化输出,并在提示词中说明工具的适用场景;但 Bedrock 在 Opus 5.5 上同时拒绝严格工具和 output_config.format,剩下可用的只有提示词层面的引导。最终修复(#49703)改为对 Opus 5.5 发送原生结构化输出,并在 Bedrock 拒绝时回退到 json 工具重试。

环境排查

  • 确认 LiteLLM 版本:Issue 覆盖 main 的 59db39626f(1.104.0 dev)与 PyPI 1.102.1,两者均复现 0/5;需确认是否已包含 #49703。
  • 确认调用通道:Converse(bedrock/...)、invoke(bedrock/invoke/...)、converse 显式前缀、/v1/chat/completions、/v1/responses、/v1/messages 以及 "stream": true 均在 Issue 中测试过,均返回纯文本。
  • 确认是否为对照模型:同配置下 bedrock/us.anthropic.claude-opus-5 可正常返回 JSON(5/5),可用于区分“模型/通道问题”与“通用配置问题”。
  • 确认是否依赖远程成本映射:Issue 中 LITELLM_LOCAL_MODEL_COST_MAP=True 与 PyPI 远程成本映射结果一致,不是成本映射导致的差异。
  • Issue 未提供操作系统、Python、CUDA、显卡或依赖版本信息,这些项目无法据此排查。

解决步骤

  1. 将 LiteLLM 升级到包含 #49703 的版本;该 PR 对 Bedrock 上的 Opus 5.5 发送原生结构化输出,并在 Bedrock 拒绝时回退到 json 工具方式重试。
  2. 升级后用与 Issue 相同的请求方式复测:向代理发送带 response_format(json_schema,City schema)的 /v1/chat/completions 请求,模型指向 bedrock/us.anthropic.claude-opus-5-5。
  3. 如仍返回纯文本,可优先尝试在提示词中明确要求必须调用该工具、输入即最终答案、不得用纯文本回复;这是 Issue 中对照实验里唯一被验证能提升工具调用率的做法(描述强化后 5/5),但它是通过工具描述生效的变通,不是原问题的正式修复。
  4. 分别检查其他通道(invoke、/v1/responses、/v1/messages、流式)是否也恢复为 JSON,因为原报告中这些入口的表现一致。

验证方法

重复执行多轮(Issue 中为 5 次)请求并解析 .choices[0].message.content:预期返回可被 json 解析的对象(如 {"name": "Paris", "country": "France"}),而不是 "Paris" 或 "Paris."。同时用 bedrock/us.anthropic.claude-opus-5 对照,确认两者行为一致;对 /v1/responses、/v1/messages 与流式请求也各做几次验证。

参考来源

BerriAI/litellm #42717

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 32064

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注