Structured OutputとFunction Callingはよく混同されますが、実際の違いは何で、いつどちらを使うべきですか?
最も直感的な区別方法:Function Callingは「外部ツールを呼び出すか、どのツールを、どんなパラメータで」を答え、Structured Outputは「ツールを呼び出したかに関わらず、今回の返却結果がどんな形式であるべきか」を答えます。
例:Agentが「ETHの現在価格を調べて、今が買い時か判断して」という指示を受けたとします。Function Callingの役割はget_eth_price()というツールを呼び出して価格を調べることを決定し、その呼び出しパラメータ(どの取引所の価格を調べるか)を構造化形式で渡すことです。ツールが価格を返した後、Agentは「現在価格」「買い推奨」「信頼スコア」の3フィールドを含む結論を生成しますが、この結論出力の形式規定こそがStructured Outputが管轄する事柄です。
実務上、両者はほぼ常に併用されます。Function Callingはどのツールをどんなパラメータで呼ぶかを構造化形式で記述する必要があり(これ自体もStructured Outputの一応用)、ツール実行後の最終結論もStructured Outputで固定形式に包んで下流処理しやすくすることが多いです。Function CallingをStructured Outputの特定の応用シナリオと理解できます——モデルから必要な構造化データが「どのツールを、どんなパラメータで呼ぶか」であればFunction Calling、それ以外の固定フィールド形式(分析結論・分類ラベル・リスクスコア)であれば広義のStructured Outputです。
「プロンプトでモデルにJSON形式の出力を要求する」ことと「APIのStructured Output機能で形式を強制する」ことで、なぜ成功率がこれほど違うのですか?
この違いは両者の実装レベルが根本的に異なることに由来します。
プロンプトレベル:プロンプトに「以下のJSON形式で回答してください:{...}」と書くのは単なる「要求」にすぎず、モデルは依然としてトークンごとにテキストを生成しており、形式から逸脱するのを防ぐメカニズムはありません。JSONの前後に「かしこまりました、こちらが分析結果です:」のような余分なテキストを追加したり、あるフィールドを漏らしたり、複雑な推論の途中で元々要求された形式を「忘れる」こともあります。これらの逸脱はプロンプトが十分シンプルで明確な場合は発生率が低いですが、複雑なタスク・長い対話・モデルが複数の指示を同時に処理する場合には逸脱率が明らかに上昇します。
APIレベル:主要なLLM APIの多くが提供するStructured Output機能は、モデルの生成プロセスの根底で制約をかけます——事後に形式が正しいかチェックするのではなく、各トークンを生成するその瞬間に、JSON Schema構文に準拠するトークンだけを選択肢として制限します(この技術は通常「制約付きデコーディング」constrained decodingと呼ばれます)。つまり技術的にモデルは形式の誤ったJSONを生成すること自体が「不可能」になります。生成の瞬間に不正な形式のトークン選択肢が排除されるためです。
実務上の影響:プロンプトレベルの形式要求は、本番環境では通常「形式検証失敗時はリトライ」という追加のフォールトトレランスロジックが必要です。成功率が90%以上であっても、10%の失敗率は高頻度呼び出しのシステムでは頻繁にトリガーされるためです。APIレベルのStructured Outputはこの層のフォールトトレランスがほぼ不要で、形式の正確性は100%に近くなります(主な例外はSchema自体が複雑すぎるか論理矛盾がある場合)。したがって本番プロダクトでは一律にAPIレベルの強制制約を使うことを推奨し、プロンプトレベルの形式要求は迅速なプロトタイプや信頼性要求の低いシナリオにのみ適します。
Structured Outputが形式の正しさを保証するなら、なぜ「形式は正しいが内容が幻覚」という問題がまだ起こるのですか?どう対処すべきですか?
これはStructured Outputが最も誤解されやすい点です。形式の正確性と内容の正確性は完全に独立した2つの保証レベルであり、Structured Outputは前者しか解決しません。
技術的な理由:制約付きデコーディング(constrained decoding)のメカニズムは、モデルが各トークンを生成する際に「JSON Schema構文に準拠する」候補トークンからのみ選ぶよう制限しますが、この制限は「準拠する構文のどのトークンを選ぶか」という背後の判断ロジックには一切干渉しません。具体例:Schemaがconfidence_scoreフィールドを0から1の間の数値と要求している場合、制約付きデコーディングはモデルの出力がこの範囲内の合法な数値形式であることは保証しますが、その数値が「実際の推論で算出されたもの」か「もっともらしく見えるだけの適当な数値」かは保証しません。同様に、Schemaがsource_urlフィールドを要求している場合、制約付きデコーディングは出力が合法な形式のURL文字列であることのみ保証し、そのURLが実在するか内容が一致するかは保証しません。
対処方法はStructured Outputの外側に追加の検証層を重ねる必要があります。検証可能なフィールド(URL・日付・IDなど)については、下流コードで追加の実在性チェックを行います(実際にURLをfetchして存在を確認する、データベースと照合してIDの有効性を確認するなど)。直接検証しにくいフィールド(分析結論・信頼スコアなど)については、モデルに同じStructured Output内に「推論根拠」フィールド(reasoningやevidenceなど)を追加させ、人間のレビューや別のAgentがこの結論に合理的な裏付けがあるか相互チェックできるようにすることが一般的です。高リスクな決定(金融取引の実行に関わるものなど)については、独立したモデル呼び出しやルールエンジンによる第二層の検証メカニズムを追加し、最初に生成された構造化結果の妥当性をチェックする(「この推奨取引額はユーザー設定の上限を超えていないか」など)ことが一般的で、Structured Outputの形式の正確性を内容の信頼性の保証と誤解すべきではありません。
マルチAgentシステムでOrchestratorが複数のSub-agentの出力を読み取り最終決定に統合する場合、Structured OutputのSchema設計は何に注意すべきですか?
マルチAgentシナリオでのSchema設計の核心原則は「各Sub-agentの出力は、Orchestratorが各Sub-agentの内部ロジックを再理解せずに統合判断できるだけの十分なメタ情報を含む」ことです。具体的には3点に注意します。
信頼スコアは比較可能な統一尺度でなければならない。Sub-agent Aの信頼スコアが「高/中/低」のテキスト分類で、Sub-agent Bが「0〜100の数値」だと、Orchestratorは両者を直接比較して統合決定できません(「高」は数値でいくつに相当するか?)。すべてのSub-agentのSchemaは信頼スコアの尺度を統一すべきで(例:統一的に0〜1の浮動小数点数)、Orchestratorが重み付き平均や最小値を取るといった統合演算を直接行えるようにします。
追跡可能な出典フィールドを含む必要がある。結論そのものに加え、各Sub-agentの出力には「この結論がどの入力データ/どのツール呼び出しに基づいているか」(例:参照したtrace_idやツール呼び出しIDを記録するsource_refsフィールド)を含めるべきです。これは複数のSub-agentが矛盾する結論を出した場合にOrchestratorにとって極めて重要です——出典追跡がなければOrchestratorはどれを信じるべきか判断できずランダムに選ぶか全て疑うしかなく、出典追跡があればどの段階のデータに問題があったかさらに調査できます。
「結論」と「不確実性/例外状態」を明確に区別する必要がある。Sub-agentのSchemaは「正常な結論」のフィールドだけでなく、明確な「判断不能」や「実行失敗」の状態フィールド(例:status: success / uncertain / failed、対応するfailure_reason)を持つべきです。この状態フィールドが設計されていないと、Sub-agentが処理できない状況に遭遇した際、Schemaの形式要求を満たすために「もっともらしく見えるが実際には推測」の結論を無理やり作り出しがちです。これはStructured Outputの設計不良がかえって幻覚を誘発する一般的な落とし穴です。Sub-agentに一見完全な答えを無理に埋めさせるより、正直に「不確実」と報告させる方が望ましいのです。
あるニュース分析AgentのStructured Output Schema設計事例
暗号資産ニュースを追跡し、特定トークンの価格への影響を判断するAgentのコア分析Schemaは次の通りです:headline_summary(文字列、20字以内の要約)、affected_assets(影響を受けるトークンシンボルの配列)、sentiment('positive' | 'negative' | 'neutral')、confidence(0〜1の浮動小数点数)、reasoning(判断根拠の簡潔な説明)、source_verified(真偽値、少なくとも2つの独立したニュースソースと照合したか)、status('success' | 'insufficient_data')。このSchema設計がどう一般的な落とし穴を回避するか:confidenceフィールドはモデルに「このニュースは結構重要そうだ」といった曖昧なテキストではなく定量化されたスコアを出させ、下流システムが明確な閾値を設定できるようにします(信頼度0.4未満の分析結果は自動通知をトリガーせず記録のみ)。source_verifiedフィールドは「形式は正しいが内容が幻覚かもしれない」という問題への直接的な防御設計です——このニュースソースが単一サイトでしか見られず他の裏付けがない場合、モデルは正直にsource_verified: falseとマークしなければならず、下流システムがこのフラグを見た場合confidenceスコアが高くても自動的に処理を格下げします(記録のみで実際の取引推奨はトリガーしない)。statusフィールドの存在は、データ不足の場合にモデルが分析結論を「捏造」させられることを防ぎます——ニュース内容自体が曖昧で影響を受けるトークンを判断できない場合、モデルはaffected_assets配列を無理に埋めるのではなく正直にstatus: insufficient_dataを報告できます。実際の運用で発見された問題:source_verifiedフィールド自体の正確性も検証が必要でした——エンジニアリングチームは、モデルが「同じ記事が複数サイトに転載されただけ」を「複数の独立ソース」と誤判定することがあると発見し、下流にドメイン重複排除ロジックを追加し、真に異なるニュース組織(異なるルートドメインで判断)による報道のみを独立ソースとしました。これは幻覚防御のために設計された検証フィールド自体も、下流でのさらなる論理検証が必要であり、無条件に信頼すべきではないことを示しています。
Structured Outputの核心的なトレードオフは「制約の厳格さ vs モデルの表現の柔軟性」です。Schemaを厳格に設計するほど(フィールド固定・型厳格・追加フィールド不可)下流のパースは信頼性が高まりますが、モデルがSchemaが想定していない状況に遭遇した際の表現の余地を制限し、不適切なフィールドに無理に押し込ませることになりかねません(前節の「結論の捏造を強いられる」問題)。緩やかに設計するほど(例:オープンエンドなadditional_notesフィールドを許可)柔軟性は高まりますが、下流コードがこの非構造化の補足内容を処理する際、また脆弱なパースの問題に戻ってしまいます。もう一つのトレードオフは「リアルタイム検証コスト」です。より複雑なSchema(ネスト構造・条件付き必須フィールド)は通常モデルにとって生成が難しく、形式準拠率を下げたり生成遅延を増やしたりする可能性があり、よりシンプルなSchemaはすべての実際の状況をカバーできず、より頻繁な改訂が必要になる可能性があります。推奨:コアとなる決定フィールド(信頼スコア・状態・金額)には一律厳格なSchemaを使い、モデルが誤る余地は明確に「補足説明」とラベル付けされた独立フィールドに残す——両者を分けて設計し、1つのSchemaで厳密さと柔軟性の両方を同時に追求しないことです。