# Anthropic Claude と OpenAI ChatGPT におけるツール呼び出しアプローチの比較 ## 概要 LLMをエージェントとして動かす上で、ツール呼び出し(function calling / tool use)の仕組みはモデルの実用性を大きく左右する。ChatGPTもClaudeも、最終的に開発者へ返るのは構造化されたJSONレスポンスである点は共通している。しかし、その裏側でモデルが実際に生成しているトークン列、ツールを定義する構文、思考過程の扱い方には明確な違いがある。本レポートでは、両者のアプローチを4つの観点から整理する。 --- ## 1. 内部出力フォーマット — XML風タグ vs 特殊制御トークン 最も根本的な違いは、モデルが生のテキストとして何を出力しているかにある。 **Claude (Anthropic)** は、``、``、`` といったXML風のタグでツール呼び出しを表現する。これらはトークナイザーから見れば普通のテキストトークンであり、APIサーバー側が正規表現でパースして構造化データに変換する。Anthropic公式のドキュメントでも、この出力は厳密なXMLとして扱われるわけではなく、正規表現パースを前提に設計されている、と明記されている。 **OpenAI (ChatGPT / gpt-oss)** は、Harmonyと呼ばれるレスポンスフォーマットを採用しており、`<|start|>`、`<|message|>`、`<|channel|>`、`<|call|>`、`<|end|>`、`<|return|>` といった**特殊制御トークン**でメッセージ構造を区切る。これらは見た目こそタグ風だが、トークナイザー内では1つの専用IDを持つ単一トークンとして扱われる。つまり、テキストを後からパースしているのではなく、トークンレベルで構造が埋め込まれている。 この違いは設計哲学の差を反映している。Claudeは可読性とトレーニングデータとの親和性を重視した「テキスト寄り」のアプローチであり、OpenAIはトークンレベルで構造を保証する「プロトコル寄り」のアプローチといえる。 --- ## 2. ツール定義の構文 — JSON Schema vs TypeScript風 開発者がツールをモデルに教える際の書き方も大きく異なる。 **Claude** ではツールはJSON Schemaで定義する。`name`、`description`、`input_schema` を持つオブジェクトの配列をAPIに渡し、APIサーバーが内部でシステムプロンプトを構築してモデルに提示する。JSON Schemaという既存の標準仕様にそのまま乗っているため、他のJSON処理エコシステムとの相性が良い。 **OpenAI** はHarmonyフォーマットの中で、ツール定義をTypeScript風の型構文で記述する。関数は `namespace functions { ... }` というブロックでまとめられ、各関数は `type get_current_weather = (_: { location: string, format?: "celsius" | "fahrenheit" }) => any;` のように定義される。コメントが説明文として機能する。 開発者がOpenAI APIを叩く際にはJSON Schema形式で渡せるが、サーバー内部で `harmony` ライブラリがこれをTypeScript風構文に変換してからモデルに渡している。最終的にモデルが「読む」のはTypeScript風の表現である。これは、コード補完タスクで大量のTypeScriptを学習しているLLMにとって型シグネチャの方が認識しやすい、という経験的判断に基づくと考えられる。 --- ## 3. 引数のフォーマット ツール呼び出し時の引数の渡し方は、両者で似てはいるが微妙に違う。 **Claude** では、文字列やスカラー値はそのままタグ内に書き、リストやオブジェクトなどの複合型はJSONとして埋め込む、というハイブリッド方式を取る。例えば `Tokyo` のようにシンプルな値は素のテキストで、配列やネストした構造はJSONで表現される。 **OpenAI (Harmony)** では、引数全体を一括してJSONで渡す。`<|channel|>commentary to=functions.get_current_weather <|constrain|>json<|message|>{"location":"San Francisco"}<|call|>` というように、`<|message|>` 以降に丸ごとJSONオブジェクトを置き、`<|call|>` トークンで実行要求を確定する。`<|constrain|>json` は出力をJSONに制約することを示すヒントとして機能する。 エンジニアリング的には、JSONで統一する方がパースが単純で予測可能だが、Claudeのハイブリッド方式は単純な値の場合のトークン消費を抑える効果がある。 --- ## 4. 思考過程の分離 エージェントモデルでは、思考と最終応答とツール呼び出しを分離する仕組みが重要になる。両者ともこれに対応しているが、構造化の度合いが異なる。 **Claude** は `thinking` ブロックを持ち、Extended Thinkingモードでは推論内容を専用ブロックに格納する。基本的には「思考」と「応答」の2層構造である。 **OpenAI (Harmony)** は **チャネル** という、より明確に分離された3層構造を採用している。 - `analysis` チャネル — 生のchain-of-thought。安全性のトレーニングを受けておらず、ユーザーには通常見せない。 - `commentary` チャネル — ツール呼び出しや、ユーザーに見せても良い計画的なコメント。 - `final` チャネル — ユーザー向けの最終応答。 このチャネル分離により、開発者は推論プロセスをログとして残しつつ、ユーザーには `final` チャネルだけを表示する、といった運用が容易になる。 --- ## 5. 開発者から見た最終的なレスポンス ここまで内部の差を見てきたが、API経由で開発者が受け取るレスポンスは両者ともJSONである。 - Claudeは `tool_use` タイプのコンテンツブロックとしてツール呼び出しを返す。 - OpenAIは `tool_calls` 配列としてツール呼び出しを返す。 つまり、開発者の視点では「JSONを送ってJSONを受け取る」点は同じであり、内部表現の違いはアプリケーション層には漏れない。違いが顕在化するのは、ファインチューニング、推論サーバーの自前構築、デバッグでモデルの生出力を観察する場合などに限られる。 --- ## 比較表 | 観点 | Claude (Anthropic) | ChatGPT (OpenAI / Harmony) | |---|---|---| | 構造の区切り | XML風タグ(通常のテキストトークン) | 特殊制御トークン(単一トークン) | | パース方式 | 正規表現ベース | トークンレベルで構造化 | | ツール定義の表現 | JSON Schema | TypeScript風型構文 + namespace | | 引数のフォーマット | スカラはそのまま、複合型はJSON | 全てJSON | | 思考の分離 | thinkingブロック(2層) | analysis / commentary / final(3層チャネル) | | API応答 | tool_useブロック(JSON) | tool_calls配列(JSON) | | 設計の傾向 | テキスト寄り・既存標準活用 | プロトコル寄り・トークン専用化 | --- ## 考察 両社のアプローチの違いは、それぞれの強みとトレードオフを反映している。 Claudeのアプローチは、JSON SchemaとXML風タグという既存の表記法を活用しており、ツールチェーンの相互運用性が高い。一方で、生成された出力が「壊れた」場合(タグの閉じ忘れなど)のパース失敗リスクは構造的に存在する。 OpenAIのHarmonyは、特殊トークンによってトークンレベルで構造が保証されるため、フォーマットの破綻が起きにくい。チャネル分離のような細かい構造化も自然に実現できる。一方で、独自プロトコルであるため、モデルを使う側のスタックがHarmonyを正しく扱う必要があり、外部ツールとの統合に追加実装が必要になる場面もある(実際、TensorRT-LLMやvLLMなどでHarmonyトークンの取り扱いに関する問題が報告されている)。 エージェント開発者にとって重要なのは、これらの差は通常APIの抽象化に隠されている、という点である。ただし、ローカルで重み付きモデルを動かす、ファインチューニングを行う、エージェントの動作をデバッグする、といった一段深い作業に踏み込む場合には、内部表現の理解が直接実装に効いてくる。 --- ## 注記 本レポートで示したOpenAI側の詳細は、主にオープンウェイトモデル `gpt-oss` 向けに公開されているHarmonyフォーマットの仕様に基づく。商用のGPT-4o / GPT-5などの内部表現は完全には公開されていないが、HarmonyはOpenAIのResponses APIを模倣するように設計されており、商用モデルもおおむね類似した構造を採用していると推測される。