Messages APIの疎通確認と、実際の開発作業の確認を分けて記録する。
Claude Codeの接続先を変更するとき、「APIが応答した」と「開発作業ができた」を同じ成功条件にすると、後から問題を切り分けにくくなります。モデルが短い文章を返せても、ツール呼び出しやファイル操作まで確認できたわけではありません。
この記事ではOpenRouter以外の候補としてCrazyrouterを取り上げ、Messages API、ツールの往復、thinking設定を確認します。実行日は2026年10月12日です。HTTPリクエストによる試験であり、Claude Codeクライアント全体の動作試験やOpenRouterの有料API試験ではありません。
今回の再現条件
| 項目 | 設定 |
|---|---|
| HTTPメソッド | POST |
| エンドポイント | https://api.crazyrouter.com/v1/messages |
| モデル | claude-haiku-5-5 |
| 認証ヘッダー | x-api-key |
anthropic-version |
2023-06-01 |
max_tokens |
512 |
| 入力 | Reply with exactly: OK |
接続だけを確認するため、ツール定義、thinking設定、長いコンテキストは含めていません。モデル名はこの試験で使った識別子です。すべてのコーディング用途に推奨するという意味ではありません。
最小リクエストを送る
以下はBash用です。事前にローカル環境でCRAZYROUTER_API_KEYを設定し、そのキーで対象モデルが許可されていることと残高を確認してください。WindowsのPowerShellとは改行の書き方が異なるため、そのまま混用しないでください。
curl --silent --show-error --fail-with-body \
https://api.crazyrouter.com/v1/messages \
-H "x-api-key: $CRAZYROUTER_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{"model":"claude-haiku-5-5","max_tokens":512,"messages":[{"role":"user","content":"Reply with exactly: OK"}]}'
実際の応答はHTTP 200で、contentには{"type":"text","text":"OK"}が含まれ、stop_reasonはend_turnでした。入力トークン数は42、出力トークン数は4で、キャッシュ作成と読み取りのカウントはどちらも0でした。
この結果から確認できるのは、指定したモデルとパラメーターでMessagesリクエストが処理されたことです。キャッシュ削減率、並列実行数、コード修正能力はこの入力では評価していません。
2026年10月12日に取得した公式ドキュメントの画面。API仕様の説明と実測結果は区別しています。
ツール試験では呼び出しと実行を区別する
次の試験では、同じモデルと512の出力上限に、整数aとbを受け取るadd_numbersを追加しました。第一リクエストのtool_choiceは{"type":"tool","name":"add_numbers"}です。ユーザー入力はUse add_numbers to calculate 3 + 4. Do not calculate it yourself.としました。
返されたtool_useの名前はadd_numbers、引数は{"a":3,"b":4}、停止理由はtool_useでした。ここでHTTP 200が返っても、まだローカルの加算処理は実行されていません。モデルが関数を要求することと、呼び出し側が関数を動かすことは別の段階です。
ローカルで7を計算した後、第一応答のassistant contentをそのまま履歴に入れ、userメッセージとしてtool_resultを追加しました。tool_use_idには実際の呼び出しIDを指定し、contentには文字列"7"を渡しました。第二リクエストでもtoolsは残し、強制選択だけを取り除きました。
第二応答はHTTP 200、end_turnで、答えは7でした。しかし説明文には「add_numbersというツールはなく、Agentというツールを呼んだ」と書かれていました。第一応答で記録した名前とは一致しません。
この試験の評価は、次のように分ける必要があります。
| 確認対象 | 観測結果 |
|---|---|
| 指定ツールと引数の生成 | このサンプルでは一致 |
| ローカル実行と結果の返信 | 実行し、対応するIDで7を返信 |
| 最終的な計算結果 | 7で一致 |
| 実行過程の自然言語説明 | ツール名が記録と不一致 |
| 並列呼び出し・ストリーミング | 今回は未試験 |
数値が合っているだけでは、過程の説明も正しいとは限りません。Claude Codeで「テストした」と表示されたときも、コマンド、終了コード、対象ファイルを確認する理由はここにあります。この不一致だけから、ゲートウェイ内部の構成やモデルの実体を推定することはできません。
thinkingの比較は同じリクエスト条件で記録する
続いて入力を9.11 and 9.9, which is larger?に固定し、max_tokens:2048とthinking:{"type":"enabled","budget_tokens":1024}を設定しました。比較したのは次の応答構造です。
| model | HTTP | contentの型 | 報告されたthinking token |
|---|---|---|---|
claude-opus-5-5 |
200 | thinking、text | 34 |
claude-haiku-5-5 |
200 | text | 0 |
claude-sonnet-5-5 |
200 | text | 0 |
claude-opus-4-8 |
200 | text | 0 |
Haikuでは予算128の試行も行い、さらに128と1024をそれぞれ再実行しましたが、可視のthinkingブロックは得られませんでした。予算を上げれば必ず解決する、という手順にはできない結果です。一方、先ほどのツール試験では同じモデルからthinking関連情報が返っており、この表をモデル全体の不変な性質として扱うこともできません。
ここでは「HTTPが設定を受け付けた」「ブロックが存在する」「ブロックに読める本文がある」「usageに数量がある」を分けて扱います。ツール試験の第一応答ではthinking本文が空でした。したがってブロックを発見するだけの判定と、表示可能な内容を取得できたという判定も同一ではありません。
また、0という計量値から内部の推論が一切なかったと結論づけることはできません。この小数比較問題は構造の観測用であり、モデルの数学能力やコーディング性能のベンチマークではありません。
Claude Codeに設定するURLは別に確認する
CrazyrouterのClaude Code連携ガイドでは、ANTHROPIC_BASE_URLにhttps://api.crazyrouter.comを指定します。クライアントがパスを追加するため、直接HTTPを送る場合の/v1/messagesまで設定する必要はありません。
OpenAI互換APIを使う別のツールでは/v1を含めたBase URLが必要な場合があります。サービスが同じでもクライアントのプロトコルは同じとは限りません。設定をコピーする前に、どのソフトウェアがパスを組み立てるのか確認します。
公式ガイドの画面、2026年10月12日取得。緑色の注記がパスの重複を避けるポイントです。
設定ファイルを書き換えた後も、起動済みのプロセスが古い環境変数を使っている可能性があります。新しいシェルから起動したか、以前の認証情報が残っていないか、モデルIDが移行先と一致するかを確認します。
エラーを再試行する前に分類する
同じリクエストを繰り返す前に、ネットワークエラーなのか、HTTPレスポンスとして返されたエラーなのかを分けます。後者ではステータスコードだけでなく、JSON内のerror.codeとメッセージを残します。
Crazyrouterのエラー説明では、403に権限不足や残高不足のケースがあります。401なら認証、400ならリクエスト内容を先に確認します。429では頻度を下げるなど、ドキュメントに沿った対応が必要です。
キーを環境別に分けることは利用状況や権限の整理には役立ちますが、利用可能な容量が増える証拠にはなりません。OpenRouterの制限に関する説明も、キーを追加してもrate limitは増えないと明記しています。
最小APIが成功してクライアントだけが失敗する場合、同じAPI試験を何度も繰り返すより、Base URLや環境変数を確認するほうが切り分けとして自然です。
「OpenRouterはAnthropic形式に非対応」という前提は置かない
OpenRouterにもClaude Code連携ガイドがあり、Anthropic互換のインターフェースを提供しています。同ガイドは最大限の互換性のためにAnthropicのfirst-party providerを優先するよう勧めています。
また、キャッシュの説明にはAnthropicの5分と1時間のTTLが記載されています。Chat Completionsの統一されたusageフィールドだけを見て、別のエンドポイントでもすべての機能が失われると推測してはいけません。
今回Crazyrouterから返された診断フィールドも、1回観測したことと永続的な保証は別です。任意フィールドがない場合でも解析できるようにし、使用したエンドポイントごとに実際の応答を保存します。
キャッシュの二つのカウンターを合算しない
OpenRouterのキャッシュ資料では、cached_tokensは読み取り、cache_write_tokensは書き込みを表します。両方をまとめて「節約できたトークン」とする集計は誤りです。Anthropicの5分キャッシュへの書き込みは通常入力の1.25倍、1時間は2倍で、読み取りは0.1倍と説明されています。
同じキャッシュ可能なプレフィックスを3回使い、2回目以降が有効期間内に必ずヒットすると仮定します。通常入力1回分の費用をCとすれば、キャッシュなしは3C、5分設定は1.45C、1時間設定は2.2Cです。これはプレフィックスだけの計算で、新しい質問や出力、ツール再試行は含みません。Crazyrouterの実際の料金に流用することもできません。
2回しか使わない場合、1時間設定は2.1Cなので通常の2Cより高くなります。長いTTLは常に安いという意味ではなく、再利用の間隔と回数が判断条件です。またprovider sticky routingより明示的なprovider.orderが優先し、障害時の別providerへの切り替えはキャッシュ状態を変える可能性があります。費用増加を調べる際には、前置文の変更だけでなく経路の変更も確認対象になります。
次に試すのは小さな実作業
Crazyrouterを候補として評価するなら、戻せる状態のリポジトリで、構造の読み取り、関数の説明、小さな修正、既存テストの実行を順番に確認します。検証結果は文章の返答だけでなく、差分とコマンド出力で判断します。
長い会話での費用を比較する際は、同じ文脈を使った複数リクエストのキャッシュ書き込み、読み取り、課金を追います。短い疎通確認とは試験を分けることで、接続問題と費用問題が混ざりません。
今回の記録から、Messagesの基準リクエストと単一ツールの往復は動作しました。一方で、ツール名の説明の不一致とthinking表示の差も残っています。採用判断ではこの両方を持ち込み、実際のリポジトリで必要な操作を通せるか確認します。特に構造化イベントを捨てて最終文章だけ記録する実装では、今回見つかった不一致を調べられなくなります。
本文のHTTP試験は実行済みです。キャッシュ費用は公式文書に基づく条件付き計算であり、実測請求額ではありません。

