0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Anthropic Python SDK 2.0 の移行ポイント 5 つを、v1 と同じコードを動かして確かめた

0
Last updated at Posted at 2026-11-07
  • 2026-10-21 に Claude API の新しい API バージョン 2026-10-21 と、それを既定で送る Python SDK 2.0.0 が出た。v1.17.0 と v2.5.0 で同じコードを 1 回ずつ動かし、7 つの書き方を比べた
  • v2 では、API キーの送り方(x-api-key → Authorization: Bearer)、MessageParam(...) の呼び出し、models.list(betas=...)、api_key と auth_token の併用で動きが変わった。Sonnet 4.6 に extra_body で送った temperature=0.2 は、v1 では通り、v2 では API 側で 400 になった
  • v2 から API バージョン 2023-06-01 を指定すると、同じ temperature は通った。どれも各 1 回の結果なので、移行するときは自分のコードを v2 で実際に動かして確かめる必要がある

背景

2026-10-21 に、Claude API の API バージョン 2026-10-21 が出ました(リリースノート)。API バージョンは、リクエストの anthropic-version ヘッダーで指定する値です。これまでは 2023-06-01 が使われてきました。

同じ日に、2026-10-21 を既定で送る SDK も出ました。Python では anthropic 2.0.0 です(CHANGELOG)。ライセンスも、2.0.0 から MIT ではなく Apache 2.0 になりました(移行ガイド)。

移行ガイド の変更点のうち、Python で書いたふつうのアプリに関係しそうなものを抜き出すと、次のとおりです。

変更 どちらの変更か 内容(移行ガイドより)
サンプリングのパラメーター API temperature・top_p・top_k を送ると、既定値でも 400 になる
アシスタントの document ブロック API assistant メッセージに直接 document ブロックを入れると 400 になる
ユーザーメッセージの citations API user メッセージの text ブロックに空でない citations があると 400 になる
MessageParam SDK 役割ごとの型の union(「どれか 1 つの型」を表す型)になる。MessageParam(...) と呼ぶと TypeError
ベータでない Models のメソッド SDK client.models.list() などが betas を受け付けない。client.beta.models を使う
API キーのヘッダー SDK X-Api-Key ではなく Authorization: Bearer <key> で送る
認証情報は 1 つ SDK api_key と auth_token などを 2 つ以上渡すと ValueError

「API」の行は、API バージョン 2026-10-21 を送ったときに API が返す結果の変更です。「SDK」の行は、SDK を上げると変わることです。

この記事では、v1 の最後の版(1.17.0)と、執筆時点の最新版(2.5.0、2026-11-04 公開)に同じコードを渡して、表のうち 5 つの変更を確かめます。API の 3 つのうちは「サンプリングのパラメーター」だけ(それも temperature を extra_body で送る場合だけ)で、SDK の 4 つはすべてです。

試してみる

やること

同じ main.py を、anthropic 1.17.0 の環境(.venv-v1)と 2.5.0 の環境(.venv)で 1 回ずつ実行します。7 つの書き方を順に試し、成功するか、どんなエラーになるかを記録します。

API を呼ぶのは 1・3・4・5・7 番です(4 番は、v2 では API を呼ぶ前に SDK がエラーにします)。モデルはふだんは安い claude-haiku-5-5 にしました。temperature の確認(3 番と 7 番)だけは、temperature の値を変えられる claude-sonnet-4-6 を使います。費用は 1 セント未満の見込みです(料金)。

動作環境

  • OS: macOS 27.2(Apple M3 / 24GB)
  • Python: 3.12.15
  • 主要ライブラリ: anthropic==1.17.0(.venv-v1)と anthropic==2.5.0(.venv)、python-dotenv==1.2.4
  • モデル: claude-haiku-5-5(3 番と 7 番だけ claude-sonnet-4-6)
  • 実行日: 2026-11-07

セットアップ

cd code
uv venv --python 3.12 .venv-v1
uv pip install --python .venv-v1 -r requirements-v1.txt
uv venv --python 3.12 .venv
uv pip install --python .venv -r requirements.txt
./run.sh   # ANTHROPIC_API_KEY はリポジトリルートの .env から読む

run.sh は、main.py を 2 つの環境で順に実行し、outputs/run.log に保存します。

コード

main.py の全体です。7 つの書き方を check() で 1 つずつ実行し、例外が出たら種類とメッセージを表示します。送ったヘッダーは、HTTP クライアントのイベントフック(リクエストを送る直前に呼ばれる関数)で記録します(API キーの値は表示しません)。extra_body は、渡した dict をそのままリクエストの JSON に足す SDK の仕組みです。SDK の引数にない項目も送れます。

"""v1 で書いたよくあるコードを、anthropic v1 と v2 の両方で動かして、どこが変わるか確かめる。

同じファイルを .venv-v1(anthropic 1.17.0)と .venv(anthropic 2.5.0)で実行する。
確かめる変更は、公式の移行ガイドに載っているもの:
https://platform.claude.com/docs/en/api/migration-2026-10-21
"""
import os
import platform
from pathlib import Path

import anthropic
from anthropic.types import MessageParam
from dotenv import load_dotenv

# API キーはリポジトリルートの .env から読む(code/ → 記事 → posts → ルート)
load_dotenv(Path(__file__).resolve().parents[3] / ".env")

MODEL = "claude-haiku-5-5"
OLD_MODEL = "claude-sonnet-4-6"  # temperature の値を変えられるモデル
API_KEY = os.environ["ANTHROPIC_API_KEY"]

# 送ったリクエストのヘッダーを記録する(キーの値は表示しない)
sent = {}


def on_request(request) -> None:
    sent.clear()
    sent.update(request.headers)


client = anthropic.Anthropic(
    http_client=anthropic.DefaultHttpxClient(event_hooks={"request": [on_request]}),
    max_retries=0,
)


def show_auth_headers() -> None:
    auth = "authorization" in sent and sent["authorization"].startswith("Bearer ")
    print(f"  anthropic-version: {sent.get('anthropic-version')}")
    print(f"  x-api-key ヘッダー: {'あり' if 'x-api-key' in sent else 'なし'}")
    print(f"  Authorization: Bearer: {'あり' if auth else 'なし'}")


def check(title: str, fn) -> None:
    print(f"\n## {title}")
    try:
        fn()
    except Exception as e:  # 何が起きたかを記録したいので、種類を問わず表示する
        msg = str(e).replace(API_KEY, "***")
        print(f"  -> {type(e).__name__}: {msg[:200]}")


def plain_request() -> None:
    msg = client.messages.create(
        model=MODEL,
        max_tokens=64,
        messages=[{"role": "user", "content": "「こんにちは」とだけ返してください。"}],
    )
    print(f"  -> 成功: {msg.content[-1].text!r}")
    show_auth_headers()


def message_param_call() -> None:
    m = MessageParam(role="user", content="Hello")
    print(f"  -> 成功: {m}")


def temperature_extra_body() -> None:
    # SDK の引数には temperature がないので、MIGRATION.md の案内どおり extra_body で送る。
    # temperature を下げる意味がある古いモデル(Sonnet 4.6)に、既定値以外の 0.2 を送る
    msg = client.messages.create(
        model=OLD_MODEL,
        max_tokens=64,
        extra_body={"temperature": 0.2},
        messages=[{"role": "user", "content": "「こんにちは」とだけ返してください。"}],
    )
    print(f"  -> 成功: {msg.content[-1].text!r}")
    print(f"  anthropic-version: {sent.get('anthropic-version')}")


def temperature_old_api_version() -> None:
    # 3 と同じ内容を、anthropic-version だけ 2023-06-01 にして送る(SDK の版と API バージョンを切り分ける)
    msg = client.messages.create(
        model=OLD_MODEL,
        max_tokens=64,
        extra_body={"temperature": 0.2},
        extra_headers={"anthropic-version": "2023-06-01"},
        messages=[{"role": "user", "content": "「こんにちは」とだけ返してください。"}],
    )
    print(f"  -> 成功: {msg.content[-1].text!r}")
    print(f"  anthropic-version: {sent.get('anthropic-version')}")


def models_list_betas() -> None:
    page = client.models.list(limit=1, betas=["message-threads-2026-08-12"])
    print(f"  -> 成功: {page.data[0].id}")


def beta_models_list() -> None:
    page = client.beta.models.list(limit=1, betas=["message-threads-2026-08-12"])
    print(f"  -> 成功: {page.data[0].id}")


def two_credentials() -> None:
    c = anthropic.Anthropic(api_key=API_KEY, auth_token="dummy-token")
    print(f"  -> 成功: クライアントを作れた({type(c).__name__})")


def main() -> None:
    print(f"Python {platform.python_version()} / {platform.system()} {platform.machine()}")
    print(f"anthropic {anthropic.__version__}")
    check("1. ふつうのリクエスト(送ったヘッダーも見る)", plain_request)
    check("2. MessageParam(role=..., content=...) で作る", message_param_call)
    check("3. temperature=0.2 を extra_body で送る(Sonnet 4.6)", temperature_extra_body)
    check("4. client.models.list(betas=...)", models_list_betas)
    check("5. client.beta.models.list(betas=...)", beta_models_list)
    check("6. api_key と auth_token を両方渡す", two_credentials)
    check("7. 3 を anthropic-version: 2023-06-01 で送る", temperature_old_api_version)


if __name__ == "__main__":
    main()

実行結果

outputs/run.log の全体です。

# run at: 2026-11-07 09:52:07 JST

################ main.py with .venv-v1
Python 3.12.15 / Darwin arm64
anthropic 1.17.0

## 1. ふつうのリクエスト(送ったヘッダーも見る)
  -> 成功: 'こんにちは'
  anthropic-version: 2023-06-01
  x-api-key ヘッダー: あり
  Authorization: Bearer: なし

## 2. MessageParam(role=..., content=...) で作る
  -> 成功: {'role': 'user', 'content': 'Hello'}

## 3. temperature=0.2 を extra_body で送る(Sonnet 4.6)
  -> 成功: 'こんにちは'
  anthropic-version: 2023-06-01

## 4. client.models.list(betas=...)
  -> 成功: claude-haiku-5-5

## 5. client.beta.models.list(betas=...)
  -> 成功: claude-haiku-5-5

## 6. api_key と auth_token を両方渡す
  -> 成功: クライアントを作れた(Anthropic)

## 7. 3 を anthropic-version: 2023-06-01 で送る
  -> 成功: 'こんにちは'
  anthropic-version: 2023-06-01

################ main.py with .venv
Python 3.12.15 / Darwin arm64
anthropic 2.5.0

## 1. ふつうのリクエスト(送ったヘッダーも見る)
  -> 成功: 'こんにちは'
  anthropic-version: 2026-10-21
  x-api-key ヘッダー: なし
  Authorization: Bearer: あり

## 2. MessageParam(role=..., content=...) で作る
  -> TypeError: Cannot instantiate typing.Union

## 3. temperature=0.2 を extra_body で送る(Sonnet 4.6)
  -> BadRequestError: Error code: 400 - {'type': 'error', 'error': {'type': 'invalid_request_error', 'message': 'temperature: Extra inputs are not permitted'}, 'request_id': 'req_011Cgneo3rW4Jy7myJQa8MvM'}

## 4. client.models.list(betas=...)
  -> TypeError: Models.list() got an unexpected keyword argument 'betas'

## 5. client.beta.models.list(betas=...)
  -> 成功: claude-haiku-5-5

## 6. api_key と auth_token を両方渡す
  -> ValueError: Pass at most one of `api_key=`, `auth_token=`, `credentials=`, `config=`, or `profile=`. Received `api_key=`, `auth_token=`.

## 7. 3 を anthropic-version: 2023-06-01 で送る
  -> 成功: 'こんにちは'
  anthropic-version: 2023-06-01

結果

7 つの書き方の結果をまとめると、次のとおりです(各 1 回)。

# 書き方 v1.17.0 v2.5.0
1 ふつうのリクエスト 成功。anthropic-version: 2023-06-01、キーは x-api-key で送る 成功。anthropic-version: 2026-10-21、キーは Authorization: Bearer で送る
2 MessageParam(role=..., content=...) 成功(dict ができる) TypeError: Cannot instantiate typing.Union
3 Sonnet 4.6 に temperature=0.2 を extra_body で送る 成功 API が 400(temperature: Extra inputs are not permitted)
4 client.models.list(betas=...) 成功 TypeError(betas を受け付けない)
5 client.beta.models.list(betas=...) 成功 成功
6 api_key と auth_token を両方渡す 成功(クライアントを作れた) ValueError: Pass at most one of ...
7 3 と同じものを anthropic-version: 2023-06-01 で送る 成功 成功

気づいたこと

v1 で extra_body を使って送っていた temperature は、v2 では API に止められた。 Python SDK は、1.0.0(2026-08-20)で temperature・top_p・top_k の引数を外しています。そのとき SDK の MIGRATION.md は、これらをまだ使う古いモデルのために、extra_body で渡す書き方を案内しています。3 番は、その例と同じ形(claude-sonnet-4-6 に temperature=0.2)です。2023-06-01 を送る v1 では成功し、2026-10-21 を送る v2 では 400 になりました。

SDK の引数ではないので、v2 に上げても型エラーにはならず、実行して初めて止まります。この 400 が SDK の版によるものか、API バージョンによるものかを分けるため、7 番では v2 から anthropic-version: 2023-06-01 を指定して同じものを送りました。こちらは成功しました。今回の 1 回の結果では、400 を決めていたのは API バージョンでした。移行ガイドの説明とも合っています(Sampling parameters are removed)。今回の結果と移行ガイドからは、v1 で extra_body を使って temperature を下げていたコードは、v2 に上げると止まると考えられます。移行ガイドでは、これらのパラメーターを外すか、そのリクエストだけ 2023-06-01 のまま送るように書かれています(7 番で確かめた形です)。

API キーのヘッダーが変わる。 1 番では、v2 の SDK が API キーを Authorization: Bearer で送っていました。SDK だけを使うなら、コードを変える必要はありませんでした。ただし、間にプロキシやゲートウェイを置いて X-Api-Key を読んでいる場合は、そちらを直す必要があります(移行ガイド)。

2・4・6 番はガイドのとおりに直せる。 2 番は dict で書く、4 番は client.beta.models を使う(5 番で成功を確認)、6 番は認証情報を 1 つにする、という直し方が移行ガイドに載っています。

まとめ

  • anthropic 1.17.0 と 2.5.0 で同じコードを 1 回ずつ動かすと、7 つの書き方のうち 5 つ(1・2・3・4・6 番)で結果が変わった。1 番はエラーにはならず、送るヘッダー(API バージョンと API キーの送り方)だけが変わった
  • 一番気をつけたいのは temperature まわりだった。Sonnet 4.6 に extra_body で送った temperature=0.2 は、v1(2023-06-01)では通り、v2(2026-10-21)では 400 になった。型エラーにならないので、実行するまで気づけない
  • 今回試したのは移行ガイドの変更の一部で、各 1 回だけだった。移行するときは、自分のコードを v2 で実際に動かして確かめる必要がある

参考

公式ドキュメント・一次情報

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?