主题
请求兼容性修正
Anthropic Messages API 对请求结构校验严格:历史消息里一个空文本块、一个没配对的 tool_use、一个已废弃的字段,都会让整个请求被拒(400)。
Zivv API 在转发前会检测并就地修正这类问题。因此同一份请求直连上游可能失败、经 Zivv 能成功——这是有意为之的兼容层,不是行为不一致。
本页列出全部修正项,按是否改变语义分组。若你的客户端依赖某项原始行为,请对照 「会改变语义的修正」一节。
适用范围
本页描述的是 Anthropic Messages 协议(POST /v1/messages)上客户端能直接观察到的 行为。OpenAI 与 Gemini 协议入口的请求会先经协议转换,转换本身已处理掉这些形态差异, 因此这份清单里的多数项对它们不适用。
POST /v1/messages/count_tokens 不做任何修正。
无损修正
这些修正只改结构或字段名,语义完全等价。不影响模型看到的内容。
| 客户端发送 | Zivv 的处理 | 直连上游 |
|---|---|---|
output_format(已废弃字段) | 迁移为 output_config.format | 400 |
max_completion_tokens(OpenAI 字段) | 迁移为 max_tokens | 400 |
role: "developer"(OpenAI 字段) | 归一为 system | 400 |
首条(或开头连续多条)role: "system" 消息 | 按序折进顶层 system 参数 | 400 |
role: "tool" 消息(OpenAI 形状) | 转为 user + tool_result 块 | 400 |
OpenAI 形状的 tool 定义({"function": {...}}) | 转为 Anthropic 形状 | 400 |
| 完全重复的 tool 定义 | 去重 | 400 |
tool_use.id 含非法字符(冒号、点、中文等) | 替为 _,tool_use 与 tool_result 两侧同步改写 | 400 |
没有配对 tool_use 的孤儿 tool_result 块 | 删除该块 | 400 |
image_url 块(OpenAI 形状) | 转为 Anthropic image 块 | 400 |
media_type 与图片实际格式不符 | 按文件魔数校正 | 400 |
空 text 块(text 为空或全空白) | 删除该块 | 400 |
空壳 thinking / redacted_thinking 块 | 删除该块 | 400 |
thought_signature、reasoning_content(其他厂商字段) | 删除 | 400 |
start_timestamp、stop_timestamp(网页端专属字段) | 删除 | 400 |
max_tokens 超出模型上限 | 收敛到该模型上限 | 400 |
max_tokens 缺失 | 补默认值 64000 | 400(必填字段) |
会改变语义的修正
以下修正在结构上救活了请求,但模型看到的内容或行为与你发送的不完全一致。 每一项都说明了原因与规避方式。
采样参数被剔除
temperature、top_p、top_k 一律不转发。
新一代模型(Opus 5 / Fable 5 / Opus 4.8 及之后)已整体移除这些参数,携带即 400; top_k 在开启思考时另有冲突(top_k must be unset when thinking is enabled)。 为保证同一份请求在所有模型上行为一致,统一剔除。
影响:无法通过 temperature: 0 追求确定性输出。当前模型代际本身也不再提供 这一能力。
孤儿 tool_use 补占位结果
Anthropic 要求每个 tool_use 块在紧接的下一条消息里有配对 tool_result。 当客户端裁剪或压缩历史时删掉了 tool_result 却留着 tool_use,请求会被拒。
Zivv 为缺失的那个补一条占位结果:
json
{
"type": "tool_result",
"tool_use_id": "toolu_...",
"content": "(tool result unavailable)"
}为什么补而不是删掉 tool_use:删掉会连带删除助手那一轮的动作记录,模型看到的 历史变成「它没调用过这个工具」,语义损失更大。补占位只是告知模型「工具调了但结果 不可用」——那本来就是事实。
影响:模型会看到这段占位文本,可能因此重试该工具或说明结果缺失。
规避:裁剪历史时成对删除 tool_use 与对应的 tool_result。
对话中途的 system 消息被并入相邻 user
部分模型不支持对话中途出现 role: "system"。Zivv 的处理分两步:
- 开头连续的
system消息 → 折进顶层system参数(无损) - 中途出现的
system消息 → 文本并入前一条user消息末尾(有损)
影响:system 的语义是「应用运营方的指令」,优先级高于用户输入;并入 user 后降级为「终端用户说的话」,模型对它的服从度下降。
为什么不并入顶层 system:顶层 system 位于 prompt cache 哈希前缀最前端, 往它追加内容会导致整段历史缓存全部失效。并入末条 user 只改动尾部,前缀 逐字不变,缓存照旧命中。
规避:把运营方指令全部放在顶层 system 参数或对话开头,不要插在中途。
thinking: {"type": "disabled"} 被删除
支持自适应思考的模型已取消 disabled 这个枚举值——思考由模型自行决定。上游返回的 建议就是「不指定该字段」,Zivv 照此删掉整个 thinking 字段。
影响:客户端本意是「不要思考」,删除后模型可能自行开启思考,多消耗 thinking token。
为什么没有更好的办法:disabled 已取消、budget_tokens: 0 不合法,当前没有 任何字段能在这批模型上表达「强制不思考」。要么这样送达、要么必然 400。
output_config.effort 被降档或删除
模型不支持 effort 时删除该字段;支持但没有 xhigh 档时降为 high。
影响:思考强度低于你的声明。
非法的 cache_control.ttl 被删除
ttl 只接受 5m 与 1h 两个字面量。写成 3600s、60m、1 hour 等形式会被拒, Zivv 删掉该 ttl 字段并保留 cache_control 本身。
影响:这轮缓存落回默认的 5 分钟档,而不是你想要的 1 小时。我们不去猜测 「60m 大概是想要 1h」——那需要替你做时长换算与取整决策。合法值原样不动。
规避:ttl 只写 "5m" 或 "1h"。
末条消息为 assistant 时追加 user
部分模型不支持 assistant 预填(This model does not support assistant message prefill)。Zivv 在末尾追加一条 {"role": "user", "content": "continue"},而不是 删掉那条 assistant——删掉会丢失客户端的引导意图。
影响:模型多看到一条内容为 continue 的用户消息。
规避:不要用末尾 assistant 做预填引导,改为写进顶层 system 或最后一条 user。
其他占位符
| 场景 | 注入内容 |
|---|---|
删空壳 thinking 后整条消息内容为空 | text 块 [Thinking removed] |
整段对话全是 system(折完后 messages 为空) | user 消息 continue |
role: "tool" 消息的 content 为空串 | tool_result 内容 (empty) |
均为「不补就必然 400」的场景,占位符是最小干预。
不修正的情况
以下属于内容问题而非结构问题,原样透传上游的错误,不做任何加工:
prompt is too long—— 上下文超出模型窗口- 图片超出尺寸或数量限制
- 模型不支持的参数组合(未在上表列出的)
- 客户端发送了不存在的
role(如role: "nonsense")—— 修法不唯一,不擅自猜测 - 账号或额度层面的错误 —— 见 错误码
如何确认某项修正是否生效
修正对客户端是静默的,响应里没有标记。若你怀疑某个字段被改写、或想确认自己的请求 命中了哪一项,请带上 request id 联系支持,我们能查到该次请求触发的修正项。
客户端原始行为
若你需要请求逐字不变地送达上游(例如做协议一致性验证),当前没有开关可关闭 本页的修正。如有此需求请联系支持。
