← 返回文章列表

Anthropic 和 OpenAI API 协议有什么区别?

AI
  • # ai
  • # anthropic
  • # openai
  • # api

接入大模型时,经常会看到「OpenAI 兼容协议」和「Anthropic 协议」这两个选项。它们看起来都只是发送一组消息,再接收模型输出,似乎换一下接口地址和模型名就能互通。

普通文本聊天确实容易转换。到了工具调用、流式输出和推理参数,两者的结构差异就会直接影响客户端实现。这篇文章从接入代码的角度整理这些区别,同时附上相关参数文档。

先说清楚比较的是哪套接口

这里的「协议」指 HTTP API 的请求与响应约定,包括路径、请求头、JSON 字段和流式事件。

Anthropic 这一侧比较的是 Messages API。OpenAI 则需要分开看:

  • Chat Completions:以 messages 为输入,响应里有 choices。
  • Responses:以 input 为输入,响应里有 output,可以承载消息、工具调用等不同类型的条目。OpenAI 官方建议新项目使用这一接口。

看到第三方服务写「OpenAI 兼容」时,要继续确认它支持哪个端点、哪些字段。只支持 /v1/chat/completions,并不能推导出它也支持 /v1/responses。

协议格式也不决定模型来源。网关可以接受 OpenAI 格式的请求,再转换成 Anthropic 格式去调用 Claude。客户端使用的格式和后端运行的模型,是两个需要分别确认的配置。

一次文本请求,区别已经很明显

下面只展示请求体结构,YOUR_*_MODEL_ID 是占位符,需要换成账号可用的模型 ID。

Anthropic Messages 把从会话开始生效的系统指令放在顶层 system,普通对话消息使用 user 和 assistant:

{
  "model": "YOUR_CLAUDE_MODEL_ID",
  "max_tokens": 1024,
  "system": "用简洁的中文回答。",
  "messages": [
    { "role": "user", "content": "解释一下什么是闭包。" }
  ]
}

部分新 Claude 模型还支持在会话中途插入 role: "system" 的消息,但有模型和位置限制,不能把它放在 messages 的第一项。初始指令仍使用顶层 system。见 Messages 的 system role 说明。

Chat Completions 把指令也表示为消息。下面使用 developer,具体模型对 developer、system 的支持要看模型文档:

{
  "model": "YOUR_OPENAI_MODEL_ID",
  "max_completion_tokens": 1024,
  "messages": [
    { "role": "developer", "content": "用简洁的中文回答。" },
    { "role": "user", "content": "解释一下什么是闭包。" }
  ]
}

Responses 可以用顶层 instructions 配合 input:

{
  "model": "YOUR_OPENAI_MODEL_ID",
  "max_output_tokens": 1024,
  "instructions": "用简洁的中文回答。",
  "input": "解释一下什么是闭包。"
}

直连官方服务时,路径与常见 API Key 请求头也不同:

项目Anthropic MessagesOpenAI Chat CompletionsOpenAI Responses
POST 地址https://api.anthropic.com/v1/messageshttps://api.openai.com/v1/chat/completionshttps://api.openai.com/v1/responses
API KeyAuthorization: Bearer ...Authorization: Bearer ...Authorization: Bearer ...
API 版本头anthropic-version: 2023-06-01不使用这个版本头不使用这个版本头

Anthropic 也仍支持旧有的 x-api-key: ... 鉴权方式,多工作区 API Key 还需要 anthropic-workspace-id。三者的 JSON 请求都使用 Content-Type: application/json。Anthropic 的版本头是 API 版本约定,不是模型发布日期;官方 SDK 会自动处理常规鉴权和版本头。云平台托管入口的鉴权可能不同,不能直接套用这张表。相关说明见 Anthropic API 概览与 OpenAI 鉴权说明。

响应也需要各自解析。Anthropic 返回 content 数组,按 block 的 type 提取文本;Chat Completions 的文本通常在 choices[0].message.content;Responses 需要检查 output 条目的类型,其中消息的文本块使用 output_text。官方 SDK 还提供 response.output_text 这样的便捷读取方式,它与原始 HTTP 响应的字段结构要分开理解。可对照 Messages 使用说明和 Responses 迁移说明。

参数名称相似,不代表可以原样转发

输出长度是一个典型例子:

  • Messages 要求提供 max_tokens。
  • Chat Completions 使用 max_completion_tokens;旧字段 max_tokens 已被标记为弃用,也不兼容部分推理模型。
  • Responses 使用 max_output_tokens。

这些都是 token 上限,不是字符数,也不承诺模型一定生成这么长。OpenAI 的后两个字段包含可见输出和推理 token,不能把整个额度都当成最终答案的长度。参数定义见 Chat Completions 参数文档与 Responses 参数文档。

temperature 更容易被旧教程误导。Chat Completions 的接口文档定义了 0–2 的范围,但具体模型未必支持设置。Anthropic 文档仍列出旧有的 0–1 范围,同时已将该参数标记为弃用:Claude Opus 4.6 之后发布的模型不支持调节它,只接受 1.0 作为向后兼容值,其他值会返回 400。接入时应先看目标模型的限制,而不是给所有 Provider 默认传 temperature: 0.7。见 Anthropic temperature 定义。

有些参数还需要按能力重新组织:

用途Anthropic MessagesOpenAI Chat CompletionsOpenAI Responses
流式响应streamstreamstream
自定义停止序列stop_sequencesstop,部分模型不支持不能直接照搬这两个字段
推理控制thinking、output_config.effort,按模型选择reasoning_effort,按模型选择reasoning.effort,按模型选择
JSON Schema 输出output_config.formatresponse_formattext.format

这张表表示参数入口,不表示所有模型都支持相应能力。尤其是推理配置,手动 token budget 和 effort 等级并没有通用的一对一换算。不同提供商支持的 JSON Schema 子集和限制也不同,不能只修改字段名。可以继续查 Claude 结构化输出、OpenAI 结构化输出和各接口的参数定义。

工具调用的区别在整个往返过程里

两边都可以声明工具,让模型生成工具名和参数,再由应用执行。这里讨论的是应用侧执行的自定义工具;服务端工具有自己的执行流程。

以 get_weather 为例,Anthropic 的工具定义把 schema 放在 input_schema:

{
  "name": "get_weather",
  "description": "查询指定城市的天气",
  "input_schema": {
    "type": "object",
    "properties": { "city": { "type": "string" } },
    "required": ["city"],
    "additionalProperties": false
  }
}

Chat Completions 则用 type: "function" 包裹 function,schema 字段叫 parameters:

{
  "type": "function",
  "function": {
    "name": "get_weather",
    "description": "查询指定城市的天气",
    "parameters": {
      "type": "object",
      "properties": { "city": { "type": "string" } },
      "required": ["city"],
      "additionalProperties": false
    }
  }
}

Responses 的函数定义同样使用 parameters,但 name、description、parameters 直接放在工具对象上,不再嵌套一层 function。三个定义都作为请求的 tools 数组元素传入。相关格式见 Claude 工具定义和 OpenAI Function calling。

更大的区别是模型怎样提出调用,以及应用怎样交回结果:

环节Anthropic MessagesOpenAI Chat CompletionsOpenAI Responses
模型提出调用assistant 的 content 中出现 tool_use blockassistant 消息的 tool_callsoutput 中出现 function_call 条目
调用参数input 是 JSON 对象function.arguments 是 JSON 字符串arguments 是 JSON 字符串
应用交回结果user 消息里的 tool_result blockrole: "tool" 消息function_call_output 输入条目
关联调用tool_use_id 对应 tool_use.idtool_call_id 对应调用的 idcall_id 对应调用的 call_id

所以 Anthropic 的工具结果会放进一条 user 消息,这并不意味着它是用户亲自输入的文本。适配器需要查看 block 类型,保留工具调用关系。OpenAI 的字符串参数则需要解析和校验,不能直接当作函数参数对象使用。交回结果时还要保留此前的调用上下文:Messages 和 Chat Completions 通常重传历史,Responses 可重传条目或引用前一个响应。完整流程见 Claude Tool use和 OpenAI Function calling。

工具结果的顺序也要保留。Anthropic 的 tool_result 应紧随提出调用的 assistant 消息,并放在该 user 消息内容数组的前部,先于普通文本。见 Claude 工具调用处理。

工具选择也有名称差异。Anthropic 强制使用某个工具时,使用 {"type":"tool","name":"get_weather"};Chat Completions 使用 {"type":"function","function":{"name":"get_weather"}}。要求必须调用工具,前者是 {"type":"any"},后者是 "required"。指定名称与限制调用次数是两个配置,不能混为一谈。

这些选项还受模型与推理模式限制。Anthropic 手动 extended thinking 模式只支持 auto 和 none,部分新模型无论 thinking 配置如何都不支持 any 和 tool。适配器不能保证所有模型都能强制调用工具,具体支持情况要查 Claude 工具选择限制。

都是 SSE,事件结构仍然不同

三套接口都可以设置 stream: true,通过 Server-Sent Events 接收增量。但 SSE 只规定传输形式,客户端仍要按各自的事件结构组装响应。

Anthropic 按消息和内容块发送事件,常见顺序是:

message_start
content_block_start
content_block_delta
content_block_stop
message_delta
message_stop

同一条消息可以有多个内容块。文本增量是 text_delta,工具参数增量是 input_json_delta,要按 block 的 index 分别累积。流式工具参数仍然是 JSON 片段,不能因为最终 input 是对象,就假设每个片段都能单独解析。可以在内容块结束后解析拼接结果,或使用支持部分 JSON 的增量解析器。实际事件还可能包含 ping、error 等类型。见 Claude Streaming messages。

Chat Completions 常见的是 choices[].delta:文本看 delta.content,工具调用看 delta.tool_calls,正常完成的流以 data: [DONE] 结束。启用 stream_options.include_usage 后,结束标记前会多发一个用量 chunk,其 choices 始终为 [],解析器不能始终假设存在 choices[0]。流中断时可能收不到最终用量 chunk。见 Chat Completions 流式参数。

Responses 使用带类型的事件,例如 response.output_text.delta、response.function_call_arguments.delta 和 response.completed,也要处理 response.failed 和 response.incomplete 终态事件。复用 Chat Completions 的 delta 解析器会漏掉这些结构。见 OpenAI Streaming API responses。

兼容层应该保留哪些信息

Messages 和 Chat Completions 的普通多轮调用都需要由客户端提供对话上下文。Responses 还提供 previous_response_id 和 Conversations 等状态管理方式。引用前一个响应省去了手动重传历史的工作,但历史上下文仍计入输入计费;使用 previous_response_id 时,前一次顶层的 instructions 不会自动沿用,需要在新请求里重新提供。见 OpenAI Conversation state和 Responses instructions 参数。

实现多 Provider 接入时,可以先统一应用真正需要的概念:文本块、工具调用、工具结果、生成状态和用量。再由各自的适配器负责序列化请求与解析响应。厂商特有的推理、缓存和服务端工具配置,可以保留独立配置入口。

尤其不要在适配时只留下文本。如果一次响应提出了工具调用,应用需要执行工具再继续;如果因为输出上限结束,答案可能尚未生成完整。Anthropic 的 stop_reason、Chat Completions 的 finish_reason 和 Responses 的状态需要分别处理,不能把所有结束情况都当成「模型已经回答完了」。

日常工作接入时怎么选

我的建议是:主要用哪家的模型,就优先用哪家的原生 API;需要多模型切换时,再统一业务接口。先把实际任务接通,再根据需要增加适配层,通常更容易控制接入成本。

可以按项目现状来选择:

场景建议选择主要考虑
新项目主要使用 ClaudeAnthropic Messages直接使用 Claude 的参数和能力,减少转换
新项目主要使用 OpenAIOpenAI Responses方便继续扩展工具调用和会话管理
已有 Chat Completions 项目,运行稳定继续使用,按需求迁移有明确的新能力需求时再承担迁移成本
多模型接入,主要做问答、摘要、翻译可以使用 OpenAI 兼容格式确认服务支持所需端点和参数后,减少重复接入工作
多模型 Agent,涉及工具、推理和缓存原生 API 配合适配层保留能力差异,分别处理工具往返和流式状态

OpenAI 官方仍支持 Chat Completions,同时建议新项目使用 Responses。因此,已有系统没有必要仅仅因为出现了新接口就立即重写。可以先把需要新能力的部分接到 Responses,再根据维护成本决定是否迁移其他调用。见 OpenAI 官方迁移说明。

选择兼容格式时,要确认「请求成功」是否代表参数生效。例如 Anthropic 的 OpenAI SDK 兼容层会忽略 response_format 和工具定义里的 strict。如果业务依赖严格的结构化输出,请求能返回文本还不够,需要确认对应约束真的被执行。Anthropic 将这一兼容层主要定位为测试和比较模型能力,多数生产场景建议使用原生 Claude API。这里说的是 Anthropic 自己提供的兼容层;第三方网关的支持情况要单独查看。见 Anthropic OpenAI SDK 兼容说明。

如果是自己开发业务系统,可以先用一家厂商的官方 SDK,只传任务需要的参数。确实需要接入第二家时,再封装应用自己的模型服务接口,统一文本、工具调用、工具结果、用量和结束状态。厂商特有的推理与缓存配置保留独立入口,避免为了统一字段而丢失业务需要的能力。

上线前也要验证完整流程。普通问答能返回,只说明最简单的请求已经接通;如果业务用到了工具调用,就要验证执行工具、交回结果和继续生成的整个过程。结构化输出、流中断和输出截断,也应按实际使用的功能分别检查。

如果只是在现成客户端里选择「OpenAI」或「Anthropic」,就按连接的服务端实际提供的协议来选。直连 Claude 的 Messages 入口选 Anthropic;服务商只提供 /v1/chat/completions 时选 OpenAI 兼容。即使后端运行的是 Claude,也要遵循这个入口接受的格式。

参数文档从哪里查

需要查字段类型、必填项、取值范围和示例时,直接从这几个官方入口开始:

排查一个「协议兼容但请求失败」的问题时,先确认端点,再确认目标模型支持哪些参数,最后检查工具往返和流式解析。这样能把字段格式、模型能力和客户端状态处理的问题分开,避免把所有失败都归到 API Key 或模型名上。