yoi/docs/ref/tool_approach_comparison.md

9.1 KiB
Raw Blame History

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で定義する。namedescriptioninput_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. 思考過程の分離

エージェントモデルでは、思考と最終応答とツール呼び出しを分離する仕組みが重要になる。両者ともこれに対応しているが、構造化の度合いが異なる。

Claudethinking ブロックを持ち、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 / final3層チャネル
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を模倣するように設計されており、商用モデルもおおむね類似した構造を採用していると推測される。