Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les exécuteurs sont les blocs de construction fondamentaux qui traitent les messages dans un flux de travail. Ils sont des unités de traitement autonomes qui reçoivent des messages typés, effectuent des opérations et peuvent produire des messages de sortie ou des événements.
Vue d’ensemble
Chaque exécuteur a un identificateur unique et peut gérer des types de messages spécifiques. Les exécuteurs peuvent être :
- Composants logiques personnalisés : traiter des données, appeler des API ou transformer des messages
- Agents IA : utilisez des llms pour générer des réponses (voir Agents dans les flux de travail)
Important
La méthode recommandée pour définir des gestionnaires de messages d’exécuteur en C# consiste à utiliser l’attribut [MessageHandler] sur les méthodes d’une partial classe qui dérive de Executor. Cela utilise la génération de code source au moment de la compilation pour l'enregistrement des gestionnaires, ce qui offre de meilleures performances, une validation à la compilation et une compatibilité AOT native.
Structure d’exécuteur de base
Les exécuteurs dérivent de la Executor classe de base et utilisent l’attribut [MessageHandler] pour déclarer des méthodes de gestionnaire. La classe doit être marquée partial pour activer la génération source.
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
}
}
Vous pouvez également envoyer manuellement des messages sans retourner une valeur :
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
}
}
Types d’entrée multiples
Gérez plusieurs types d’entrée en définissant plusieurs [MessageHandler] méthodes :
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);
}
}
Exécuteurs basés sur des fonctions
Créez un exécuteur à partir d’une fonction à l’aide de la méthode d’extension BindExecutor :
Func<string, string> uppercaseFunc = s => s.ToUpperInvariant();
var uppercase = uppercaseFunc.BindExecutor("UppercaseExecutor");
Structure d’exécuteur de base
Les exécuteurs héritent de la Executor classe de base. Chaque exécuteur utilise des méthodes décorées avec le @handler décorateur. Les gestionnaires doivent avoir des annotations de type appropriées pour spécifier les types de messages qu’ils traitent.
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())
Exécuteurs basés sur des fonctions
Créez un exécuteur à partir d’une fonction à l’aide du @executor décorateur :
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())
Types d’entrée multiples
Gérez plusieurs types d’entrée en définissant plusieurs gestionnaires :
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)
Paramètres de type explicites
En guise d’alternative aux annotations de type, vous pouvez spécifier des types explicitement via des paramètres décoratifs :
Important
Lorsque vous utilisez des paramètres de type explicites, vous devez spécifier tous les types via le décorateur . Vous ne pouvez pas combiner des paramètres explicites avec des annotations de type. Le input paramètre est obligatoire et outputworkflow_output facultatif.
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)
Objet WorkflowContext
Les WorkflowContext méthodes permettant d’interagir avec le flux de travail pendant l’exécution sont les suivantes :
-
send_message— envoyer des messages à des exécuteurs connectés -
yield_output— produire des sorties de flux de travail retournées/diffusées en continu vers l’appelant
class OutputExecutor(Executor):
@handler
async def handle(self, message: str, ctx: WorkflowContext[Never, str]) -> None:
await ctx.yield_output("Hello, World!")
Si un gestionnaire n’envoie ni messages ni génère de sorties, aucun paramètre de type n’est nécessaire :
class LogExecutor(Executor):
@handler
async def handle(self, message: str, ctx: WorkflowContext) -> None:
print("Doing some work...")