Skip to content

请求兼容性修正

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.format400
max_completion_tokens(OpenAI 字段)迁移为 max_tokens400
role: "developer"(OpenAI 字段)归一为 system400
首条(或开头连续多条)role: "system" 消息按序折进顶层 system 参数400
role: "tool" 消息(OpenAI 形状)转为 user + tool_result400
OpenAI 形状的 tool 定义({"function": {...}}转为 Anthropic 形状400
完全重复的 tool 定义去重400
tool_use.id 含非法字符(冒号、点、中文等)替为 _tool_usetool_result 两侧同步改写400
没有配对 tool_use 的孤儿 tool_result删除该块400
image_url 块(OpenAI 形状)转为 Anthropic image400
media_type 与图片实际格式不符按文件魔数校正400
text 块(text 为空或全空白)删除该块400
空壳 thinking / redacted_thinking删除该块400
thought_signaturereasoning_content(其他厂商字段)删除400
start_timestampstop_timestamp(网页端专属字段)删除400
max_tokens 超出模型上限收敛到该模型上限400
max_tokens 缺失补默认值 64000400(必填字段)

会改变语义的修正

以下修正在结构上救活了请求,但模型看到的内容或行为与你发送的不完全一致。 每一项都说明了原因与规避方式。

采样参数被剔除

temperaturetop_ptop_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 的处理分两步:

  1. 开头连续的 system 消息 → 折进顶层 system 参数(无损)
  2. 中途出现的 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 只接受 5m1h 两个字面量。写成 3600s60m1 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 联系支持,我们能查到该次请求触发的修正项。

客户端原始行为

若你需要请求逐字不变地送达上游(例如做协议一致性验证),当前没有开关可关闭 本页的修正。如有此需求请联系支持。

Zivv — OpenAI / Anthropic / Gemini 多协议 AI Gateway