Agentes em fluxos de trabalho

Este tutorial demonstra como integrar agentes de IA em fluxos de trabalho usando o Agent Framework. Você aprenderá a criar fluxos de trabalho que aproveitam o poder de agentes de IA especializados para criação, revisão e outras tarefas colaborativas de conteúdo.

O que você vai construir

Você criará um fluxo de trabalho que:

  • Usa o Azure Foundry Agent Service para criar agentes inteligentes
  • Implementa um agente de tradução francês que traduz a entrada para o francês
  • Implementa um agente de tradução espanhol que traduz francês para espanhol
  • Implementa um agente de tradução em inglês que traduz espanhol de volta para inglês
  • Conecta agentes em um pipeline de fluxo de trabalho sequencial
  • Transmite atualizações em tempo real à medida que os agentes processam solicitações
  • Demonstra a limpeza adequada de recursos para agentes do Azure Foundry

Conceitos abordados

Pré-requisitos

Etapa 1: Instalar pacotes NuGet

Primeiro, instale os pacotes necessários para seu projeto .NET:

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

Etapa 2: Configurar o Azure Foundry Client

Configure o cliente do Azure Foundry com variáveis de ambiente e autenticação:

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

Passo 3: Método de Criar Fábrica de Agentes

Implemente um método auxiliar para criar agentes do Azure Foundry com instruções específicas:

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

Passo 4: Criar Agentes Especializados Azure Foundry

Crie três agentes de tradução usando o método auxiliar:

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

Etapa 5: Criar o fluxo de trabalho

Conecte os agentes em um fluxo de trabalho sequencial usando o WorkflowBuilder:

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

Etapa 6: Executar com streaming

Execute o fluxo de trabalho com streaming para observar atualizações em tempo real de todos os agentes:

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

Etapa 7: Limpeza de recursos

Limpe corretamente os agentes do Azure Foundry após o uso:

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

Como funciona

  1. Configuração do Cliente do Azure Foundry: Usa AIProjectClient com credenciais da CLI do Azure para autenticação
  2. Criação de Agentes: Cria agentes versionados no Azure Foundry com instruções específicas para tradução
  3. Processamento sequencial: o agente francês traduz primeiro a entrada, depois o agente espanhol e, em seguida, o agente inglês
  4. Padrão de token: os agentes armazenam mensagens em cache e só processam quando recebem um TurnToken
  5. Streaming Updates: AgentResponseUpdateEvent fornece atualizações de token em tempo real à medida que os agentes geram respostas
  6. Gerenciamento de recursos: limpeza adequada dos agentes do Azure Foundry usando a API de administração

Conceitos-chave

  • Azure Foundry Agent Service: agentes de IA baseados em nuvem com recursos avançados de raciocínio
  • AIProjectClient: Cliente para criar e gerir agentes no Azure Foundry
  • WorkflowEvent: Os eventos de saída (type="output") contêm dados de saída do agente (AgentResponseUpdate para streaming, AgentResponse para não-streaming)
  • TurnToken: Sinal que aciona o processamento do agente após o cache de mensagens
  • Fluxo de trabalho sequencial: agentes conectados em um pipeline onde a saída flui de um para o próximo

Implementação Completa

Para obter a implementação de trabalho completa deste fluxo de trabalho de agentes do Azure Foundry, consulte o exemplo de Program.cs do FoundryAgent no repositório do Agent Framework.

O que você vai construir

Você criará um fluxo de trabalho que:

  • Usa FoundryChatClient para criar agentes inteligentes
  • Implementa um agente do Writer que cria conteúdo com base em prompts
  • Implementa um agente revisor que fornece comentários sobre o conteúdo
  • Conecta agentes em um pipeline de fluxo de trabalho sequencial
  • Transmite atualizações em tempo real à medida que os agentes processam solicitações

Conceitos abordados

Pré-requisitos

  • Python 3.11 ou versão posterior
  • Agent Framework instalado: pip install agent-framework
  • Azure OpenAI Responses configurado com variáveis de ambiente adequadas
  • Autenticação da CLI do Azure: az login

Etapa 1: Importar dependências necessárias

Comece por importar os componentes necessários para fluxos de trabalho e agentes Azure OpenAI Responses:

import asyncio
import os

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

Passo 2: Criar o Cliente de Respostas Azure OpenAI

Crie um cliente partilhado que possa usar para construir múltiplos agentes:

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

Passo 3: Criar Agentes Especializados

Crie dois agentes especializados para criação e revisão de conteúdo:

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

Etapa 4: Criar o fluxo de trabalho

Ligue os agentes num fluxo de trabalho sequencial usando o construtor:

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

Etapa 5: Executar com streaming

Execute o fluxo de trabalho com streaming para observar atualizações em tempo real de ambos os agentes:

    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)

Passo 6: Completar a função principal

Encapsule tudo na função principal com execução assíncrona correta.

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

Como funciona

  1. Configuração do Cliente: Usa um FoundryChatClient com credenciais de CLI Azure para autenticação.
  2. Criação de Agentes: Cria agentes Escritor e Revisor a partir da mesma configuração de cliente.
  3. Processamento Sequencial: O agente escritor gera primeiro o conteúdo e depois passa-o ao agente revisor.
  4. Atualizações de Streaming: Os eventos de saída (type="output") com dados de AgentResponseUpdate fornecem atualizações de tokens em tempo real enquanto os agentes geram respostas.

Conceitos-chave

  • FoundryChatClient: Cliente partilhado usado para criar agentes de workflow com configuração consistente.
  • WorkflowEvent: Os eventos de saída (type="output") contêm dados de saída do agente (AgentResponseUpdate para streaming, AgentResponse para não streaming).
  • Fluxo de Trabalho Sequencial: Agentes ligados num pipeline onde a saída flui de um para o outro.

Implementação Completa

Para a implementação funcional completa, veja azure_ai_agents_streaming.py no repositório Agent Framework.

O que você vai construir

Você criará um fluxo de trabalho que:

  • Utiliza agentes de implementação de modelos Microsoft Foundry como executores de workflow
  • Implementa um agente de tradução em francês
  • Implementa um agente de tradução para espanhol
  • Implementa um agente de tradução para inglês
  • Conecta agentes em um pipeline de fluxo de trabalho sequencial
  • Transmite atualizações em tempo real à medida que os agentes processam solicitações

Conceitos abordados

Pré-requisitos

  • Go 1.26 ou posterior
  • Endpoint do projeto Microsoft Foundry e implementação do modelo configurados
  • Autenticação da CLI do Azure ou outra origem de credenciais do Azure

Num novo diretório, inicialize um módulo Go e instale o Agent Framework:

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

Defina o endpoint do projeto e o nome do seu modelo implementado:

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

Passo 1: Configurar a Configuração da Fundição

As secções seguintes constroem a runExample função na implementação completa. Comece pelas importações e configuração:

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 é conveniente para o desenvolvimento, mas requer uma consideração cuidadosa na produção. Em produção, considere usar uma credencial específica, como azidentity.NewManagedIdentityCredential, para evitar problemas de latência, sondagens não intencionais de credenciais e potenciais riscos de segurança provenientes de mecanismos de recurso.

Passo 2: Criar Função de Fábrica do Agente

Crie agentes com instruções específicas de tradução:

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

Passo 3: Criar Agentes Especializados em Fundição

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

Etapa 4: Criar o fluxo de trabalho

Os agentes podem ser usados como executores de workflows, permitindo passos de workflow potenciados por IA.

Associe cada agente como executor de fluxo de trabalho, depois ligue os executores entre si com arestas:

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) passa a resposta de cada agente a jusante sem também encaminhar a entrada desse agente. Cada executante hospedado gere a sua própria sessão de agente.

Registe o francês e o espanhol como fontes intermédias de saída para que os chamadores possam observar os três agentes. O inglês continua a ser a origem da saída do terminal. A designação de saída controla o que o autor da chamada vê, não quais as mensagens que fluem ao longo das arestas.

Etapa 5: Executar com streaming

Execute o fluxo de trabalho e ative eventos de atualização com um workflow.TurnToken. Lidar com eventos de falha no fluxo de trabalho, bem como erros do iterador de eventos:

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

O resultado contém traduções em francês, espanhol e inglês, agrupadas por executor. O exemplo completo retorna de runExample antes de registar um erro fatal, por isso a limpeza diferida do fluxo de trabalho continua a correr.

Ao contrário do exemplo do C#, este exemplo do Go não cria versões armazenadas do agente que precisam de ser eliminadas no Foundry.

Como funciona

  1. Configuração do Cliente: Utiliza um endpoint de projeto Foundry, implementação do modelo e credencial Azure.
  2. Criação de Agentes: Cria agentes especializados com instruções específicas da língua.
  3. Alojamento de Agentes: Utiliza agentworkflow.New para associar cada agente como executor de fluxo de trabalho.
  4. Processamento Sequencial: O executor francês executa primeiro, depois espanhol, depois inglês.
  5. Turn Token Pattern: Os agentes alojados armazenam mensagens e executam quando recebem um workflow.TurnToken.
  6. Atualizações em Streaming: Os registos de saída intermédios e terminais expõem atualizações dos três agentes.
  7. Gestão de falhas: O anfitrião verifica ErrorEvent e ExecutorFailedEvent e fecha a execução do fluxo de trabalho antes de reportar a falha.

Conceitos-chave

  • Agente da Foundry: Um agent.Agent suportado por uma implementação de modelo da Foundry.
  • agentworkflow. Novo: Adapta um agente para ser usado como executor de workflow.
  • fluxo de trabalho. TurnToken: Sinal que desencadeia agentes alojados para processar mensagens em buffer.
  • Workflow OutputEvent: Transporta atualizações de resposta do agente e resultados finais do fluxo de trabalho.
  • Fluxo de Trabalho Sequencial: Agentes ligados num pipeline onde a saída flui de um para o outro.

Implementação Completa

Guarde este exemplo como main.go no seu módulo de 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
}

Execute o exemplo:

go run .

Warning

azidentity.NewDefaultAzureCredential é conveniente para o desenvolvimento, mas requer uma consideração cuidadosa na produção. Em produção, considere usar uma credencial específica, como azidentity.NewManagedIdentityCredential, para evitar problemas de latência, sondagens não intencionais de credenciais e potenciais riscos de segurança provenientes de mecanismos de recurso.

Tip

Consulte o exemplo de agentes em workflows para outro pipeline de tradução executável.

Próximas Etapas