Partilhar via


Conceitos principais de fluxos de trabalho do Microsoft Agent Framework - Executores

Este documento fornece uma visão detalhada do componente Executores do sistema de fluxo de trabalho do Microsoft Agent Framework.

Visão geral

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

Os executores herdam da Executor<TInput, TOutput> classe base. Cada executor tem um identificador exclusivo e pode lidar com tipos de mensagens 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 múltiplos tipos de entrada sobrescrevendo 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 a partir de uma função usando o BindExecutor método de extensão:

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

Os executores herdam da Executor classe base. Cada executor tem um identificador único e pode lidar com tipos de mensagens 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 processar.

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 é parametrizado com o tipo de mensagens que o manipulador emitirá e o tipo de saídas que ele pode produzir.

O método mais comumente 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 serão 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 envia mensagens nem produz saídas, nenhum parâmetro de tipo é 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óximo Passo