Agenter i arbetsflöden

Den här självstudien visar hur du integrerar AI-agenter i arbetsflöden med hjälp av Agent Framework. Du lär dig att skapa arbetsflöden som utnyttjar kraften hos specialiserade AI-agenter för att skapa, granska och andra samarbetsuppgifter.

Vad du kommer att bygga

Du skapar ett arbetsflöde som:

  • Använder Azure Foundry Agent Service för att skapa intelligenta agenter
  • Implementerar en fransk översättningsagent som översätter indata till franska
  • Implementerar en spansk översättningsagent som översätter franska till spanska
  • Implementerar en engelsk översättningsagent som översätter spanska tillbaka till engelska
  • Ansluter agenter i en pipeline för sekventiellt arbetsflöde
  • Strömmar realtidsuppdateringar när agenter bearbetar begäranden
  • Visar korrekt resursrensning för Azure Foundry-agenter

Begrepp som omfattas

Förutsättningar

Steg 1: Installera NuGet-paket

Installera först de nödvändiga paketen för .NET-projektet:

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

Steg 2: Konfigurera Azure Foundry-klienten

Konfigurera Azure Foundry-klienten med miljövariabler och autentisering:

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());

Steg 3: Skapa agentfabriksmetod

Implementera en hjälpmetod för att skapa Azure Foundry-agenter med specifika instruktioner:

    /// <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);
    }
}

Steg 4: Skapa specialiserade Azure Foundry-agenter

Skapa tre översättningsagenter med hjälpmetoden:

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

Steg 5: Skapa arbetsflödet

Anslut agenterna i ett sekventiellt arbetsflöde med hjälp av WorkflowBuilder:

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

Steg 6: Kör med direktuppspelning

Kör arbetsflödet med direktuppspelning för att observera realtidsuppdateringar från alla agenter:

        // 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}");
            }
        }

Steg 7: Resursrensning

Rensa Azure Foundry-agenterna korrekt efter användning:

        // 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);
    }

Så här fungerar det

  1. Konfiguration av Azure Foundry-klient: Använder AIProjectClient med Azure CLI-autentiseringsuppgifter för autentisering
  2. Skapande av agent: Skapar versionshanterade agenter på Azure Foundry med specifika instruktioner för översättning
  3. Sekventiell bearbetning: Fransk agent översätter indata först, sedan spansk agent och sedan engelsk agent
  4. Vänd tokenmönster: Agenter cachelagrar meddelanden och bearbetar endast när de tar emot en TurnToken
  5. Direktuppspelningsuppdateringar: AgentResponseUpdateEvent tillhandahåller tokenuppdateringar i realtid när agenter genererar svar
  6. Resurshantering: Korrekt rensning av Azure Foundry-agenter med hjälp av administrations-API:et

Viktiga begrepp

  • Azure Foundry Agent Service: Molnbaserade AI-agenter med avancerade resonemangsfunktioner
  • AIProjectClient: Klient för att skapa och hantera agenter på Azure Foundry
  • WorkflowEvent: Utdatahändelser (type="output") innehåller agentutdata (AgentResponseUpdate för direktuppspelning, AgentResponse för icke-direktuppspelning)
  • TurnToken: Signal som utlöser agentbearbetning efter cachelagring av meddelanden
  • Sekventiellt arbetsflöde: Agenter som är anslutna i en pipeline där utdata flödar från en till en annan

Fullständig implementering

Den fullständiga implementeringen av det här Arbetsflödet för Azure Foundry-agenter finns i FoundryAgent-Program.cs exempel på Agent Framework-lagringsplatsen.

Vad du kommer att bygga

Du skapar ett arbetsflöde som:

  • Använder FoundryChatClient för att skapa intelligenta agenter
  • Implementerar en Writer-agent som skapar innehåll baserat på frågor
  • Implementerar en granskaragent som ger feedback om innehållet
  • Ansluter agenter i en pipeline för sekventiellt arbetsflöde
  • Strömmar realtidsuppdateringar när agenter bearbetar begäranden

Begrepp som omfattas

Förutsättningar

  • Python 3.11 eller senare
  • Agent Framework har installerats: pip install agent-framework
  • Azure OpenAI-svar konfigurerade med rätt miljövariabler
  • Azure CLI-autentisering: az login

Steg 1: Importera nödvändiga beroenden

Börja med att importera nödvändiga komponenter för arbetsflöden och Azure OpenAI-svarsagenter:

import asyncio
import os

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

Steg 2: Skapa Azure OpenAI-svarsklient

Skapa en delad klient som du kan använda för att skapa flera agenter:

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

Steg 3: Skapa specialiserade agenter

Skapa två specialiserade agenter för att skapa och granska innehåll:

    # 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."
        ),
    )

Steg 4: Skapa arbetsflödet

Anslut agenterna i ett sekventiellt arbetsflöde med hjälp av byggverktyget:

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

Steg 5: Kör med direktuppspelning

Kör arbetsflödet med direktuppspelning för att observera realtidsuppdateringar från båda agenterna:

    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)

Steg 6: Slutför huvudfunktionen

Inneslut allt i huvudfunktionen med korrekt asynkron körning.

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

Så här fungerar det

  1. Klientinstallation: Använder en FoundryChatClient med Azure CLI-autentiseringsuppgifter för autentisering.
  2. Skapande av agent: Skapar skrivare och granskare från samma klientkonfiguration.
  3. Sekventiell bearbetning: Skrivagenten genererar först innehåll och skickar det sedan till granskaragenten.
  4. Direktuppspelningsuppdateringar: Utdatahändelser (type="output") med AgentResponseUpdate data ger uppdateringar av token i realtid när agenter genererar svar.

Viktiga begrepp

  • FoundryChatClient: Delad klient som används för att skapa arbetsflödesagenter med konsekvent konfiguration.
  • WorkflowEvent: Utdatahändelser (type="output") innehåller agentutdata (AgentResponseUpdate för direktuppspelning, AgentResponse för icke-direktuppspelning).
  • Sekventiellt arbetsflöde: Agenter som är anslutna i en pipeline där utdata flödar från en till en annan.

Fullständig implementering

Den fullständiga arbetsimplementeringen finns i azure_ai_agents_streaming.py på Agent Framework-lagringsplatsen.

Vad du kommer att bygga

Du skapar ett arbetsflöde som:

  • Använder Microsoft Foundry-agenter för modellimplementering som arbetsflödesexekutorer
  • Implementerar en fransk översättningsagent
  • Implementerar en spansk översättningsagent
  • Implementerar en engelsk översättningsagent
  • Ansluter agenter i en pipeline för sekventiellt arbetsflöde
  • Strömmar realtidsuppdateringar när agenter bearbetar begäranden

Begrepp som omfattas

Förutsättningar

  • Go 1.26 eller senare
  • Microsoft Foundry-projektslutpunkt och modelldistribution konfigurerad
  • Azure CLI autentisering eller någon annan källa för Azure autentiseringsuppgifter

I en ny katalog initierar du en Go-modul och installerar Agent Framework:

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

Ange projektets endpoint och namnet på din driftsatta modell:

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

Steg 1: Konfigurera Foundry

I följande avsnitt byggs runExample funktionen upp i den fullständiga implementeringen. Börja med import och konfiguration:

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
}

Varning

azidentity.NewDefaultAzureCredential är praktiskt för utveckling men kräver noggrant övervägande i produktion. I produktion bör du överväga att använda en specifik autentiseringsuppgift, till exempel azidentity.NewManagedIdentityCredential, för att undvika problem med svarstid, oavsiktlig avsökning av autentiseringsuppgifter och potentiella säkerhetsrisker från reservmekanismer.

Steg 2: Skapa agentfabriksfunktion

Skapa agenter med specifika översättningsinstruktioner:

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"},
    })
}

Steg 3: Skapa specialiserade Foundry-agenter

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

Steg 4: Skapa arbetsflödet

Agenter kan användas som arbetsflödesexekutorer, vilket möjliggör AI-baserade arbetsflödessteg.

Bind varje agent som en exekverare i arbetsflödet och anslut sedan exekverarna med kanter:

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) skickar varje agents svar nedströms utan att även vidarebefordra agentens indata. Varje värdbaserad exekverare hanterar sin egen agentsession.

Registrera franska och spanska som mellanliggande utdatakällor så att anropare kan observera alla tre agenterna. Engelska är fortfarande källan för terminalutdata. Utdataetiketten styr vad anroparen ser, inte vilka meddelanden som flödar längs kanterna.

Steg 5: Kör med direktuppspelning

Kör arbetsflödet och aktivera uppdateringshändelser med hjälp av workflow.TurnToken. Hantera arbetsflödesfelhändelser samt fel från händelse iteratorn:

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()
}

Utdata innehåller franska, spanska och engelska översättningar grupperade efter utförare. Det fullständiga exemplet returnerar från runExample innan ett allvarligt fel loggas, så uppskjuten rensning av arbetsflöden körs fortfarande.

Till skillnad från C#-exemplet skapar det här Go-exemplet inte lagrade agentversioner som behöver tas bort i Foundry.

Så här fungerar det

  1. Klientinställning: Använder en slutpunkt för Foundry-projektet, modelldistribution och Azure-autentiseringsuppgifter.
  2. Skapande av agent: Skapar specialiserade agenter med språkspecifika instruktioner.
  3. Agentvärdtjänst: Använder agentworkflow.New för att koppla varje agent som en arbetsflödesexekverare.
  4. Sekventiell bearbetning: Den franska exekveraren körs först, därefter den spanska och sedan den engelska.
  5. Turordningsmönster för token: Värdbaserade agenter buffrar meddelanden och körs när de tar emot en workflow.TurnToken.
  6. Strömningsuppdateringar: Registreringar av mellan- och utdata i terminalen visar uppdateringar från alla tre agenterna.
  7. Felhantering: Värden kontrollerar ErrorEvent och ExecutorFailedEvent och stänger arbetsflödeskörningen innan fel rapporteras.

Viktiga begrepp

  • Foundry-agent: En agent.Agent agent som backas upp av en Foundry-modellimplementering.
  • agentworkflow. Ny: Anpassar en agent för användning som arbetsflödesexekutor.
  • Arbetsflöde. TurnToken: Signal som utlöser värdbaserade agenter för att bearbeta buffrade meddelanden.
  • Arbetsflödets utdatabegivenhet: Innehåller uppdateringar av agentens svar och arbetsflödets slutliga utdata.
  • Sekventiellt arbetsflöde: Agenter som är anslutna i en pipeline där utdata flödar från en till en annan.

Fullständig implementering

Spara det här exemplet som main.go i go-modulen:

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
}

Kör exemplet:

go run .

Varning

azidentity.NewDefaultAzureCredential är praktiskt för utveckling men kräver noggrant övervägande i produktion. I produktion bör du överväga att använda en specifik autentiseringsuppgift, till exempel azidentity.NewManagedIdentityCredential, för att undvika problem med svarstid, oavsiktlig avsökning av autentiseringsuppgifter och potentiella säkerhetsrisker från reservmekanismer.

Tip

Se exemplet agents in workflows för en annan körbar översättningspipeline.

Nästa steg