AIエージェントの信頼性を高める12の原則:Herokuから学ぶ、プロダクションレベルLLMアプリケーション構築の秘訣
近年、AIエージェントは私たちの想像力をかき立て、多くの企業がその可能性に飛び込んでいます。しかし、概念実証から実際に機能するプロダクションレベルのエージェントを構築する道のりは、決して平坦ではありません。多くの開発者が試行錯誤を繰り返し、時には最初からやり直すという苦悩を経験しています。
AI Engineer World's Fairのプレゼンテーション「Building Agents in 2025」では、このエージェント構築の旅における共通の課題が浮き彫りにされ、それを克服するための画期的なフレームワーク「12-Factor Agents - Principles for building reliable LLM applications」が紹介されました。本記事では、このプレゼンテーションの内容を深く掘り下げ、信頼性の高いLLMアプリケーションを構築するための12の原則、その具体的な機能、ビジネスへの影響、そして将来性について詳細に解説します。
エージェント構築の「現実」:開発者の苦悩
プレゼンターは、自身を含め多くの開発者が経験するエージェント構築の典型的な「旅」をユーモラスに語ります。
- エージェントを構築すると決意する: 最初の興奮と可能性に満ちた段階です。
- プロダクトデザイン、UXマッピング、解決すべき問題の特定: どのようなエージェントを作るべきか、ユーザー体験はどうか、どのような問題を解決するのかを検討します。
- 迅速な開発のためにフレームワークを導入し、構築を開始: 開発者は車輪の再発明を避け、既存のライブラリやフレームワークを活用して開発を加速させようとします。
- 品質が70〜80%のレベルに到達: ここで多くのプロジェクトが一旦の成果を出します。CEOも興奮し、チームメンバーも増員されるかもしれません。
- しかし、80%では十分ではないと気づく: ユーザーが実際に利用するプロダクション環境では、80%の品質ではエラーや不満が頻発します。
- 80%を超えるには、フレームワーク、プロンプト、フローなどをリバースエンジニアリングする必要があると悟る: フレームワークの内部構造やプロンプトの生成ロジック、エージェントの実行フローを深く理解し、カスタマイズしなければならない壁にぶつかります。
- 最初からやり直す: 多くの場合、既存のコードやフレームワークに縛られすぎて、最終的には全てを捨ててゼロから再構築するという決断に至ります。
- そして、それがエージェントに適した問題ではないと気づく!: 最もつらい結末かもしれません。プレゼンター自身もDevOpsエージェントを構築しようとした際、Makefileを解釈させてプロジェクトをビルドさせようとしましたが、エージェントは正しい順序でコマンドを実行できず、最終的には「90秒でBashスクリプトを書けばよかった」と悟ったと言います。
この経験は、「すべての問題にエージェントが必要なわけではない」という重要な教訓を示しています。しかし、本当にエージェントが適している問題に対して、どのようにすれば信頼性の高いプロダクションレベルのアプリケーションを構築できるのでしょうか?
信頼性の高いLLMアプリケーション構築の転換点:「12-Factor Agents」とは
プレゼンターは、100人以上の創業者、開発者、エンジニアとの対話を通じて、信頼性の高いLLMアプリケーションを構築している人々が共通して行っているパターンを発見しました。
- ほとんどのプロダクションエージェントは、「エージェント的」ではなく、単なる堅牢なソフトウェアである: 一般的にイメージされるような自律的に思考し行動する「エージェント」というよりは、特定の目的のために設計された信頼性の高いソフトウェアシステムに近いものでした。
- フレームワークを使ったグリーンフィールドでの再開発は非生産的である可能性がある: ゼロから最新のフレームワークを使って構築するよりも、既存のシステムにLLMの要素を効果的に組み込む方が現実的である場合があります。
- 小さく、モジュール化された概念を既存のコードに適用する: 未定義の小さなモジュール化されたコンセプトを既存のコードベースに適用することで、より良い結果を生み出していました。
- AIのバックグラウンドは必要ない: 驚くべきことに、これらの成功事例の多くは、高度なAIの専門知識なしに、基本的なソフトウェアエンジニアリングの原則に基づいて構築されていました。
これらの洞察に基づき、プレゼンターはHerokuの「The Twelve-Factor App」にインスパイアされ、信頼性の高いLLMアプリケーションを構築するための「12-Factor Agents」という原則を策定しました。この原則はGitHubで公開され、瞬く間にHacker Newsでトップページを飾り、20万件以上のインプレッションと4000以上のGitHubスターを獲得しました。これは、多くの開発者が同様の課題に直面し、このような実践的なガイドラインを求めていた証拠です。
プレゼンターは、「フレームワークを非難する意図はない」と強調しつつ、むしろ「既存のフレームワークをどう改善できるか」、特に「高速開発と深い制御を求める開発者のニーズに応える方法」に焦点を当てていると述べます。そして、エージェントに関する既成概念を捨て、ソフトウェアエンジニアリングの原則を適用して、真に優れたエージェントを構築することを提唱します。
「12-Factor Agents」の具体的な原則:詳細解説
それでは、「12-Factor Agents」の主要な原則を具体的に見ていきましょう。
Factor 1: 自然言語からツール(API)呼び出しへ
LLMの最も強力な機能の一つは、人間が理解できる自然言語の要求を、コンピュータが実行できる構造化された形式(JSONなど)に変換する能力です。例えば、「テリに2月のミートアップのスポンサーとして750ドルの支払いリンクを作成できますか?」という要求は、以下のようなJSON形式の関数呼び出しに変換されます。
{
"function": "create_payment_link",
"name": "create_payment_link",
"parameters": {
"amount": 750,
"customer": "cust_128934ddasF9",
"product": "prod_8675389",
"price": "prc_09874329fds",
"quantity": 1,
"memo": "Hey Jeff - see below for the payment link for the february ai tinkerers meetup"
}
}
このJSONが実際に何を処理するかは別の原則(Factor 4)の範疇ですが、LLMがこのような構造化された出力を生成できることが、エージェントの基盤となります。これは単なるテキスト生成ではなく、特定の意図を解釈し、実行可能なアクションに変換する能力を示しています。
Factor 4: ツールは構造化された出力である
1968年のEdgar Dijkstraの論文「Go To Statement Considered Harmful(Go To文は有害である)」は、ソフトウェア開発における制御フローの重要性を説きました。プレゼンターは、この比喩を用いて「ツール利用は有害である」(引用符付き)と主張します。ここでいう「ツール利用」とは、LLMが環境と魔法のように相互作用するという誤解です。
実際には、LLMはJSONを出力し、そのJSONを開発者が記述した決定論的なコードが受け取って処理します。例えば、Pythonのif/elif/else文やswitch文を使って、LLMが出力した意図(create_payment_linkやsearch_issuesなど)に基づいて適切なAPI呼び出しを実行します。
if next_step.intent == 'create_payment_link':
stripe.paymentlinks.create(next_step.parameters)
return # or whatever you want, see below
elif next_step.intent == 'wait_for_a_while':
# do something monadic idk
else: #... the model didn't call a tool we know about
# do something else
このように、LLMはツールを直接「使う」のではなく、ツールを呼び出すための構造化された情報(JSON)を生成する役割を担います。これにより、開発者はツールのロジックを完全に制御でき、柔軟性とプロンプト制御の恩恵を受けられます。ツールはJSONとそれを処理するコードの組み合わせに過ぎないのです。
Factor 8: コントロールフローを所有する
60年前から、ソフトウェアは有向グラフ(Directed Acyclic Graph: DAG)として書かれてきました。if文やwhileループは、コードの実行パスを定義するDAGの一種です。20年前には、AirflowのようなDAGオーケストレーターが登場し、より複雑なワークフロー管理を可能にしました。
エージェントの初期の約束は「DAGを書く必要がない」というものでした。LLMに目標を伝えれば、LLMが自律的に一連のステップ(DAG)を生成してくれる、という期待です。しかし、このアプローチは特に長いコンテキストウィンドウを持つワークフローではうまくいかないことが判明しました。LLMがどんなに賢くなっても、小さく、焦点を絞ったプロンプトとコンテキストを使う方が、常により良い結果が得られるのです。
信頼性の高いエージェントを構築するためには、開発者自身がコントロールフローを所有することが不可欠です。エージェントは以下の4つの基本的な要素で構成されます。
- プロンプト: 次のステップを選択するための指示。
- Switch Statement: モデルが出力したJSONを受け取り、何らかの処理を行う決定論的コード。
- Context: 過去のイベント履歴やツール呼び出し結果など、エージェントの現在の状況を示す情報。
- For Loop: エージェントが次のステップを繰り返し決定し、実行するためのループ。
このコントロールフローを所有することで、開発者はエージェントの挙動を詳細に制御できるようになり、例えば、必要に応じて処理を中断したり(Break)、異なる経路に切り替えたり(Switch)、過去のコンテキストを要約したり(Summarize)、LLMに特定の判断をさせたり(Judge)することが可能になります。これにより、エージェントは単なる線形的な処理の連鎖ではなく、より洗練された意思決定と動的なプロセス制御を実現できるようになります。
Factor 5 & 6: 実行状態とビジネス状態の統合
エージェントが複雑なタスクを実行する際、その内部状態を管理することは極めて重要です。この状態は大きく二つに分けられます。
- 実行状態 (Execution state): エージェントの実行に関するメタデータ。現在のステップ、次のステップ、待機ステータス、リトライ設定などが含まれます。これは、従来のワークフローオーケストレーターが管理するような情報です。
- ビジネス状態 (Business state): エージェントのワークフローで何が起こったかを示す情報。OpenAIメッセージのリスト、ツール呼び出しとその結果のリスト、ユーザーに表示しているデータ、承認待ちの項目などが含まれます。
これらの状態を統合し、標準的なAPI(Launch、Pause、Resume)で管理できることが、エージェントの信頼性を高める鍵となります。エージェントが長時間実行されるツールを呼び出す場合、処理を中断して現在のコンテキストをシリアライズし、データベースに保存できます。ツールの実行が完了し、Webhookを通じて結果が返されると、保存された状態をデータベースからロードし、その結果をコンテキストに追加してエージェントの処理を再開できます。エージェントはバックグラウンドで何が起こっていたかを知る必要がなく、すべてがシームレスに機能します。
このアプローチにより、エージェントはまるで通常のソフトウェアアプリケーションのように、ローンチ、一時停止、再開といったライフサイクルを持つことが可能になり、デバッグや監視も容易になります。これにより、エージェントの複雑さが軽減され、全体的な信頼性が向上します。
Factor 2: プロンプトを所有する
LLMが純粋な関数であり「トークン入力→トークン出力」である以上、エージェントの信頼性は、いかに良い入力トークンをLLMに与え、いかに良い出力トークンを引き出すかにかかっています。フレームワークが提供する抽象化は便利ですが、ある一定の品質バーを超えようとすると、開発者はプロンプトの細部まで完全に制御する必要があることに気づきます。
すべてのトークンを手書きし、エージェントのロール、目標、個性、利用可能なツール、タスクの指示、期待される出力モデルなどを明確に定義することが求められます。これにより、LLMの振る舞いを精密に調整し、特定のユースケースに最適化することが可能になります。これは、開発者が試行錯誤を繰り返し、さまざまなプロンプトを評価する能力に直結します。プロンプトを所有し、柔軟に実験できる環境を持つことは、最高のパフォーマンスと信頼性を実現するために不可欠です。
Factor 3: コンテキスト構築を所有する
プロンプトだけでなく、LLMに提供される情報の全てが「コンテキストエンジニアリング」の対象です。これには、記憶(Memory)、RAG(Retrieval Augmented Generation)、エージェントの履歴(Agentic History)、構造化された出力(Structural Outputs)、およびそれらをまとめる方法が含まれます。
重要なのは、開発者がこのコンテキストをどのように構築し、LLMに提示するかを完全に制御することです。OpenAIの標準メッセージフォーマットを使用することもできますが、イベントの履歴を独自のThreadモデルとして定義し、それを最適化された形式(例えば、XMLタグ付きの文字列)でLLMへの単一のユーザーメッセージまたはシステムメッセージに変換することも可能です。これにより、情報密度と明確さが向上し、LLMがより正確に次のステップを判断できるようになります。すべての入力トークンを意識的に最適化することで、LLMから引き出せる品質の可能性を最大限に高めることができます。
Factor 9: エラーをコンテキストウィンドウに圧縮する
エージェント開発において避けられないのがエラーです。LLMが間違ったツール呼び出しをしたり、呼び出したAPIがダウンしたりすることは頻繁に起こります。このような場合、エラー情報を適切に処理し、エージェントの学習と回復に役立てることが重要です。
単にエラーメッセージやスタックトレース全体をコンテキストウィンドウに追加するだけでは、コンテキストが肥大化し、エージェントが混乱したり、「暴走」したりする原因になります。これを防ぐためには、以下の対策が有効です。
- エラーのクリア: 有効なツール呼び出しが得られたら、それ以前の保留中のエラーをコンテキストからクリアします。
- 要約と編集: スタックトレースのような詳細なエラー情報ではなく、モデルが理解しやすいようにエラーを要約し、必要に応じて編集します。
- ループ回数の制限: エージェントが同じエラーで無限ループに陥らないよう、リトライ回数やステップ数を制限します。
これらの対策により、エージェントはエラーから効果的に学習し、コンテキストウィンドウの健全性を保ちながら、より堅牢に回復できるようになります。エラー処理もまた、開発者がコントロールフローを所有することの重要な側面です。
Factor 7: ツールを使って人間と連絡を取る
エージェントが常に自律的にタスクを完了できるとは限りません。時には人間の介入や承認が必要になります。このような状況を適切に管理することが、エージェントの信頼性を高める上で非常に重要です。
LLMの出力の「最初のトークン」は、エージェントの意図や結果に大きく影響します。この最初のトークンで、LLMが「ツールを呼び出す」か「人間へのメッセージを生成する」かの選択を制御できます。例えば、複雑なデプロイメントのタスクにおいて、エージェントが「確認が必要」と判断した場合、request_human_inputのようなツール呼び出しを生成し、人間に追加の質問や承認を求めることができます。
{
"function": "request_human_input",
"intent": "request_human_input",
"question": "Would you like to proceed with deploying v1.2.3 to production?",
"context": "This is a production deployment that will affect live users.",
"options": {
"urgency": "high",
"format": "yes_no"
}
}
人間からの応答(例:「はい、進めてください」)を受け取ると、エージェントはその情報をコンテキストに追加し、次のステップ(例:deploy_backend)に進むことができます。このように、エージェントと人間がツールを通じてシームレスに協力することで、より複雑で責任の伴うタスクを安全に実行できるようになります。これは、モデルに明確な指示を与えること、インナーループとアウターループの境界を定義すること、そして複数の人間(承認者、専門家など)にアクセスする手段を提供することのメリットを示しています。
Factor 11: どこからでもトリガーし、ユーザーがいる場所で対応する
現代のビジネス環境では、ユーザーは様々なプラットフォームで活動しています。エージェントもまた、そのユーザーがいる場所で利用可能であるべきです。メール、Slack、Webアプリケーション、Telegram、SMSなど、多岐にわたるチャネルからエージェントがトリガーされ、ユーザーとコラボレーションできることが理想です。
ユーザーは、複数のChatGPTスタイルのエージェントのタブをいくつも開いて管理することを望んでいません。彼らはエージェントがまるで同僚のように、慣れ親しんだコミュニケーションチャネルを通じて自然にやり取りできることを期待しています。これにより、エージェントはユーザーの既存のワークフローにスムーズに統合され、より広く採用される可能性が高まります。これは、エージェントが単なるツールではなく、ユーザーの生産性を向上させるパートナーとなるための重要な要素です。
Factor 10: 小さく焦点を絞ったエージェント
大規模で汎用的なエージェントは、しばしば信頼性やパフォーマンスの問題を抱えます。多くの場合、より効果的なアプローチは、小さく焦点を絞った「マイクロエージェント」を構築し、それらを組み合わせてより大きなワークフローを処理することです。これらのマイクロエージェントは、通常10〜100個のツールを持ち、3〜10ステップの短いエージェントループを実行します。
例えば、GitHub PRのマージとテストのパスをトリガーとして、開発環境へのデプロイメントを管理するマイクロエージェントを考えてみましょう。デプロイメントパイプラインの大部分は決定論的なCI/CDコードで構成されますが、人間による承認が必要なステップや、問題発生時のロールバックエージェントへの引き渡しといった部分は、LLMが次のステップを決定するエージェントループに任せます。
このようなアプローチのメリットは以下の通りです。
- 管理しやすいコンテキスト: エージェントループが小さいため、コンテキストウィンドウが肥大化せず、LLMの推論精度が向上します。
- 明確な責任: 各マイクロエージェントが特定のタスクに集中するため、責任範囲が明確になります。
- 高い信頼性: 小さな単位でテストしやすく、問題の切り分けが容易なため、全体の信頼性が向上します。
- 容易なテスト/デバッグ: 各マイクロエージェントを独立してテスト・デバッグできるため、開発効率が高まります。
LLMがどんなに賢くなっても、その能力の限界ギリギリのところで最高の品質を引き出すためには、システム全体を巧みにエンジニアリングする必要があります。マイクロエージェントは、そのための強力なパターンを提供します。
Factor 12: ステートレスなリデューサーについて
エージェントの信頼性と保守性を高める最後の原則は、エージェントを「ステートレスなリデューサー」として設計することです。プレゼンターは、これは厳密には「トランスデューサー」であると訂正しつつも、この考え方が重要だと強調します。
エージェントをステートレスな関数として扱います。つまり、エージェントのロジック自体は状態を持たず、現在のコンテキストとイベントを入力として受け取り、次のステップを決定して新しいコンテキストを返します。エージェントの「状態」は、外部のデータベースやストレージで管理されます。
このアプローチにより、以下のメリットが得られます。
- 予測可能性: 常に同じ入力に対して同じ出力が生成されるため、エージェントの挙動が予測しやすくなります。
- テスト容易性: 各ステップを独立した関数としてテストできるため、デバッグが容易になります。
- スケーラビリティ: 状態が外部で管理されるため、エージェントのインスタンスを容易にスケールアウトできます。
- 堅牢性: エージェントのインスタンスがクラッシュしても、状態は失われず、他のインスタンスが処理を引き継ぐことができます。
開発者がエージェントの状態とコントロールフローを完全に所有し、それをどのように管理するかを自由に選択できることで、極めて柔軟で堅牢なシステムを構築できるのです。
ビジネスへの影響と将来性
「12-Factor Agents」の原則は、単なる技術的なガイドラインにとどまらず、AIエージェントのビジネス展開に多大な影響を与えます。
- 信頼性と品質の向上: 不安定だったエージェントが、プロダクションレベルの厳しい要件に耐えうる信頼性と品質を獲得します。これにより、ミッションクリティカルなビジネスプロセスへのAIエージェントの適用が可能になります。
- 開発効率の改善: 開発者はフレームワークの内部構造と格闘するのではなく、AIの「ハードな部分」(プロンプト設計、コンテキストエンジニアリング、人間との協調)に集中できるようになります。これにより、開発サイクルが加速し、市場投入までの時間が短縮されます。
- 柔軟な運用と拡張性: マイクロエージェントのアプローチとステートレスな設計により、エージェントは容易に拡張・変更できるようになり、変化するビジネスニーズや技術の進化に迅速に対応できます。
- 人間とAIの協調の深化: ツールを通じた人間との協調を前提とすることで、AIは単独でタスクをこなすだけでなく、人間の知見や判断力を活用しながら、より高度で複雑な問題解決に貢献できるようになります。
将来的には、これらの原則が、LLMをバックエンドロジックに組み込み、自動化されたワークフロー全体を駆動する際の標準的なプラクティスとなるでしょう。さまざまなAPIやWebhookの管理といった退屈な作業はツールに任せ、開発者はAIの真の可能性を解き放つ創造的な側面にエネルギーを集中できるようになるはずです。
結論:AIエージェントの未来を共に築く
AIエージェントの構築は、依然として多くの課題を伴う困難な作業です。しかし、この動画が示すように、エージェントは単なる「魔法」ではなく、堅牢なソフトウェアエンジニアリングの原則を適用することで、誰でも構築できる現実的な技術です。
要約すると:
- エージェントはソフトウェアである。
- LLMはステートレスな関数である。
- すべてはコンテキストエンジニアリングである。
- エージェントの状態とコントロールフローを所有する。
- 最先端を見つけ、限界に挑む。
- エージェントは人間とともにあることでより良くなる。
フレームワークがAIの難しい部分を隠蔽しようとする傾向がある一方で、この「12-Factor Agents」は、開発者がAIの難しい部分に積極的に取り組み、その過程でより優れたシステムを構築することを奨励します。そして、人間とエージェントがシームレスに連携し、互いの強みを活かす未来を築くことに焦点を当てています。
この旅はまだ始まったばかりです。正しい抽象化を見つけるために、私たち全員が協力し、実験を続ける必要があります。 さあ、構築しましょう! (Let's go build!)