Condividi tramite


Concetti di base relativi ai flussi di lavoro di Microsoft Agent Framework - Executor

Questo documento fornisce un'analisi approfondita del componente Executors del sistema flusso di lavoro di Microsoft Agent Framework.

Informazioni generali

Gli executor sono i blocchi predefiniti fondamentali che elaborano i messaggi in un flusso di lavoro. Sono unità di elaborazione autonome che ricevono messaggi tipizzato, eseguono operazioni e possono produrre messaggi o eventi di output.

Gli executor ereditano dalla Executor<TInput, TOutput> classe base. Ogni executor ha un identificatore univoco e può gestire tipi di messaggio specifici.

Struttura di Base dell'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
    }
}

È possibile inviare messaggi manualmente senza restituire un valore:

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

È anche possibile gestire più tipi di input eseguendo l'override del ConfigureRoutes metodo :

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

È anche possibile creare un executor da una funzione usando il BindExecutor metodo di estensione:

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

Gli executor ereditano dalla Executor classe base. Ogni executor ha un identificatore univoco e può gestire tipi di messaggio specifici usando metodi decorati con il decoratore @handler. I gestori devono avere l'annotazione corretta per specificare il tipo di messaggi che possono elaborare.

Struttura di Base dell'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())

È possibile creare un executor da una funzione usando il decoratore @executor:

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

È anche possibile gestire più tipi di input definendo più gestori:

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)

Oggetto WorkflowContext

L'oggetto WorkflowContext fornisce metodi per consentire al gestore di interagire con il flusso di lavoro durante l'esecuzione. Viene WorkflowContext parametrizzato con il tipo di messaggi che il gestore emetterà e il tipo di output che può fornire.

Il metodo più comunemente usato è send_message, che consente al gestore di inviare messaggi agli executor connessi.

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!")

Un gestore può usare yield_output per produrre output che verranno considerati come output del flusso di lavoro e restituiti/trasmessi al chiamante come evento di output:

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 un gestore non invia né messaggi né restituisce output, non è necessario alcun parametro di tipo per WorkflowContext:

from agent_framework import WorkflowContext

class SomeHandler(Executor):

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

Passaggio successivo