用 OpenAI SDK 调用 Claude(以及 Gemini、Grok)
一个 SDK,一个 base_url。OpenAI 兼容路径让你现有的 Python 代码不重写就能打到 Anthropic、Google、xAI 的模型。
OpenAI Python SDK 是 LLM 这一行最接近"普通话"的客户端。它不是表达能力最强的那一个,也不是和每家上游都能完美对齐的那一个,但它几乎一定就是你代码库、你的依赖、你的链路追踪和你的重试策略已经会说的那一种语言。真正值得讨论的不是"要不要用它",而是"模型策略不再只盯着 OpenAI 之后,你能不能继续用它"。
结论是能。用 BUZZ AI Gateway,同一个 openai 客户端可以在同一行代码里调 gpt-5、claude-opus-4-8、Gemini 或 Grok。改的字符串只有两个:base_url 和 model。这篇文章讲为什么这条路能走通、它的代价是什么,以及哪些边角它不再无缝。
1. 为什么大家会用 OpenAI SDK 去调 Claude
维护过对接两个以上模型家族的服务的人都知道,真正的摩擦不在那次 API 调用本身,而在调用周围的一切。
OpenAI 那套基础设施你已经搭好了。2023 年之后写的、和 LLM 沾边的代码库,大多有一行 from openai import OpenAI。某个角落里一定有一个薄薄的封装层在管 timeout,挂着配好 TLS 的 HTTP client,注册着 tracer,带着懂得在 429 上退避的重试策略。每多一个 SDK,你要么再复刻一份这套封装,要么抽一层更高的抽象 —— 都是真实的工程成本,而且这成本不会推动产品向前。
上层框架已经认它了。LangChain 的 ChatOpenAI、LlamaIndex 的 OpenAI 集成、Vercel AI SDK 的 openai provider,以及大多数 agent 框架,都接受 base_url 覆盖。把它们指到一个 OpenAI 兼容端点,改的是配置文件里的一行;换成另一家原生 SDK,改的是一个 feature 分支。
可观测性栈是按它的形状校准的。OpenTelemetry 的 GenAI 语义约定围绕 OpenAI 的形状写。Langfuse、Helicone、Phoenix,以及大多数自研日志中间件,都在解析 chat.completions 的请求体和响应体。线协议保持不变,你的看板就保持不变。
心智模型是统一的。半年后翻代码的工程师不需要记住哪个 SDK 用 messages、哪个用 contents,也不需要记住 system 是顶层字段还是 messages 列表里的第一条。client.chat.completions.create(model="...", messages=[...]) 一句话就够。
这并不是说 Anthropic SDK 不好。这是说,对绝大多数应用层代码,"一个 SDK 通吃所有模型家族"的价值高于"为某一家拿到原生人体工学"的价值。
2. /v1 上的 OpenAI 兼容适配器
BUZZ 在同一把 key 上同时暴露两套协议:
- Anthropic Messages,在
https://buzzai.cc—— 即插即用,对接官方 Anthropic SDK 和 Claude Code。 - OpenAI
chat.completions,在https://buzzai.cc/v1—— 即插即用,对接官方 OpenAI SDK 和任何接受 OpenAI 兼容 base URL 的客户端。
/v1 端点接收 OpenAI 形状的请求,根据 model 字段分发到对应上游,再把响应翻译回 chat.completions 格式。整个翻译过程是机械的:messages 映射成 Anthropic 的 content blocks 或 Gemini 的 contents,tools 与 tool_choice 映射成 Anthropic 的 tool_use 或 Gemini 的 functionDeclarations,流式 chunk 映射成 OpenAI 的 delta 事件,finish reason 映射成 stop / length / tool_calls。用户能看到的内容文本一字不动。
3. 实战:用 OpenAI SDK 调 Claude
装常规的 OpenAI 客户端就行,BUZZ 没有任何自定义包要装。
pip install openai
用你的 BUZZ key 和网关的 OpenAI 兼容 base URL 配置 client。
from openai import OpenAI
client = OpenAI(
api_key="YOUR_BUZZ_KEY",
base_url="https://buzzai.cc/v1",
)
resp = client.chat.completions.create(
model="claude-opus-4-8",
messages=[
{"role": "system", "content": "You are a precise technical writer."},
{"role": "user", "content": "Explain content-addressable storage in three sentences."},
],
temperature=0.3,
max_tokens=400,
)
print(resp.choices[0].message.content)
这就是全部对接。模型是 Claude,SDK 是 OpenAI 的,响应对象是 ChatCompletion,choices、message、finish_reason、usage 都在你预期的位置。
Streaming
流式调用用的开关和迭代方式,跟真实 OpenAI 调用完全一样。token 通过每个 chunk 的 delta.content 到达。
stream = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[{"role": "user", "content": "Write a haiku about cold storage."}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
网关把上游的 SSE 事件按到达顺序原样下发。token 不缓冲、不重写。如果你有直接消费 iter_lines 的封装,也能继续工作 —— SSE 帧结构是保留的。
用 OpenAI tools schema 做 Tool Use
按 OpenAI 的形状定义 tools。网关在出向把它们映射到 Anthropic 的 tool_use 块,再把模型的工具选择回译成 OpenAI 的 tool_calls 进来。
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"},
"units": {"type": "string", "enum": ["c", "f"]},
},
"required": ["city"],
},
},
}]
resp = client.chat.completions.create(
model="claude-opus-4-8",
messages=[{"role": "user", "content": "What is the weather in Tokyo right now?"}],
tools=tools,
tool_choice="auto",
)
call = resp.choices[0].message.tool_calls[0]
print(call.function.name, call.function.arguments)
如果你已经有一段 OpenAI tool calling 循环 —— 处理 tool_calls、解析参数、跑函数、再把 {"role": "tool", "tool_call_id": ...} 消息塞回对话 —— 这段循环对接到 Claude 上能直接继续跑,一行不用动。
切到 Gemini 或 Grok
切换到不同家族就是改一个 model 名字。同一个 client、同一段代码、同一套重试封装。
# 同一个 client,只换 model
gemini_resp = client.chat.completions.create(
model="gemini-2.5-pro",
messages=[{"role": "user", "content": "Summarize this 200-page PDF transcript..."}],
)
grok_resp = client.chat.completions.create(
model="grok-4",
messages=[{"role": "user", "content": "What happened in markets this week?"}],
)
支持的模型标识符以及它们的实时 token 单价,看在线列表:https://buzzai.cc/models 和 https://buzzai.cc/api/pricing。
4. 相对直连 OpenAI,有哪些变化
调用现场几乎什么都不变,差异是手术刀级别的。
| 关注点 | 直连 OpenAI | BUZZ /v1 |
|---|---|---|
base_url | https://api.openai.com/v1(默认) | https://buzzai.cc/v1 |
api_key | OpenAI key | BUZZ key(一把通用) |
model 命名空间 | 仅 OpenAI 家族 | Claude、GPT、Gemini、Grok |
| 请求形状 | chat.completions | chat.completions |
| 响应形状 | ChatCompletion | ChatCompletion |
| Streaming | SSE delta | SSE delta |
| Tool calling | tools + tool_calls | tools + tool_calls |
| 重试 / 追踪 / 日志 | 你现有的封装 | 你现有的封装,原样 |
这种迁移通常一个 config diff 就能搞定。如果 client 的构造是集中管理的,那就是一个文件;如果不是,那本来就是一笔你早该做的重构。
采样参数
常用参数(temperature、top_p、max_tokens、stop、上游支持时的 seed、上游支持时的 presence_penalty 和 frequency_penalty)都按最近似的语义转发到对应上游。行为以上游模型为准,不是 OpenAI。temperature=0.7 在 Claude 上的分布,和 temperature=0.7 在 GPT-5 上不一样 —— 不管你是走网关还是直连都一样。调参要按模型分别调,而不是按数字调。
5. 哪些功能没法干净映射
chat.completions 这套 schema 是公约数 —— 大多数应用代码只需要这一层表面。但有几个特性不在这个交集里。
Anthropic extended thinking。Claude 可以在答案旁边返回一个 thinking 块。OpenAI 响应里没有规范位置放这个块,所以 /v1 适配器不会暴露它。如果你的应用真的要消费 thinking 轨迹,直接用 Anthropic SDK 走 https://buzzai.cc,读结构化响应。
Anthropic Prompt Cache。具体 content block 上的 cache_control 是 Anthropic 原生概念。OpenAI 请求形状里没有放它的字段。要在 Claude 上用 Prompt Cache,用 Anthropic SDK 打到同一个网关即可。
Gemini 专属的安全 / grounding 控制。分类粒度的安全阈值、grounding-with-search 之类的 Gemini-only 旋钮,在 chat.completions 里没有等价物,只能走原生 Google 协议。
上游原生流式事件。Anthropic 会发出有类型的事件,例如 content_block_start、content_block_delta、message_delta。OpenAI 适配器把它们压平成 chat.completion.chunk 的 delta。token 文本被保留,有类型的结构没有。如果你确实需要 Anthropic 的事件分类(比如把 thinking 块和最终答案分开渲染),用 Anthropic SDK。
务实的做法是:应用代码默认用 OpenAI SDK,只在少数确实需要 Claude 原生特性的地方,加一个 Anthropic SDK 作为第二个 client —— 用同一把 key、同一个网关。pip install anthropic,base_url="https://buzzai.cc",完事。
from anthropic import Anthropic
ant = Anthropic(
api_key="YOUR_BUZZ_KEY",
base_url="https://buzzai.cc",
)
msg = ant.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=[{"role": "user", "content": "Plan a refactor of this module..."}],
extra_body={"thinking": {"type": "enabled", "budget_tokens": 8000}},
)
同一把 key,同一个网关,只在需要的时候换协议。
6. 关于成本
这套配置有一个不太一样的属性:OpenAI 兼容适配器并不是套在 OpenAI 上的壳。它是一个能分发到任何受支持家族的统一壳,而且按 BUZZ 的费率计费,不是一手官方费率。昨天还指着 https://api.openai.com/v1 跑 gpt-5 的脚本,把 URL 改成 https://buzzai.cc/v1 之后,跑同一个 prompt 的成本会明显更低。代码里除了 URL 之外不用动。
BUZZ 不公布一个固定折扣百分比,因为不同模型、不同 token 配比下省下来的额度不一样。最实在的答案是看实时数字 —— 所有受支持家族(Claude、GPT、Gemini、Grok)的全部变体的实时单价都在 https://buzzai.cc/api/pricing。把它和上游官方价目页对一遍,乘以你每月 token 体量,Excel 就会给你一个真实数字。
同一把 key 在 Claude Code 上
如果你也用 Claude Code 当终端编程助手,同一把 BUZZ key 可以在那边直接用。一行命令把 CLI 指到网关:
curl -fsSL https://buzzai.cc/sh/claudecode.sh | bash
应用代码通过 OpenAI SDK 打 https://buzzai.cc/v1,Claude Code 通过 Anthropic 协议打 https://buzzai.cc,账单都落到同一把 key、同一个看板。
7. FAQ
真的能用官方 OpenAI Python SDK 直接调 Claude 吗?
能。设 base_url="https://buzzai.cc/v1",把 api_key 填成 BUZZ key,给 client.chat.completions.create 传 model="claude-opus-4-8"(或任何其他支持的模型标识)。SDK 不需要知道上游是 Anthropic。网关替你在 chat.completions 和 Anthropic Messages 之间双向翻译。
Streaming 还能正常用吗?
能。传 stream=True。网关按 OpenAI 的 chunk 格式下发 SSE delta。遍历响应拿到的 chunk.choices[0].delta.content 和真实 OpenAI 流一模一样,网关侧零缓冲。
Tool Calling / Function Calling 怎么办?
走标准 OpenAI 的 tools 和 tool_choice 参数。网关出向把它们映射到 Anthropic 的 tool_use 块或 Gemini 的 functionDeclarations,入向把上游的工具选择回译成 OpenAI 的 tool_calls。已有的 tool calling 循环原样工作。
重试、日志、链路追踪要改吗?
不用。包在 OpenAI 客户端外面的所有东西 —— LangChain、LlamaIndex、OpenTelemetry instrumentation、retry 装饰器、请求日志中间件 —— 全部原样工作。只有 base_url 和 model 名字变了。
temperature、max_tokens 这些采样参数会被尊重吗?
标准 chat.completions 参数(temperature、top_p、max_tokens、stop、presence_penalty、frequency_penalty、上游支持的 seed)按最近似语义转发。行为以上游模型为准,不是 OpenAI 语义,所以同一个数值在不同家族下分布可能不同。按模型调参,不要按数字调。
OpenAI 兼容路径下哪些功能没法干净映射?
在 chat.completions 里没有规范位置的上游原生特性:Anthropic 的 extended_thinking 块、Anthropic 的 prompt cache 控制、Gemini 专属的安全和 grounding 控制,以及上游有类型的流式事件。需要这些时,用 Anthropic SDK 打到 https://buzzai.cc。同一把 key 在两套协议上都有效。
跨家族的模型名怎么写?
model 字段就是路由 key。claude-opus-4-8、claude-sonnet-4-6、claude-haiku-4-5、gpt-5、gpt-5.5、gpt-5.4、gpt-5.4-mini,以及当下的 Gemini 和 Grok 名字都能正确路由。完整在线列表见 https://buzzai.cc/models。
价格相对直连 OpenAI 怎么样?
BUZZ 在所有支持的家族上都明显低于一手官方价。因为只有 base_url 改了,代码路径不变,同一份代码就更便宜。各模型实时单价见 https://buzzai.cc/api/pricing。
同一把 key 能在 Claude Code 上用吗?
能。curl -fsSL https://buzzai.cc/sh/claudecode.sh | bash 装好预配置过的 Claude Code。CLI 走 Anthropic 协议打到 https://buzzai.cc,和 OpenAI SDK 用 https://buzzai.cc/v1 共享同一把 key。
这是真透明转发,还是网关偷偷改了 prompt?
BUZZ 透明转发请求体和响应体。不修改 system prompt、不注入指令、不偷换模型。唯一的转换是 chat.completions 与上游原生协议之间的协议桥,只动结构,不动内容。
8. 结论
OpenAI Python SDK 已经赢下了应用层 LLM 代码的"普通话"之争 —— 这没什么不好。生产代码大多数事情只要发消息、流 token、调工具、暴露用量,它够用了。错误的姿势是把它当成一份把你和某一个模型家族绑死的合约。一旦有一个网关在入向说同一种协议、在出向按你写的 model 名字分发,SDK 就退化成传输细节,模型名字才是选择本身。
把 OpenAI SDK 指到 https://buzzai.cc/v1,你换来的是:一行配置打通所有主流模型家族;成本明显更低;零数据留存;Streaming 和 Tool Use 全部保真;现有重试、日志、追踪封装一个不动。哪天某个 Claude 原生特性(比如 extended thinking)真的需要时,Anthropic SDK 就在同一把 key、同一个网关上,多一个依赖而已。无聊的部分继续无聊 —— 这才是基础设施工作唯一诚实的目标。
把 URL 丢进 client 构造器,改一下 model 名字,跑一遍现有测试。这种迁移要的是一杯咖啡,不是一个 sprint。