Delen via


Uitvoerders

Uitvoerders zijn de fundamentele bouwstenen waarmee berichten in een werkstroom worden verwerkt. Het zijn autonome verwerkingseenheden die getypte berichten ontvangen, bewerkingen uitvoeren en uitvoerberichten of gebeurtenissen kunnen produceren.

Overzicht

Elke uitvoerder heeft een unieke id en kan specifieke berichttypen verwerken. Uitvoerders kunnen:

  • Aangepaste logische onderdelen : gegevens verwerken, API's aanroepen of berichten transformeren
  • AI-agents : LLM's gebruiken om antwoorden te genereren (zie Agents in werkstromen)

Belangrijk

De aanbevolen manier om uitvoerders voor berichthandlers in C# te definiëren, is door het [MessageHandler] kenmerk te gebruiken voor methoden binnen een partial klasse die is afgeleid van Executor. Dit maakt gebruik van het genereren van compilatietijdbronnen voor handlerregistratie, waardoor betere prestaties, compileertijdvalidatie en systeemeigen AOT-compatibiliteit worden geboden.

Basisuitvoeringsstructuur

Uitvoerders zijn afgeleid van de Executor basisklasse en gebruiken het [MessageHandler] kenmerk om handlermethoden te declareren. De klasse moet worden gemarkeerd partial om brongeneratie in te schakelen.

using Microsoft.Agents.AI.Workflows;

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

U kunt berichten ook handmatig verzenden zonder een waarde te retourneren:

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

Meerdere invoertypen

Meerdere invoertypen verwerken door meerdere [MessageHandler] methoden te definiëren:

internal sealed partial class SampleExecutor() : Executor("SampleExecutor")
{
    [MessageHandler]
    private ValueTask<string> HandleStringAsync(string message, IWorkflowContext context)
    {
        return ValueTask.FromResult(message.ToUpperInvariant());
    }

    [MessageHandler]
    private ValueTask<int> HandleIntAsync(int message, IWorkflowContext context)
    {
        return ValueTask.FromResult(message * 2);
    }
}

Functiegebaseerde uitvoerders

Maak een uitvoerder van een functie met behulp van de BindExecutor extensiemethode:

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

Basisuitvoeringsstructuur

Uitvoerders nemen over van de Executor basisklasse. Elke uitvoerder gebruikt methoden die zijn gedecoreerd met de @handler decorator. Handlers moeten over de juiste typeaantekeningen beschikken om de berichttypen op te geven die ze verwerken.

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."""
        await ctx.send_message(text.upper())

Functiegebaseerde uitvoerders

Maak een uitvoerder van een functie met behulp van de @executor decorator:

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."""
    await ctx.send_message(text.upper())

Meerdere invoertypen

Meerdere invoertypen verwerken door meerdere handlers te definiëren:

class SampleExecutor(Executor):

    @handler
    async def to_upper_case(self, text: str, ctx: WorkflowContext[str]) -> None:
        await ctx.send_message(text.upper())

    @handler
    async def double_integer(self, number: int, ctx: WorkflowContext[int]) -> None:
        await ctx.send_message(number * 2)

Expliciete typeparameters

Als alternatief voor het typen van aantekeningen kunt u typen expliciet opgeven via decoratorparameters:

Belangrijk

Wanneer u expliciete typeparameters gebruikt, moet u alle typen opgeven via de decorator. U kunt geen expliciete parameters combineren met typeaantekeningen. De input-parameter is vereist; output en workflow_output zijn optioneel.

class ExplicitTypesExecutor(Executor):

    @handler(input=str, output=str)
    async def to_upper_case(self, text, ctx) -> None:
        await ctx.send_message(text.upper())

    @handler(input=str | int, output=str)
    async def handle_mixed(self, message, ctx) -> None:
        await ctx.send_message(str(message).upper())

    @handler(input=str, output=int, workflow_output=bool)
    async def process_with_workflow_output(self, message, ctx) -> None:
        await ctx.send_message(len(message))
        await ctx.yield_output(True)

Het WorkflowContext-object

De WorkflowContext biedt methoden voor interactie met de werkstroom tijdens de uitvoering:

  • send_message — berichten verzenden naar verbonden uitvoerders
  • yield_output — werkstroomuitvoer produceren die wordt geretourneerd/gestreamd naar de aanroeper
class OutputExecutor(Executor):

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

Als een handler geen berichten verzendt of uitvoer oplevert, is er geen typeparameter nodig:

class LogExecutor(Executor):

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

Volgende stappen