先に要点
- コード主導のオーケストレーションは、AIエージェント 同士の流れや分岐条件を、LLM のその場判断だけでなくアプリ側のコードで決める設計です。OpenAI の公式ガイドでは「速度・コスト・性能の面でより決定的(deterministic)で予測可能になる」と説明されています。
- 向いているのは、分岐条件を明示したい場面、速度・コスト・再現性を上げたい場面、承認点を厳密に置きたい場面です。曖昧で開いたタスクは LLM 主導の方が強いこともあります。
- 後半で記事生成フロー1本を実際にトレースし、どの分岐をコードに固定したか、retry 上限を 3 回・評価 NG のしきい値を 80 点未満にした根拠まで具体的な値で示します。
- 実務の答えは「骨格はコード、各ステップの知的処理は エージェント」のハイブリッドであることが多いです。
AI エージェントの構成を見ていると、LLM が自律的に次を決める流れと、コード側で流れを決める形の2つが出てきます。前者は agentic で柔軟ですが、後者は速度・コスト・予測しやすさの面で強いことがあります。
OpenAI Agents SDK の orchestration ガイドでも、オーケストレーションには大きく分けて
- LLM に判断させる方法(the agent's intelligence で自律的に計画・実行する)
- コードで流れを決める方法(your code determines the flow)
の2つがあり、それぞれに tradeoff があると整理されています。公式は後者について「より決定的で、速度・コスト・性能の面で予測しやすくなる」と明記しています。
この記事では、2026年6月時点の OpenAI Agents SDK の公式ドキュメントを土台にしつつ、単なる言い換えでは終わらせず、コード主導のオーケストレーションとは何か、LLM 任せと何が違うのか、そして実際の記事生成フロー1本でどの分岐をどんな値でコードに固定したのかまで踏み込んで整理します。
コード主導のオーケストレーションとは何か
コード主導のオーケストレーションとは、どの エージェント をどの順番で走らせるか、どの条件で次へ進むかを、アプリ側のコードで決める設計です。
たとえば次のような流れです。
- まず分類エージェントに依頼内容を分類させる
- その結果が
bugなら修正フローへ進む docなら記事生成フローへ進む- 修正後は必ず評価エージェントを通す
- 評価 NG なら再試行、OK なら人間承認へ進む
ここで重要なのは、次に誰へ渡すかを LLM がその場で好きに決めるのではなく、コード側が条件分岐として持つことです。LLM が出すのは「分類結果」や「評価スコア」といった検査できるデータであって、「次にどのエージェントを呼ぶか」という制御フローそのものは if や while がにぎります。
LLM が決めること
各ステップの中身の知的処理。分類ラベル、下書き本文、評価スコアと指摘コメントなど、コードが後で検査できる「データ」を返す。
コードが決めること
制御フロー。どの順で呼ぶか、どの条件で次へ進むか、何回まで再試行するか、どこで人間承認を挟むか。
LLM任せのオーケストレーションと何が違うのか
OpenAI のドキュメントでは、LLM 主導のオーケストレーションは、エージェントが tools や handoffs を使って自律的に流れを決める形として説明されています。一方、コード主導のオーケストレーションは your code determines the flow という考え方です。
ざっくり違いを表で見るとこうです。
| 観点 | LLM主導 | コード主導 |
|---|---|---|
| 次の流れ | LLMがその場で判断(tools / handoffs) | コードの条件分岐で決める(if / while) |
| 柔軟性 | 高い | 中程度 |
| 再現性 | ぶれやすい | 高めやすい |
| 速度・コスト | 流れ次第で増減しやすい | 予測しやすい(呼び出し回数が読める) |
| 失敗時の追跡 | どの判断で外れたか追いにくい | どの分岐で止まったかログで特定しやすい |
| 向く場面 | 曖昧で開いたタスク | 明確な分岐や承認フロー |
つまり、柔軟性を優先するなら LLM 主導、制御しやすさを優先するならコード主導、という見方ができます。
なぜコード主導が必要になるのか
1. 速度とコストを読みやすくしたい
LLM に流れを全部決めさせると、何回 handoff が起きるか、どこで再試行するか、どの specialist を何回呼ぶかが読みにくくなります。小さなぶれでも、積み重なるとレイテンシやコストに効きます。
たとえば1依頼あたりのトークンを試算すると差がわかります。コード主導で「分類1回 + 生成1回 + 評価1回 + (NG時のみ)再生成」と固定すれば、最悪ケースでも LLM 呼び出しは 4〜5 回に収まります。対して LLM 主導で handoff を任せると、エージェントが「念のためもう一度調べよう」を繰り返し、同じ依頼でも呼び出しが 10 回を超えることがあります。1回あたり入出力で数千〜1万トークン程度を消費するフローなら、この差はそのままコストとレイテンシの差になります。
コード主導なら、何回まで再試行するか、どの条件で評価エージェント(LLM-as-a-Judge)を通すか、並列にするか逐次にするかを固定しやすくなります。
2. 危ない操作の承認点を置きたい
本番反映、課金、外部送信、権限変更のような処理は、どこで人間確認を入れるかが大事です。こうした承認点(human-in-the-loop)は、コード主導の方が明示しやすいです。「この関数を呼ぶ前に必ず承認待ちで止まる」とコードに書けば、LLM の気分で承認を飛ばす余地がなくなります。
3. 分岐条件がすでに明確
たとえば、ラベルが billing なら請求担当、優先度が high なら人間レビュー必須、出力が schema 不一致なら再実行、のように分岐条件がはっきりしているなら、LLM に毎回考えさせるより、コードへ置いた方が素直で安く速いです。
実例トレース:記事生成フロー1本を最後まで追う
ここが本題です。「記事の下書きを作る」という定型業務を、コード主導でどう組み、どの分岐をコードに固定し、どんな値を踏んで判断したのかを1本トレースします。値はこのフロー設計でよく採る現実的な目安として示します。
フローの骨格
このフローのエージェントは3つだけです。役割を分け、つなぎ目はすべてコードが持ちます。
どの分岐をコードに固定したか
このフローでコードに固定した分岐と、その「踏んで決めた値」は次の通りです。
| 分岐ポイント | コードが見る値 | 固定したしきい値・根拠 |
|---|---|---|
| 入口の振り分け | 分類の category と confidence |
confidence < 0.7 なら自動進行せず人間へエスカレーション。誤分類1件の手戻りコストが分類の再確認より大きいため、低信頼は人に倒す。 |
| 評価の合否 | Judge の score と issues |
score >= 80 かつ「事実誤り」系の issue がゼロなら OK。80 未満、または重大 issue が1件でもあれば NG。 |
| 再試行ループ | ループ回数 attempts |
最大 3 回(while attempts < 3)。3 回で OK が出なければ自動進行を止め、人間レビューに回す。 |
| 最終反映 | 承認フラグ | 公開や保存の直前で必ず承認待ちに入る。OK が出てもここはコードが止める。 |
擬似コードにすると、骨格はこれだけです。LLM が制御文を握らないことが見て取れます。
cls = classify(request)
if cls.category != "doc" or cls.confidence < 0.7:
return escalate_to_human(request, reason=cls)
draft = generate(request)
attempts = 0
while attempts < 3:
review = judge(draft)
if review.score >= 80 and not review.has_factual_issue():
return await_human_approval(draft) # 承認点
draft = generate(request, feedback=review.issues)
attempts += 1
return escalate_to_human(draft, reason="3 attempts exhausted")
なぜ retry 上限を 3 回にしたか
無制限ループにしないのは、評価エージェントが満点を出さない限り永遠に回り続ける事故を防ぐためです。実際に運用すると、改善が効くのはたいてい 1〜2 回目までで、3 回目以降は同じ指摘を堂々巡りしてスコアがほとんど上がらなくなることが多いです。それでも上がらないなら、それは「もう少し回せば直る」問題ではなく「指示や素材の方に欠けがある」問題なので、回数を増やすより人間に渡した方が速い、という判断で 3 回に固定しています。コストの上限も同時に決まり、最悪でも「生成1 + (生成+評価)×3 + 分類1」で LLM 呼び出しは 8 回に収まります。
なぜ評価 NG を「80点未満 または 重大issue 1件」にしたか
点数だけで切ると、文章はきれいだが事実が間違っているドラフトを通してしまいます。そこで合否を2軸にしました。1つは総合スコアの下限(80 点)、もう1つは「事実誤り・禁止表現・必須セクション欠落」のような一発アウト条件です。後者は点数が 95 点でも1件あれば NG にします。Judge には「採点」だけさせ、「80 点で合格かどうか」という基準はコード側に置くのがポイントです。基準を変えたくなったときに、LLM のプロンプトを書き直さずコードの定数を変えるだけで済みます。
失敗例:ループが止まらなかったケース
- 現象:あるカテゴリの依頼だけ、必ず retry を 3 回使い切って人間エスカレーションに落ちる。スコアは毎回 72〜78 をうろつく。
- 原因:Judge のプロンプトに「必須セクションが5つあること」と書いていたのに、生成側に渡すプロンプトには4つしか列挙していなかった。生成は4つで満点のつもり、評価は5つを期待、で永遠にかみ合わない。
- 確認手順:各 attempt の
review.issuesをログに残していたので、毎回同じ「セクション不足」の指摘が出ていることがすぐ見えた。コード主導だと「どの attempt のどの分岐で落ちたか」が構造化ログに残るため特定が速い。 - 回避:生成と評価で参照する「必須セクション定義」を1つの定数に共通化し、両方のプロンプトへ同じものを差し込むようにした。基準を二重管理しないのが教訓。
この1本を通すだけでも、「LLM に任せる部分(分類・生成・採点)」と「コードで固定する部分(しきい値・回数・承認)」の線引きが具体的に見えてきます。
どんな形で使うのか
OpenAI の orchestration ドキュメントでは、コード主導でよくあるパターンとして次の4つが挙げられています。先ほどのフローもこれらの組み合わせです。
1. 分類して分岐する
最初に structured output でカテゴリを出し、その結果を見てコード側で次のエージェントを選ぶ形です。上の例の入口がこれにあたります。
2. 直列にチェーンする
リサーチ → 下書き → 改善 → 評価のように、一方の出力を次の入力へ変換しながら手順をコードでつなぐ形です。公式もブログ執筆を research / outline / draft / critique / refine に分解する例を挙げています。
3. evaluator でループする
出力を評価エージェントに見せ、基準を満たすまで生成エージェントをループで回す形です。上の while ループがこれです。上限回数を持たせるのがコード主導らしさです。
4. 並列に走らせる
独立した複数タスクを asyncio.gather のようなコード側の並列処理で同時に走らせる形です。互いに依存しないタスクをまとめて投げて速度を稼ぎます。このときも、誰を並列にするかはコードが決めます。
向いている場面 / 向かない場面
向いている
問い合わせ分類、社内申請、レビュー導線、記事生成のように手順が決まっている業務。監査や再現性が要る業務。不要な specialist 呼び出しを減らしてコストを抑えたい業務。schema 不一致や評価 NG など失敗条件が明確な業務。
向かない
何を調べるべきか自体が曖昧な調査。途中で論点が大きく変わる壁打ち。かなり開いた創造作業。こうした場面で無理にコード主導へ寄せると、分岐だらけになってかえって複雑化する。
迷ったら次の3つで見ると判断しやすいです。「こういうときはこのエージェント」と短く言語化できるか。評価 NG や schema mismatch のような失敗条件を定義できるか。監査や説明責任が必要か。どれも Yes ならコード主導に寄せる価値が高いです。
実務でよくある誤解
1. コード主導ならAIらしさがなくなる
そんなことはありません。流れをコードで決めて、各ステップの知的処理はエージェントに任せる、という分担ができます。上の例でも、分類・生成・採点はすべて LLM の仕事です。
2. コード主導の方が必ず安全
制御しやすくはなりますが、ルール設計が雑なら危ないです。危険な tool を開きっぱなしにしていれば、コード主導でも事故は起きます。プロンプトインジェクション 経由で想定外の入力が来る前提で、権限は最小に絞るべきです。
3. LLM主導より常に安い
単純なフローなら安くなりやすいですが、コード側で評価や retry を組みすぎると逆に重くなることもあります。上限回数や評価頻度を決めずに足すと、固定したはずのコストがじわじわ膨らみます。
コード主導オーケストレーションに関するよくある質問
Q. コード主導 vs LLM主導はどう選びますか?
A. 業務フローが明確、再現性が必要、監査要件があるならコード主導です。柔軟な対応や予測困難な分岐が必要なら LLM 主導です。実務では「骨格はコード、判断は LLM」のハイブリッドが多数派で、上のトレース例もこの形です。
Q. 評価 NG のしきい値はどう決めればいいですか?
A. 総合スコアの下限と、一発アウト条件の2軸で持つのが扱いやすいです。例では「score >= 80 かつ事実誤りゼロ」で OK としました。最初は緩め(70 点など)から始め、通ってはいけない出力が混じったらしきい値や一発アウト条件を足して締めていくと運用しやすいです。基準はプロンプトでなくコード側の定数に置くと変更が楽です。
Q. retry 上限は何回が妥当ですか?
A. 多くの改善は 1〜2 回目で効き、3 回目以降は伸びにくくなるため、3 回前後を上限にして打ち切り、人間へ回す設計が現実的です。重要なのは「無制限にしない」ことで、上限を決めればコストの天井も同時に決まります。
Q. コード主導の実装にはどんなフレームワークを使いますか?
A. OpenAI Agents SDK のほか、LangGraph、Temporal、AWS Step Functions、Apache Airflow、Prefect、Inngest などがあります。LangGraph は AI 向けに最適化、Step Functions や Temporal はビジネスワークフロー全般、と用途差があります。
Q. ハイブリッド構成の具体例は?
A. 「タスク振り分けはコードの if/else、各タスク内の処理は LLM」「成功・失敗判定はコード、失敗時の対応案は LLM が提案」などです。上のトレース例も、分岐と回数はコード、中身の生成と採点は LLM というハイブリッドです。
Q. コード主導でも LLM のハルシネーションは防げますか?
A. 完全には防げません。LLM の出力をコード側で検証し(structured output の schema チェックや Judge の採点)、想定外なら再生成、それでもダメなら人間エスカレーション、という多重防御にします。コード = 100%安全ではありません。
Q. デバッグはどうやりますか?
A. 各ステップの入出力と分岐結果(分類ラベル、各 attempt のスコアと issues、最終的にどの分岐で抜けたか)を構造化ログに残します。上の失敗例のように、コード主導なら「どの attempt のどの条件で止まったか」が明確で、可視化ツール(LangSmith、Langfuse、OpenTelemetry)と組み合わせると追跡が速いです。
まとめ
コード主導のオーケストレーションとは、AIエージェント同士の流れや分岐条件を、LLMのその場判断だけでなくコード側で決める設計 です。柔軟性は少し下がりますが、速度・コスト・再現性・承認フローの明示ではかなり強くなります。
大事なのは、どこを LLM に任せ、どこをコードで固定し、どこで評価や人間承認を入れるかを分けて考えることです。トレース例で見たように、分類の信頼度しきい値、評価の合否基準、retry の上限、最終承認点といった「踏んで決めた値」をコードに明示できるかどうかが、運用に耐えるフローの分かれ目になります。
マルチエージェント全体の前提は マルチエージェントとは?複数のAIエージェントを分けて使う意味と注意点を整理 から、受け渡しは Handoffとは?AIエージェントが役割を受け渡す仕組みを整理 とあわせて読むとつながりやすいです。
参考リンク
- OpenAI Agents SDK: Agent orchestration
- OpenAI Agents SDK: Context management
- OpenAI Agents SDK: Handoffs
- OpenAI Agents SDK: Run config