如果你正在开发一个调用大语言模型的应用,那么你很可能需要对接 OpenAI 的 /v1/chat/completions 或 Anthropic 的 /v1/messages 接口。虽然两者的基本目标相同——将对话发送给 LLM 并获取回复——但它们在认证方式、请求结构、响应格式、工具调用、流式传输等方面存在显著差异。
本文详细梳理了两者的每一个主要区别,帮助你在选择服务商或构建统一抽象层时做出明智的决策。
认证方式
| 方面 | OpenAI | Anthropic |
|---|---|---|
| 认证头 | Authorization: Bearer sk-... | x-api-key: sk-ant-... |
| 版本头 | 无需提供 | anthropic-version: 2023-06-01(必填) |
| 组织/项目头 | OpenAI-Organization、OpenAI-Project(可选) | 无 |
Anthropic 强制要求 anthropic-version 头来锁定 API 行为版本,将 API 版本管理与模型名称解耦。OpenAI 则通过模型名称和接口变更来实现版本控制。
系统提示词
这是两者之间最直观的架构差异之一。
OpenAI 将系统提示词放在 messages 数组内部:
{
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello"}
]
}
Anthropic 使用独立的顶层 system 参数,与消息数组完全分离:
{
"system": "You are a helpful assistant.",
"messages": [
{"role": "user", "content": "Hello"}
]
}
Anthropic 的 system 字段还支持内容块数组(不仅仅是字符串),从而可以通过 cache_control 对系统提示词进行缓存。
消息角色与排序
| OpenAI | Anthropic |
|---|---|
system / developer(o 系列模型) | 无(system 为顶层参数) |
user | user |
assistant | assistant |
tool(用于工具结果) | 无(工具结果放在 user 消息内部) |
OpenAI 有 4 种不同角色,Anthropic 只有 2 种(user 和 assistant)。Anthropic 严格要求消息交替排列——不能连续出现两条相同角色的消息。OpenAI 则更灵活,会自动拼接同角色的连续消息。
响应格式
OpenAI 将响应包装在 choices 数组中(支持通过 n 参数生成多个补全):
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"choices": [{
"index": 0,
"message": {"role": "assistant", "content": "Hello!"},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 13,
"completion_tokens": 7,
"total_tokens": 20
}
}
Anthropic 直接返回类型化的内容块数组:
{
"id": "msg_abc123",
"type": "message",
"role": "assistant",
"content": [
{"type": "text", "text": "Hello!"}
],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 13,
"output_tokens": 7,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0
}
}
| 方面 | OpenAI | Anthropic |
|---|---|---|
| 内容类型 | message.content 为字符串 | content 为类型化块数组 |
| 停止标识 | finish_reason: "stop" | stop_reason: "end_turn" |
| 长度停止 | "length" | "max_tokens" |
| 工具调用停止 | "tool_calls" | "tool_use" |
| 多个补全 | 支持(通过 n 参数) | 不支持(始终返回 1 个) |
| 总 token 数 | 直接提供 | 需自行计算 |
| 缓存统计 | 响应中无 | 内置(cache_creation_input_tokens、cache_read_input_tokens) |
关键参数
| 参数 | OpenAI | Anthropic |
|---|---|---|
| 最大输出 token | max_completion_tokens(可选) | max_tokens(必填) |
| 温度 | 0–2(默认 1) | 0–1(默认 1) |
| Top P | top_p | top_p |
| Top K | 不支持 | top_k |
| 频率惩罚 | frequency_penalty(-2 到 2) | 不支持 |
| 存在惩罚 | presence_penalty(-2 到 2) | 不支持 |
| 停止序列 | stop(字符串或数组) | stop_sequences(数组) |
| 种子(可复现性) | seed | 不支持 |
| 对数概率 | logprobs | 不支持 |
| 用户标识 | user | metadata.user_id |
| 扩展思考 | 无(o 系列内部推理) | thinking 对象,含 budget_tokens |
迁移时最容易踩的两个坑:Anthropic 强制要求每个请求都设置 max_tokens(OpenAI 默认使用模型最大值),以及 Anthropic 的温度范围上限为 1.0,而 OpenAI 可达 2.0。
工具调用 / 函数调用
这是两个 API 之间最大的架构分歧之一。
工具定义
OpenAI 使用 type/function 包装结构:
{
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get weather for a location",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string"}},
"required": ["location"]
}
}
}]
}
Anthropic 采用更扁平的结构,使用 input_schema:
{
"tools": [{
"name": "get_weather",
"description": "Get weather for a location",
"input_schema": {
"type": "object",
"properties": {"location": {"type": "string"}},
"required": ["location"]
}
}]
}
响应中的工具调用
OpenAI 通过独立的 tool_calls 数组返回工具调用,参数为需要解析的 JSON 字符串:
"tool_calls": [{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Paris\"}"
}
}]
Anthropic 以内容块形式返回工具调用,input 为已解析的 JSON 对象:
"content": [{
"type": "tool_use",
"id": "toolu_01D7FLrfh4GYq7yT1ULFeyMV",
"name": "get_weather",
"input": {"location": "Paris"}
}]
返回工具结果
OpenAI 使用专用的 tool 角色:
{"role": "tool", "tool_call_id": "call_abc123", "content": "Sunny, 22C"}
Anthropic 将工具结果作为内容块放在 user 消息中,并提供显式的 is_error 标志:
{
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": "toolu_01D7...",
"content": "Sunny, 22C",
"is_error": false
}]
}
工具选择
| 行为 | OpenAI | Anthropic |
|---|---|---|
| 模型自行决定 | "auto" | {"type": "auto"} |
| 必须使用工具 | "required" | {"type": "any"} |
| 指定工具 | {"type": "function", "name": "X"} | {"type": "tool", "name": "X"} |
| 不使用工具 | "none" | {"type": "none"} |
视觉 / 多模态
OpenAI 使用 data URL 方案编码 base64 图片:
{
"type": "image_url",
"image_url": {
"url": "data:image/jpeg;base64,{BASE64_DATA}",
"detail": "high"
}
}
Anthropic 使用独立字段分别指定媒体类型和数据:
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": "BASE64_DATA"
}
}
| 方面 | OpenAI | Anthropic |
|---|---|---|
| 清晰度控制 | detail: "high"/"low"/"auto" | 无 |
| PDF 支持 | Chat Completions 中不支持 | 原生 document 内容块 |
| 音频支持 | 支持 | 不支持 |
Anthropic 拥有独特的一等公民 document 块类型,支持 PDF 和文本文件,并可选启用引用功能——这是 OpenAI Chat Completions 接口所不具备的。
流式传输
两个 API 都使用 Server-Sent Events,但事件结构截然不同。
OpenAI 使用扁平的无名称 data: 行流,以 data: [DONE] 结束:
data: {"choices":[{"delta":{"content":"Hello"}}]}
data: {"choices":[{"delta":{},"finish_reason":"stop"}]}
data: [DONE]
Anthropic 使用命名事件类型,具有结构化的生命周期:
event: message_start
data: {"type":"message_start","message":{...}}
event: content_block_start
data: {"type":"content_block_start","index":0,...}
event: content_block_delta
data: {"type":"content_block_delta","delta":{"type":"text_delta","text":"Hello"}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: message_stop
data: {"type":"message_stop"}
Anthropic 的流式传输更为精细,包含 6 种以上的命名事件类型,覆盖完整的消息生命周期。这使得处理混合内容(文本与工具调用交织)更加方便,但增加了解析复杂度。OpenAI 的方式更简洁——本质上只有一种事件类型加一个终止标记。
错误处理
OpenAI 包含 param 字段,指明是哪个参数导致了错误:
{
"error": {
"message": "Incorrect API key",
"type": "invalid_request_error",
"param": null,
"code": "invalid_api_key"
}
}
Anthropic 使用基于 type 的辨别模式:
{
"type": "error",
"error": {
"type": "authentication_error",
"message": "Invalid API key"
}
}
Anthropic 将 overloaded_error 与 api_error 区分开来,使得针对容量问题实现退避逻辑更加容易。
速率限制
| 方面 | OpenAI | Anthropic |
|---|---|---|
| 头部前缀 | x-ratelimit-(小写) | RateLimit-(IETF 草案格式) |
| 重置格式 | 相对时长(1s、6m0s) | ISO 8601 时间戳 |
| 重试头 | 非标准 | Retry-After |
两者在遇到速率限制时都返回 HTTP 429,并建议使用指数退避加随机抖动。
各自独有的功能
OpenAI 独有
- 多个补全——
n参数可在单次请求中生成 N 个替代回复 - 对数概率——
logprobs返回 token 级别的概率信息 - 结构化输出——
response_format配合json_schema保证 JSON 结构 - 频率/存在惩罚用于控制重复
- 音频输入/输出多模态消息支持
- 种子参数用于可复现输出
Anthropic 独有
- 扩展思考——显式
thinking参数配合budget_tokens,返回可见的思考块 - 提示缓存——内容块上的
cache_control支持 TTL 选项,使用量数据中包含缓存命中/未命中统计 - PDF/文档处理——原生
document内容块,支持引用 - Top K 采样——
top_k参数控制 token 选择 - 内置服务端工具——
web_search、code_execution、text_editor等运行在 Anthropic 基础设施上 - 工具错误标志——工具结果上的
is_error字段
SDK 快速参考
# OpenAI
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}]
)
print(response.choices[0].message.content)
# Anthropic
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-5-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
print(response.content[0].text)
迁移清单
如果你正在两者之间切换,或者构建统一的抽象层,以下是需要注意的关键事项:
- 移动系统提示词——从
messages内部(OpenAI)移到顶层system字段(Anthropic),反之亦然 - 设置
max_tokens——在 Anthropic 中为必填,在 OpenAI 中为可选 - 限制温度范围——Anthropic 上限为 1.0;OpenAI 允许到 2.0
- 重构工具定义——
parametersvsinput_schema,包装对象差异 - 处理工具结果的方式不同——
tool角色(OpenAI)vsuser消息中的内容块(Anthropic) - 解析工具调用参数——JSON 字符串(OpenAI)vs 已解析对象(Anthropic)
- 消息交替排列——Anthropic 强制要求,OpenAI 灵活处理
- 更新认证头——
Authorization: Bearervsx-api-key+anthropic-version - 适配流式解析器——扁平数据块 vs 命名生命周期事件
- 解包响应——
choices[0].message.contentvscontent[0].text
两个 API 都很强大且设计精良,但它们体现了不同的设计哲学。OpenAI 的 Chat Completions API 倾向于灵活性和向后兼容,而 Anthropic 的 Messages API 则更注重显式性和结构化数据。理解这些差异将帮助你无论选择哪家服务商都能构建出稳健的集成方案。