Building Effective AI Agents \ Anthropicの翻訳です。
本書は著者が手動で翻訳したものであり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
我々は様々な業界でLLMエージェントを構築する多数のチームと共に取り組んでいます。一貫して、最も成功する実装では、複雑なフレームワークではなく、シンプルで組み合わせ可能なパターンを用いてます。
我々は去年様々な業界で大規模言語モデル(LLM)エージェントを構築している数多くのチームと共に取り組みを行いました。一貫して、最も成功した実装では、複雑なフレームワークや特殊なライブラリを使っていませんでした。代わりに、かれらはシンプルで組み合わせ可能なパターンを用いて構築を行なっていました。
この記事では、我々のお客様との取り組み、自身によるエージェントの構築からの学びを共有し、効果的なエージェントを構築する技術者向けに実践的なアドバイスを提供します。
エージェントとは?
「エージェント」はいくつかの方法で定義することができます。いくつかのお客様は、複雑なタスクを達成するために様々なツールを用いて、長い時間を通じて独立的に動作する完全自律システムとしてエージェントを定義しています。他のお客様では、事前に定義されたワークフローに従うより規範的な実装を説明するためのこの用語を用いています。Anthropicにおいては、これらのバリエーションのすべてをエージェンティックシステムとしてカテゴライズしますが、ワークフローとエージェントの間には重要なアーキテクチャ上の区別をしています:
- ワークフローは事前に定義されたコードバスを通じて、LLMとツールがオーケストレートされるシステムです。
- 一方、エージェントはタスクをどのように達成するのかに対するコントロールを維持しながらも、自身のプロセスとツールの用法をLLMが動的に指示するシステムです。
以下では、エージェンティックシステムの両方のタイプを詳細に探索します。付録1(エージェントの実践)では、お客様がこれらの種類のシステムを用いる際に、特に価値を見出した2つのドメインを説明します。
いつエージェントを使うべきか(使うべきでないか)
LLMを用いたアプリケーションを構築する際、可能な限りシンプルなソリューションを特定し、必要な場合にのみ複雑性を増加させることを推奨します。これは、エージェンティックシステムを全く構築しない場合があることを意味します。多くの場合、エージェンティックシステムでは優れたタスクパフォーマンスのためにレイテンシーとコストのトレードを行うこととなり、このトレードオフが合理的なものな場合には検討を行うべきです。
複雑性が正当化される際には、ワークフローは適切に定義されたタスクにおける予測可能性と一貫性を提供しますが、大規模に柔軟性とモデル駆動の意思決定が必要とされる際にはエージェントが優れた選択肢となります。しかし、多くのアプリケーションにおいては、リトリーバルとコンテキスト内の例を用いた単一のLLMコールを最適化するだけで、通常は十分です。
フレームワークを使う時、使い方
以下のように、エージェンティックシステムの実装を容易にする数多くのフレームワークが存在します:
- LangChainのLangGraph
- Amazon BedrockのAI Agent framework
- ドラッグ&ドロップのGUI LLMワークフロービルダーのRivet
- 複雑なワークフローの構築、テストのための別のGUIツールであるVellum
これらのフレームワークは、LLM呼び出し、ツールの定義と解析、呼び出しの連鎖のような標準的な低レベルのタスクをシンプルにすることでスタートすることを容易にします。しかし、これらは多くの場合、背後のプロンプトやレスポンスを不明瞭にする場合がある追加の抽象化レイヤーを作り出し、デバッグを困難にします。また、これらは、シンプルな環境で十分な場合にも複雑性を追加する傾向があります。
我々は開発者にはLLMのAPIを直接使用することからスタートすることをお勧めします: 多くのパターンは数行のコードで実装することができます。フレームワークを使う際には、背後のコードを理解するようにしましょう。内部動作に対する間違った仮説は、お客様におけるエラーのよくある原因となります。
いくつかのサンプル実装に関しては、我々のcookbookをご覧ください。
ビルディングブロック、ワークフロー、エージェント
このセクションでは、我々は本番運用で目撃したエージェンティックシステムの共通的なパターンを探索します。基本的なビルディングブロックである拡張LLMからスタートし、シンプルな組み合わせ可能なワークフローから自律的なエージェントへと徐々に複雑性を増やしていきます。
ビルディングブロック: 拡張LLM
エージェンティックシステムの基本的なビルディングブロックは、リトリーバル、ツール、メモリーのような拡張で強化されたLLMとなります。我々の現行のモデルは、検索クエリーを生成し、適切なツールを選択し、どの情報を保持するのかを決定するなど、アクティブにこれらの機能を活用することができます。
この実装の2つの側面にフォーカスすることをお勧めします: あなたの特定のユースケースのこれらの能力をカスタマイズし、これらがLLMに対して容易で適切に文書化されたインタフェースを提供するようにしましょう。これらの拡張を実装する方法は多数存在しますが、一つのアプローチはシンプルなクライアント実装によってサードパーティツールのエコシステムを用いて開発者が連携できるように最近リリースしたModel Context Protocolを通じたものです。
この記事の残りでは、それぞれのLLMがこれらの拡張機能にアクセスできることを前提とします。
ワークフロー: プロンプトの連鎖
プロンプトの連鎖は、それぞれのLLM呼び出しが以前の呼び出しのアウトプットを処理するステップのシーケンスに分解します。プロセスが引き続き正常に進行していることを確認するために、すべての中間ステップにプログラム的なチェック機能(以下の図の「gate」をご覧ください)を追加することができます。
このワークフローを使うべき時: タスクを容易かつ綺麗に固定的なサブタスクに分解できる場合には、このワークフローは理想的なものとなります。主要なゴールは、それぞれのLLMコールをより容易なタスクにすることで、高い精度とレイテンシーをトレードオフすることです。
プロンプト連鎖が有用な例:
- マーケティングコピーを生成し、別の言語に翻訳する。
- ドキュメントのアウトラインの記述、アウトラインが特定の評価指標に合致するかをチェック、アウトラインに基づいてドキュメントの記述。
ワークフロー: ルーティング
ルーティングでは、入力を分類し、特定のフォローアップのタスクに指示します。このワークフローによって、関心の分離、より特化したプロンプトの構築を可能にします。このワークフローなしには、一種類の入力の最適化は、他の入力におけるパフォーマンスを損なう場合があります。
このワークフローを使うべき時: ルーティングは、適切かつ分離して対応できる個別のカテゴリーがあり、LLMやより古典的な分類モデル/アルゴリズムによって分類が正確に行われる場合には、ルーティングは適切に動作します。
ルーティングが有用な例:
- カスタマーサービスの問い合わせの様々なタイプ(汎用的な質問、返金リクエスト、技術サポート)を、様々な後段のプロセス、プロンプト、ツールに指示します。
- コストとスピードを最適化するために、簡単/一般的な質問をClaude 3.5 Haikuにルーティングし、困難/特異な質問をClaude 3.5 Sonnetのようにより能力のあるモデルにルーティングします。
ワークフロー: 並列化
LLMは時には、タスクを同時に実行し、アウトプットをプログラム的に集約することができます。この並列化ワークフローには、2つの主要なバリエーションがあります:
- セクション分け: タスクを並列で独立したサブタスクに分割します。
- 投票: 様々なアウトプットを得るために、同じタスクを複数回実行します。
このワークフローを使うべき時: スピード目的で分割されたサブタスクが並列化される場合、より高い信頼性の結果のために、複数の観点や試行が必要な際には並列化が効果的です。複数の検討を伴う複雑なタスクにおいては、それぞれの検討が個別のLLM呼び出しで対応され、それぞれの固有の観点に対してフォーカスされた検討が可能な場合には、通常LLMは優れたパフォーマンスを示します。
並列化が有用な例:
-
セクション分け:
- あるモデルインスタンスがユーザーの問い合わせを処理しつつも、別のモデルが不適切なコンテンツやリクエストをスクリーニングするガードレイルの実装。これは、同じLLMがガードレイルとコアのレスポンスの両方に対応するよりも、優れたパフォーマンスを示す傾向があります。
- それぞれのLLMコールが特定のプロンプトにおけるモデルのパフォーマンスをの異なる観点を評価する、LLMパフォーマンスの評価の自動化。
-
投票:
- いくつかの異なるプロンプトがレビューを行い、問題を特定した際にはコードにフラグをつける、コードピースの脆弱性のレビュー。
- 様々な観点で評価する複数のプロンプトや偽陽性、偽陰性のバランスを取るために様々な投票の閾値を用いた、特定のコンテンツが不適切であるかどうかの評価。
ワークフロー: オーケストレーター - ワーカー
オーケストレーター - ワーカーワークフローでは、中央のLLMが動的にタスクを分割し、ワーカーLLMにそれらを委任し、結果を統合します。
このワークフローを使うべき時: このワークフローは、必要なサブタスクを予測できないような複雑なタスク(例えば、コーディングにおいてタスクに応じて変更が必要なファイルの数や、それぞれのファイルの変更の特質)によく合います。これは、トポロジー的には並列化と似ていますが、並列化との熾な違いはその柔軟性です。サブタスクは事前に定義されませんが、特定の入力に基づいてオーケストレーターによって決定されます。
オーケストレーター - ワーカーが有用な例:
- 毎回複数のファイルに複雑な変更をおこおなうコーディング製品。
- 適切な可能性のある情報の複数のソースからの情報の収集、分析を含む検索タスク。
ワークフロー: エバリュエーター - オプティマイザ
エバリュエーター - オプティマイザワークフローでは、一つのLLMコールがレスポンスを生成しますが、他のLLMはループで評価とフィードバックを提供します。
このワークフローを使うべき時: 明確な評価指標を持ち、繰り返しの改善が計測可能な価値を提供する際には特に効果的です。適応性を示す2つのサインは、一つが人間が自身のフィードバックを明確に述べられる際にはLLMのレスポンスは劇的に改善されるということ、もう一つがLLMがそのようなフィードバックを提供できるということです。これは、人間のライターが洗練されたドキュメントを通じて行う記述プロセスと似たものとなります。
エバリュエーター - オプティマイザが有用な例:
- 翻訳LLMが最初は補足できない場合のあるニュアンスが存在しますが、評価LLMが有用な批評を提供できる場合の文献翻訳。
- 評価者が更なる検索が正当化されるかどうかを決定し、包括的な情報を収集するために、複数回の検索と分析を必要とする複雑な検索タスク。
エージェント
LLMが主要な能力、複雑な入力の理解、推論と計画への関与、信頼性を持ったツールの使用、エラーからの復旧などで成熟することで、エージェントは本格運用に投入されるようになっています。エージェントは、指示や人間のユーザーとの議論から自分の作業をスタートします。タスクが明確になると、エージェントは独立して計画や作業を行い、場合によっては更なる情報や判断のために人間に指示を求めます。実行過程では、エージェントは進捗を評価するt前に、それぞれのステップ(ツール呼び出しの結果やコード実行)で環境から「正解データ」を取得します。エージェントはチェックポイントやブロッカーに遭遇した際には、人間のフィードバックを得るために一時停止します。多くの場合、このタスクは完了することで停止しますが、コントロールを維持するために停止条件(繰り返し数の最大値)を含めることが一般的です。
エージェントは洗練されたタスクに対応できますが、この実装は多くの場合わかりやすいものです。これらは、通常はループにおいて環境フィードバックに基づいてツールを用いるLLMです。このため、ツールセットとそれらのドキュメントを明確かつ注意深く設計することが重要となります。付録2(あなたのツールに対するプロンプトエンジニアリング)でツール開発のベストプラクティスを説明しています。
エージェントを使うべき時: エージェントは必要なステップ数の予測が困難や不可能であり、固定的なパスをハードコードできないオープンエンドの問題で活用することができます。LLMは多数のターンの作業を行うことがあり、あなたは意思決定に対してある程度の信頼をしなくてはなりません。エージェントの自律性によって、信頼された環境におけるタスクのスケールに最適なものとなります。
エージェントの自律的な特性はコストの増加や複合的なエラーの可能性を意味します。サンドボックス環境と適切なガードレイルを用いた徹底的なテストを行うことをお勧めします。
エージェントが有用な例:
以下の例は我々自身の実装によるものです:
- タスクの記述に基づいて多数のファイルの編集を含むSWE-bench tasksを解決するためのコーディングエージェント。
- タスクを達成するためにClaudeが使用する“computer use” reference implementation。
これらのパターンの組み合わせとカスタマイズ
これらのビルディングブロックは規範的なものではありません。これらは、様々なユースケースに適合させるために、開発者が形づくり、組み合わせることができる共通的なパターンです。すべてのLLM機能と同じように、成功の鍵はパフォーマンスを計測し、実装に対するイテレーションを行うことです。繰り返しになりますが、成果が劇的に改善する際にのみ、複雑性を追加することを検討すべきです。
まとめ
LLM領域における成功は、最も洗練されたシステムを構築することではありません。あなたの要件に応じた適切なシステムを構築することです。シンプルなプロンプトからスタートし、包括的な評価を通じて最適化し、シンプルなソリューションで不十分な場合にのみマルチステップのエージェンティックシステムを追加しましょう。
我々はエージェントを実装する際、3つのコア原則に従うようにしています:
- あなたのエージェントのデザインでのシンプルさを維持します。
- エージェントの計画ステップを明示的に表示することで、透明性の優先度を上げましょう。
- 全体的なツールのドキュメント作成とテストを通じて、あなたのエージェント - コンピューターインタフェース(ACI)を注意深く構築しましょう。
フレームワークはクイックにスタートする助けになりますが、プロダクションに行くに従って、抽象化例やを削減し、基本的なコンポーネントを用いて構築することに躊躇しないでください。これらの原則に従うことで、パワフルなだけでなく信頼でき、維持可能で、ユーザーによって信頼されるエージェントを構築することができます。
謝辞
Erik SchluntzとBarry Zhangによって執筆されました。この取り組みは、Anthropicにおけるエージェント構築の経験とお客様によって共有された価値のある洞察によって得られたものであり、深く感謝するものです。
付録1: エージェントの実践
お客様との我々の取り込みによって、上で議論したパターンの実践的な価値を示す2つの有望なAIエージェントのアプリケーションを明らかにしました。両方のアプリケーションでは、会話とアクションの両方を必要し、明確な成功基準があり、フィードバックループを実現し、意味のある人間の監視を組み込みむタスクにおいて、どのようにしてエージェントが最大の価値を追加するのかを説明しています。
A. カスタマーサポート
カスタマーサポートでは、ツール連携を通じて強化された能力と馴染みのあるチャットbotインタフェースを組み合わせます。これは、以下の理由からよりオープンエンドなエージェントに適応します:
- サポートのやり取りは自然に会話のフローに従いますが、外部の情報やアクションへのアクセスを必要とします。
- 顧客データ、注文履歴、知識ベースの記事を取得するためにツールが組み込まれます。
- 返金の実施、チケットの更新のようなアクションはプログラム的に対応できます。そして、
- ユーザーが定義した解法を通じて、明確に成功を計測できます。
いくつかの企業では、成功した解決策に対して課金する利用ベースの課金モデルを通じてこのアプローチの重要性を示しており、彼らのエージェントの効果に対する自信が伺えます。
B. コーディングエージェント
ソフトウェア開発領域では、コードコンプリーションから自律的な問題解決に進化した機能によって、LLMの機能において特筆すべきポテンシャルを示しています。以下の理由から、エージェントは特に効果的です:
- 自動化テストを通じてコードソリューションを検証可能です。
- フィードバックとしてテストのっ結果を用いて、ソリューションに対してエージェントが繰り返しを行うことができます。
- 問題領域は適切に定義され構造化されています。そして、
- 出力の品質は客観的に計測可能です。
我々自身の実装においては、エージェントはプルリクエスト単体のみに基づいたSWE-bench VerifiedベンチマークにおけるリアルなGitHubのイシューを解決することができます。しかし、自動テストは機能の検証の助けとなりますが、ソリューションがより広範なシステム要件とアラインするためには人間のレビューは重要であり続けます。
付録2: あなたのツールに対するプロンプトエンジニアリング
どのようなエージェンティックシステムを構築するにしても、あなたのエージェントにおいてはツールが重要な部品となることでしょう。APIで自身の正確な構造や定義を指定することで、ツールを用いてClaudeは外部サービスやAPIとやり取りを行うことができます。Claudeがレスポンスする際には、ツールの呼び出しを計画した際には、APIレスポンスにツール使用ブロックを含めます。ツール定義と仕様には、あなたの全体的なプロンプトと同じようなプロンプトエンジニアリングに対する注意を払う必要があります。この簡単な付録では、あなたのツールに対してどのようなプロンプトエンジニアリングを行うのかを説明します。
同じアクションを指定するには、多くの場合複数の方法が存在します。例えば、diffを記述したり、ファイル全体を書き換えることで、ファイルの編集を指定することができます。構造化アウトプットにおいては、マークダウンやJSON内でコードを返却することができます。ソフトウェアエンジニアリングにおいては、これらのような違いは表面的なものであり、損失なしに変換することができます。しかし、いくつかのフォーマットは、他のフォーマットよりもLLMによる記述が困難なものがあります。diffの記述には、新たなコードを記述する前にチャンクヘッダーで何行が変更されるのかを理解する必要があります。(マークダウンと比較して)JSON内にコードを記述するには、新規行のや引用符に対する追加のエスケープが必要となります。
ツールのフォーマットに対する意思決定に関する提案は以下の通りとなります:
- 行きづま得る前に、モデルが「考える」ための十分なトークンを与えましょう。
- インターネットにおけるテキストで通常モデルが目撃するものに近いフォーマットを維持しましょう。
- 数千行のコードの正確なカウントを維持したり、記述するすべてのコードの文字列エスケープのようなフォーマットの「オーバーヘッド」が存在しないようにしてください。
経験則の一つは、human-computer interfaces (HCI)にどれだけの工数を割くのかを考えることであり、優れたエージェント - コンピューターインタフェース(ACI)への投資を計画することです。どのようにこれを行うのかに関する考えを示します:
- モデルと同じ靴を履きましょう。説明文やパラメータに基づいてこのツールの使い方は明確か、あるいは、注意深く検討する必要があるでしょうか?もしそうであれば、モデルにとっても同じことでしょう。優れたツールの定義は、多くの場合、使い方の例、エッジケース、入力フォーマットの要件、他のツールからの明確な領域が含まれます。
- 物事をより明確にするために、パラメータ名や説明文をどのように変更しますか?あなたのチームにおける新人の開発者に素晴らしいdocstringを書くようなものとして考えましょう。多くの類似したツールを使う際には、これは特に重要になります。
- モデルがあなたのツールをどのように使うのかをテストしましょう: モデルがどのような間違いをするのかを確認するために我々のワークベンチで多数の入力例を実行し、繰り返しましょう。
- あなたのツールをpoka-yokeしましょう。間違いが起こりにくいように引数を変更しましょう。
SWE-bench向けにエージェントを構築している際、我々はプロンプト全体よりもツールの最適化に多くの時間を費やしました。例えば、エージェントがルートディレクトリから移動した後に、モデルが相対ファイルパスを使用するツールで間違いをすることに気づきました。これを修正するために、ツールが常に絶対ファイルパスを求めるように変更を行い、これによってモデルがこのメソットを完璧に使うことを発見しました。