0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

エージェント・オーケストレーションについて考えてみる ― 1つの巨大プロンプトをやめて、小さな専門AIを束ねる設計

0
Posted at

この記事で考えてみたこと

  • オーケストレーション(複数AIエージェントの連携)が流行している理由は?
  • それはトークン削減・性能(精度/レイテンシ/コスト)に効くのか?という素朴な疑問を考える
  • OpenAI Agents SDK が何を提供してくれるのか
  • 実際に作ったリテール接客エージェントのアーキテクチャを紹介

動くデモとソースはGitHubに公開しておきました。


1. まず「オーケストレーション」とは何か

一言でいうと、1体の万能AIに全部やらせるのをやめて、役割を分けた複数の小さなAIを、司令塔(オーケストレーター)が交通整理する設計です。

レストランに例えると分かりやすいです。

役割 担当
オーケストレーター フロア責任者。お客様の用件を聞いて「これは厨房」「これは会計」と振り分ける。自分では料理しない
専門エージェント 各担当(注文担当・商品担当・有人対応担当)。狭い守備範囲のプロ
ツール 厨房の道具(在庫DBを見る、注文状況を引く等)。実際の作業はここで起きる

今回作ったリテール接客エージェントも、この構造です。

  • 🧭 オーケストレーター: 用件を読み取り、適切な専門家へ引き継ぐ(ルーティングに専念)
  • 📦 注文管理: 注文状況・追跡・到着予定
  • 🔎 商品サポート: 商品検索+倉庫横断のリアルタイム在庫
  • 🙋 有人エスカレーション: 返金・クレーム等を、要約つきで人間に引き継ぐ

そして重要なのが、この同じ"頭脳"をテキストチャットでも音声でも使うという点です。デモには文字で会話する画面(/)と、マイクでしゃべって会話するライブ音声画面(/voice)の両方があり、裏側のエージェントとツールはまったく同じものを共有しています。(音声の仕組みはセクション4で触れます)


2. なぜ設計を「分ける」のか(定性的な理由)

「なぜ役割を分けるといいことがあるのか」というのをまとめてみました。

(1) 1つの巨大プロンプトは「壊れやすい」

「注文も商品も返金も多言語も全部こなして」という指示を1つのプロンプトに詰め込むと、指示同士が干渉し、ツールの数も増え、モデルがどれを使うべきか迷い始めます。結果、誤ったツール選択・指示の取りこぼし・予測不能な振る舞いが増えます。

役割を分ければ、各エージェントの責務が1つに絞られ、指示も明快になります。「このエージェントは注文のことだけ考えればよい」という状態は、人間にとっても読みやすく、AIにとっても判断しやすい。複雑さを"1か所に集中させない"ことがポイントです。

(2) 各部品を個別に改善・テスト・差し替えできる

商品検索だけ精度を上げたい、返金フローだけ厳格にしたい――オーケストレーションなら該当エージェントだけを直せます。モノリシックな1プロンプトだと、1か所いじると別の挙動が崩れる「もぐら叩き」になりがちです。

(3) 「人間に渡す」を design に組み込める

AIが万能であるかのように振る舞うのは危険です。返金・苦情のような領域は、有人エスカレーション専用エージェントに、会話の要約と適切なキューを付けて渡す。この「うまく人間に劣化させる(graceful degradation)」が設計として自然に書けます。

(4) チャネル/モダリティをまたいで再利用できる

同じ「エージェントの頭脳」を、テキストチャットでも音声でも使い回せます。今回もテキストUIと音声UIが同一のエージェント+ツールを共有しています。


3. トークンコストは安くなるのか?

色々調べる限り、「やり方次第で得する。ただし"常に安くなる魔法"ではない」ということのようです。

✅ 得するポイント

(a) プロンプトが短くなる(=入力トークン減)

専門エージェントは守備範囲が狭いので、システムプロンプトも、列挙するツール定義も小さい。1ターンあたりの入力トークンが減ります。万能プロンプト+全ツール定義を毎回送るより軽い。

(b) モデルを"階層化"できる(=コスト・レイテンシ減)

タスクの難しさに応じて、強いモデルと軽いモデルを使い分けます。

レイヤー モデルの種別 理由
オーケストレーター 高性能(賢い)モデル ルーティングを間違えると以降が全部ズレる。推論力の高いモデルで品質を守る
専門エージェント 軽量(小型・高速・低コスト)モデル 範囲が狭くツールも数個。引数を埋めて根拠ある回答を整える程度なら軽量モデルで十分

会話の大半のターンは専門エージェント側で起きます。 だから、そこを軽量モデルに落とすと、トラフィックの大部分でコストとレイテンシが下がる。一方で、最も間違いが高くつくルーティングにだけ高性能モデルを使う。「お金をかける場所を選ぶ」のがミソです。

具体的なモデル名と「賢さ」の関係について

今回はオーケストレーターに gpt-4o-mini、専門エージェントに gpt-4.1-nano を割り当てました。「4o-mini の方が 4.1-nano より新しそうなのに賢い扱い?」と混乱しがちですが、数字の大小やリリース時期ではなく、モデルの"サイズ感(nano < mini)"が判断の指標です。OpenAI のラインナップでは概ね nano が最小・最速・最安、mini はその一段上に位置づけられます。重要なのは固有名ではなく**「難所に強いモデル、量をさばく所に軽いモデル」という役割分担**です。SDK ではエージェントごとに model を指定でき、今回は環境変数 APP_ORCHESTRATOR_MODEL / APP_SUBAGENT_MODEL で切り替え可能にしました。

(c) ツール選択が速く・正確になる

候補ツールが少ないほど、モデルは正しいツールを選びやすい。やり直し(無駄なAPI往復)が減り、体感速度も上がります。

⚠️ 注意点(オーケストレーションのコスト)

  • ホップが増えると往復も増える: オーケストレーター→専門家、と段が増えれば、その分のモデル呼び出しが発生します。1ターンで完結する単純タスクなら、むしろ単一エージェントの方が安いことも。
  • だから「常に得」ではない: 効くのは、役割が明確に分かれ、会話が多ターンで、かつトラフィックが多いケース。今回のリテール接客はまさにそれに当てはまります。

まとめると、"賢く設計すれば"トークンもコストもレイテンシも下げられる。鍵は「短いプロンプト」「狭いツール」「モデルの階層化」です。


4. OpenAI Agents SDK は何をしてくれるのか

ゼロから組むと大変な「エージェントのループ」を、SDKが面倒みてくれます。今回使った機能は次の通りです。

Agent(エージェントの定義)

指示(instructions)+ツール+モデルをまとめた単位。「あなたは注文管理担当です。これらのツールを使えます」を宣言的に書くだけ。

ハンドオフ(handoffs)

エージェント同士を引き継ぎ線でつなぐ機能。オーケストレーターに「注文の用件なら注文管理へ」と handoff を登録しておけば、ルーティングは自動。専門家同士が相互に引き継いだり、いつでも有人対応へ渡すことも線を引くだけ。

関数ツール(function tools)

ただのPython関数にデコレーターを付けると、モデルが呼べるツールになります。SDKが型ヒントやdocstringから引数スキーマを自動生成してくれるので、面倒な定義書きが不要。今回は get_order_status / check_stock / create_support_ticket などを用意しました。関数は実データ(モックDB)を返すので、回答が"それっぽい嘘"にならず根拠に基づくのが重要点です。

Runner(実行ループ)

「ユーザー発話 → モデル思考 → ツール呼び出し → 結果を読む → 必要なら別エージェントへ handoff」という一連のループを回してくれる実行役。

OpenAI Realtime API(音声)

テキストとは別系統で、音声対音声をWebRTCで実現します。「文字起こし→考える→読み上げ」の3段パイプラインではなく、直接しゃべって直接返るので自然で速い。ブラウザは短命の一時キーでOpenAIに直接つながり(本物のAPIキーはブラウザに渡さない)、音声中でも同じバックエンドツールを呼べます。


5. アーキテクチャについて

今回作成したデモエージェントの問い合わせが、どう流れて答えになるかを順に追います。

記事の核心:「背骨」としての SessionContext

オーケストレーション設計で**一番大事なのが、この SessionContext(セッション・コンテキスト)です。何をしているかを一言で言うと、「会話全体で共有される1つのメモ帳」**です。

実装はとてもシンプルで、ただの dataclass(データの入れ物)です。 中身はこんなフィールドです。

  • customer_id(誰か)、language(何語か)、channel/modality(テキストか音声か)
  • handoff_trail(どのエージェントが順番に対応したかの履歴)
  • escalations(有人対応チケットの記録)

ポイントは「誰がこれを持ち回るか」です。Runner(実行ループ)が、この同じ1つのオブジェクトをすべてのエージェントとツールに引数として渡し続けます。各ツールは RunContextWrapper 経由でこのメモ帳を読み書きできます。だから――

  • オーケストレーターが検出した言語を書き込めば、引き継ぎ先の専門エージェントも同じ言語で応答できる(毎回聞き直さない)
  • ハンドオフのたびに note_handoff() で足跡を1行残すので、「triage → 注文管理 → 商品サポート」という経路が後から見える
  • 有人対応に渡すときは、ただ"転送"するのではなく、このメモ帳ごと渡すので会話の文脈が人間にも引き継がれる

ここが「ハンドオフ=制御の受け渡し」と「コンテキスト=状態の受け渡し」を分けて考える設計の肝です。制御はエージェント間を飛び回っても、状態(メモ帳)は1つのまま壊れずに残る。これがあるから、話題が別エージェントに移っても会話が"ぶつ切り"になりません。

具体的な流れの例

  1. 「注文 ORD-50001 はどこ?」→ 司令塔が 📦 注文管理 へ handoff
  2. 注文管理が get_order_status ツールを実行 → DBから実ステータス+到着予定を取得して回答
  3. 続けて「在庫ある?」→ 🔎 商品サポート へ handoff(文脈は維持)、倉庫横断で在庫確認
  4. 「返金して、人と話したい」→ 🙋 有人エスカレーション へ。要約付きチケットを作成して人間のキューへ

GitHubに公開したテスト版エージェントではモックDBを参照して返答します。


6. うまくいかないときどうするか(誤ルーティング・循環ハンドオフ)

「うまくいく理由」だけでは信用できません。オーケストレーションには固有の失敗モードがあり、そこへの備えこそが実用性を分けます。

ケース1:オーケストレーターが誤ルーティングした

例:在庫の質問なのに注文管理へ送ってしまう。対策は2つ。

再ハンドオフできる道を残す:各専門家は「自分の担当外」と気づいたら再ハンドオフできるようにしておきます。今回の実装ではどちらも可能にしています――(a) オーケストレーターへ戻る、(b) 他の専門エージェントへ直接渡すの両方です。ただし基本はオーケストレーターへ戻すのが安全です。司令塔に「振り直し」を一任すれば、ルーティング判断が1か所に集約され、専門家同士の直接受け渡しで起きがちな"たらい回し"を避けられます(専門家間の直行は、明らかに隣の担当だと分かる時の近道として使う)。いずれにせよ、一本道の「行き止まり」をなくすことがポイントです。

ケース2:ハンドオフが循環する

A→B→A→B…と互いに押し付け合って無限ループに陥るリスク。対策は次の3つです。

  • ターン上限(max turns)を設ける:Runner には一連の処理の上限があり、暴走を打ち切れる
  • handoff_trail を監視する:同じ遷移が繰り返されていたらループと検知して、オーケストレーターへ戻すか人間にエスカレートする
  • 迷ったら人間へ:どのエージェントも最終手段として有人エスカレーションへ走れるようにしておく

ケース3:ツールが失敗した・データがない

存在しない注文番号など。ツールは推測で埋めずに「見つからない」と明示的に返し、モデルには「勝手に推測しない」よう指示しておく。根拠のない回答(ハルシネーション)を防ぐためです。

こうした「うまくいかない時の振る舞い」を設計に組み込めるのも、役割を分けているからこそ考えやすいという利点です。


7. 多言語・マルチチャネルへの"伸びしろ"

  • 多言語: 検出した言語をコンテキストに入れ、各エージェントの指示へ動的に注入。同じ構造のまま、英語・スペイン語・日本語などに応答できる。
  • マルチチャネル/マルチモーダル: 同じ頭脳をテキストにも音声にも。音声では「短く・箇条書きを避け・IDはゆっくり読む」など、チャネルに応じた話し方へ切替。

「1つの設計を、言語・チャネル・モダリティへ横展開できる」のがオーケストレーションの旨味です。


8. まとめ

ポイント 内容
なぜ流行るか 巨大プロンプトの"壊れやすさ"を解き、部品ごとに改善・テスト・差し替えができるから
トークン/性能 「設計次第で」得する。鍵は短いプロンプト・狭いツール・モデルの階層化
SDK の役割 Agent/ハンドオフ/functionツール/Runner/Realtime API を提供し、実装に集中できる
背骨 SessionContext。制御(ハンドオフ)と状態(コンテキスト)を分離し、文脈を失わない
失敗への備え 誤ルーティング・循環・ハルシネーションそれぞれに逃げ道を設計する
ツールと実データ ツールが実データを返すので根拠に基づく回答。本番連携は局所的な差し替えで済む
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?