101 lines
9.1 KiB
Markdown
101 lines
9.1 KiB
Markdown
# Anthropic Claude と OpenAI ChatGPT におけるツール呼び出しアプローチの比較
|
||
|
||
## 概要
|
||
|
||
LLMをエージェントとして動かす上で、ツール呼び出し(function calling / tool use)の仕組みはモデルの実用性を大きく左右する。ChatGPTもClaudeも、最終的に開発者へ返るのは構造化されたJSONレスポンスである点は共通している。しかし、その裏側でモデルが実際に生成しているトークン列、ツールを定義する構文、思考過程の扱い方には明確な違いがある。本レポートでは、両者のアプローチを4つの観点から整理する。
|
||
|
||
---
|
||
|
||
## 1. 内部出力フォーマット — XML風タグ vs 特殊制御トークン
|
||
|
||
最も根本的な違いは、モデルが生のテキストとして何を出力しているかにある。
|
||
|
||
**Claude (Anthropic)** は、`<function_calls>`、`<invoke>`、`<parameter>` といった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として埋め込む、というハイブリッド方式を取る。例えば `<parameter name="city">Tokyo</parameter>` のようにシンプルな値は素のテキストで、配列やネストした構造は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を模倣するように設計されており、商用モデルもおおむね類似した構造を採用していると推測される。
|