上个月我接了个私活,甲方要做一个合同的小工具,指定要用 Claude Opus 4.7 来做长文本分析。说实话需求不复杂,但光是把 Claude API 在 Python 里跑通这一步,我就折腾了大半天——官方文档更新滞后、SDK 版本对不上、请求格式还分两套协议。踩完坑之后我把整个过程整理了一下,省得你们再走弯路。

Python 调用 Claude API 的核心步骤是:安装 Anthropic 官方 SDK(或用 OpenAI 兼容协议),配置 API Key 和 base_url,用 messages.create() 发起请求。下面我把三种方案都跑一遍,附完整代码和实测延迟。

先说结论

方案 协议 上手难度 适合场景
Anthropic 官方 SDK Anthropic 原生 最简单 纯用 Claude,不需要切模型
OpenAI SDK 兼容模式 OpenAI 兼容 简单 项目里同时用 GPT 和 Claude
裸 HTTP 请求 REST API 稍麻烦 极端定制、调试、或者不想装 SDK

我个人最后选了方案二,因为项目后期甲方又加了个需求要对比 GPT-5.5 的结果,用 OpenAI SDK 兼容协议切模型只要改一行 model 参数。

环境准备

Python 3.10+,建议开个虚拟环境:

python -m venv claude-demo
source claude-demo/bin/activate # Windows 用 claude-demo\Scripts\activate

# 两个 SDK 都装上,后面三种方案都要用
pip install anthropic>=0.42.0 openai>=1.58.0

API Key 的话,你可以去 Anthropic 官网 console.anthropic.com 申请,也可以用聚合平台的 Key。我这边测试用的是 ofox.ai 的 Key,因为 Anthropic 官方通道有时候注册要绑海外信用卡挺烦人的。

方案一:Anthropic 官方 SDK(最正统)

这是最直接的方式,SDK 封装得很干净:

import anthropic
import time

client = anthropic.Anthropic(
 api_key="sk-your-api-key",
 base_url="https://api.ofox.ai/v1" # 也可以用官方默认地址
)

start = time.time()
message = client.messages.create(
 model="claude-sonnet-4-20250514",
 max_tokens=1024,
 messages=[
 {"role": "user", "content": "用 Python 写一个快速排序,要求支持自定义比较函数"}
 ]
)
elapsed = (time.time() - start) * 1000

print(message.content[0].text)
print(f"耗时: {elapsed:.0f}ms")
print(f"Token 用量: 输入 {message.usage.input_tokens}, 输出 {message.usage.output_tokens}")

实测跑了 5 次,P50 延迟在 280ms 左右(首 token),P95 大概 350ms。返回的代码质量没啥问题,快排实现带了 key 参数支持。

流式输出

做聊天界面的话肯定要 streaming,不然用户盯着空白页等 3 秒体验很差:

with client.messages.stream(
 model="claude-sonnet-4-20250514",
 max_tokens=1024,
 messages=[
 {"role": "user", "content": "解释一下 Python 的 GIL 是什么,为什么它让多线程变慢了"}
 ]
) as stream:
 for text in stream.text_stream:
 print(text, end="", flush=True)

stream 模式下首 token 基本 200ms 以内就出来了,体感快很多。

方案二:OpenAI SDK 兼容协议(我最终用的)

如果你项目里已经在用 OpenAI SDK 调 GPT,切 Claude 只需要改 base_url 和 model 名:

from openai import OpenAI
import time

client = OpenAI(
 api_key="sk-your-api-key",
 base_url="https://api.ofox.ai/v1"
)

start = time.time()
response = client.chat.completions.create(
 model="claude-sonnet-4-20250514",
 messages=[
 {"role": "system", "content": "你是一个资深 Python 开发者,回答简洁直接。"},
 {"role": "user", "content": "asyncio.gather 和 asyncio.TaskGroup 有什么区别?什么时候用哪个?"}
 ],
 max_tokens=1024,
 stream=False
)
elapsed = (time.time() - start) * 1000

print(response.choices[0].message.content)
print(f"耗时: {elapsed:.0f}ms")

这里有个坑。Claude 原生协议其实不支持 system 作为 messages 里的 role,它是用单独的 system 参数传的。但走 OpenAI 兼容协议的话,聚合网关会自动帮你转换,所以上面代码直接跑没问题。

我一开始不知道这个,直接用 Anthropic SDK 往 messages 里塞 {"role": "system", ...},结果报了这个错:

anthropic.BadRequestError: Error code: 400 - {'type': 'error', 'error': {'type': 'invalid_request_error', 'message': 'messages: roles must alternate between "user" and "assistant", and messages must start with "user" role'}}

查了半天才发现 Anthropic SDK 里 system prompt 要这么写:

message = client.messages.create(
 model="claude-sonnet-4-20250514",
 max_tokens=1024,
 system="你是一个资深 Python 开发者,回答简洁直接。", # 注意:单独参数!
 messages=[
 {"role": "user", "content": "你的问题"}
 ]
)

这就是我为什么更推荐方案二——OpenAI 兼容协议把这些差异都抹平了,不用记每家 API 的格式区别。

方案三:裸 HTTP 请求(调试用)

有时候 SDK 报错信息不够详细,或者你在一个不方便装包的环境(比如 AWS Lambda 冷启动要控制包体积),直接用 requests 也行:

import requests
import json

url = "https://api.anthropic.com/v1/messages"
headers = {
 "x-api-key": "sk-your-api-key",
 "anthropic-version": "2023-06-01",
 "content-type": "application/json"
}
payload = {
 "model": "claude-sonnet-4-20250514",
 "max_tokens": 1024,
 "messages": [
 {"role": "user", "content": "Python 里 match-case 语法有哪些实际用途?举3个例子"}
 ]
}

resp = requests.post(url, headers=headers, json=payload, timeout=30)

if resp.status_code == 200:
 data = resp.json()
 print(data["content"][0]["text"])
else:
 print(f"请求失败: {resp.status_code}")
 print(resp.text)

注意 Anthropic 原生协议的 header 是 x-api-key 不是 Authorization: Bearer xxx,这个跟 OpenAI 不一样。我第一次用 Authorization 头发请求,返回了个 401 authentication_error,对着屏幕发呆了五分钟才反应过来。

调用链路长什么样

graph LR
 A[你的 Python 代码] -->|API Key + 请求| B{选择协议}
 B -->|Anthropic SDK| C[Anthropic 原生协议]
 B -->|OpenAI SDK| D[OpenAI 兼容协议]
 B -->|requests| E[HTTP REST API]
 C --> F[API 网关]
 D --> F
 E --> F
 F --> G[Claude Opus 4.7]
 F --> H[Claude Sonnet 4.6]
 F --> I[Claude Haiku 4.5]

三种方案最终都是走 HTTP 到服务端,区别只是 SDK 帮你封装了多少。

踩坑记录

坑 1:anthropic-version header 过期

4 月 22 号我用 anthropic-version: 2023-01-01 发请求,返回了一堆 deprecated warning,虽然还能用但响应格式跟文档对不上。改成 2023-06-01 就正常了。这个版本号不是 SDK 版本,是 API 协议版本,别搞混。

坑 2:max_tokens 是必填的

OpenAI 的 API 里 max_tokens 可以不传(默认给你一个值),但 Claude API 里这个参数是必填的。不传直接 400:

{'type': 'error', 'error': {'type': 'invalid_request_error', 'message': 'max_tokens: field required'}}

坑 3:并发限制

Anthropic 官方的免费 tier 限制很紧,我测试的时候开了 5 个并发就触发了 429 rate limit。后来换了聚合平台的 Key 才跑通压测。如果你也遇到 429 rate_limit_error,要么升级 tier 要么走 OpenRouter、ofox.ai 这类聚合网关绕开单账户限流——ofox.ai 是 Anthropic 官方授权的服务商,走的是 Anthropic 和 AWS Bedrock 的官方通道,不是那种野路子中转。

坑 4:图片输入的 base64 大小限制

Claude 支持多模态,但图片 base64 编码后不能超过 20MB。我传了一张 4K 截图(原图 8MB,base64 编码后膨胀到 ~11MB),没问题。但同事传了一张未压缩的设计稿(原图 18MB),直接超限了。建议先压缩到 1080p 再传。

Function Calling 示例

这个是 4 月份很多人问的,Claude 的 tool use 跟 OpenAI 的 function calling 思路一样但格式不同:

import anthropic

client = anthropic.Anthropic(
 api_key="sk-your-api-key",
 base_url="https://api.ofox.ai/v1"
)

tools = [
 {
 "name": "get_weather",
 "description": "获取指定城市的天气信息",
 "input_schema": {
 "type": "object",
 "properties": {
 "city": {"type": "string", "description": "城市名称"},
 "unit": {"type": "string", "enum": ["celsius", "fahrenheit"], "description": "温度单位"}
 },
 "required": ["city"]
 }
 }
]

message = client.messages.create(
 model="claude-sonnet-4-20250514",
 max_tokens=1024,
 tools=tools,
 messages=[
 {"role": "user", "content": "东京今天天气怎么样?"}
 ]
)

# 检查是否触发了 tool_use
for block in message.content:
 if block.type == "tool_use":
 print(f"调用工具: {block.name}")
 print(f"参数: {json.dumps(block.input, ensure_ascii=False)}")

输出:

调用工具: get_weather
参数: {"city": "东京", "unit": "celsius"}

注意 Anthropic 的 tool 定义用的是 input_schema 不是 OpenAI 的 parameters,又是一个格式差异。

小结

三种方案各有适用场景。只用 Claude 的话方案一最干净;项目里要同时调多家模型,方案二省心;调试或者极端轻量场景,方案三够用。

我目前自己的项目全部用方案二,代码里统一 OpenAI SDK,切模型改一行字符串就行。也不确定这是不是最佳实践,但至少跑了一个月没出过问题。反正能跑就行,别过度设计。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐