返回归档
🎉LLM 与 Agent

主流模型协议:OpenAI 与 Anthropic

Chat Completions、Responses、Messages 的对象模型、HTTP 头、请求/响应字段、工具回传和流式事件。对照官方 Create 文档。

文章目录

对话协议是一层 HTTP 契约:客户端 POST JSON,服务端返回 JSON(或 SSE)。契约规定三件事——上下文如何编码、模型输出落在哪个字段、以及生成停止后客户端读哪一个键决定下一步。

当前主流是三套:

Chat Completions Responses Messages
厂商 OpenAI OpenAI Anthropic
方法 / 路径 POST /v1/chat/completions POST /v1/responses POST /v1/messages
Host api.openai.com 同左 api.anthropic.com
核心对象 messages[](Message) input / output(Item) messages[] + content[](Content Block)
系统提示 messages[].role = "system""developer" 顶层 instructions 顶层 system
停止信号 choices[0].finish_reason status + output[].type stop_reason

OpenAI 推荐新集成走 Responses,Chat Completions 仍保持支持。Assistants API 已弃用,日落时间为 2026-08-26。GPT-5.4 起,Chat Completions 在 reasoning: none 时不再接受 tool calling。

三套协议的差异来自对象模型,不是「会不会对话」。

对象模型

Chat Completions 以 Message 为基本单位。系统指令、用户输入、助手输出、工具结果都是 { role, content },靠 role 区分职责。一次响应把助手 Message 放进 choices[]n > 1choices 长度大于 1。

Responses 以 Item 为基本单位。messagefunction_callfunction_call_outputreasoning 以及托管工具调用是不同类型,靠 type 区分。官方迁移文档的表述是:Chat 把多种关注点粘在一条 Message 上,Responses 把它们拆开。Responses 去掉了 n

Messages 以 Message + Content Block 为基本单位。一条 assistant Message 的 content 是块数组,同一轮里可以按序出现 thinkingtexttool_use。系统提示不进入 messages,而在顶层 system。官方正文仍写:不要在 messages 里使用 role: "system"(schema 里后来出现的 mid_conv_system 只用于中途改指令)。

因此协议转换不是改 baseURL。至少要映射:系统提示的位置、工具 schema 的外壳、工具结果的承载对象、停止信号的键名、流式增量的事件形状。

HTTP 头

认证、版本、限流不在 JSON body 里。漏头或取值不合法,请求在进入模型之前就会 400 / 401。

OpenAI(Chat Completions 与 Responses 共用)

Header 取值 约束
Authorization Bearer <secret> 必填。<secret> 为 API key,或 Workload Identity Federation 换取的 access token
Content-Type application/json JSON body 时必填
OpenAI-Organization org-... 可选。空字符串会 401:OpenAI-Organization header should match organization for API key
OpenAI-Project proj_... 可选。与上一行共同决定计费项目。SDK 读 OPENAI_ORG_ID / OPENAI_PROJECT_ID
X-Client-Request-Id 客户端 trace 可选。仅 ASCII,≤ 512 字符,否则 400
OpenAI-Beta assistants=v2 Chat / Responses 主路径不需要

请求头合计须小于 64 KiB。Azure OpenAI 常见认证是 api-key: <key>,不是 Bearer。

响应头:x-request-id(排障)、openai-organizationopenai-version(当前文档为 2020-10-01,REST 兼容版本)、openai-processing-msx-ratelimit-limit-requests / remaining-requests / reset-requestsx-ratelimit-*-tokens,以及可选的 x-ratelimit-*-project-tokens。流式响应的 Content-Typetext/event-stream

Anthropic Messages

Header 取值 约束
x-api-key sk-ant-api03-... Authorization 二选一
Authorization Bearer <token> <token> 来自 POST /v1/oauth/token,不能把 API key 再包一层 Bearer
anthropic-version 2023-06-01 必填。缺失、或被代理复写成 2023-06-01, 2023-06-01,均为 400。2023-01-01 的 SSE 语义不同(前缀累加 + data: [DONE]
content-type application/json 必填
anthropic-beta feature-name-YYYY-MM-DD 可选,多个用逗号。无效或互斥 → 400 invalid_request_error
anthropic-dangerous-direct-browser-access true 仅浏览器直连需要,用于 CORS

Amazon Bedrock 上版本写在 body:"anthropic_version": "bedrock-2023-05-31",beta 为 "anthropic_beta": ["..."] 数组。

响应头:request-id(无 x- 前缀)、anthropic-organization-idanthropic-workspace-idretry-after(429 时的等待秒数)、anthropic-ratelimit-requests-*anthropic-ratelimit-input-tokens-*anthropic-ratelimit-output-tokens-**-reset 是 RFC 3339 绝对时间,不能按相对秒数 sleep。多数模型下缓存命中不计入 ITPM;OTPM 按实际生成计,不按 max_tokens 预扣。

请求体

先看必填项,再看语义相同但键名不同的字段。

语义 Chat Completions Responses Messages
模型 model(必填) model model(必填)
上下文 messages(必填) inputstring 或 Item 数组。纯字符串等价一条 role: "user" messages(必填,上限 10 万条)
系统提示 messagesrole: "system" / "developer" 顶层 instructions 顶层 systemstring 或 text 块数组)
输出上限 max_tokens(旧);新模型 / o 系列用 max_completion_tokens max_output_tokens max_tokens 必填0 表示只预热 cache
停词 stopstring 或最多 4 个 stringo3 / o4-mini 不支持 无对等字段 stop_sequences: string[]
采样 temperature(0–2)、top_p 同左。部分推理模型不接受 temperature temperature(0–1)、top_p。开启 thinking 时 temperature 必须为 1
流式 streamstream_options.include_usage streamstream_options.include_obfuscation stream
工具定义 tools tools tools
工具策略 tool_choice"none" / "auto" / "required" / { type, function.name } "none" / "auto" / "required" / { type: "function", name } { type: "auto" | "any" | "tool" | "none" }any ≡ OpenAI required
并行工具 parallel_tool_calls parallel_tool_calls;另有 max_tool_calls tool_choice.disable_parallel_tool_use
结构化输出 response_format text.format output_config.format
推理配置 reasoning_effort reasoning thinkingbudget_tokens ≥ 1024 且 < max_tokens
多候选 n 不支持 不支持
跨轮状态 store store(默认 true)+ previous_response_id / conversation 无服务端会话。每轮重传 messages
用户标识 user / safety_identifier 同左 metadata.user_id
缓存控制 隐式;可选 prompt_cache_key 同左 显式 cache_control

Chat Completions 的 functions / function_call 已弃用,应使用 tools / tool_choice

messages[].role(Chat)的取值是 developer | system | user | assistant | tool,以及已弃用的 functiontool 消息必须带 tool_call_idassistant 在纯 tool 回合允许 content: nulluser 的多模态块类型为 image_url,URL 位于 image_url.urldetailauto | low | high

Responses 的 input Item 常见类型:

  • messagerole + content。输入文本块类型是 input_text,回放助手文本块类型是 output_text
  • function_call:模型发起的调用
  • function_call_output:客户端回传
  • reasoning:推理过程。多轮需原样回放;store: false 时通过 include: ["reasoning.encrypted_content"] 取得密文

previous_response_id 引用上一轮响应的 idresp_...)。它不继承上一轮顶层 instructions。链路中的历史 input token 仍计入本轮 input。store: false 被 ZDR 组织强制开启。

Messages 请求里,content 写成字符串等价于 [{ "type": "text", "text": "..." }]。响应侧没有这种简写,content 恒为数组。若最后一条 roleassistant 且内容不完整,模型会从该处续写。

结构化输出的键路径不同,不能互换:

// Chat Completions
{ "response_format": { "type": "json_schema", "json_schema": { "name": "person", "strict": true, "schema": { } } } }

// Responses
{ "text": { "format": { "type": "json_schema", "name": "person", "strict": true, "schema": { } } } }

// Messages
{ "output_config": { "format": { "type": "json_schema", "schema": { } } } }

type: "json_object" 只约束合法 JSON,不约束 schema。三家均不接受根节点为 $ref 的 JSON Schema,须先展开。

响应体

语义 Chat Completions Responses Messages
对象种类 object: "chat.completion" object: "response" type: "message"
响应 id idchatcmpl-... idresp_... idmsg_...),不同于响应头 request-id
时间戳 created(Unix 秒) created_at 无对等顶层字段
读正文 choices[0].message.content SDK output_text;或遍历 output[]type == "message"content[].text(块类型 output_text content[]type == "text".text
停止信号 choices[0].finish_reason status + output[].type stop_reason
输入用量 usage.prompt_tokens usage.input_tokens usage.input_tokens(不含 cache 读写)
输出用量 usage.completion_tokens usage.output_tokens usage.output_tokens
合计 usage.total_tokens usage.total_tokens input + cache_creation + cache_read(再加 output)
缓存命中 usage.prompt_tokens_details.cached_tokens usage.input_tokens_details.cached_tokens usage.cache_read_input_tokens
推理用量 completion_tokens_details.reasoning_tokens output_tokens_details.reasoning_tokens output_tokens_details.thinking_tokens

停止信号的枚举需要对齐后再做转换:

语义 finish_reason Responses stop_reason
自然结束 stop status == "completed"output 中无待回传的 function_call end_turn
命中停词 stop stop_sequence(具体串在 stop_sequence
输出上限 length status == "incomplete"incomplete_details.reason == "max_output_tokens" max_tokens
客户端工具 tool_calls output[].type == "function_call"不能status == "incomplete" 判断 tool_use
安全拦截 content_filter incomplete_details.reason == "content_filter",或 outputtype == "refusal" refusal
长轮次暂停 pause_turn(将完整响应作为下轮 assistant 回放即可续写)
上下文溢出 无独立枚举 无独立枚举 model_context_window_exceeded
旧 function function_call(弃用)

Responses 的 status 取值是 completed | failed | in_progress | cancelled | queued | incomplete,描述本次生成是否结束,不描述是否需要执行客户端工具。error 仅在 failed 时非空。不要假设 output[0] 是最终文本:推理模型通常先输出 type: "reasoning"

Messages 非流式时 stop_reason 恒非空。流式时 message_start 中为 null,终态只出现在 message_delta

工具调用

工具协议分三段:定义(请求 tools)、调用(响应中的调用对象)、回传(下一轮请求中的结果对象)。JSON Schema 本身可以相同,外壳和关联键不同。

定义

Chat Completions 使用外部标签(externally tagged):

{
  "type": "function",
  "function": {
    "name": "get_weather",
    "description": "Get weather for a city",
    "strict": true,
    "parameters": {
      "type": "object",
      "properties": { "location": { "type": "string" } },
      "required": ["location"],
      "additionalProperties": false
    }
  }
}

Responses 使用内部标签(internally tagged),不再嵌套 function。省略 strict 时会尝试严格模式,schema 不兼容则回退,并在返回的工具上标注 strict: false

{
  "type": "function",
  "name": "get_weather",
  "description": "Get weather for a city",
  "parameters": {
    "type": "object",
    "properties": { "location": { "type": "string" } },
    "required": ["location"],
    "additionalProperties": false
  }
}

Messages 的 schema 字段名为 input_schema

{
  "name": "get_weather",
  "description": "Get weather for a city",
  "input_schema": {
    "type": "object",
    "properties": {
      "location": { "type": "string", "description": "City and state, e.g. San Francisco, CA" }
    },
    "required": ["location"]
  }
}

{ "type": "web_search" }(Responses)或 { "type": "web_search_20250305", "name": "web_search" }(Messages)属于服务端工具,由平台在同一次请求内执行,客户端不走回传协议。

调用

Chat Completions:位于 choices[0].message.tool_calls[]

{
  "id": "call_abc123",
  "type": "function",
  "function": {
    "name": "get_weather",
    "arguments": "{\"location\":\"San Francisco, CA\"}"
  }
}

function.arguments 的类型是 string,须 JSON.parsecontent 在此回合常为 null

Responses:位于 output[]typefunction_call

{
  "type": "function_call",
  "id": "fc_001",
  "call_id": "call_abc123",
  "name": "get_weather",
  "arguments": "{\"location\":\"San Francisco, CA\"}"
}

id 是 Item id;回传必须使用 call_idarguments 同样是 string。

Messages:位于 content[]typetool_use

{
  "type": "tool_use",
  "id": "toolu_01ABC",
  "name": "get_weather",
  "input": { "location": "San Francisco, CA" }
}

input 的类型是 object,不要再 JSON.parse。

回传

Chat Completions 增加一条 Message:

{ "role": "tool", "tool_call_id": "call_abc123", "content": "18°C, cloudy" }

并行 N 个 tool_calls 必须回 N 条 role: "tool"tool_call_id 一一对应,缺一则 400。上一轮 assistant(含 tool_calls)必须一并重放。

Responses 增加一个 Item。使用 previous_response_id 时只需提交增量;手动管理状态时须同时回放对应的 function_call

{ "type": "function_call_output", "call_id": "call_abc123", "output": "18°C, cloudy" }

结果字段名是 output,不是 content

Messages 没有 role: "tool"。结果放在 user Message 的 content 中:

{
  "role": "user",
  "content": [
    { "type": "tool_result", "tool_use_id": "toolu_01ABC", "content": "18°C, cloudy" }
  ]
}

上一轮 assistant 的 content(含全部 tool_use)必须原样重放。开启 extended thinking 时,thinking 块及其 signature 同样必须原样回放,修改会导致 400。同一条 user 中若同时有文本,tool_result 须排在文本之前。失败时设 "is_error": truetool_choice.type == "any" 与 extended thinking 互斥。

客户端循环的判定条件可以收成:

Chat:       finish_reason == "tool_calls"      → tool_calls / tool_call_id
Responses:  output[].type == "function_call"   → function_call / call_id
Messages:   stop_reason == "tool_use"          → tool_use / tool_use_id
否则:      stop | completed | end_turn        → 读取文本字段

流式

stream: true 后,三套协议都使用 Content-Type: text/event-stream,但帧格式不同。客户端应发送 Accept: text/event-stream,避免中间代理按 JSON 缓冲。

Chat Completions 是 data-only SSE:每帧 data: <chat.completion.chunk>,以字面量 data: [DONE] 结束。增量在 choices[0].deltatool_calls[].idfunction.name 只在该 call 的首帧出现,后续帧只有 function.arguments 碎片。用 tool_calls[].index 分桶,对 arguments 做字符串拼接后再 parse。finish_reason 在最后一帧非 [DONE] 给出。usage 默认不出现,须设置 stream_options.include_usage = true,位于 [DONE] 前一个 choices: [] 的 chunk;连接中断则丢失。openai-python 的 accumulate_delta 对 string 执行 +=,对 list 按 index 对齐,不累加 index / type

Messages 是 named SSE:event:data: 成对。content_block_starttool_use.input{} 占位;实参来自同 indexdelta.type == "input_json_delta"partial_json 拼接。文本块的 delta 类型是 text_deltastop_reason 只在 message_delta 中出现。message_delta.usage.output_tokens 是累计值,不能再与 message_start.usage 相加。ping 丢弃。无 [DONE]

Responses 是 typed 事件。文本听 response.output_text.delta。工具参数听 response.function_call_arguments.deltaarguments += delta),完整值在 response.function_call_arguments.done。生命周期事件为 response.created / response.completed / response.failed / response.incomplete。不能用 Chat 的 choices[0].delta.content 消费。

缓存

Anthropic 使用显式断点。cache_control 可写在顶层(自动标到最后一个可缓存块),或写在具体的 system / tools / content 块上:{ "type": "ephemeral", "ttl": "5m" | "1h" },默认 5 分钟。可缓存前缀顺序为 tools → system → messages。修改工具描述会使后续前缀全部失效。断点必须落在跨请求不变的最后一块。低于模型最小可缓存长度(512–4096,依型号)时静默不生效。

计量关系:

总输入 = cache_read_input_tokens + cache_creation_input_tokens + input_tokens

input_tokens 只覆盖断点之后的部分。

OpenAI 为隐式自动缓存,请求侧没有 cache_control。命中量读 cached_tokens。官方给出的内部对比是 Responses 相对 Chat Completions 缓存利用率高 40%–80%。previous_response_id 减少的是重传字节,不把历史 token 计费清零。

协议选择

已有大量 Chat Completions 集成、且只需补全与客户端 function:继续使用 Chat Completions,按流量迁移。

需要完整 messages 以便审计、回放、跨厂商转换:使用 Messages。代价是每轮重传上下文,缓存断点由客户端维护。

需要托管工具(搜索、沙箱、远程 MCP)、或推理 Item 必须在多轮中保留:使用 Responses。服务端状态与内置工具会提高对 OpenAI 的耦合。

字段映射以官方文档为准:Migrate to the Responses APICreate chat completionCreate a model responseMessagesStreaming