Claude Media
ClaudeへOpenAI SDKのまま移行する — 互換レイヤーの対応表と落とし穴

ClaudeへOpenAI SDKのまま移行する — 互換レイヤーの対応表と落とし穴

OpenAI SDKのコードをほぼそのままClaudeへ向ける互換レイヤーの使い方。3つの変更点、対応・無視されるフィールド、システムメッセージのhoistingとthinkingの制約を扱います。

OpenAI SDKのままClaudeを試せる互換レイヤーとは

結論から言うと、Anthropicは、公式OpenAI SDKのコードをほぼそのまま使ってClaude APIを呼び出せる互換レイヤーを提供しています。ベースURLとAPIキー、モデル名の3か所を書き換えるだけで、既存のOpenAI SDKの資産を使ってClaudeのモデル性能を試せます。

ただしこれは評価・比較用の機能です。Anthropicは互換レイヤーを「長期利用や本番運用を想定したものではない」と明言しており、優先されるのは常にネイティブのClaude APIの信頼性です。破壊的変更が入らないよう維持はされますが、PDF処理、Citations、拡張思考、プロンプトキャッシュといったClaude API本来の機能追加は常にネイティブAPI側が先行します。評価フェーズで問題が無かったからといって本番の設計をこのレイヤー前提で固定すると、後から機能不足に気づいたときの手戻りが大きくなります。

3つの変更だけでClaudeに向き先を変える

必要な変更は次の3点だけです。

  1. ベースURLを https://api.anthropic.com/v1/ に変更する
  2. APIキーをOpenAIのものからClaude APIキーに差し替える
  3. モデル名をClaudeのモデル名(claude-opus-5 など)に変更する

複数ワークスペースにアクセスできる個人・サービスアカウントキーを使う場合は、リクエストごとに anthropic-workspace-id ヘッダーも送る必要があります。単一ワークスペースのAPIキーなら不要ですが、複数プロジェクトでキーを使い回している組織では指定漏れがコスト計上先のワークスペースを取り違える原因になるため、移行チェックリストの1項目にしておく価値があります。TypeScriptではdefaultHeadersが同じ役割を持ちます。

client = OpenAI(
    api_key=os.environ.get("ANTHROPIC_API_KEY"),
    base_url="https://api.anthropic.com/v1/",
    default_headers={"anthropic-workspace-id": "wrkspc_..."},
)
import os
from openai import OpenAI
 
client = OpenAI(
    api_key=os.environ.get("ANTHROPIC_API_KEY"),
    base_url="https://api.anthropic.com/v1/",
)
 
response = client.chat.completions.create(
    model="claude-opus-5",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Who are you?"},
    ],
)
print(response.choices[0].message.content)

TypeScriptでも変更点は同じ3つです。

import OpenAI from "openai";
 
const openai = new OpenAI({
  apiKey: process.env.ANTHROPIC_API_KEY,
  baseURL: "https://api.anthropic.com/v1/"
});
 
const response = await openai.chat.completions.create({
  messages: [{ role: "user", content: "Who are you?" }],
  model: "claude-opus-5"
});

サポートされていないフィールドの大半はエラーにならず無視されます。動かなくなるのではなく、静かに効かなくなる点が本番運用で見落とされやすい落とし穴です。

対応フィールドと無視されるフィールドの一覧

主要なリクエストパラメータの扱いをまとめました。

パラメータ互換レイヤーでの扱い
max_tokens / max_completion_tokens / stream / stream_options / top_p / parallel_tool_calls互換レイヤーでの扱い完全対応
stop互換レイヤーでの扱い完全対応。空白のみで構成されない停止シーケンスであれば動作する
temperature互換レイヤーでの扱い0〜1の範囲のみ対応。1を超える値は1に丸められる
n互換レイヤーでの扱い1固定。2以上を指定してもエラーにはならず1として扱われる
tools[].function.strict互換レイヤーでの扱い無視される。スキーマ準拠を保証したい場合はネイティブAPIのStructured Outputsを使う
response_format互換レイヤーでの扱い無視される。JSON出力の固定にはネイティブAPIのStructured Outputsが必要
presence_penalty / frequency_penalty / seed / logit_bias / service_tier互換レイヤーでの扱い無視される
logprobs / top_logprobs / metadata / prediction / store / user / modalities / reasoning_effort互換レイヤーでの扱い無視される
audio / 音声入力互換レイヤーでの扱い未対応。入力から取り除かれる

エラーにならず黙って効かない設計なので、strictresponse_format に依存したコードをそのまま移すと、スキーマ違反のJSONが返ってくるまで気づけません。移行時はこの表の「無視される」列を先にチェックリスト化し、既存のテストスイートを一度そのまま流してから本番投入を判断すると安全です。logprobsuserのように監視・トレーシング用途で送っているだけのフィールドも黙って無視されるため、外部の監視基盤と連携している実装は、そのフィールドに依存した処理が本当に届いているかを個別に確認します。

ツール定義とfunctions(非推奨)の扱い

tools[].functionnamedescriptionparametersは完全対応で、既存のツール定義をそのまま使えます。差が出るのは前述のstrictだけです。OpenAIが非推奨にしたfunctionsフィールド(tools登場以前の古いツール定義形式)も、namedescriptionparametersは同じ扱いで動きますが、strictフィールドは同様に無視されます。まだfunctionsベースのコードが残っている実装は、互換レイヤーへの移行を機にtoolsへ書き換えておくと、将来的なOpenAI SDK自体の破壊的変更にも影響を受けにくくなります。

メッセージロールごとの対応状況

messages配列の各ロールも、フィールド単位で対応が分かれます。

ロール主要フィールドの扱い
system / developer主要フィールドの扱いcontentは対応するが会話冒頭へhoistされる。nameは無視
user主要フィールドの扱いテキストと画像URL(image_url)は対応。音声入力(input_audio)とファイル添付は無視
assistant主要フィールドの扱いテキストとtool_callsは対応。refusal型のcontentとaudioフィールドは無視
tool / function主要フィールドの扱いcontenttool_call_idは対応。nameは無視

画像URLは対応していますが、detail(解像度指定)フィールドは無視されます。音声入力とファイル添付のuserメッセージをそのまま流用しているコードは、互換レイヤー経由では黙って情報が欠けた状態でリクエストが送られる点に注意します。

レスポンス側は大半のフィールドがFully supportedですが、いくつか仕様の違いがあります。choices[]の長さは常に1に固定され(OpenAIのように複数候補を1回のリクエストで返すことはできません)、choices[].message.refusalchoices[].message.audiologprobsservice_tiersystem_fingerprintは常に空です。トークン数を集計するコードにも影響があります。usage.completion_tokensusage.prompt_tokensusage.total_tokensは完全対応ですが、その内訳を返すusage.completion_tokens_detailsusage.prompt_tokens_detailsは常に空のオブジェクトになるため、キャッシュ利用分や推論トークンを内訳から取り出すコストダッシュボードは、この2フィールドに依存しない集計方法に切り替える必要があります。エラーメッセージのフォーマットはOpenAI形式を維持しますが、詳細な文言までは互換ではないため、エラー内容をユーザー表示にそのまま使わず、ログ・デバッグ用途に留めます。

ヘッダー面では、レート制限系のヘッダー(x-ratelimit-*retry-after)とrequest-idauthorizationは完全対応です。openai-versionは常に固定文字列を返し、openai-processing-msは常に空になります。OpenAI SDKはヘッダーを自動管理するため通常は意識しませんが、独自にリトライロジックを書いている場合や、サポート問い合わせでrequest-idをログに残す運用にしている場合は、この違いを踏まえてヘッダー処理を書きます。

システムメッセージの統合とthinkingの制約

OpenAI SDKは会話の途中にsystem / developerメッセージを複数回挟められますが、Claude APIが受け付けるのは会話冒頭の単一システムメッセージだけです。互換レイヤーはすべてのsystem / developerメッセージを改行(\n)でつなぎ、1本のシステムメッセージとして会話の先頭に差し込みます。プロンプトの構成をsystem/developerの出現順に依存させている実装は、この結合順で意味が変わらないか確認が必要です。

拡張思考(thinking)は thinking パラメータを追加すれば有効化できます。以下は公式ドキュメントのサンプルをそのまま引いています。claude-opus-5のようなClaude 5系ではthinkingが既定で有効なため、公式は手動での拡張思考の指定をレガシーな方式と位置づけています。

response = client.chat.completions.create(
    model="claude-sonnet-4-6",
    messages=[{"role": "user", "content": "Who are you?"}],
    extra_body={"thinking": {"type": "enabled", "budget_tokens": 2000}},
)

現行モデルの思考は既定でアダプティブに動作し、Claudeが必要な深さを自分で判断します。ただし互換レイヤー経由では、Claudeの思考過程の詳細な出力は返ってきません。思考の中身まで見たい実装は、ここでもネイティブのClaude APIに戻ります。

出力の質そのものにも注意が必要です。長くOpenAIで運用してきたプロンプトは、OpenAIのモデル特有の反応パターンに合わせてチューニングが積み重なっていることが珍しくありません。そのプロンプトをそのままClaudeへ流しても、同じ効果は保証されません。移行はコードの3行だけで終わっても、プロンプトの調整は別作業として見積もっておくのが安全です。

本番移行で起きやすいつまずき

  • プロンプトキャッシュが効くと思い込んで本番投入する。互換レイヤーはプロンプトキャッシュに対応していないため、リクエスト数が多いバッチ処理ほどネイティブAPIとの単価差が広がります。コスト最適化が必要な本番実装は、Prompt Cachingをネイティブに使えるAnthropic SDKへ移行してから組み込みます。
  • PHPからOpenAI互換で呼ぼうとする。公式のOpenAI PHP SDKが存在しないため、PHPはこの互換レイヤーの対象外です。ネイティブのClaude API呼び出しに直接進みます。
  • usageの内訳フィールドをコスト集計に使い続けるusage.completion_tokens_detailsusage.prompt_tokens_detailsは常に空のオブジェクトを返すため、これらを参照してキャッシュ利用分や推論トークンを分離集計しているダッシュボードは、互換レイヤー経由のリクエストだけ数値が欠落します。集計ロジックをusage.total_tokensベースに作り直すか、内訳が必要な部分はネイティブAPIへ切り替えます。

互換レイヤーが向く場面・向かない場面

ここまでの対応表を踏まえると、互換レイヤーを使う判断は次のように整理できます。

用途向き不向き理由
モデル性能の評価・A/Bテスト向き不向き理由コード変更が3点で済み、既存のOpenAI向け評価パイプラインをそのまま流用できる
音声入力を使うプロダクト向き不向き×理由音声入力自体が未対応で入力から取り除かれるため、機能が成立しない
スキーマ厳密なツール呼び出しが必須の本番API向き不向き理由strictが無視されるため、パース失敗を前提とした防御的な実装が別途必要
コスト最適化が優先の高頻度バッチ処理向き不向き×理由プロンプトキャッシュが効かないため、リクエスト数が多いほどネイティブAPIとの単価差が広がる
社内PoC・技術検証の初期段階向き不向き理由本番要件を固める前に、最小の変更でClaudeの応答品質を確認できる

評価目的なら互換レイヤーは合理的な入口ですが、本番の意思決定基準にするのは避けます。表の×や△が多い行に該当する要件があるなら、評価もネイティブのClaude API経由で行ったほうが、後で移行し直す手戻りを避けられます。

なお互換性の実装漏れや想定外の挙動に気づいた場合、Anthropicは専用のフィードバックフォームでの報告を受け付けています。Detailed OpenAI compatible API supportにまとまっている対応表は今後の更新で内容が変わり得るため、本番投入前には表を鵜呑みにせず、手元の環境で実際のリクエスト・レスポンスを流して確認しておくのが確実です。特にツール呼び出しと画像入力は、パラメータ単位で対応・無視が細かく分かれているため、既存のテストケースを一度そのまま互換レイヤー経由で流し、レスポンスの差分を見るのが最短の検証方法です。

まとめ

互換レイヤーへの移行そのものは数分で終わりますが、判断すべきことは残ります。互換レイヤーは、既存のOpenAI SDKコードを書き換えずにClaudeの出力品質を評価するための入口です。ベースURL・APIキー・モデル名の3点を変えるだけで動きますが、strict やプロンプトキャッシュ、thinkingの詳細出力のように無視されるか機能が制限される項目が本番の信頼性を左右します。評価で手応えを感じたら、Structured Outputsやプロンプトキャッシュをフルに使えるネイティブのClaude APIへ切り替えるのが公式の推奨経路です。構造化出力を安定して取りたい場合は、Agent SDKの構造化出力も選択肢に入ります。

この記事を共有:XはてブLinkedIn