このリポジトリは、Azure Durable Functionsを使用して、Anthropicのブログ「Building effective agents」で紹介されたオーケストレーター-ワーカーのパターンを実装するためのテンプレートプロジェクトです。

Durable Functions を使用してサーバーレス AI エージェントを構築する方法について詳しく知りたい方は、Chris Gillum のブログ記事をご覧ください: Building Serverless AI Agents using Durable Functions on Azure
同期エンドポイントの場合:
sequenceDiagram
participant Client
participant Sarter
participant DurableOrchestrator
participant AgentDeciderActivity
participant WorkerAgentActivity
participant SynthesizerActivity
Client->>Sarter: Web APIリクエスト
Sarter->>DurableOrchestrator: 開始
DurableOrchestrator ->> AgentDeciderActivity: 呼び出すAgentを決定
AgentDeciderActivity ->> DurableOrchestrator: 呼び出すべきAgent
DurableOrchestrator -->> Sarter: 呼び出すべきAgentがない場合、プレーンテキストを返す
DurableOrchestrator ->> WorkerAgentActivity: 呼び出し(複数および並行)
WorkerAgentActivity ->> DurableOrchestrator: 結果
DurableOrchestrator ->> SynthesizerActivity: 結果を合成し、回答を生成
SynthesizerActivity ->> DurableOrchestrator: 合成された回答
DurableOrchestrator ->> Sarter: 回答
Sarter ->> Client: Web APIレスポンス
このマルチエージェントシステムは、旅行コンシェルジュのシナリオに基づいています。
各エージェントは、サンプル用に固定値を応答として返すように設定されています。
テンプレートで定義されているサンプルエージェントは以下の通りです:
- GetDestinationSuggestAgent:目的地の提案を取得
- GetClimateAgent:目的地の気候を取得
- GetSightseeingSpotAgent:目的地の観光地を取得
- GetHotelAgent:目的地のホテル情報を取得
- SubmitReservationAgent:ホテルの予約を送信
固定値になっている各Agentの実装をを改変してRAGやAction、その他処理を実装することで要件にあったAgentを作成してください。 各AgentではDIコンテナからOpenAI ClientやCosmos DB Client、アプリケーション構成値などが利用可能です。
各AgentのActivityメソッドは、LLMの推論時間をエミュレートするために以下のように待機時間が実装されています。 実際にAgentを実装する際にサンプルAgentをベースにする場合はコードから以下の部分を削除してください。
await Task.Delay(3000);Durable Functionsのリトライ機能を実証するために、各AgentにはLLMなどの外部サービス呼び出しの失敗をエミュレートするコードが記述されています。 Agent Activityはランダムに30%の確率で実行が失敗します。 実際にAgentを実装する際にサンプルAgentをベースにする場合はコードから以下の部分を削除してください。
if(Random.Shared.Next(0, 10) < 3)
{
logger.LogInformation("Failed to get climate information");
throw new InvalidOperationException("Failed to get climate information");
}-
事前に以下のリソースを作成してください。
- Azure OpenAI Serviceとチャット補完モデルのデプロイ(埋め込みモデルのデプロイは任意)
- Azure Cosmos DB(使用しない場合は省略可能)
- Azure Cosmos DBの代わりに、Azure Cosmos DB Emulator(エミュレーター)を使用することもできます。詳細については、以下のドキュメントをご参照ください。
Azure Cosmos DB エミュレーターを使用したローカルでの開発
- Azure Cosmos DBの代わりに、Azure Cosmos DB Emulator(エミュレーター)を使用することもできます。詳細については、以下のドキュメントをご参照ください。
-
DurableMultiAgentTemplateプロジェクトのlocal.settings.jsonを更新し、ご自身の以下のリソースの情報を設定します。- Azure OpenAIのエンドポイントとデプロイ名
- Azure Cosmos DBのエンドポイント(使用しない場合は省略可能)
各サービスへの認証はAPIキーまたはEntra ID認証を選択できます。
- APIキーを使用する場合:
local.settings.jsonファイルにAPIキーを記述してください。 - Entra ID認証を使用する場合:Azure CLIを使用して
az loginコマンドで認証してください。local.settings.jsonファイルAPIキーは空白にしてください。この際に、認証したユーザーに各サービスのRBACが付与されている必要があることに注意してください。
-
azuriteによりローカルにストレージアカウントをインストールし起動します。
azuriteはAzuriteはMicrosoftが提供しているオープンソースのAzure Storageエミュレーターです。 Functionsが起動するのに必要なBlobストレージやQueueストレージを本操作によりローカル端末上に立ち上げます。
まずはAzuriteをインストールします。
npm install -g azurite
インストール方法の詳細については以下のページをご参照ください。 https://learn.microsoft.com/ja-jp/azure/storage/common/storage-use-azurite?tabs=visual-studio%2Cblob-storage
その後、azuriteを起動します。フォアグラウンドで起動してよい(後続の操作を別ウィンドウで実行できる場合には以下のコマンドを用います。
azurite同一ウィンドウで後続のコマンドを動作させる必要がある場合には以下のコマンドを用いてバックグラウンド実行します
nohup azurite > azurite.log 2>&1 &- プロジェクトを実行します。
プロジェクトのテストには .NET Blazor クライアントまたは Python streamlit クライアントのどちらかを使用できます。
.NET のシンプルなチャットアプリを使用して動作をテストできます:
simpleagentchat.mp4
- Visual Studio 2022 でソリューションファイル
DurableMultiAgentTemplate.slnを開きます。 - スタートアッププロジェクトとして
Multi agent testを選択します。- これにより、Durable Functions プロジェクトと .NET クライアントプロジェクトの両方が同時に実行されます。
F5を押してプロジェクトを実行します。- エラーが発生した場合は、
DurableMultiAgentTemplateプロジェクトのlocal.settings.jsonファイルを確認してください。
- エラーが発生した場合は、
- Visual Studio Code のアクティビティバーから
実行とデバッグを選択します。 - ドロップダウンリストから、
C#: Attach to DurableMultiAgentTemplate worker processを選択し、ドロップダウンリスト左の実行ボタンを押します。- これにより、タスク
host start (functions)でFunctionsホストが起動します。 - Functionsホストのターミナルに、
"{ "name":"dotnet-worker-startup", "workerProcessId" : 12345 }"というログが出力されます。workerProcessIdが、デバッガーをアタッチするプロセスのIDです。 prelaunchTaskのダイアログが表示されたら、このままデバッグする(Debug Anyway)を選びます。- デバッガーをアタッチするプロセスの一覧が表示されます。先ほどFunctionsホストのログに出力されたプロセスを選択してください。
- デバッガーがアタッチされ、デバッグ実行が始まります。
- これにより、タスク
- ドロップダウンリストから、
C#: Debug DurableMultiAgentTemplate.Clientを選択し、ドロップダウンリスト左の実行ボタンを押します。
プロジェクトを実行した後、http://localhost:{your port number} でクライアントにアクセスできます。
client.py を使用して、Orchestrator-Workers パターンをテストできます。 次のコマンドで実行できます:
dotnet run --project .\DurableMultiAgentTemplate\DurableMultiAgentTemplate.csprojクライアントは Streamlit で作成されているため、次のコマンドで実行できます:
streamlit run client.py
The full-resolution video is here.
Starter関数のエンドポイントには同期と非同期の2種類があります。エージェントの処理に時間がかかる場合は、非同期エンドポイントを使用することをお勧めします。 Durable Functionsの非同期パターンの詳細についてはこちら。
- 同期エンドポイント:
http://{your base url}/api/invoke/sync - 非同期エンドポイント:
http://{your base url}/api/invoke/async
リクエストボディは、次のようになります。
{
"messages": [
{
"role": "user",
"content": "おすすめの旅行先を見つけて欲しい"
},
{
"role": "assistant",
"content": "旅行先についての希望の条件を教えてください。例えば、ビーチがある場所、歴史的な観光地が多い場所、自然が豊かな場所など、ご希望に応じておすすめの旅行先を提案します。"
},
{
"role": "user",
"content": "歴史的な観光地が多い場所かな〜"
}
],
"requireAdditionalInfo": true
}レスポンスは次のようになります。
{
"additionalInfo": [
{
"$type": "mardown",
"markdownText": "### おすすめの歴史的観光地が多い旅行先\n\n#### 国内\n1. **沖縄本島** \n - 透明度の高いビーチ、首里城、美ら海水族館など観光名所が豊富。 \n - 冬でも暖かく、リラックスした雰囲気を楽しめる。\n\n2. **石垣島・宮古島** \n - 南国らしい美しい自然が広がり、ダイビングやシュノーケリングが人気。 \n - 島ならではの郷土料理も楽しめる。\n\n3. **鹿児島・奄美大島** \n - 奄美の黒糖焼酎や島唄、特有の自然環境を満喫。 \n - 亜熱帯の雰囲気を楽しめる。"
}
],
"content": "歴史的な観光地が多い場所としては以下の旅行先がおすすめです。\n\n1. **沖縄本島** - 首里城をはじめ、美ら海水族館など歴史と観光が融合したスポットがあります。\n2. **鹿児島・奄美大島** - 島唄や亜熱帯の雰囲気が楽しめます。\n3. **石垣島・宮古島** - 島独特の郷土料理と自然景観が魅力です。\n\n詳しくは補足情報を参照してください。",
"calledAgentNames": [
"GetDestinationSuggestAgent"
]
}一般にエージェントからの返答(特にRAGを含む場合)は文章量が長くなり、チャット体験を阻害する要因になることがあります。
そのため、ストック型の補足情報とフロー型のチャットを分離し、チャット体験を向上できます。
このテンプレートではリクエストの際にrequireAdditionalInfoをtrueに設定すると、補足情報を要求することができます。
補足情報はレスポンスのadditionalInfoに格納されチャットの返答とは別に返されます。
テストのためのクライアントコード内のREQUIRE_ADDITIONAL_INFOフラグを切り替えることでこの機能を体験できます。

この機能は副次的にチャット履歴のmessages配列のトークン量を削減し、LLMの動作を軽快にする効果もあります。 ただし、シナリオによってはmessages配列のコンテキストが欠落し、エージェントの返答が不自然になることがあります。 そのような場合には必要に応じて補足情報の内容をmessagesにマージしてエージェントにリクエストすることも検討してください。