Il Microsoft Agent Framework (MAF) è un framework open source multi-linguaggio pensato per costruire, orchestrare e distribuire agenti AI. Con le ultime versioni, il framework ha introdotto un modello di programmazione a workflow che permette di comporre più agenti e unità di lavoro in pipeline multi-step. In questo articolo vedremo come funziona questo modello, come aggiungere durabilità ai workflow e come fare il deploy su Azure Functions.
Il modello di programmazione a Workflow
Il sistema si basa su due concetti fondamentali: Executor e WorkflowBuilder.
Executor: l’unità di lavoro
Un Executor è la granularità minima del workflow. Riceve un input tipizzato, lo elabora e produce un output. Si crea estendendo Executor<TInput, TOutput>:
internal sealed class OrderLookup() : Executor<OrderCancelRequest, Order>("OrderLookup")
{
public override async ValueTask<Order> HandleAsync(
OrderCancelRequest message,
IWorkflowContext context,
CancellationToken cancellationToken = default)
{
await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken);
return new Order(
Id: message.OrderId,
OrderDate: DateTime.UtcNow.AddDays(-1),
IsCancelled: false,
CancelReason: message.Reason,
Customer: new Customer(Name: "Mario", Email: "mario@example.com"));
}
}
internal sealed class OrderCancel() : Executor<Order, Order>("OrderCancel")
{
public override async ValueTask<Order> HandleAsync(
Order message, IWorkflowContext context,
CancellationToken cancellationToken = default)
{
await Task.Delay(TimeSpan.FromMilliseconds(200), cancellationToken);
return message with { IsCancelled = true };
}
}
internal sealed class SendEmail() : Executor<Order, string>("SendEmail")
{
public override ValueTask<string> HandleAsync(
Order message, IWorkflowContext context,
CancellationToken cancellationToken = default)
{
return ValueTask.FromResult(
$"Email di cancellazione inviata per l'ordine {message.Id} a {message.Customer.Email}.");
}
}
I parametri di tipo definiscono il contratto: TInput è ciò che riceve dal passo precedente, TOutput è ciò che passa al passo successivo. Il framework verifica la compatibilità dei tipi a compile time.
WorkflowBuilder: il grafo di esecuzione
Il WorkflowBuilder collega gli executor in un grafo diretto. Si definiscono gli archi tra executor e si ottiene un oggetto Workflow immutabile:
OrderLookup orderLookup = new();
OrderCancel orderCancel = new();
SendEmail sendEmail = new();
Workflow cancelOrder = new WorkflowBuilder(orderLookup)
.WithName("CancelOrder")
.WithDescription("Cancella un ordine e notifica il cliente")
.AddEdge(orderLookup, orderCancel)
.AddEdge(orderCancel, sendEmail)
.Build();
Esecuzione in-process
Per eseguire il workflow senza dipendenze esterne si usa InProcessExecution.RunStreamingAsync. Restituisce uno StreamingRun che emette eventi man mano che ogni step completa:
var cancelRequest = new OrderCancelRequest(OrderId: "123", Reason: "Colore errato");
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(
cancelOrder, input: cancelRequest);
await foreach (WorkflowEvent evt in run.WatchStreamAsync())
{
if (evt is ExecutorCompletedEvent completed)
Console.WriteLine($"{completed.ExecutorId}: {completed.Data}");
}
Bastano i pacchetti NuGet Microsoft.Agents.AI e Microsoft.Agents.AI.Workflows. Nessuna infrastruttura, nessun Docker, solo una console app .NET.
Aggiungere la durabilità con DurableTask
L’esecuzione in-process perde lo stato se il processo termina. Per workflow di produzione — che devono sopravvivere ai riavvii, girare per ore e rimanere osservabili — si aggiunge il pacchetto Microsoft.Agents.AI.DurableTask:
dotnet add package Microsoft.Agents.AI.DurableTask --prerelease
dotnet add package Microsoft.DurableTask.Client.AzureManaged
dotnet add package Microsoft.DurableTask.Worker.AzureManaged
dotnet add package Microsoft.Extensions.Hosting
Il runtime durable fornisce:
- Esecuzione stateful e durabile: il workflow sopravvive ai riavvii del processo
- Checkpointing automatico: il progresso viene salvato dopo ogni step
- Esecuzione distribuita: gli executor possono girare su macchine diverse
- Orchestrazioni long-running: i workflow possono durare minuti, ore o giorni
- Osservabilità: dashboard integrata per monitorare e gestire le esecuzioni
Il punto chiave è che la definizione del workflow non cambia. Si usa lo stesso WorkflowBuilder, cambia solo l’hosting:
string dtsConnectionString = "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None";
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.ConfigureDurableWorkflows(
workflowOptions => workflowOptions.AddWorkflow(cancelOrder),
workerBuilder: builder => builder.UseDurableTaskScheduler(dtsConnectionString),
clientBuilder: builder => builder.UseDurableTaskScheduler(dtsConnectionString));
})
.Build();
await host.StartAsync();
IWorkflowClient workflowClient = host.Services.GetRequiredService<IWorkflowClient>();
IAwaitableWorkflowRun run = (IAwaitableWorkflowRun)await workflowClient
.RunAsync(cancelOrder, new OrderCancelRequest("12345", "Colore errato"));
string? result = await run.WaitForCompletionAsync<string>();
Console.WriteLine($"Workflow completato: {result}");
Per lo sviluppo locale si avvia il DTS Emulator in Docker:
docker run -d --name dts-emulator -p 8080:8080 -p 8082:8082 mcr.microsoft.com/dts/dts-emulator:latest
La dashboard è disponibile su http://localhost:8082 e mostra la timeline di ogni executor, gli input/output per ciascun step e lo stato delle esecuzioni.
Fan-Out / Fan-In con agenti AI
Uno dei pattern più potenti è il fan-out/fan-in: più agenti AI elaborano lo stesso input in parallelo, poi un executor aggrega i risultati. MAF supporta l’uso diretto di agenti AI come executor tramite il metodo estensione AsAIAgent:
AIAgent physicist = chatClient.AsAIAgent(
"Sei un esperto di fisica. Rispondi in 2-3 frasi concise.", "Physicist");
AIAgent chemist = chatClient.AsAIAgent(
"Sei un esperto di chimica. Rispondi in 2-3 frasi concise.", "Chemist");
Workflow workflow = new WorkflowBuilder(parseQuestion)
.WithName("ExpertReview")
.AddFanOutEdge(parseQuestion, [physicist, chemist])
.AddFanInBarrierEdge([physicist, chemist], aggregator)
.Build();
Con il runtime durable, il fisico potrebbe eseguire su una VM e il chimico su un’altra. Se il processo si riavvia a metà esecuzione, gli agenti già completati non vengono rieseguiti grazie al checkpointing.
Deploy su Azure Functions
Per il deploy serverless si aggiunge il pacchetto Microsoft.Agents.AI.Hosting.AzureFunctions. I vantaggi:
- Scaling serverless: Azure Functions scala automaticamente in base al carico
- HTTP endpoint automatici: ogni workflow registrato ottiene un HTTP trigger, senza scrivere controller o routing
- Supporto MCP: i workflow possono essere esposti come MCP tool con un singolo flag, rendendoli scopribili da altri agenti AI
- Zero boilerplate: il pacchetto genera orchestratori e activity function automaticamente
Conclusioni
Il Microsoft Agent Framework propone un’astrazione pulita per costruire workflow di agenti AI: si definisce il grafo una volta sola, e si sceglie il runtime — in-process per lo sviluppo, durable per la produzione, Azure Functions per il serverless. La separazione netta tra definizione del workflow e modalità di hosting è il punto di forza dell’approccio: consente di passare da un prototipo locale a un’orchestrazione distribuita con modifiche minime al codice.
Il framework è open source e in evoluzione rapida. Il codice di esempio completo è disponibile nella repository GitHub del Microsoft Agent Framework.
Fonte originale: Durable Workflows in the Microsoft Agent Framework — .NET Blog, Shyju Krishnankutty