Como orquestrar a execução de agentes no Microsoft Agent Framework utilizando Workflows

Os workflows no Microsoft Agent Framework introduzem um modelo de orquestração que vai além do comportamento dinâmico de cada agent isolado. Com eles, você define fluxos de execução previsíveis, tipados e reutilizáveis, conectando agents e executores em um grafo direcionado.

Neste artigo, você vai explorar os conceitos principais e a implementação prática em C#. Além disso, vai da construção do grafo até a orquestração sequencial de agents com streaming de eventos.

A diferença entre agent e workflow

Antes de escrever código, vale entender o papel de cada abstração. Um agent é orientado por um LLM (Large Language Model) e decide de forma dinâmica quais ferramentas usar e quais passos executar, com base no contexto da conversa.

Um workflow, por outro lado, é uma sequência de operações definidas explicitamente. O fluxo é determinístico, e cada etapa sabe exatamente para onde enviar a sua saída.

Essa distinção importa porque o workflow não substitui o agent. Na verdade, ele engloba o agent como um componente dentro de um processo maior.

A combinação dos dois modelos permite construir sistemas em que a lógica de negócio continua previsível. Enquanto isso, a inteligência artificial contribui com raciocínio contextual em etapas específicas do fluxo.

Se você ainda não criou um agent, comece pelo artigo criando seu primeiro agente de IA. Depois, volte aqui para orquestrar vários deles com workflows no Microsoft Agent Framework.

Conceitos fundamentais dos workflows no Microsoft Agent Framework

Os workflows no Microsoft Agent Framework seguem o modelo de um grafo dirigido. Esse grafo tem dois elementos principais: executores e arestas.

Executors

Executors são as unidades de processamento. Cada executor recebe uma mensagem de entrada, executa alguma lógica e envia uma mensagem para o próximo nó.

Essa lógica pode ser código personalizado ou a chamada a um agent de IA. Em C#, a forma recomendada é criar uma classe partial que herda de Executor e marcar os métodos de tratamento com o atributo [MessageHandler].

Segundo a documentação oficial de executores, esse atributo usa geração de código em tempo de compilação. Com isso, você ganha desempenho, validação antecipada e compatibilidade com Native AOT.

Edges

Edges são as conexões entre executores. Elas definem a ordem de execução e podem incluir condições para roteamento condicional.

Você declara as arestas diretamente no WorkflowBuilder, que monta o grafo antes da execução. Além das arestas diretas, o framework suporta arestas condicionais, switch case, fan-out e fan-in.

Events e checkpointing

Outros dois conceitos importantes são os Events e o Checkpointing. Os eventos dão observabilidade ao processo, expondo informações sobre o ciclo de vida de cada executor.

O checkpointing, por sua vez, salva o estado de um workflow em execução. Assim, processos de longa duração podem se recuperar de falhas e retomar do ponto em que pararam.

Construindo um workflow simples no Microsoft Agent Framework

Para entender a mecânica básica, o exemplo mais direto é um pipeline de transformação de texto. O primeiro executor converte o texto para maiúsculas, e o segundo inverte a string resultante.

using Microsoft.Agents.AI.Workflows;

// Converte o texto para maiúsculas e envia ao próximo nó
internal sealed partial class UppercaseExecutor() : Executor("UppercaseExecutor")
{
    [MessageHandler]
    private async ValueTask HandleAsync(string text, IWorkflowContext context)
    {
        await context.SendMessageAsync(text.ToUpperInvariant());
    }
}

// Inverte o texto e publica o resultado final do workflow
internal sealed partial class ReverseTextExecutor() : Executor("ReverseTextExecutor")
{
    [MessageHandler]
    private async ValueTask HandleAsync(string text, IWorkflowContext context)
    {
        string reversed = new(text.Reverse().ToArray());
        await context.YieldOutputAsync(reversed);
    }
}

O método SendMessageAsync encaminha a mensagem para o próximo nó do grafo. Já o método YieldOutputAsync sinaliza que aquele executor produz um resultado do workflow para quem o chamou.

Também existe a opção de criar executores a partir de funções. Nesse caso, o método de extensão BindExecutor transforma um delegate em um nó do grafo, como em uppercaseFunc.BindExecutor("UppercaseExecutor").

Montando e executando o grafo

Com os executores prontos, você monta o grafo e executa o workflow da seguinte forma:

UppercaseExecutor uppercase = new();
ReverseTextExecutor reverse = new();

// O construtor recebe o executor inicial do grafo
var workflow = new WorkflowBuilder(uppercase)
    .AddEdge(uppercase, reverse)
    .WithOutputFrom(reverse)
    .Build();

// Execução sem streaming: aguarda o fim e lê os eventos gerados
Run run = await InProcessExecution.RunAsync(workflow, "hello world");

foreach (WorkflowEvent evt in run.NewEvents)
{
    if (evt is WorkflowOutputEvent output)
        Console.WriteLine($"Output: {output.Data}");
}
// Output: DLROW OLLEH

O WorkflowBuilder recebe o executor inicial no construtor e conecta os demais por meio do método AddEdge. Em seguida, o método Build valida a compatibilidade de tipos, a conectividade do grafo e as arestas duplicadas.

Na prática, essa validação evita que um workflow quebrado chegue à execução. Por exemplo, se um executor envia int e o próximo só aceita string, o erro aparece na construção.

Roteamento condicional com arestas

Nem todo fluxo é uma linha reta. Em muitos processos, o próximo passo depende do conteúdo da mensagem, e é aí que entram as arestas condicionais.

O método AddEdge<T> aceita um predicado que recebe a mensagem e devolve true ou false. Assim, a aresta só é percorrida quando a condição é verdadeira.

using Microsoft.Agents.AI.Workflows;

// Mensagem trocada entre os executores do exemplo
internal sealed record OrderRequest(string Id, decimal Amount);

WorkflowBuilder builder = new(validator);

// Pedidos acima de 1000 seguem para aprovação manual
builder.AddEdge<OrderRequest>(validator, manualApproval, order => order!.Amount > 1000);

// Os demais pedidos seguem para aprovação automática
builder.AddEdge<OrderRequest>(validator, autoApproval, order => order!.Amount <= 1000);

var workflow = builder.Build();

Nesse exemplo, o executor validator envia um OrderRequest, e o valor do pedido decide o caminho. Dessa forma, a regra de negócio fica visível no próprio desenho do grafo, e não escondida dentro de um executor.

Além das arestas condicionais, o framework oferece outros formatos de conexão. O fan-out envia a mesma mensagem para vários destinos, enquanto o fan-in reúne mensagens de várias origens em um único executor.

// Aguarda os três workers antes de acionar o agregador
builder.AddFanInBarrierEdge(sources: [worker1, worker2, worker3], target: aggregator);

Na prática, a combinação de fan-out e fan-in é a base de qualquer processamento paralelo dentro de workflows no Microsoft Agent Framework. Por exemplo, você pode consultar três fontes de dados ao mesmo tempo e consolidar as respostas em um único resumo.

Lembre-se, porém, do modelo de supersteps. Se um dos caminhos paralelos tiver uma cadeia longa de executores, o outro caminho vai esperar a barreira de sincronização antes de avançar.

Como os workflows no Microsoft Agent Framework executam

Por baixo dos panos, os workflows no Microsoft Agent Framework usam um modelo de execução inspirado no Pregel, organizado em supersteps. Em cada superstep, o motor coleta as mensagens pendentes, roteia cada uma para o executor de destino e roda esses executores em paralelo.

Depois, o motor espera todos terminarem antes de avançar, como uma barreira de sincronização. Dessa forma, a mesma entrada sempre produz a mesma ordem de execução.

Esse modelo também explica onde os checkpoints acontecem. Afinal, o framework salva o estado ao fim de cada superstep, quando nenhum executor está no meio do trabalho.

Integrando agents nos workflows do Microsoft Agent Framework

A capacidade mais relevante dos workflows no Microsoft Agent Framework é incluir agents de IA como nós do grafo. Você pode usar o tipo ChatClientAgent ou agents hospedados no Azure AI Foundry.

Quando você adiciona um AIAgent ao grafo, o framework o envolve automaticamente em um executor especializado. Portanto, não é preciso criar esse executor à mão.

Configurando o cliente do Azure OpenAI

Para usar modelos do Azure OpenAI, o primeiro passo é configurar o cliente:

using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Extensions.AI;

var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
    ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");

var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME")
    ?? "gpt-4o-mini";

// Converte o cliente do Azure OpenAI para a abstração IChatClient
IChatClient client = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
    .GetChatClient(deploymentName)
    .AsIChatClient();

Como o ChatClientAgent depende apenas de IChatClient, você pode trocar o provedor sem mudar o restante do workflow. Inclusive, modelos locais compatíveis com Microsoft.Extensions.AI funcionam da mesma forma.

Encadeando agents em sequência

Com o cliente configurado, você cria agents especializados e os encadeia em um workflow:

using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;

// Cria um agent que traduz qualquer entrada para o idioma informado
static ChatClientAgent GetTranslationAgent(string targetLanguage, IChatClient chatClient) =>
    new(chatClient,
        $"You are a translation assistant who only responds in {targetLanguage}. " +
        $"Translate the input to {targetLanguage}.");

var translationAgents = new[] { "French", "Spanish", "English" }
    .Select(language => GetTranslationAgent(language, client));

var workflow = AgentWorkflowBuilder.BuildSequential(translationAgents);

O método estático AgentWorkflowBuilder.BuildSequential recebe uma coleção de agents e monta automaticamente um pipeline. Nele, cada agent processa a saída do anterior.

Por padrão, cada agent da sequência recebe a conversa completa do agent anterior, incluindo as mensagens de entrada e as respostas. Assim, o último agent enxerga todo o histórico construído ao longo do pipeline.

Streaming e eventos nos workflows do Microsoft Agent Framework

Os workflows no Microsoft Agent Framework também rodam em modo streaming, o que permite acompanhar o progresso em tempo real. Esse modo é útil em aplicações que exibem respostas incrementais ou que reagem a eventos intermediários.

var messages = new List<ChatMessage>
{
    new(ChatRole.User, "Hello, world!")
};

await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, messages);

// Sinaliza aos agents que podem começar a processar
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));

string? lastExecutorId = null;
List<ChatMessage> result = [];

await foreach (WorkflowEvent evt in run.WatchStreamAsync())
{
    if (evt is AgentResponseUpdateEvent update)
    {
        // Imprime o nome do executor sempre que outro agent assume
        if (update.ExecutorId != lastExecutorId)
        {
            lastExecutorId = update.ExecutorId;
            Console.WriteLine();
            Console.Write($"{update.ExecutorId}: ");
        }

        Console.Write(update.Update.Text);
    }
    else if (evt is WorkflowOutputEvent outputEvent)
    {
        result = outputEvent.As<List<ChatMessage>>()!;
        break;
    }
}

O papel do TurnToken

O TurnToken é um sinal especial que instrui os agents a iniciar o processamento. Os agents encapsulados em executores recebem as mensagens, guardam tudo em cache e só chamam o LLM quando esse token chega.

Depois de concluir o seu turno, cada agent envia um novo TurnToken adiante. Dessa forma, o próximo agent da cadeia começa a trabalhar no momento certo.

O evento AgentResponseUpdateEvent carrega as atualizações incrementais da resposta, identificadas por ExecutorId. Por fim, o WorkflowOutputEvent sinaliza a conclusão do workflow e entrega o resultado final.

Usando agents do Azure AI Foundry

Para cenários que exigem agents com estado gerenciado no Azure, o framework se integra ao Azure AI Foundry. Nesse modelo, você cria e registra os agents no Foundry antes de incluí-los no workflow.

As primeiras versões do framework faziam isso com o PersistentAgentsClient. Atualmente, a documentação usa o AIProjectClient, que cria versões de agents declarativos no projeto do 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;

var endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT")
    ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");

var model = Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
var projectClient = new AIProjectClient(new Uri(endpoint), new AzureCliCredential());

// Cria no Foundry um agent tradutor para o idioma informado
static async Task<FoundryAgent> GetTranslationAgentAsync(
    string targetLanguage,
    AIProjectClient projectClient,
    string model)
{
    var version = await projectClient.AgentAdministrationClient.CreateAgentVersionAsync(
        $"{targetLanguage}Translator",
        new ProjectsAgentVersionCreationOptions(
            new DeclarativeAgentDefinition(model)
            {
                Instructions = $"You are a translation assistant that translates the provided text to {targetLanguage}."
            }));

    return projectClient.AsAIAgent(version);
}

Com os agents criados, a construção do workflow segue o padrão do WorkflowBuilder, conectando os nós por meio de arestas:

AIAgent frenchAgent = await GetTranslationAgentAsync("French", projectClient, model);
AIAgent spanishAgent = await GetTranslationAgentAsync("Spanish", projectClient, model);
AIAgent englishAgent = await GetTranslationAgentAsync("English", projectClient, model);

var workflow = new WorkflowBuilder(frenchAgent)
    .AddEdge(frenchAgent, spanishAgent)
    .AddEdge(spanishAgent, englishAgent)
    .Build();

Depois do uso, remova os agents do Foundry para evitar custos desnecessários:

// Remove os agents criados para o exemplo
await projectClient.AgentAdministrationClient.DeleteAgentAsync(frenchAgent.Name);
await projectClient.AgentAdministrationClient.DeleteAgentAsync(spanishAgent.Name);
await projectClient.AgentAdministrationClient.DeleteAgentAsync(englishAgent.Name);

Nesse cenário, o gerenciamento explícito do ciclo de vida dos agents é responsabilidade do desenvolvedor. Por isso, trate a limpeza como parte do próprio fluxo, e não como um detalhe opcional.

Agents e executores customizados nos workflows do Microsoft Agent Framework

Um dos pontos mais poderosos dos workflows no Microsoft Agent Framework é combinar agents de IA com executores de lógica própria no mesmo pipeline. Esse padrão ajuda quando certas etapas não exigem um LLM, como validações, transformações de dados ou chamadas a APIs externas.

Quando um executor customizado vem depois de um agent, ele recebe as mensagens da conversa que o agent acumulou. No SDK de Python, esse pacote chega como AgentExecutorResponse, com a propriedade full_conversation.

O exemplo abaixo mostra a mesma ideia em C#, com um executor que conta as mensagens e acrescenta um resumo:

using Microsoft.Agents.AI.Workflows;
using Microsoft.Extensions.AI;

// Executor determinístico que resume a conversa recebida do agent
internal sealed partial class SummarizerExecutor() : Executor("SummarizerExecutor")
{
    [MessageHandler]
    private async ValueTask HandleAsync(List<ChatMessage> conversation, IWorkflowContext context)
    {
        int users = conversation.Count(m => m.Role == ChatRole.User);
        int assistants = conversation.Count(m => m.Role == ChatRole.Assistant);

        var summary = new ChatMessage(ChatRole.Assistant,
            $"Summary: users={users}, assistants={assistants}");

        await context.YieldOutputAsync(conversation.Append(summary).ToList());
    }
}

A construção do workflow que mistura agent e executor segue o mesmo padrão:

var contentAgent = new ChatClientAgent(client,
    "Produce a concise paragraph answering the user's request.");

SummarizerExecutor summarizer = new();

var workflow = new WorkflowBuilder(contentAgent)
    .AddEdge(contentAgent, summarizer)
    .WithOutputFrom(summarizer)
    .Build();

Esse modelo de composição separa bem as responsabilidades. O agent contribui com raciocínio e geração de texto, enquanto o executor customizado aplica lógica determinística ao resultado.

Padrões de orquestração dos workflows no Microsoft Agent Framework

O framework suporta vários padrões de orquestração multi-agent, além do sequencial explorado até aqui. Segundo a documentação, os padrões prontos são cinco.

  • Sequencial: os agents executam um após o outro, em ordem definida.
  • Concorrente: os agents rodam em paralelo, e o workflow coleta os resultados antes de seguir.
  • Hand-off: um agent passa o controle para outro com base no contexto da conversa.
  • Group chat: os agents colaboram em uma conversa compartilhada, coordenada por um orquestrador.
  • Magentic: um agent gerente planeja a tarefa e coordena dinamicamente agents especializados.

Todos esses padrões usam o mesmo mecanismo de executores e arestas. Ou seja, muda apenas a topologia do grafo e o tipo das mensagens trocadas entre os nós.

Para entender como monitorar esses fluxos em produção, o artigo sobre observabilidade de agentes e workflows aprofunda o uso de telemetria.

Workflows no Microsoft Agent Framework em produção

Levar workflows no Microsoft Agent Framework para produção exige alguns cuidados adicionais. O primeiro deles envolve a autenticação.

Credenciais específicas

O DefaultAzureCredential é conveniente em desenvolvimento, porque tenta várias fontes de credencial automaticamente. Em produção, porém, esse comportamento pode trazer latência e riscos de segurança, já que o mecanismo de fallback testa várias opções antes de falhar.

A própria documentação recomenda usar uma credencial específica em produção, como ManagedIdentityCredential. Com isso, você elimina a ambiguidade e reduz o tempo de autenticação.

Gerenciamento de recursos

Agents hospedados no Azure AI Foundry têm custo associado e precisam sair do projeto após o uso. Em pipelines de curta duração, o padrão try/finally garante a limpeza mesmo quando uma exceção acontece.

Checkpointing em processos longos

Por fim, o checkpointing permite interromper e retomar workflows de longa duração sem perda de estado. Para ativar o recurso, você fornece um CheckpointManager na execução e retoma com InProcessExecution.ResumeStreamingAsync.

Esse recurso vale ainda mais em processos com interação humana ou com integrações sujeitas a falhas temporárias. No entanto, ao reconstruir o workflow, mantenha a mesma topologia e IDs estáveis para cada agent, ou o checkpoint deixa de ser compatível.

Conclusão sobre workflows no Microsoft Agent Framework

Os workflows no Microsoft Agent Framework oferecem uma abordagem estruturada para orquestrar agents de IA em processos de negócio. A separação entre a lógica determinística dos executores e o raciocínio dinâmico dos agents permite construir sistemas robustos, observáveis e fáceis de manter.

Além disso, a arquitetura baseada em grafos soma streaming, checkpointing e vários padrões de orquestração. Por isso, os workflows no Microsoft Agent Framework se posicionam como uma base completa para automação inteligente em aplicações .NET corporativas.

Para continuar estudando, o artigo uma visão geral do Microsoft Agent Framework apresenta as demais peças do framework.

FAQ

O workflow substitui o uso de agents individuais?

Não. O workflow é uma camada de orquestração que coordena vários agents e executores, e um agent individual continua útil para tarefas que não exigem um fluxo de várias etapas.

É possível usar agents locais, sem Azure, em um workflow?

Sim. O ChatClientAgent aceita qualquer implementação de IChatClient, incluindo modelos locais ou outros provedores compatíveis com Microsoft.Extensions.AI.

O que acontece se um executor não chamar YieldOutputAsync?

O workflow não registra saída para aquele executor. Isso é normal em executores intermediários que só encaminham mensagens, mas o nó final precisa produzir a saída para que o chamador receba um resultado.

Como funciona o histórico de conversa entre agents sequenciais?

Por padrão, cada agent recebe a conversa completa do agent anterior. Assim, ele enxerga todas as mensagens anteriores, inclusive as respostas dos agents que vieram antes no pipeline.

O TurnToken é obrigatório em todos os cenários de streaming?

Em cenários com agents, sim. Sem o TurnToken, os agents encapsulados como executores ficam aguardando e o workflow não avança.

É possível ter roteamento condicional entre executores?

Sim. As arestas aceitam condições que avaliam o conteúdo das mensagens, o que permite roteamento dinâmico sem alterar a estrutura do grafo.

Qual a diferença entre AgentWorkflowBuilder e WorkflowBuilder?

O AgentWorkflowBuilder oferece métodos de conveniência, como BuildSequential, voltados para pipelines de agents. Já o WorkflowBuilder é a API de nível mais baixo, com controle total sobre executores e arestas.