维护咨询 大模型部署 问题解决 技能定制 大模型训练
如果你最近把 Anthropic API、Claude 工作流、提取脚本或自建 agent 从 Sonnet 4.x 升到 Sonnet 5,然后马上撞上这些问题,这篇就是给你的:
- 模型名一换成
claude-sonnet-5,请求就直接报400 - 同样的代码在 Sonnet 4.6 正常,到了 Sonnet 5 突然开始空结果、截断或 JSON 解析错
- 长文档抽取、强制 tool use、结构化输出,升级后要么变浅、要么结果静默坏掉
- 你明明没改 prompt,只是升级模型,成本和响应行为却变了
这篇教程适合两类人:
- 直接调用 Anthropic API,把 Claude 接到你自己的产品、脚本或工作流里的人
- 用 Claude Code、n8n、后端服务或中间层包了一层 Claude 调用,底层其实还是 Anthropic Messages API 的人
说明:本文里的模型行为、参数边界和 JSON 示例,均为基于 Anthropic 官方文档验证。本文没有把未在本文环境里实发的 Anthropic API 请求冒充成实机跑通结果。
先判断:你是不是中了 Sonnet 5 的迁移坑
| 现象 | 更像哪类问题 | 第一动作 |
|---|---|---|
一切正常,唯独切到 claude-sonnet-5 就 400 |
旧参数不兼容 | 先删 temperature/top_p/top_k 和旧 thinking 配置 |
response.content[0].text 以前好好的,现在报错或拿到空值 |
响应里前面多了 thinking block | 改成遍历 content blocks |
| 请求返回成功,但正文被截断,甚至几乎没有正文 | max_tokens 被 thinking 吃掉 |
检查 stop_reason,给 max_tokens 留余量或降 effort |
tool use 第二轮继续请求时报 400 invalid_request_error |
thinking block 被你过滤、重排或重构了 | continuation 时把 thinking blocks 原样带回 |
如果你现在的故障属于上面四种,别先去怪网络、SDK 或 SDK 版本。
Sonnet 5 的 breaking change 足够大,很多 Sonnet 4.x 时代“默认没事”的写法,升级后就是会炸。
适用场景
这篇主要处理下面几种真实场景:
- 你有一套 Sonnet 4.6 的文档抽取、分类、判定、审核或工具调用链路
- 你原来会给不同任务动态设置
temperature - 你还在用
thinking: {type: "enabled", budget_tokens: N} - 你把
response.content[0]当成固定文本块,或者用“空字符串兜底”吞掉解析异常 - 你会把上一次 assistant 消息拼回去继续 tool use,但中间做了 block 过滤
如果你只是用 Claude Code 聊天,不自己调 API,这篇不是首选。
你更应该先看:
- Sonnet 5 高 effort 烧额度怎么办?用 /model、/effort 和 /usage-credits 把 Claude Code 成本压下来
- Claude Sonnet 5 怎么在 Claude Code 里启用?更新、切换模型与回滚教程
先复现一遍:为什么 Sonnet 4.6 正常,Sonnet 5 就不行了
最常见的迁移事故是:你只换了模型 ID,其他参数一行没动。
比如你原来的请求长这样:
{
"model": "claude-sonnet-4-6",
"max_tokens": 4096,
"temperature": 0.2,
"thinking": {
"type": "enabled",
"budget_tokens": 2048
},
"messages": [
{
"role": "user",
"content": "提取这份工单里的高风险变更,只返回 JSON。"
}
]
}
你把模型改成 claude-sonnet-5 之后,官方文档明确说明会发生三类变化:
- adaptive thinking 默认开启
- manual extended thinking 不再支持,直接返回
400 - 非默认
temperature、top_p、top_k也会直接返回400
也就是说,这不是“偶发兼容性问题”,而是官方明确写出来的 breaking change。
原因判断:这次到底变了什么
Anthropic 官方文档里,和这次问题最相关的有 5 个点。
1. Sonnet 5 默认就会 thinking
Sonnet 4.6 没带 thinking 字段时,不会按 Sonnet 5 现在这套默认策略去思考。
Sonnet 5 则会默认跑 adaptive thinking。
这带来两个直接后果:
- 响应内容里可能先出现
thinkingblock,再出现text max_tokens不再是“只留给正文”的预算,而是 thinking + 正文共享
2. 旧 budget_tokens 写法直接废了
Sonnet 5 不支持下面这类手动 extended thinking:
{
"thinking": {
"type": "enabled",
"budget_tokens": 32000
}
}
这类请求在 Sonnet 5 上会直接 400。
正确方向是改成 adaptive thinking,并用 effort 控制深浅。
3. 非默认采样参数不再默默忽略,而是直接 400
如果你以前用:
temperaturetop_ptop_k
给不同任务做“创意一点 / 保守一点”的调参,迁到 Sonnet 5 后先别继续传。
官方文档的结论很明确:非默认值返回 400。
4. 旧代码把 content[0] 当成文本,是这轮最容易漏掉的坑
官方 primer 对 extended thinking 的说明很直接:开启 thinking 后,响应会包含 thinking content block,然后才是 text block。
所以你如果沿用下面这种写法:
text = response.content[0].text
在 Sonnet 5 上就很危险:
- 有时拿到的不是文本块
- 有时你在异常处理里把它吞了,最后变成“成功但空输出”
- 有时正文被截断了,你还以为请求完整结束了
5. 新 tokenizer 会让你旧的预算心智失准
官方说明 Sonnet 5 的新 tokenizer 会让同样文本大约多出 30% token。
这会直接影响:
- 你的
max_tokens - 你的成本估算
- 你的上下文容量
- 你的结构化输出任务稳定性
第一步:先把会直接 400 的旧参数删掉
下面这几项,迁到 Sonnet 5 后优先排查:
thinking: {type: "enabled", budget_tokens: N}- 非默认
temperature - 非默认
top_p - 非默认
top_k
更稳的基础请求,可以先改成这样:
{
"model": "claude-sonnet-5",
"max_tokens": 8192,
"output_config": {
"effort": "medium"
},
"messages": [
{
"role": "user",
"content": "提取这份工单里的高风险变更,只返回最终结果。"
}
]
}
这里有三个关键点:
- 不再传旧
budget_tokens - 不再传非默认采样参数
- 先用
medium,不要一上来默认high
上面的 output_config.effort 与 Sonnet 5 的 adaptive thinking,均为基于 Anthropic 官方文档验证。
第二步:不需要思考块的任务,显式关掉 thinking
如果你的任务本来就是:
- 简单抽取
- 字段改写
- JSON 转换
- 规则明确的结构化输出
那你完全可以先把 thinking 关掉,换更低延迟、更稳定的输出。







暂无评论内容