Anthropic 在本周终于发布了 anthropic==1.0.0。发布说明只用一句话概括 breaking changes:客户端迁到 httpx2,再加一些较小的破坏性调整。源码里实际删掉了 LegacyAPIResponse、Text Completions、客户端压缩逻辑和多组废弃参数。
这次没有 Claude API v2。Messages 仍然请求 /v1/messages。升级风险集中在 Python 客户端和应用代码的接缝处。我把固定版本的迁移指南、v0.125.0...v1.0.0 源码差异和测试逐项对过,普通 Messages 调用的改动很小,边界代码需要认真查。
1.0 改了哪一层
SDK 的公开调用链可以压成四层:资源方法负责 Python 签名,类型层把参数转成请求体,BaseClient 处理 header、重试和错误,HTTP 客户端负责网络传输。
1.0 同时收紧了四处:传输从 httpx 切到 httpx2;资源层删除 Text Completions;参数层清理 sampling 和旧 structured-output 入口;响应层删除 LegacyAPIResponse。服务端 Messages 协议没有因此换代。
本地做了一个不发送 API 请求的定向探针。0.125.0 仍有 HUMAN_PROMPT、AI_PROMPT、Transport、ProxiesTypes 和 client.completions;1.0.0 里全部消失。旧 httpx.Client 传进新客户端会在构造时抛 TypeError。Python 3.9 的依赖解析也直接失败。
httpx2 带来的对象边界
httpx2 保留了接近 httpx 的调用形状,两套包的类身份互不相同。httpx.Client is not httpx2.Client,Request、Response、Timeout、Transport 和异常也一样。
下面这些项目要改成 httpx2:
- 传给
http_client= 的同步或异步 Client - 自建 Timeout、Transport、Limits、Proxy
APIStatusError.response 和 APIConnectionError.request 的类型注解- raw response 的
http_response、headers、url 类型判断 - 自定义 event hook 的 request/response 参数
SDK 自己导出的 anthropic.Timeout、DefaultHttpxClient、DefaultAsyncHttpxClient 和 DefaultAioHttpClient 还在,只是已经指向新实现。
应用可以在任何 httpx 导入之前调用 httpx2.alias_httpx(),把进程内的 import httpx 和 import httpcore 指向新包。这个桥接应由应用入口决定。库代码擅自全局 alias,会修改宿主进程的导入语义。
更隐蔽的问题在测试和监控。旧版本的 RESPX、pytest-httpx 或 APM 继续 patch httpx,进程可能没有报错,却看不到 SDK 经 httpx2 发出的请求。测试退出码为 0 也不能证明 mock 命中,有机会误打真实 API。我会额外断言 route 或 cassette 的命中次数,并在测试环境禁网。
截至 8 月 24 日,OpenTelemetry 0.65b0、Sentry 2.62.0、VCR.py 8.2.0 已有官方 HTTPX2 支持;RESPX 0.23.1 和 pytest-httpx 0.36.2 的原生支持仍停留在开放 PR。这里的版本状态会变化,迁移时要按自己的锁文件复查。
Raw response 的调用方式变了
.with_raw_response 不再返回 LegacyAPIResponse。同步客户端拿到 APIResponse,异步客户端拿到 AsyncAPIResponse。
完整映射如下:
| | |
|---|
parse() | parse() | await parse() |
text | text() | await text() |
content | read() | await read() |
http_response.json() | json() | await json() |
http_response.iter_*() | iter_*() | async for |
headers、status_code、url、request_id、retries_taken、http_response 和 elapsed 仍是普通属性。异步代码漏掉 await 时,拿到的是 coroutine,错误经常到下游才暴露。我觉得这组改动应单独做一个 sync/async 契约测试,成本不高,定位价值很大。
旧 API 和请求参数逐项清理
Text Completions 整组删除
删除项包括:
client.completions.create()Completionanthropic.HUMAN_PROMPT
迁移到 Messages 需要改三处数据结构:拼接字符串 prompt 变成带 role 的 messages 数组,max_tokens_to_sample 变成 max_tokens,Completion.completion 字符串变成 Message.content 内容块。机械替换方法名会留下返回值 bug。
Sampling 参数移出公开签名
temperature、top_p、top_k 从这些接口删除:stable 和 beta 的 create()、parse()、stream(),beta tool_runner(),以及对应的 batch request 参数类型。
直接调用方法时继续传旧关键字会在发请求前触发 TypeError。这只能证明 SDK 公开签名删除,不能外推所有历史模型都拒绝同名 JSON 字段。官方保留了 extra_body 逃生口,只有固定旧模型且服务端契约已验证时才值得用。普通项目直接删掉最省心。
Structured outputs 分成两个入口
手写 schema dict 放到:
output_config={ "format": { "type": "json_schema", "schema": Order.model_json_schema(), }}
helper 的 output_format=Order 继续保留,由 SDK 生成 schema 并解析结果。把 schema dict 传给 helper 的 output_format= 会抛 TypeError。
接口边界还有一个细节:stable count_tokens() 仍支持 output_format=ModelType;beta count_tokens() 的 output_format 已完全删除,只接受 output_config。beta create() 也不再接受旧 raw output_format,beta parse()、stream()、tool_runner() 则保留类型 helper。
删除的导出与别名
| |
|---|
BetaBase64PDFBlockParam | BetaRequestDocumentBlockParam |
anthropic.Transport | httpx2.BaseTransport |
anthropic.ProxiesTypes | httpx2.Proxy |
| httpx2.AsyncBaseTransport |
| |
READ_MAX_BYTES | DEFAULT_MAX_FILE_BYTES |
八个容易漏掉的行为变化
parse(stream=True) 删除
parse() 一直是非流式 helper,旧 stream=True 也无法正常工作。流式 structured output 改用 messages.stream(..., output_format=ModelType)。
tool runner 客户端压缩删除
compaction_control= 和 CompactionControl 被移除。替代方案是 server-side compaction beta 加 context_management.edits,触发阈值至少 50,000 tokens。
执行位置也变了。旧 runner 会额外调用模型做总结,再在本地重写消息历史;新方案由 API 触发压缩。token、成本、失败点和日志都要重新观察。
raw bytes 改走 content=
低层 client.get/post/put/patch/delete 里,body= 只做 JSON 序列化。原始 bytes 使用 content=,它也能接 iterator 做流式上传。
MessageStream 不再伪装成 Stream
messages.stream() 返回的 MessageStream 很早就没有继承 raw Stream,0.x 用兼容 shim 让 isinstance() 暂时返回 True。1.0 删除 shim,判断结果变成 False。需要分流时检查 MessageStream 或 AsyncMessageStream。messages.create(stream=True) 返回的 raw Stream 没被删除。
Header 按大小写不敏感合并
default_headers、extra_headers、with_options、环境变量和 SDK 默认 header 现在统一按 HTTP 语义合并。后写入的同名字段覆盖前者,omit 也能跨大小写删除。
如果旧代码靠 X-Key 和 x-key 同时发送两行,行为会改变。确需多值时要按协议显式合并。bytes header value 也不再接受,应按协议转成文本、hex 或 Base64。
Bedrock region 改成启动期校验
AnthropicBedrock 和异步版本过去找不到 region 时 warning 后回退 us-east-1。1.0 按 aws_region、环境变量、boto3 profile 的顺序解析,全都没有就抛 ValueError。旧版忽略 profile region 的问题也一起修掉了。
Bedrock 独立 metrics chunk 被过滤
源码边界比迁移指南的一句话更细:带字符串 type 的事件仍发出;没有 type 但有 legacy completion 的 chunk 仍处理;两者都没有才跳过。独立的 amazon-bedrock-invocationMetrics 会消失,附在 typed message_stop 里的 metrics 仍保留。
升级门怎么设
我会按项目命中面安排回归:
- 环境门:生产镜像、CI 和开发机确认 Python 3.10+
- 接口门:搜索 Completions、prompt 常量、sampling、raw
output_format - 传输门:搜索 httpx 对象、异常捕获、event hook、proxy 和企业 CA
- 响应门:raw response 同步和异步各留一个读取用例
- 观测门:成功、4xx、timeout 都检查 trace 与 mock 命中
- 云端门:Bedrock 覆盖 region 三条来源和两种 metrics 形态
只用标准 Messages、Python 已在 3.10+、没有自定义 HTTP 或 raw response 的项目,可以进入常规升级分支。使用 structured-output helper、tool runner、headers 的项目先改再灰度。Python 3.9、企业 TLS、旧 mocking/APM、Bedrock metrics 依赖,适合单独开兼容性分支。
总结
Claude Python SDK 1.0 清掉了长期兼容负担,也把 HTTP 运行时换到新的维护分支。它的升级难度与业务功能多少关系不大,真正决定成本的是项目有没有跨过 SDK 边界去持有 HTTP 对象、响应对象和运行时 hook。
我更关心静默失败:mock 没命中、trace 少字段、header 覆盖变化、Bedrock metrics 消失。这些问题不会都在启动时提醒你。把 22 项变化映射到项目实际用法,保留少量高信息增益的契约测试,通过后再放量,迁移会清楚很多。