Claude 的 SDK 和命令行:重试和超时到底怎么工作,用 OpenAI 的 SDK 调 Claude,以及官方命令行 ant
官方给 Claude 的接口配了七种语言的 SDK、一个命令行和两个兼容层。本文整理各自怎么装、适合谁,并做了实测:对着假服务器看 Python SDK 的重试和超时(碰到带 retry-after 60 的 503,它等了两分钟才报错);用 OpenAI 的 SDK 调 Claude;通过中转站用官方命令行 ant。
本站已实测,测试日期:2026-10-13。
本页目录(13 节)
这篇教程解决一个问题:自己写程序调 Claude,官方给了哪些现成的工具,各自适合谁?SDK 替你做的重试和超时,实际是怎么工作的?
这是《第一次直接调 Claude 的接口》的续篇。那一篇讲请求和响应长什么样,这一篇讲用什么去发。
| 实测环境 | |
|---|---|
| 日期 | 2026-10-13 |
| 版本 | Anthropic Python SDK 1.13.0,TypeScript SDK 0.133.0,openai 包 3.29.0,ant 1.40.0,Node.js 22 |
| 模型 | Sonnet 5.5 |
| 连接方式 | 通过酷站AI 中转站;重试和超时那一组对着本机的假服务器 |
先看全貌:三类工具
| 类别 | 是什么 | 适合 |
|---|---|---|
命令行 ant |
在终端里调接口的工具 | 写 shell 脚本、临时查点东西 |
| 客户端 SDK | 七种语言的库 | 在程序里调接口,绝大多数人用这个 |
| 兼容层 | 让 Claude 出现在别的框架的接口里 | 已经有一套用 OpenAI SDK 或 Apple 框架写的代码 |
这三类都是你自己发每一个请求、处理每一个响应。要现成的智能体循环、工具执行,那是更上一层的东西:Claude Code、Agent SDK、Managed Agents。
一、七种语言的 SDK
| 语言 | 怎么装 | 要求 |
|---|---|---|
| Python | pip install anthropic |
Python 3.10 及以上 |
| TypeScript | npm install @anthropic-ai/sdk |
TypeScript 5.0 及以上,Node.js、Deno、Bun、浏览器都能跑 |
| Go | go get github.com/anthropics/anthropic-sdk-go |
Go 1.24 及以上 |
| Java | Maven 或 Gradle 里加 com.anthropic:anthropic-java |
Java 8 及以上 |
| C# | dotnet add package Anthropic |
.NET Standard 2.0 及以上 |
| PHP | composer require "anthropic-ai/sdk" |
PHP 8.1 及以上。目前是测试版 |
| Ruby | bundle add anthropic |
Ruby 3.2 及以上 |
它们做的事是一样的:帮你带上认证、版本、内容类型这几个请求头,把响应变成有类型的对象,处理流式、重试和报错。
读地址和 key 的方式也一样,都从环境变量里拿:ANTHROPIC_API_KEY 是 key,ANTHROPIC_BASE_URL 是接口地址。通过中转站,设这两个就行,代码不用改。
Python SDK 从 0.x 升到 1.x 有不兼容的改动,官方有一份迁移说明。老项目升级前先看。
二、实测:Python SDK 的重试
文档说:连接错误、408、409、429 和 500 以上的错误会自动重试,默认 2 次,带指数退避。
本站在本机起了一个假服务器,让它按设定返回各种状态码,数它实际收到了几次请求、隔了多久。这样不用碰真实的接口,也看得最清楚:
| 假服务器的表现 | 它收到几次请求 | 两次之间隔多久 | 最后的结果 |
|---|---|---|---|
| 一直 500 | 3 次 | 0.4 秒、0.8 秒 | InternalServerError |
一直 500,max_retries=0 |
1 次 | InternalServerError |
|
一直 500,max_retries=5 |
6 次 | 0.5、0.8、1.7、4.0、6.4 秒 | InternalServerError,共 13.4 秒 |
| 一直 400 | 1 次 | BadRequestError |
|
| 一直 401 | 1 次 | AuthenticationError |
|
一直 429,带 retry-after: 2 |
3 次 | 2.0 秒、2.0 秒 | RateLimitError |
一直 503,带 retry-after: 60 |
3 次 | 60 秒、60 秒 | InternalServerError,共 120 秒 |
| 前两次 529,第三次成功 | 3 次 | 0.6 秒、0.8 秒 | 成功 |
从这张表里能读出:
- 默认是“1 次加重试 2 次”,一共 3 次。 每次重试的请求带着一个计数的头,值是 0、1、2。
- 400 和 401 不重试。 请求本身有问题,重试没有意义。
- 退避是越等越久的,从不到半秒开始,大致翻倍。
- 服务器给了
retry-after,它就照着等。 给 2 秒等 2 秒,给 60 秒等 60 秒。 - 临时的过载能自己扛过去。 前两次 529、第三次好了,你的代码完全感觉不到。
倒数第二行值得多说一句。酷站AI 在请求缺 max_tokens 时返回的就是一个带 retry-after: 60 的 503(见《报错、限流和停止原因》)。SDK 看到的是“服务暂时不可用,60 秒后再试”,于是老老实实等两分钟,三次都失败才把错误交给你。Python SDK 自己不会漏掉 max_tokens,它是必填参数;但用别的方式拼请求的话,这类“看起来是临时故障、其实怎么重试都没用”的返回,会让程序卡很久才报错。
怎么改:
client = anthropic.Anthropic(max_retries=0) # 全局
client.with_options(max_retries=5).messages.create(...) # 只管这一次
三、实测:超时
文档说默认超时是 10 分钟,超时了会抛 APITimeoutError,而且超时也会重试两次。
| 情况 | 收到几次请求 | 结果 |
|---|---|---|
| 服务器 3 秒才回,客户端超时设 1 秒 | 3 次 | APITimeoutError,共 4.2 秒 |
端口根本没人听,max_retries=1 |
APIConnectionError,0.4 秒 |
所以把超时设成 1 秒,并不是“最多等 1 秒”,是“最多等 3 个 1 秒再加退避”。要严格控制总时间,超时和重试次数要一起设。
client = anthropic.Anthropic(timeout=30.0, max_retries=1)
另外一条相关的规矩:非流式请求如果预计会超过 10 分钟(max_tokens 很大的时候),SDK 直接拒绝发送,要你改用流式。原因和怎么写,见上一篇的流式一节。
四、Python SDK 里几样顺手的东西
都通过中转站跑过:
| 想做的事 | 写法 |
|---|---|
| 同时发很多请求 | anthropic.AsyncAnthropic(),接口和同步的一模一样,前面加 await |
| 流式,逐段拿文字 | with client.messages.stream(...) as s: 再遍历 s.text_stream |
| 拿响应头和状态码 | client.messages.with_raw_response.create(...) |
| 翻页 | 直接 for m in client.models.list():,它自己取下一页 |
| 用测试中的功能 | client.beta.messages.create(betas=[...], ...) |
| 数 token | client.messages.count_tokens(...) |
异步并发量大的时候,文档建议把底层的 HTTP 库换成 aiohttp,装的时候带上对应的可选依赖。
响应对象是 Pydantic 模型,可以 model_dump() 成字典。要注意的一点:字段是 None,可能是接口明确返回了空值,也可能是根本没返回这个字段,两者要分的话看 model_fields_set。
五、中间件:在请求前后插一段自己的代码
SDK 留了一个钩子:请求发出去之前、响应回来之后,各跑一段你的代码。适合放日志、给请求打标记、自定义重试。
def logging_middleware(request, call_next):
print(f"-> {request.method} {request.url}")
response = call_next(request) # 交给后面的环节
print(f"<- {response.status_code}")
return response
client = anthropic.Anthropic(middleware=[logging_middleware])
实测发一个请求,它记下了两行:-> post /v1/messages 和 <- 200(本站只打印了网址里的路径)。
注册了多个的话按顺序套:第一个的“之前”最先跑,它的“之后”最后跑。
写日志时别把请求头整个打出来,认证信息在里面。
SDK 自带一个现成的中间件,用来处理拒答:模型拒绝回答时自动换一个模型重试。
六、用 OpenAI 的 SDK 调 Claude
已经有一套用 OpenAI SDK 写的代码,想试试换成 Claude 是什么效果,不用重写。改三处:接口地址、key、模型名。
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["ANTHROPIC_API_KEY"],
base_url=os.environ["ANTHROPIC_BASE_URL"] + "/v1", # 直连官方是 https://api.anthropic.com/v1/
)
response = client.chat.completions.create(
model="claude-sonnet-5-5",
max_tokens=300,
messages=[
{"role": "system", "content": "回答不超过十个字。"},
{"role": "user", "content": "天空为什么是蓝的?"},
],
)
print(response.choices[0].message.content)
官方对这个兼容层的定位很明确:主要用来测试和比较,不建议当成长期的方案。 它的限制:
| 限制 | 说明 |
|---|---|
| 没有提示缓存 | 这一条对成本影响最大 |
| 拿不到思考的内容 | 思考可以开,但返回里不给 |
strict 被忽略 |
函数调用的参数不保证符合你给的结构 |
response_format 被忽略 |
要 JSON 输出得用原生接口的结构化输出 |
| system 消息会被提到最前面 | 对话中间的 system 和 developer 消息,都被拼起来放到开头 |
| 很多字段悄悄忽略 | seed、logprobs、presence_penalty、user、reasoning_effort 等,不报错,也不起作用 |
| 没有 PDF、引用这些 Claude 特有的功能 |
实测:通过中转站
| 试了什么 | 结果 |
|---|---|
| 基本请求,带 system | 正常。回答是“因为大气对蓝光散射更强。” |
| 流式 | 正常 |
| 函数调用 | 正常,finish_reason 是 tool_calls,参数是 {"city":"上海"} |
stop=["3"] |
没生效,照常数到了 5 |
response_format 用 JSON 结构 |
返回了 {"country":"中国"} |
reasoning_effort="low" |
请求被接受 |
| 模型名写错 | 404,报错是中文的 |
要说明一点:通过中转站走的是中转站自己的 OpenAI 兼容接口,不是 Anthropic 官方的那个兼容层。 所以这张表和上面官方的限制表对不上是正常的。比如 response_format,官方说会被忽略,这里却返回了合乎结构的 JSON。哪些字段真的起作用,以你用的那一家为准,自己测一遍。
停止序列不生效这一条,和用原生接口测到的一样。
七、TypeScript 的第一个请求
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic(); // 自动读环境变量里的地址和 key
const message = await client.messages.create({
model: "claude-sonnet-5-5",
max_tokens: 300,
messages: [{ role: "user", content: "用一句话解释什么是 SDK。" }],
});
const text = message.content.filter((b) => b.type === "text").map((b: any) => b.text).join("");
console.log(text, message.stop_reason);
通过中转站跑通了:非流式、流式(client.messages.stream(...) 加 finalMessage())、报错(模型名写错时抛的是 Anthropic.NotFoundError,status 是 404)。选项名是驼峰写法(maxRetries),响应里的字段名仍然是下划线写法(stop_reason),这一点和 Agent SDK 的 TypeScript 版一样。
八、官方命令行 ant
ant 把每一种接口资源做成一个子命令。和手写 curl 比,它的好处是:请求体用带类型的参数或者 YAML 来拼,不用手写 JSON;可以用 @路径 把文件内容塞进某个字段;自带一个取字段的参数,不用再接 jq。
ant messages create \
--model claude-sonnet-5-5 --max-tokens 300 \
--message '{role: user, content: "用一句话解释什么是 API。"}'
| 说明 | |
|---|---|
| 怎么装 | macOS 用 Homebrew;Linux 下载发布页上的二进制;也可以用 Go 从源码装 |
| 登录 | ant auth login 走浏览器登录官方控制台,不用自己建 key。也认 ANTHROPIC_API_KEY 环境变量,设了的话它优先 |
| 换接口地址 | 设 ANTHROPIC_BASE_URL,或者加 --base-url |
| 命令的形状 | “资源 动作”,嵌套的用冒号,测试中的资源在 beta: 下面 |
| 取字段 | --transform 后面跟路径,配 --raw-output 去掉引号,方便赋给 shell 变量 |
| 输出格式 | --format,在终端里列表类的命令默认打开一个可以折叠、搜索的浏览界面,接管道时默认是 JSON |
它还有两样和 Managed Agents 配套的功能:
ant apply:把智能体、环境、skill 这些资源写成仓库里的文件,运行一次就按文件创建或更新,先给你看计划再执行。它会生成一个claude-lock.json记下每个文件对应的资源,要和文件一起提交。ant beta:sessions connect:把终端接到一个正在跑的托管会话上,实时看它在做什么,可以插话、打断、批准或拒绝等着确认的工具调用。
文档还提了一句:Claude Code 可以直接用 ant。装好并登录之后,让 Claude Code 帮你查、帮你改接口上的资源就行。
实测:通过中转站用 ant
本站在 Linux 服务器上装的是 1.40.0:从官方仓库的发布页下载压缩包(10.5 MB),核对 SHA-256 和 GitHub 上记录的一致,解压出一个 35 MB 的可执行文件,放在普通用户的目录里就能用,不需要 root。文档里的安装命令是解压到 /usr/local/bin,那才要 sudo。
设好 ANTHROPIC_BASE_URL 和 ANTHROPIC_API_KEY 两个环境变量,下面这些都跑通了:
| 试了什么 | 结果 |
|---|---|
ant messages create,用参数拼请求 |
正常,打印完整的 JSON |
加 --transform 和 --raw-output 只取回答的文字 |
正常,只输出一行文字 |
--transform '{stop_reason,usage.input_tokens}' --format yaml |
正常,每个字段一行 |
--system @./sys.txt,系统提示从文件读 |
正常,回答遵守了文件里的要求 |
| 请求体用 YAML 从标准输入给 | 正常 |
--stream --format jsonl |
正常,每个流式事件一行 JSON |
ant messages count-tokens |
正常,返回了一个数 |
ant models list --transform id --raw-output |
正常,每行一个模型 ID |
ant beta:messages create,带上下文编辑的参数 |
正常 |
ant beta:agents list |
404,这家中转站没有开托管智能体的接口 |
只取文字的那一条长这样:
$ ant messages create --model claude-sonnet-5-5 --max-tokens 300 \
--message '{role: user, content: "用一句话解释什么是命令行。"}' \
--transform 'content.#(type=="text").text' --raw-output
命令行是一种通过键盘输入文字指令(而不是点击图形界面)来让计算机执行操作的交互方式。
出错时它的退出码是 1,报错打在标准错误上,脚本里好判断:
$ ant messages create --model claude-does-not-exist --max-tokens 10 --message '{role: user, content: "hi"}'
POST "https://api.koozhan.com/v1/messages": 404 Not Found
{"error": {"message": "模型 \"claude-does-not-exist\" 不存在,请检查模型名称……", "type": "model_not_found"}, "type": "error"}
加上 --transform-error error.message --format-error yaml,就只剩那一句报错的文字。
三点提醒:
ant auth status会把 key 的开头一段显示出来。 它列出当前用的是哪个凭据、哪个接口地址,其中 key 那一行是前十几个字符加省略号。排查问题时很有用,但不要把它的输出原样贴到聊天、工单或截图里。- 不要加
--debug之后把输出贴出去。 调试输出里有完整的请求。 --message里的写法是放宽了的 YAML,键不用加引号。值里有冒号、引号这类字符时,老老实实用 JSON 的写法,或者改用标准输入给请求体。
apply 和 sessions connect 用的是托管智能体的接口,在这家中转站上用不了,没有试。浏览器登录(ant auth login)登的是官方控制台,也没有试。
九、Apple 的 Foundation Models
给做苹果平台应用的人:官方出了一个 Swift 包,让 Claude 作为服务端模型接进苹果的 Foundation Models 框架。应用里像用别的模型一样用它,请求从应用直接发到 Claude 的接口,不经过苹果。
它目前是测试版,要 iOS 27、macOS 27 这一代系统和 Xcode 27。它不是一个通用的接口客户端,只实现了那个框架要求的部分。本站没有试。
通过中转站用这些工具
| 工具 | 结果 |
|---|---|
| Python SDK | 正常。读 ANTHROPIC_BASE_URL 和 key,代码不用改 |
| TypeScript SDK | 正常,同上 |
| OpenAI 的 SDK | 能用,走的是中转站自己的兼容接口,行为和官方的兼容层不同 |
ant |
发消息、流式、数 token、列模型都正常;托管智能体的那些子命令用不了 |
| 其他五种语言的 SDK | 没有试 |
花费
重试和超时那一组没有花钱,对着的是本机的假服务器。通过中转站的请求一共三十次左右,都很短,按官方价估算不到 0.03 美元。
这次实测没有覆盖到的
- 官方接口没有测。 OpenAI 兼容那一节测的是中转站的兼容接口,官方兼容层的那张限制表是照文档写的。
- Go、Java、C#、PHP、Ruby 的 SDK 没有装,表里的安装方式和要求出自各自的文档。
ant的浏览器登录、apply、sessions connect没有试,Apple 的包也没有试(它要 macOS 27 和 Xcode 27)。- 重试只在 Python SDK 上测了。 其他语言的默认次数和退避方式,文档说是一致的,本站没有验证。
- SDK 自带的拒答回退中间件没有试。
来源
- SDKs, CLI, and libraries(Claude 开发平台文档)
- Python SDK(Claude 开发平台文档)
- TypeScript SDK(Claude 开发平台文档)
- Go SDK(Claude 开发平台文档)
- Java SDK(Claude 开发平台文档)
- C# SDK(Claude 开发平台文档)
- PHP SDK(Claude 开发平台文档)
- Ruby SDK(Claude 开发平台文档)
- SDK middleware(Claude 开发平台文档)
- OpenAI SDK compatibility(Claude 开发平台文档)
- Apple Foundation Models(Claude 开发平台文档)
- CLI quickstart(Claude 开发平台文档)
- Using the CLI(Claude 开发平台文档)
- CLI authentication options(Claude 开发平台文档)
- CLI scripting and automation(Claude 开发平台文档)
- Manage resources as code with ant apply(Claude 开发平台文档)
- Connect to a Managed Agents session from your terminal(Claude 开发平台文档)