Compartilhar via


Conceitos principais dos fluxos de trabalho do Microsoft Agent Framework – Executores

Este documento fornece uma análise detalhada do componente Executores do sistema de fluxo de trabalho do Microsoft Agent Framework.

Visão geral

Executores são os blocos de construção fundamentais que processam mensagens em um fluxo de trabalho. São unidades de processamento autônomas que recebem mensagens tipadas, executam operações e podem produzir mensagens ou eventos de saída.

A classe base Executor<TInput, TOutput> é herdada pelos executores. Cada executor tem um identificador exclusivo e pode lidar com tipos de mensagem específicos.

Estrutura básica do executor

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

internal sealed class UppercaseExecutor() : Executor<string, string>("UppercaseExecutor")
{
    public async ValueTask<string> HandleAsync(string message, IWorkflowContext context)
    {
        string result = message.ToUpperInvariant();
        return result; // Return value is automatically sent to connected executors
    }
}

É possível enviar mensagens manualmente sem retornar um valor:

internal sealed class UppercaseExecutor() : Executor<string>("UppercaseExecutor")
{
    public async ValueTask HandleAsync(string message, IWorkflowContext context)
    {
        string result = message.ToUpperInvariant();
        await context.SendMessageAsync(result); // Manually send messages to connected executors
    }
}

Também é possível lidar com vários tipos de entrada substituindo o ConfigureRoutes método:

internal sealed class SampleExecutor() : Executor("SampleExecutor")
{
    protected override RouteBuilder ConfigureRoutes(RouteBuilder routeBuilder)
    {
        return routeBuilder
            .AddHandler<string>(this.HandleStringAsync)
            .AddHandler<int>(this.HandleIntAsync);
    }

    /// <summary>
    /// Converts input string to uppercase
    /// </summary>
    public async ValueTask<string> HandleStringAsync(string message, IWorkflowContext context)
    {
        string result = message.ToUpperInvariant();
        return result;
    }

    /// <summary>
    /// Doubles the input integer
    /// </summary>
    public async ValueTask<int> HandleIntAsync(int message, IWorkflowContext context)
    {
        int result = message * 2;
        return result;
    }
}

Também é possível criar um executor de uma função usando o BindExecutor método de extensão:

Func<string, string> uppercaseFunc = s => s.ToUpperInvariant();
var uppercase = uppercaseFunc.BindExecutor("UppercaseExecutor");

A classe base Executor é herdada pelos executores. Cada executor tem um identificador exclusivo e pode lidar com tipos de mensagem específicos usando métodos decorados com o @handler decorador. Os manipuladores devem ter a anotação adequada para especificar o tipo de mensagens que podem ser processadas.

Estrutura básica do executor

from agent_framework import (
    Executor,
    WorkflowContext,
    handler,
)

class UpperCase(Executor):

    @handler
    async def to_upper_case(self, text: str, ctx: WorkflowContext[str]) -> None:
        """Convert the input to uppercase and forward it to the next node.

        Note: The WorkflowContext is parameterized with the type this handler will
        emit. Here WorkflowContext[str] means downstream nodes should expect str.
        """
        await ctx.send_message(text.upper())

É possível criar um executor a partir de uma função usando o @executor decorador:

from agent_framework import (
    WorkflowContext,
    executor,
)

@executor(id="upper_case_executor")
async def upper_case(text: str, ctx: WorkflowContext[str]) -> None:
    """Convert the input to uppercase and forward it to the next node.

    Note: The WorkflowContext is parameterized with the type this handler will
    emit. Here WorkflowContext[str] means downstream nodes should expect str.
    """
    await ctx.send_message(text.upper())

Também é possível lidar com vários tipos de entrada definindo vários manipuladores:

class SampleExecutor(Executor):

    @handler
    async def to_upper_case(self, text: str, ctx: WorkflowContext[str]) -> None:
        """Convert the input to uppercase and forward it to the next node.

        Note: The WorkflowContext is parameterized with the type this handler will
        emit. Here WorkflowContext[str] means downstream nodes should expect str.
        """
        await ctx.send_message(text.upper())

    @handler
    async def double_integer(self, number: int, ctx: WorkflowContext[int]) -> None:
        """Double the input integer and forward it to the next node.

        Note: The WorkflowContext is parameterized with the type this handler will
        emit. Here WorkflowContext[int] means downstream nodes should expect int.
        """
        await ctx.send_message(number * 2)

O WorkflowContext objeto

O WorkflowContext objeto fornece métodos para o manipulador interagir com o fluxo de trabalho durante a execução. O WorkflowContext parâmetro é parametrizado com o tipo de mensagens que o manipulador emitirá e o tipo de saída que ele pode produzir.

O método mais usado é send_message, que permite que o manipulador envie mensagens para executores conectados.

from agent_framework import WorkflowContext

class SomeHandler(Executor):

    @handler
    async def some_handler(message: str, ctx: WorkflowContext[str]) -> None:
        await ctx.send_message("Hello, World!")

Um manipulador pode usar yield_output para produzir saídas que serão consideradas como saídas de fluxo de trabalho e retornadas/transmitidas para o chamador como um evento de saída:

from agent_framework import WorkflowContext

class SomeHandler(Executor):

    @handler
    async def some_handler(message: str, ctx: WorkflowContext[Never, str]) -> None:
        await ctx.yield_output("Hello, World!")

Se um manipulador não enviar mensagens nem produzir saídas, nenhum parâmetro de tipo será necessário para WorkflowContext:

from agent_framework import WorkflowContext

class SomeHandler(Executor):

    @handler
    async def some_handler(message: str, ctx: WorkflowContext) -> None:
        print("Doing some work...")

Próxima Etapa