結論|土台の入れ替えが 1 つ、あとは削除と細かい仕様変更

anthropic Python SDK が v1.0 になりました。 公開は 2026 年 8 月 20 日 (協定世界時) です。前日の 0.125.0 から続けて上げると、次のコマンド 1 本で破壊的変更が全部入ります。

pip install --upgrade "anthropic>=1,<2"

変更の性格は 2 つに分かれます。1 つは HTTP 層が httpx から httpx2 へ移ったこと。これだけが土台の入れ替えで、影響範囲を読むのに少し手間がかかります。残りは長く非推奨だったものの削除で、こちらは機械的に直せます。

期限は設定されていません。上げなければ何も起きない代わりに、上げた瞬間に全部来る形です。以下では、壊れる場所を影響の大きい順に並べ、それぞれ何を grep すれば見つかるかまで書きます。

注意

いちばん危ないのは、エラーが出ないまま壊れる箇所です。respx や OpenTelemetry のように httpx を差し替えて動く道具は、import に成功したまま SDK の通信を見失います。詳しくは後述します。

変更の一覧

変わったもの
Python の下限3.93.10
HTTP ライブラリhttpxhttpx2
Text Completions APIclient.completions.create()削除。Messages API へ
temperature / top_p / top_k直接指定できた削除。extra_body 経由
output_format の生スキーマoutput_format={...}output_config={"format": {...}}
非同期の .with_raw_responseresponse.parse()await response.parse()
.text / .content属性メソッド (.text() / .read())
tool_runner の圧縮compaction_controlサーバー側の context_management
AnthropicBedrock のリージョン未指定なら us-east-1 に落ちるValueError を送出
ヘッダ名の突き合わせ大文字小文字を区別区別しない

型チェッカを入れているなら、v1.0 を入れたあとに 1 回走らせるのがいちばん早い見つけ方です。ここに並べた大半は型エラーとして出ます。

Python 3.10 以上が必須になった

v1.0 は Python 3.10 以上を要求します。PyPI 上のメタデータも >=3.10 です。3.9 のまま pip install --upgrade を打っても、依存解決が最後の 0.x に留まるだけで壊れません。逆に言うと、上げたつもりで上がっていない状態になります。

CI のマトリクスや Dockerfile のベースイメージに 3.9 が残っているなら、SDK の移行とは別の判断が要ります。ここを動かすと SDK 以外の依存も一緒に動くので、同じコミットに混ぜないほうが後で追いやすくなります。

httpx から httpx2

何が入れ替わったのか

httpx2httpx の後継として公開されている HTTP クライアントです。PyPI の配布元は pydantic/httpx2 で、作者欄には httpx の原作者である Tom Christie の名前が入っています。README にも httpx とコミュニティの成果を引き継いだものだと書かれています。

anthropic 1.0.0 の依存宣言は httpx2<3,>=2.0.0 です。SDK を入れれば一緒に入るため、追加の install は要りません。

補足

依存の監査ツールやレビュアーは、見慣れないパッケージ名をタイポスクワットとして疑います。差分に httpx2 が現れるなら、上の出自を PR の説明に 1 行添えておくと止まりません。

直すのは SDK との境界だけ

書き換えが要るのは、SDK に渡す httpx オブジェクトと、SDK から受け取る httpx オブジェクトだけです。timeout=30.0max_retries=3 のような素の値は何も変わりません。

# 変更前
import httpx
from anthropic import Anthropic, DefaultHttpxClient
 
client = Anthropic(
    timeout=httpx.Timeout(60.0, connect=5.0),
    http_client=DefaultHttpxClient(
        proxy="http://my.proxy.example",
        transport=httpx.HTTPTransport(local_address="0.0.0.0"),
    ),
)
# 変更後
import httpx2 as httpx
from anthropic import Anthropic, DefaultHttpxClient
 
client = Anthropic(
    timeout=httpx.Timeout(60.0, connect=5.0),
    http_client=DefaultHttpxClient(
        proxy="http://my.proxy.example",
        transport=httpx.HTTPTransport(local_address="0.0.0.0"),
    ),
)

httpx2httpx と同じクラス名・同じ振る舞いを持つため、その module を SDK 用途にしか使っていないなら import の別名を変えるだけで済みます。SDK 以外の通信にも使っているなら両方を import して、SDK に渡すものだけ httpx2 にします。

受け取る側も型が変わります。APIStatusError.responseAPIConnectionError.request、raw レスポンスの .http_response などが httpx2 の型になるので、httpx.Response を名指しした型注釈と isinstance の判定は書き換えが要ります。属性は同じなので、それ以外は動きます。

自前のミドルウェアを挟んでいる場合は、いちばん外側だけ直しても足りません。httpx.BaseTransport を継承したクラス、その内側で委譲している httpx.HTTPTransport()event_hooks に渡すコールバックの型注釈まで、全部 httpx2 側へ寄せる必要があります。1 つでも古い httpx に委譲したままだと、SDK に旧来の httpx.Response が渡ります。

アプリなら 1 行で済ませる手もある

httpx2 には、process 全体で import httpxhttpx2 に解決させる仕組みがあります。

# アプリケーションの入口、いちばん先頭
import httpx2
 
httpx2.alias_httpx()
 
import httpx  # ここから先の httpx は httpx2

守る条件が 2 つあります。httpxhttpcore が読み込まれる前に呼ぶこと (後だと RuntimeError になる)。そして、これはアプリケーション向けだということ。ライブラリの import 経路に置くと、そのライブラリを使う側の process 全体を書き換えてしまいます。ライブラリなら個別の import を直してください。

静かに壊れるのはここ

httpx を差し替えて動く道具は、import に成功したまま SDK の通信を捕まえられなくなります。該当するのは次のあたりです。

種類具体例起きること
モックrespx / pytest-httpx / vcrpyスタブが外れて本物の通信に出る
計装OpenTelemetry の HTTPXClientInstrumentor / SentrySDK の通信だけ記録が消える

どちらも例外は出ません。モックは、外れたことに気づかないままテストが通信を試みて初めておかしくなります。計装は黙ってトレースが欠けます。

対処はどちらも同じで、それらより先に alias_httpx() を実行することです。テストなら pytest の早期プラグインとして読ませるのが確実です。

# tests/_alias_httpx.py
import httpx2
 
httpx2.alias_httpx()
# pyproject.toml
[tool.pytest.ini_options]
addopts = "-p tests._alias_httpx"
pythonpath = ["."]

既に addopts があるなら、置き換えずに追記してください。なお httpx2 向けを名乗る計装パッケージへ乗り換える方法は、名前を思いつきで補完せず、その配布が実在して中身があることを確かめてから選んでください。

コツ

DefaultHttpxClient の代わりに DefaultAioHttpClient を使うために httpx-aiohttp を入れているなら、その pin は外せます。aiohttp の transport は SDK 本体に入り、extra は aiohttp 本体だけを入れるようになりました。

削除された引数

temperature / top_p / top_k

3 つとも messages.create() やその beta 版の引数から消えました。移行ガイドが示す書き換え先は extra_body です。

# 変更前
client.messages.create(..., temperature=0.2)
 
# 変更後
client.messages.create(..., extra_body={"temperature": 0.2})

SDK の signature から消えただけで、リクエスト JSON としては送れるためこの形が成立します。ただし、送った先が受け付けるかは別の話です。API リファレンスには、temperature について「Claude Opus 4.6 より後に公開されたモデルは temperature の設定に対応しない。後方互換のため 1.0 は受け付けるが、それ以外の値は 400 で拒否する」と記載されています。top_p は 0.99 以上のみ、top_k はどの値でも拒否されます。

つまり新しいモデルを使っているなら、extra_body に移す作業自体が無駄になります。素直に消して、出力の深さは output_configeffort で調整するほうが筋が通ります。extra_body を使う価値があるのは、古いモデルを明示的に固定していて、かつその設定に依存する理由が説明できるときだけです。

注意

ここは「動かしてみたら 400 が返った」で気づく類の変更です。型チェッカは extra_body の中身までは見ないため、機械的に移すと検出をすり抜けます。移す前に、その呼び出しがどのモデルを指しているかを確認してください。

output_format の生スキーマ

辞書で構造化出力のスキーマを渡していた形は output_config に移りました。

# 変更前
client.beta.messages.create(
    ...,
    output_format={"type": "json_schema", "schema": Order.model_json_schema()},
)
 
# 変更後
client.beta.messages.create(
    ...,
    output_config={"format": {"type": "json_schema", "schema": Order.model_json_schema()}},
)

紛らわしいのは、output_format という名前自体は残っている点です。parse()stream() に Pydantic のモデルクラスを渡す形は変わりません。値が辞書なら書き換え、クラス名ならそのまま、で見分けられます。

parse(stream=True)compaction_control

messages.parse()stream 引数は削除されました。もともとストリーミングしない引数だったため、実質は誤解の除去です。ストリーミングしたい場合は streaming の helper に寄せます。

with client.messages.stream(..., output_format=Order) as stream:
    order = stream.get_final_message().parsed_output

tool_runner() のクライアント側圧縮 compaction_control も削除され、サーバー側の圧縮に一本化されました。

# 変更前
runner = client.beta.messages.tool_runner(
    ...,
    compaction_control={"enabled": True, "context_token_threshold": 100_000},
)
 
# 変更後
runner = client.beta.messages.tool_runner(
    ...,
    betas=["compact-2026-01-12"],
    context_management={
        "edits": [
            {"type": "compact_20260112", "trigger": {"type": "input_tokens", "value": 100_000}}
        ]
    },
)

旧来の閾値はそのまま trigger の値に持ち越せます。この runner の周りで messages を自前で組み立て直しているなら、応答の content を丸ごと積み直しているかも一緒に確認してください。圧縮の結果はその中のブロックとして返るため、テキストだけ抜き出して積むと状態が消えます。

Text Completions API の削除

client.completions.create() (/v1/complete) と、HUMAN_PROMPT / AI_PROMPT の定数が削除されました。今回の変更で唯一、機械的に置き換えられない箇所です。

# 変更前
from anthropic import AI_PROMPT, HUMAN_PROMPT
 
completion = client.completions.create(
    model="claude-2.1",
    max_tokens_to_sample=256,
    prompt=f"{HUMAN_PROMPT} Why is the sky blue?{AI_PROMPT}",
)
print(completion.completion)
# 変更後
message = client.messages.create(
    model="claude-opus-5",
    max_tokens=256,
    messages=[{"role": "user", "content": "Why is the sky blue?"}],
)
print("".join(block.text for block in message.content if block.type == "text"))

対応関係は次のとおりです。

  • 最初の HUMAN_PROMPT より前にあった指示文は system=
  • 交互に現れる HUMAN_PROMPT / AI_PROMPTuser / assistant のメッセージへ
  • max_tokens_to_sample=max_tokens= へ。stop_sequences= はそのまま
  • completion.completionmessage.content のテキストブロックを連結する形へ
  • stream=True の完了は client.messages.stream(...)text_stream

補足

ここに残っているコードは、たいてい claude-2.xclaude-instant-* のような提供終了済みのモデルを固定しています。その場合、SDK のバージョンに関係なく呼び出し自体が通りません。モデルの選び直しが先で、SDK の移行はそのついでになります。

非同期の .with_raw_response が await 必須に

.with_raw_response の戻り値のクラスが変わりました。非同期クライアントでは、本文を読む操作が coroutine になっています。

# 変更前 (非同期クライアント)
raw = await client.messages.with_raw_response.create(...)
print(raw.headers["request-id"], raw.text)
message = raw.parse()
# 変更後
raw = await client.messages.with_raw_response.create(...)
print(raw.headers["request-id"], await raw.text())
message = await raw.parse()

同期・非同期の対応は次のとおりです。.text.content がメソッドになる点は、同期クライアントにも効きます。

0.x1.x (同期)1.x (非同期)
r.parse()r.parse()await r.parse()
r.textr.text()await r.text()
r.contentr.read()await r.read()
r.headers変わらない変わらない
r.status_code変わらない変わらない

.headers.status_code は普通の属性のままです。await を付けると壊れるので、まとめて書き換えないでください。判断の基準は、その値がどのクライアントから来たか 1 点です。関数が async def かどうかでは決まりません。

.with_streaming_response を使っているコードは変わりません。

Bedrock のリージョンが必須になった

AnthropicBedrock()AsyncAnthropicBedrock() は、リージョンが解決できないとき警告を出して us-east-1 に落ちる挙動をやめ、ValueError を送出するようになりました。

# 変更前
client = AnthropicBedrock()  # 暗黙で us-east-1
 
# 変更後
client = AnthropicBedrock(aws_region="us-east-1")

解決の順番は、引数の aws_region=、環境変数の AWS_REGION / AWS_DEFAULT_REGION、boto3 のセッションや aws_profile に設定されたリージョンです。デプロイ環境が環境変数を渡しているなら、コードは触らなくても通ります。

注意

ここで ValueError が出たら、リージョンを書き足す前に「本当はどこで動かしたかったのか」を確認してください。暗黙の us-east-1 に落ちていたということは、意図した場所とは違うリージョンへ推論を投げていた可能性があります。aws_region="us-east-1" を機械的に足すと、その事実に蓋をすることになります。

Bedrock ではストリーミングの挙動も変わりました。SDK が知らないイベントは yield されず読み飛ばされます。移行ガイドが挙げている該当例は amazon-bedrock-invocationMetrics です。このフレームを除外する処理を書いていたなら削除できますが、逆に値を使っていた場合は取得手段が無くなります。

残りの細かい削除

型エイリアスと定数の入れ替えは、名前を置き換えるだけです。

削除されたもの置き換え先
anthropic.types.beta.BetaBase64PDFBlockParamBetaRequestDocumentBlockParam
anthropic.Transport / anthropic.ProxiesTypeshttpx2.BaseTransport / httpx2.Proxy
anthropic.lib.tools.agent_toolset.READ_MAX_BYTESDEFAULT_MAX_FILE_BYTES

挙動が変わるものが 3 つ残っています。

低レベルの client.post() などに生の bytes を body= で渡していた場合、body= は常に JSON へ直列化されるようになったため content= に移します。

# 変更前
client.post("/v1/example", body=b"raw payload")
 
# 変更後
client.post("/v1/example", content=b"raw payload")

isinstance(x, anthropic.Stream)client.messages.stream() の戻り値を判定していた箇所は、互換のための仕組みが外れたため False になります。anthropic.lib.streaming.MessageStream (非同期は AsyncMessageStream) を見るように変えてください。create(stream=True) の生のストリームを判定しているなら、そちらは Stream のままです。

ヘッダ名は大文字小文字を区別せずに突き合わせるようになりました。同じ名前を 2 通りの綴りで書いて両方送っていた場合、後の 1 つだけが残ります。また bytes をヘッダの値に渡すとエラーになるため、.decode() が要ります。

どこから手を付けるか

一度に読むより、grep で当たりを付けてから直すほうが速く済みます。仮想環境やビルド生成物は除外してください。

探す文字列見つかるもの
import httpx / from httpxhttpx2 へ寄せる候補
respx / httpx_mock / vcr / Instrumentor静かに壊れる箇所
with_raw_responseawait と メソッド化の対象
completions.create / HUMAN_PROMPTText Completions の残骸
temperature / top_p / top_k削除された引数 (誤検出が多い)
output_format辞書ならば書き換え対象
compaction_controlサーバー側圧縮へ
AnthropicBedrock(リージョン必須化の影響

temperature はサーモスタットの変数など無関係な語に当たりやすいので、SDK の呼び出しに繋がっているかを 1 件ずつ見てください。ひととおり直したら、同じ grep をもう一度かけて、残った件に理由が付くかを確認します。あとは python -m compileall と型チェッカ、テストの順で通せば大体片付きます。

AI エージェントに移行作業を任せる場合も、この grep の結果を先に渡しておくと範囲が固定されて安定します。エージェントへの作業の渡し方は Claude Code のサブエージェント設計パターンにまとめています。

FIXITFIXIT

メジャーバージョンって、そんなに身構えるものなの?

DodaiDodai

今回は身構えたほうがいいです。まず壊れ方から考えると、怖いのは削除ではありません。

FIXITFIXIT

えっ、消えたやつのほうが怖くないの?

DodaiDodai

消えたものは実行した瞬間に落ちます。落ちない変更のほうが後で効きます。

FIXITFIXIT

落ちない変更って、たとえば?

DodaiDodai

モックが外れて本物の API を叩く。テストは緑のままです。そこは事故ります。

まとめ

期限が無い変更なので、慌てて上げる必要はありません。ただ上げると決めた日には全部まとめて来ます。順番としては、Python 3.10 の下限を先に片付け、次に httpx の境界を洗い、最後に削除された引数を機械的に潰す形が手戻りが少なく済みます。

いちばん時間を取られるのは、モックと計装が黙って外れる箇所です。テストが緑のまま通るので、移行が終わったつもりで本番に出てしまいます。alias_httpx() を先に仕込むか、モックが実際に効いていることを 1 件だけ手で確かめてから進めてください。

依存の更新が積み上がって手を付けられなくなっているなら、AI 開発ツール導入支援で移行の進め方から伴走しています。手元の構成でどこが引っかかるか分からない場合は、お問い合わせからご相談ください。

出典は anthropic-sdk-python の v1 移行ガイドv1.0.0 のリリースページPyPI の anthropichttpx2、および Messages API リファレンスです。