用 OpenAI SDK 调用 Claude:官方兼容层配置与被忽略的参数(2026)
可以用 OpenAI SDK 调用 Claude。Anthropic 官方提供了一个 OpenAI SDK 兼容层:把 SDK 的 base_url 改成 https://api.anthropic.com/v1/,换成 Claude API Key,模型名填 claude-sonnet-5 这类 Claude 模型 ID 即可。对话补全、流式输出和工具调用都能用,但有一批 OpenAI 专属参数会被静默忽略。
真正需要花时间的是最后那半句。本文按 Anthropic 官方兼容性文档,讲清楚三件事:怎么配、哪些字段生效或被丢弃,以及官方文档里那个思考(thinking)示例为什么原样搬到 Claude 5 模型上会直接报 400。
OpenAI SDK 兼容层是什么
Anthropic 在原生 Messages API 旁边提供了一个 OpenAI 形状的 Chat Completions 端点。你继续用官方 openai 包,继续调 client.chat.completions.create(),Anthropic 在服务端把请求翻译成 Messages 调用。
官方对它的定位说得很直白:这个兼容层主要用于测试和对比模型能力,对多数场景而言不算长期方案,也不算生产就绪方案;它会保持可用、尽量不做破坏性变更,但优先级在原生 Claude API 上。换成大白话:它是在现有 OpenAI 代码里最快试用 Claude 的方式,而不是承载 Claude 专属能力的地方。
由此带来两个直接影响:
- 限流沿用 Messages API 的额度。 官方说明兼容层的请求遵循
/v1/messages的标准限流,不是另一套独立额度。 - 错误格式像 OpenAI,错误文案不一样。 报错结构与 OpenAI API 保持一致,但具体提示语不同。官方建议只拿它做日志和排查,不要让代码逻辑依赖错误文本做分支判断。
配置:base_url、API Key 与模型 ID
需要改的只有三项,调用处其余代码不用动。
|
配置项 |
调用 Claude 时的取值 |
|---|---|
|
Base URL |
|
|
API Key |
Claude API Key(下面示例从环境变量 |
|
模型 |
Claude 模型 ID: |
Python:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["ANTHROPIC_API_KEY"],
base_url="https://api.anthropic.com/v1/",
)
response = client.chat.completions.create(
model="claude-sonnet-5",
max_tokens=1024,
messages=[
{"role": "system", "content": "你是一名简洁的代码评审。"},
{"role": "user", "content": "评价一下这个函数名:getData2()"},
],
)
print(response.choices[0].message.content)Node.js:
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.ANTHROPIC_API_KEY,
baseURL: "https://api.anthropic.com/v1/",
});
const response = await client.chat.completions.create({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [
{ role: "system", content: "你是一名简洁的代码评审。" },
{ role: "user", content: "评价一下这个函数名:getData2()" },
],
});
console.log(response.choices[0].message.content);首次调用失败,多半卡在下面三处:
- 模型名必须是 Claude 的 ID,不会替你映射 GPT 名字。 官方参考写明
model字段使用 Claude 模型名,配置里残留的 GPT 模型名不会被自动翻译。模型 ID 从 Anthropic 的模型总览页复制,别凭记忆手打。 - 多工作区 Key 要带工作区请求头。 如果你用的是能访问多个工作区的个人 Key 或服务账号 Key,官方要求每个请求都带
anthropic-workspace-id请求头。用 OpenAI SDK 时,Python 放在default_headers,Node 放在defaultHeaders。 - 只针对官方 OpenAI SDK。 官方的第一步就是「使用官方 OpenAI SDK」。第三方封装可能会自己加参数或改写路径。
如果 base URL 本身就在报 404 或出现重复的 /v1,OpenAI 兼容 Base URL 该填什么 里的排查步骤在这里同样适用。
哪些参数生效、被截断或被忽略
迁移代码时建议把这张表开在旁边。它整理自 Anthropic 官方逐字段的兼容性说明(请求参数部分)。
|
参数 |
在 Claude 上的表现 |
|---|---|
|
|
必须是 Claude 模型 ID |
|
|
完全支持 |
|
|
完全支持 |
|
|
完全支持 |
|
|
完全支持 |
|
|
非空白字符的停止序列可用 |
|
|
取值 0 到 1,大于 1 会被截成 1 |
|
|
必须等于 1 |
|
|
忽略,工具参数不保证符合 schema |
|
|
忽略 |
|
|
忽略 |
|
|
忽略 |
|
|
忽略 |
|
|
忽略 |
|
|
忽略 |
这张表里最关键的词是「忽略」。官方说明,多数不支持的字段会被静默忽略,而不是报错:请求照常成功、你拿到一条正常回复,只是你要的那个功能根本没生效。通用规律见 OpenAI 兼容性问题;具体到这个端点,最容易出事的是三项:
response_format被忽略。 JSON 模式不会被强制执行。解析器默认拿到的是合法 JSON 的话,要么加校验,要么把这次调用改走原生 API 的结构化输出,思路见 Claude API 结构化输出。- 工具定义里的
strict被忽略。 工具调用参数大多数时候符合 schema,但没有任何保证。执行工具前先校验参数。 seed被忽略。 依赖固定采样来做可复现测试的场景,会变得不可复现。
消息内容也有缺口:user 消息支持纯文本和 image_url(其中 detail 子字段被忽略),input_audio 和 file 类型的内容会被忽略;所有角色上的 name 字段都被忽略。
会改变结果的几处行为差异
除了单个参数,还有四处行为和 OpenAI 代码的默认假设不一样。
system / developer 消息会被提到最前面。 OpenAI 允许在对话任意位置插入 system 或 developer 消息;Claude 只支持一段开头的系统提示词。所以兼容层会把所有 system 和 developer 消息收集起来,用一个换行符拼接,作为唯一的系统提示词放在对话开头。像「从现在起改用法语回答」这种中途插入的指令,就不再处于对话的那个位置,而是变成了开场指令的一部分。
不支持提示词缓存。 官方把提示词缓存列为兼容层不支持、但 Anthropic 自家 SDK 支持的能力。系统提示词很长且反复使用时,两条路径的成本差距可能很明显,参见 Claude API 提示词缓存。
部分返回字段恒为空。 choices 长度恒为 1。usage.prompt_tokens、usage.completion_tokens、usage.total_tokens 有值,但 usage.prompt_tokens_details 和 usage.completion_tokens_details 恒为空,logprobs、system_fingerprint、service_tier 也一样。如果你的用量看板是从这些 details 对象里读缓存 token 或推理 token,会一直显示为空。
针对 GPT 调过的提示词可能要重写。 官方的建议是:精调过的提示词很可能是专门贴合 OpenAI 模型的,可参考其提示词最佳实践针对 Claude 调整。
通过 OpenAI SDK 使用思考(thinking)
OpenAI SDK 没有 thinking 这个参数,所以要把 Claude 的思考配置作为额外的请求体字段传进去:Python 用 extra_body,Node 直接在请求对象里加这个键(TypeScript 需要加一行类型忽略注释)。
传什么取决于模型,这也是官方示例容易踩坑的地方。兼容层文档里的思考示例是在较早的 Sonnet 模型上传 {"type": "enabled", "budget_tokens": 2000}。而按照 Anthropic 的思考故障排查表:
|
模型 |
默认是否开启思考 |
会被 400 拒绝的取值 |
|---|---|---|
|
|
开启(自适应) |
|
|
|
开启(自适应) |
|
|
|
关闭(仅支持扩展思考) |
|
也就是说,在 Claude 5 模型上通常什么都不用传,思考本来就是开着的;把带 budget_tokens 的示例照搬到 claude-sonnet-5 上会返回 400。Haiku 4.5 反而要用这种旧写法:
# Claude 5:默认开启思考。简单、追求速度的调用可以关掉。
fast = client.chat.completions.create(
model="claude-sonnet-5",
max_tokens=512,
messages=[{"role": "user", "content": "给 getData2() 起个更清楚的名字。"}],
extra_body={"thinking": {"type": "disabled"}},
)
# Haiku 4.5:默认关闭,使用扩展思考。
deliberate = client.chat.completions.create(
model="claude-haiku-4-5",
max_tokens=4096,
messages=[{"role": "user", "content": "找出这个日期解析函数的边界情况。"}],
extra_body={"thinking": {"type": "enabled", "budget_tokens": 2000}},
)不管用哪个模型,有一条限制不变:官方说明 OpenAI SDK 不会返回 Claude 的详细思考过程。你拿到的是思考后的答案,而不是推理文本。需要读取或记录思考内容,就得走原生 API。
流式输出与工具调用
智能体代码最依赖的这两条路径都支持:
- 流式输出。
stream=True和stream_options完全支持,SDK 自带的迭代器照常可用。如果你不用 SDK、而是自己解析原始 SSE 事件,要针对这个端点实测,别假设分块和 OpenAI 逐字节一致。 - 工具调用。 工具的
name、description、parameters完全支持;assistant 消息里的tool_calls、tool 消息里的tool_call_id、tool_choice与parallel_tool_calls也都支持,旧版functions字段同样可用。缺口只有上面说过的strict。
const stream = await client.chat.completions.create({
model: "claude-sonnet-5",
max_tokens: 1024,
stream: true,
stream_options: { include_usage: true },
messages: [{ role: "user", content: "列出参数被静默丢弃的三个风险。" }],
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}什么时候该换原生 SDK 或网关
在 OpenAI 代码库里评估 Claude 时,兼容层是合适的工具。官方推荐用原生 Claude API 获取完整能力,并点名了 PDF 处理、引用(citations)、思考和提示词缓存。某段代码需要这些能力之一,或者需要严格保证输出符合 schema 时,就把它迁到原生 Anthropic SDK。原生请求怎么写,见 Claude API 使用教程。
还有第三种情况:你想用一个 OpenAI 兼容客户端同时调用多家模型,这时可以在前面放一层网关。LiteLLM 接入 Claude 是自建的做法,ROIBest AI 这类托管端点则是服务化的做法,两者的取舍见 什么是 OpenAI 兼容 API。网关处在同样的「翻译」位置,所以规则也一样:依赖某个参数之前,先确认它是被透传、丢弃还是被映射。ROIBest AI 的 base URL 与当前模型列表见其文档。
上线前的快速验证
迁移完别急着相信,把代码真正依赖的调用跑一遍,看字段而不只是看回复文本:
r = client.chat.completions.create(
model="claude-sonnet-5",
max_tokens=256,
temperature=0.2,
messages=[{"role": "user", "content": "只回复 ok。"}],
)
print(r.model) # 实际应答的模型
print(r.choices[0].finish_reason) # 回复是否被 max_tokens 截断
print(r.usage.prompt_tokens, r.usage.completion_tokens)
print(len(r.choices)) # 这个端点上恒为 1然后对代码里发送的每个可选参数问一句:它在上面的「忽略」清单里吗?在的话,要么删掉,免得别人以为它生效了;要么把这次调用迁到原生 API。这一遍检查,能在上线前拦住大部分迁移问题。
常见问题
OpenAI 的 Python SDK 能直接调用 Claude 吗?
能。把 base_url 设为 https://api.anthropic.com/v1/,传入 Claude API Key,模型名用 claude-sonnet-5 这类 Claude 模型 ID。官方的 Node、Go、Java、C#、Ruby 版 OpenAI SDK 做法相同。
Anthropic 的 OpenAI 兼容层适合用在生产环境吗?
官方定位是主要用于测试和对比模型,对多数场景不算长期或生产就绪方案。它会保持可用,但优先级在原生 Claude API。
通过 OpenAI SDK 调 Claude,response_format 的 JSON 模式有效吗?
无效。response_format 会被忽略,工具定义里的 strict 也一样。需要严格符合 schema 时,官方建议使用原生 Claude API 的结构化输出。
为什么在 claude-sonnet-5 上开启思考会报 400?
Claude Sonnet 5 只支持自适应思考,而且默认开启,会拒绝带 budget_tokens 的 {"type": "enabled"}。不传思考字段即可;想关掉就传 {"type": "disabled"}。