ワークフロー内のエージェント

このチュートリアルでは、Agent Framework を使用して AI エージェントをワークフローに統合する方法について説明します。 コンテンツの作成、レビュー、その他の共同作業タスクに特化した AI エージェントの機能を活用するワークフローを作成する方法について説明します。

あなたが構築するもの

次のワークフローを作成します。

  • Azure Foundry Agent Service を使用してインテリジェント エージェントを作成する
  • 入力をフランス語に変換するフランス語翻訳エージェントを実装します
  • フランス語をスペイン語に翻訳するスペイン語翻訳エージェントを実装します
  • スペイン語を英語に翻訳する英語翻訳エージェントを実装します
  • シーケンシャル ワークフロー パイプライン内のエージェントを接続します
  • エージェントが要求を処理する際にリアルタイムの更新をストリーム配信する
  • Azure Foundry エージェントの適切なリソース クリーンアップを示します

対象となる概念

前提条件

手順 1: NuGet パッケージをインストールする

まず、.NET プロジェクトに必要なパッケージをインストールします。

dotnet add package Microsoft.Agents.AI.Foundry --prerelease
dotnet add package Microsoft.Agents.AI.Workflows --prerelease

手順 2: Azure Foundry クライアントを設定する

環境変数と認証を使用して Azure Foundry クライアントを構成します。

using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Extensions.AI;

public static class Program
{
    private static async Task Main()
    {
        // Set up the Azure AI Project client
        var endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
            ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
        var deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-4o-mini";
        var aiProjectClient = new AIProjectClient(new Uri(endpoint), new AzureCliCredential());

手順 3: Agent Factory メソッドを作成する

特定の手順で Azure Foundry エージェントを作成するヘルパー メソッドを実装します。

    /// <summary>
    /// Creates a translation agent for the specified target language.
    /// </summary>
    /// <param name="targetLanguage">The target language for translation</param>
    /// <param name="aiProjectClient">The AIProjectClient to create the agent</param>
    /// <param name="model">The model to use for the agent</param>
    /// <returns>A FoundryAgent configured for the specified language</returns>
    private static async Task<FoundryAgent> GetTranslationAgentAsync(
        string targetLanguage,
        AIProjectClient aiProjectClient,
        string model)
    {
        string agentName = $"{targetLanguage}Translator";
        var version = await aiProjectClient.AgentAdministrationClient.CreateAgentVersionAsync(
            agentName,
            new ProjectsAgentVersionCreationOptions(
                new DeclarativeAgentDefinition(model)
                {
                    Instructions = $"You are a translation assistant that translates the provided text to {targetLanguage}."
                }));

        return aiProjectClient.AsAIAgent(version);
    }
}

手順 4: 特殊な Azure Foundry エージェントを作成する

ヘルパー メソッドを使用して、次の 3 つの変換エージェントを作成します。

        // Create agents
        AIAgent frenchAgent = await GetTranslationAgentAsync("French", aiProjectClient, deploymentName);
        AIAgent spanishAgent = await GetTranslationAgentAsync("Spanish", aiProjectClient, deploymentName);
        AIAgent englishAgent = await GetTranslationAgentAsync("English", aiProjectClient, deploymentName);

手順 5: ワークフローを構築する

WorkflowBuilder を使用して、シーケンシャル ワークフロー内のエージェントを接続します。

        // Build the workflow by adding executors and connecting them
        var workflow = new WorkflowBuilder(frenchAgent)
            .AddEdge(frenchAgent, spanishAgent)
            .AddEdge(spanishAgent, englishAgent)
            .Build();

手順 6: ストリーミングを使用して実行する

ストリーミングを使用してワークフローを実行し、すべてのエージェントからのリアルタイムの更新を観察します。

        // Execute the workflow
        await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, new ChatMessage(ChatRole.User, "Hello World!"));

        // Must send the turn token to trigger the agents.
        // The agents are wrapped as executors. When they receive messages,
        // they will cache the messages and only start processing when they receive a TurnToken.
        await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
        await foreach (WorkflowEvent evt in run.WatchStreamAsync())
        {
            if (evt is AgentResponseUpdateEvent executorComplete)
            {
                Console.WriteLine($"{executorComplete.ExecutorId}: {executorComplete.Data}");
            }
        }

手順 7: リソースのクリーンアップ

使用後に Azure Foundry エージェントを適切にクリーンアップします。

        // Cleanup the agents created for the sample.
        await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(frenchAgent.Name);
        await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(spanishAgent.Name);
        await aiProjectClient.AgentAdministrationClient.DeleteAgentAsync(englishAgent.Name);
    }

しくみ

  1. Azure Foundry クライアントのセットアップ: Azure CLI資格情報を使用して認証を行います​​
  2. エージェントの作成: 翻訳の具体的な手順を使用して、Azure Foundry にバージョン管理されたエージェントを作成します
  3. 順次処理: フランス語エージェントが最初に入力を変換し、次にスペイン語エージェント、次に英語エージェントを変換します。
  4. ターン トークン パターン: エージェントはメッセージをキャッシュし、メッセージを受信したときにのみ処理します。 TurnToken
  5. ストリーミング更新: エージェントが応答を生成する際に、 AgentResponseUpdateEvent によってリアルタイムのトークン更新が提供されます
  6. リソース管理: 管理 API を使用した Azure Foundry エージェントの適切なクリーンアップ

主な概念

  • Azure Foundry Agent Service: 高度な推論機能を備えたクラウドベースの AI エージェント
  • AIProjectClient: Azure Foundry でエージェントを作成および管理するためのクライアント
  • WorkflowEvent: 出力イベント (type="output") には、エージェント出力データ (ストリーミング用のAgentResponseUpdate 、非ストリーミング用の AgentResponse ) が含まれています
  • TurnToken: メッセージ キャッシュ後にエージェントの処理をトリガーするシグナル
  • シーケンシャル ワークフロー: 出力が 1 つから次のパイプラインに流れるパイプラインで接続されているエージェント

完全な実装

この Azure Foundry エージェント ワークフローの完全な実装については、Agent Framework リポジトリの FoundryAgent Program.cs サンプルを参照してください。

あなたが構築するもの

次のワークフローを作成します。

  • FoundryChatClientを使用してインテリジェント エージェントを作成する
  • プロンプトに基づいてコンテンツを作成するライター エージェントを実装します
  • コンテンツに関するフィードバックを提供するレビュー担当者エージェントを実装します
  • シーケンシャル ワークフロー パイプライン内のエージェントを接続します
  • エージェントが要求を処理する際にリアルタイムの更新をストリーム配信する

対象となる概念

前提条件

  • Python 3.11 以降
  • Agent Framework がインストールされている: pip install agent-framework
  • 適切な環境変数で構成された Azure OpenAI 応答
  • Azure CLI 認証: az login

手順 1: 必要な依存関係をインポートする

まず、ワークフローと Azure OpenAI Responses エージェントに必要なコンポーネントをインポートします。

import asyncio
import os

from agent_framework import AgentResponseUpdate, WorkflowBuilder
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential

手順 2: Azure OpenAI Responses クライアントを作成する

複数のエージェントを構築するために使用できる共有クライアントを 1 つ作成します。

async def main() -> None:
    client = FoundryChatClient(
        project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
        model=os.environ["FOUNDRY_MODEL"],
        credential=AzureCliCredential(),
    )

手順 3: 特殊なエージェントを作成する

コンテンツの作成と確認のために、次の 2 つの特殊なエージェントを作成します。

    # Create a Writer agent that generates content
    writer_agent = client.as_agent(
        name="Writer",
        instructions=(
            "You are an excellent content writer. You create new content and edit contents based on the feedback."
        ),
    )

    # Create a Reviewer agent that provides feedback
    reviewer_agent = client.as_agent(
        name="Reviewer",
        instructions=(
            "You are an excellent content reviewer. "
            "Provide actionable feedback to the writer about the provided content. "
            "Provide the feedback in the most concise manner possible."
        ),
    )

手順 4: ワークフローを構築する

ビルダーを使用して、シーケンシャル ワークフロー内のエージェントを接続します。

        # Build the workflow with agents as executors
        workflow = WorkflowBuilder(start_executor=writer_agent).add_edge(writer_agent, reviewer_agent).build()

手順 5: ストリーミングを使用して実行する

ストリーミングを使用してワークフローを実行し、両方のエージェントからのリアルタイムの更新を観察します。

    last_author: str | None = None

    events = workflow.run("Create a slogan for a new electric SUV that is affordable and fun to drive.", stream=True)
    async for event in events:
        if event.type == "output" and isinstance(event.data, AgentResponseUpdate):
            update = event.data
            author = update.author_name
            if author != last_author:
                if last_author is not None:
                    print()
                print(f"{author}: {update.text}", end="", flush=True)
                last_author = author
            else:
                print(update.text, end="", flush=True)

手順 6: Main 関数を完了する

main関数で適切な非同期実行を用いてすべてをカプセル化します。

if __name__ == "__main__":
    asyncio.run(main())

しくみ

  1. クライアント セットアップ: 認証に Azure CLI 資格情報で 1 つの FoundryChatClient を使用します。
  2. エージェントの作成: 同じクライアント構成からライター エージェントとレビュー担当者エージェントを作成します。
  3. 順次処理: ライター エージェントは最初にコンテンツを生成し、次にレビュー担当者エージェントに渡します。
  4. ストリーミング更新: type="output" データを含む出力イベント (AgentResponseUpdate) は、エージェントが応答を生成する際にリアルタイムのトークン更新を提供します。

主な概念

  • FoundryChatClient: 一貫性のある構成でワークフロー エージェントを作成するために使用される共有クライアント。
  • WorkflowEvent: 出力イベント (type="output") には、エージェント出力データ (ストリーミング用のAgentResponseUpdate 、非ストリーミング用の AgentResponse ) が含まれます。
  • シーケンシャル ワークフロー: 出力が 1 つから次のパイプラインに流れるパイプラインで接続されているエージェント。

完全な実装

完全に動作する実装については、Agent Framework リポジトリの azure_ai_agents_streaming.py を参照してください。

あなたが構築するもの

次のワークフローを作成します。

  • Microsoft Foundry モデルデプロイ エージェントをワークフロー 実行プログラムとして使用します
  • フランス語翻訳エージェントを実装します
  • スペイン語翻訳エージェントを実装します
  • 英語翻訳エージェントを実装します
  • シーケンシャル ワークフロー パイプライン内のエージェントを接続します
  • エージェントが要求を処理する際にリアルタイムの更新をストリーム配信する

対象となる概念

前提条件

  • Go 1.26 以降
  • Microsoft Foundry プロジェクト エンドポイントとモデルのデプロイが構成されている
  • Azure CLI認証または別のAzure資格情報ソース

新しいディレクトリで Go モジュールを初期化し、Agent Framework をインストールします。

go mod init example.com/agent-workflow
go get github.com/microsoft/agent-framework-go

プロジェクト エンドポイントとデプロイされたモデルの名前を設定します。

$env:FOUNDRY_PROJECT_ENDPOINT = "https://<resource>.services.ai.azure.com/api/projects/<project>"
$env:FOUNDRY_MODEL = "<deployment-name>"

手順 1: Foundry 構成を設定する

次のセクションでは、完全な実装で runExample 関数を実装します。 インポートと構成から始めます。

import (
    "context"
    "errors"
    "fmt"
    "log"
    "os"
    "strings"

    "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
    "github.com/microsoft/agent-framework-go/agent"
    "github.com/microsoft/agent-framework-go/message"
    "github.com/microsoft/agent-framework-go/provider/foundryprovider"
    "github.com/microsoft/agent-framework-go/workflow"
    "github.com/microsoft/agent-framework-go/workflow/agentworkflow"
    "github.com/microsoft/agent-framework-go/workflow/inproc"
)

endpoint := strings.TrimSpace(os.Getenv("FOUNDRY_PROJECT_ENDPOINT"))
if endpoint == "" {
    return fmt.Errorf("set FOUNDRY_PROJECT_ENDPOINT")
}
model := strings.TrimSpace(os.Getenv("FOUNDRY_MODEL"))
if model == "" {
    return fmt.Errorf("set FOUNDRY_MODEL to your model deployment name")
}

token, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
    return err
}

Warning

azidentity.NewDefaultAzureCredential は開発には便利ですが、運用環境では慎重に考慮する必要があります。 運用環境では、待機時間の問題、意図しない資格情報のプローブ、フォールバック メカニズムによる潜在的なセキュリティ リスクを回避するために、 azidentity.NewManagedIdentityCredentialなどの特定の資格情報を使用することを検討してください。

手順 2: エージェント ファクトリ関数を作成する

特定の翻訳手順を使用してエージェントを作成します。

newTranslationAgent := func(language string) *agent.Agent {
    return foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
        Instructions: fmt.Sprintf(
            "Translate the user's text to %s. Return only the translation.",
            language,
        ),
        Config: agent.Config{Name: language + "Agent"},
    })
}

手順 3: 特殊な Foundry エージェントを作成する

frenchAgent := newTranslationAgent("French")
spanishAgent := newTranslationAgent("Spanish")
englishAgent := newTranslationAgent("English")

手順 4: ワークフローを構築する

エージェントはワークフロー 実行プログラムとして使用でき、AI を利用したワークフロー ステップが可能になります。

各エージェントをワークフロー 実行プログラムとしてバインドしてから、Executor をエッジに接続します。

cfg := agentworkflow.Config{ForwardIncomingMessages: new(false)}
french := agentworkflow.New(frenchAgent, cfg)
spanish := agentworkflow.New(spanishAgent, cfg)
english := agentworkflow.New(englishAgent, cfg)

wf, err := workflow.NewBuilder(french).
    AddEdge(french, spanish).
    AddEdge(spanish, english).
    WithIntermediateOutputFrom(french, spanish).
    WithOutputFrom(english).
    Build()
if err != nil {
    return err
}

ForwardIncomingMessages: new(false) は、各エージェントの応答をダウンストリームに渡し、入力は転送しません。 ホストされる各 Executor は、独自のエージェント セッションを管理します。

呼び出し元が 3 つのエージェントをすべて観察できるように、フランス語とスペイン語を中間出力ソースとして登録します。 英語はターミナルの出力ソースのままです。 出力指定は、エッジに沿って流れるメッセージではなく、呼び出し元に表示される内容を制御します。

手順 5: ストリーミングを使用して実行する

ワークフローを実行し、 workflow.TurnTokenを使用して更新イベントを有効にします。 ワークフロー失敗イベントとイベント反復子からのエラーを処理します。

run, err := inproc.Default.RunStreaming(ctx, wf, message.NewText("Hello World"))
if err != nil {
    return err
}
defer func() {
    err = errors.Join(err, run.Close(context.WithoutCancel(ctx)))
}()

emitEvents := true
if accepted, err := run.TrySendMessage(ctx, workflow.TurnToken{EmitEvents: &emitEvents}); err != nil {
    return err
} else if !accepted {
    return fmt.Errorf("workflow doesn't accept turn tokens")
}

lastExecutorID := ""
for evt, streamErr := range run.WatchStream(ctx) {
    if streamErr != nil {
        return streamErr
    }
    switch event := evt.(type) {
    case workflow.OutputEvent:
        update, ok := event.Output.(*agent.ResponseUpdate)
        if !ok || update.String() == "" {
            continue
        }
        if event.ExecutorID != lastExecutorID {
            if lastExecutorID != "" {
                fmt.Println()
            }
            fmt.Printf("%s: ", event.ExecutorID)
            lastExecutorID = event.ExecutorID
        }
        fmt.Print(update.String())
    case workflow.ErrorEvent:
        return event.Error
    case workflow.ExecutorFailedEvent:
        return fmt.Errorf("executor %q failed: %w",
            event.ExecutorID, event.Error)
    }
}
if lastExecutorID != "" {
    fmt.Println()
}

出力には、Executor でグループ化されたフランス語、スペイン語、英語の翻訳が含まれています。 完全な例では、致命的なエラーをログに記録する前に runExample から戻るので、遅延ワークフローのクリーンアップは引き続き実行されます。

C# の例とは異なり、この Go の例では、Foundry で削除が必要な格納済みエージェント バージョンは作成されません。

しくみ

  1. クライアント セットアップ: Foundry プロジェクト エンドポイント、モデル配置、および Azure 資格情報を使用します。
  2. エージェントの作成: 言語固有の命令を使用して特殊なエージェントを作成します。
  3. エージェント ホスティング: agentworkflow.New を使用して、各エージェントをワークフロー 実行プログラムとしてバインドします。
  4. シーケンシャル処理: フランス語の Executor が最初に実行され、次にスペイン語、次に英語が実行されます。
  5. ターン トークン パターン: ホストされているエージェントはメッセージをバッファーし、 workflow.TurnTokenを受信したときに実行します。
  6. ストリーミング更新: 中間出力登録とターミナル出力登録では、3 つのエージェントすべてからの更新を取得できます。
  7. 障害処理: ホストは ErrorEvent と ExecutorFailedEvent をチェックし、エラーを報告する前にワークフローの実行を閉じます。

主な概念

  • Foundry エージェント: Foundry モデルのデプロイによって支えられる agent.Agent。
  • agentworkflow。新規: ワークフロー実行プログラムとして使用するエージェントを調整します。
  • ワークフロー。TurnToken: バッファリングされたメッセージを処理するためにホストされたエージェントをトリガーするシグナル。
  • Workflow OutputEvent: エージェント応答の更新と最終的なワークフロー出力を実行します。
  • シーケンシャル ワークフロー: 出力が 1 つから次のパイプラインに流れるパイプラインで接続されているエージェント。

完全な実装

次の例を Go モジュールに main.go として保存します。

package main

import (
    "context"
    "errors"
    "fmt"
    "log"
    "os"
    "strings"

    "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
    "github.com/microsoft/agent-framework-go/agent"
    "github.com/microsoft/agent-framework-go/message"
    "github.com/microsoft/agent-framework-go/provider/foundryprovider"
    "github.com/microsoft/agent-framework-go/workflow"
    "github.com/microsoft/agent-framework-go/workflow/agentworkflow"
    "github.com/microsoft/agent-framework-go/workflow/inproc"
)

func main() {
    if err := runExample(context.Background()); err != nil {
        log.Fatal(err)
    }
}

func runExample(ctx context.Context) (err error) {
    endpoint := strings.TrimSpace(os.Getenv("FOUNDRY_PROJECT_ENDPOINT"))
    if endpoint == "" {
        return fmt.Errorf("set FOUNDRY_PROJECT_ENDPOINT")
    }
    model := strings.TrimSpace(os.Getenv("FOUNDRY_MODEL"))
    if model == "" {
        return fmt.Errorf("set FOUNDRY_MODEL to your model deployment name")
    }

    token, err := azidentity.NewDefaultAzureCredential(nil)
    if err != nil {
        return err
    }

    newTranslationAgent := func(language string) *agent.Agent {
        return foundryprovider.NewAgent(
            endpoint,
            token,
            foundryprovider.ModelDeployment(model),
            foundryprovider.AgentConfig{
                Instructions: fmt.Sprintf(
                    "Translate the user's text to %s. Return only the translation.",
                    language,
                ),
                Config: agent.Config{Name: language + "Agent"},
            },
        )
    }

    cfg := agentworkflow.Config{ForwardIncomingMessages: new(false)}
    french := agentworkflow.New(newTranslationAgent("French"), cfg)
    spanish := agentworkflow.New(newTranslationAgent("Spanish"), cfg)
    english := agentworkflow.New(newTranslationAgent("English"), cfg)

    wf, err := workflow.NewBuilder(french).
        AddEdge(french, spanish).
        AddEdge(spanish, english).
        WithIntermediateOutputFrom(french, spanish).
        WithOutputFrom(english).
        Build()
    if err != nil {
        return err
    }

    run, err := inproc.Default.RunStreaming(ctx, wf, message.NewText("Hello World"))
    if err != nil {
        return err
    }
    defer func() {
        err = errors.Join(err, run.Close(context.WithoutCancel(ctx)))
    }()

    emitEvents := true
    if accepted, err := run.TrySendMessage(ctx, workflow.TurnToken{EmitEvents: &emitEvents}); err != nil {
        return err
    } else if !accepted {
        return fmt.Errorf("workflow doesn't accept turn tokens")
    }

    lastExecutorID := ""
    for evt, streamErr := range run.WatchStream(ctx) {
        if streamErr != nil {
            return streamErr
        }
        switch event := evt.(type) {
        case workflow.OutputEvent:
            update, ok := event.Output.(*agent.ResponseUpdate)
            if !ok || update.String() == "" {
                continue
            }
            if event.ExecutorID != lastExecutorID {
                if lastExecutorID != "" {
                    fmt.Println()
                }
                fmt.Printf("%s: ", event.ExecutorID)
                lastExecutorID = event.ExecutorID
            }
            fmt.Print(update.String())
        case workflow.ErrorEvent:
            return event.Error
        case workflow.ExecutorFailedEvent:
            return fmt.Errorf("executor %q failed: %w",
                event.ExecutorID, event.Error)
        }
    }
    if lastExecutorID != "" {
        fmt.Println()
    }
    return nil
}

例を実行する:

go run .

Warning

azidentity.NewDefaultAzureCredential は開発には便利ですが、運用環境では慎重に考慮する必要があります。 運用環境では、待機時間の問題、意図しない資格情報のプローブ、フォールバック メカニズムによる潜在的なセキュリティ リスクを回避するために、 azidentity.NewManagedIdentityCredentialなどの特定の資格情報を使用することを検討してください。

Tip

別の実行可能な翻訳パイプラインについては、ワークフロー内のエージェントのサンプルを参照してください。

次のステップ