Microsoft Agent Framework : premier agent, MCP et workflows multi-agents

Microsoft Agent Framework avec Ollama et MCP

Microsoft Agent Framework : premier agent, MCP et workflows multi-agents

Partie 4 de la série “Développement IA avec Ollama et .NET” : Partie 1 – Ollama et .NET | Partie 2 – RAG local | Partie 3 – Agents IA | Partie 3.5 – Serveur MCP | English

Dans les posts précédents, on a couvert pas mal de terrain. Ollama pour rouler des LLM localement. Un serveur MCP météo en C# pour exposer des outils à n’importe quel client IA. Et entre les deux, des agents ReAct bricolés à la main : parsing de TOOL: nom, registre d’outils, boucle maison.

Ça fonctionnait. Mais le côté client était du code jetable. Chaque intégration demandait sa propre plomberie.

Microsoft Agent Framework règle ce problème. C’est le successeur officiel de Semantic Kernel et AutoGen, construit par les mêmes équipes chez Microsoft. Il prend n’importe quel IChatClient (Ollama, OpenAI, Azure, etc.), gère la boucle d’appel d’outils automatiquement, et offre des workflows multi-agents prêts à l’emploi.

Dans ce billet : trois exemples progressifs. Un agent hello world. Le même agent branché sur notre serveur MCP météo. Et un workflow séquentiel avec deux agents spécialisés.

Le code complet est disponible ici : mongeon/code-examples · agent-framework-ollama-mcp.

C’est quoi le Microsoft Agent Framework?

Agent Framework est la convergence de deux projets Microsoft : Semantic Kernel (l’intégration IA dans .NET) et AutoGen (la recherche multi-agents). Les mêmes équipes ont fusionné les meilleures idées des deux dans un framework unifié.

Deux concepts centraux :

  • Agent : un LLM + des instructions + des outils optionnels. Il gère la boucle de conversation, l’appel d’outils et l’historique de messages automatiquement.
  • Workflow : plusieurs agents qui collaborent selon un pattern d’orchestration (séquentiel, concurrent, handoff, group chat).

Le framework est en Release Candidate (RC4 au moment d’écrire). L’API est stable. Quelques ajustements mineurs possibles avant la GA, mais rien qui va casser votre code.

Note pour les débutants : Agent Framework ne remplace pas Ollama. Ollama est le moteur d’inférence (il roule le LLM). Agent Framework est la couche au-dessus : il orchestre les conversations, les outils et les workflows.

Installation

dotnet add package Microsoft.Agents.AI --prerelease
dotnet add package OllamaSharp

Pour les workflows multi-agents (exemple 3), ajoutez aussi :

dotnet add package Microsoft.Agents.AI.Workflows --prerelease

Pour la connexion MCP (exemples 2 et 3) :

dotnet add package ModelContextProtocol

Note : le --prerelease est nécessaire tant que le framework est en RC. Épinglez les versions dans votre .csproj pour éviter les surprises lors d’un dotnet restore.

Premier agent : Hello World avec Ollama

using Microsoft.Agents.AI;
using OllamaSharp;

// OllamaApiClient implémente IChatClient. Agent Framework accepte n'importe quel IChatClient.
var chatClient = new OllamaApiClient(
    new Uri("http://localhost:11434"), "qwen3");

// Créer l'agent : un nom, des instructions, un client. C'est tout.
AIAgent agent = new ChatClientAgent(
    chatClient,
    name: "Assistant",
    instructions: "You are a concise assistant. Answer in two sentences or fewer.");

// RunAsync envoie le prompt, gère la boucle de conversation, retourne la réponse.
var response = await agent.RunAsync("What is the Model Context Protocol?");

Console.WriteLine(response);

C’est 10 lignes utiles. OllamaApiClient implémente IChatClient (l’abstraction de Microsoft.Extensions.AI), donc Agent Framework l’accepte directement. Pas de wrapper, pas de configuration supplémentaire.

ChatClientAgent est le type d’agent générique : il prend n’importe quel IChatClient et ajoute la gestion de l’historique, des instructions système et de la boucle d’appel d’outils.

RunAsync fait tout le travail : envoie le message, reçoit la réponse, et retourne le texte final. Si l’agent avait des outils, il les appellerait automatiquement avant de répondre.

Brancher le serveur MCP météo

Le serveur MCP du post précédent expose un outil GetCurrentWeather. On ne modifie rien côté serveur, on le branche simplement comme source d’outils pour notre agent.

using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol.Transport;
using OllamaSharp;

// 1. Démarrer le serveur MCP comme processus enfant via stdio.
var mcpClient = await McpClientFactory.CreateAsync(
    new McpClientOptions { ClientInfo = new() { Name = "WeatherAgent", Version = "1.0.0" } },
    new StdioClientTransport(new StdioClientTransportOptions
    {
        Command = "dotnet",
        Arguments = ["run", "--project", "../chemin/vers/mcp-weather-server"]
    }));

// 2. Découvrir les outils exposés par le serveur.
var mcpTools = await mcpClient.ListToolsAsync();

// 3. Construire le client Ollama avec support d'appel de fonctions.
IChatClient chatClient = new ChatClientBuilder(
        new OllamaApiClient(new Uri("http://localhost:11434"), "llama3.2"))
    .UseFunctionInvocation()
    .Build();

// 4. Créer l'agent avec les outils MCP.
AIAgent agent = new ChatClientAgent(
    chatClient,
    name: "WeatherAgent",
    instructions: "You help users check the weather. Use the available tools to get real data.",
    tools: [.. mcpTools]);

// 5. L'agent appelle GetCurrentWeather automatiquement.
var response = await agent.RunAsync("Quel temps fait-il à Montréal?");
Console.WriteLine(response);

await mcpClient.DisposeAsync();

Trois choses importantes ici :

  1. McpClientFactory.CreateAsync démarre le serveur MCP comme processus enfant. Le transport stdio fonctionne exactement comme quand Claude Desktop lance le serveur. Même protocole, même binaire.

  2. UseFunctionInvocation() est le pont entre Ollama et MCP. Ollama ne supporte pas MCP nativement (il a son propre format de tool-calling). Agent Framework comble le fossé : il traduit les outils MCP en fonctions que le LLM peut appeler, et exécute les appels automatiquement.

  3. tools: [.. mcpTools] passe les outils découverts à l’agent. Le LLM voit les descriptions des outils et décide quand les appeler. Pas de boucle ReAct manuelle.

Workflow multi-agents

Un agent, c’est bien. Deux agents spécialisés, c’est mieux. Voici un workflow séquentiel :

  • Agent 1 (WeatherFetcher) : a accès aux outils MCP, cherche la météo brute
  • Agent 2 (FriendlyFormatter) : pas d’outils, reformule la réponse de façon conviviale en français
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Extensions.AI;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol.Transport;
using OllamaSharp;

// --- Setup MCP (identique à l'exemple 2) ---
var mcpClient = await McpClientFactory.CreateAsync(
    new McpClientOptions { ClientInfo = new() { Name = "WorkflowDemo", Version = "1.0.0" } },
    new StdioClientTransport(new StdioClientTransportOptions
    {
        Command = "dotnet",
        Arguments = ["run", "--project", "../chemin/vers/mcp-weather-server"]
    }));
var mcpTools = await mcpClient.ListToolsAsync();

var ollamaEndpoint = new Uri("http://localhost:11434");
const string model = "qwen3";

// --- Agent 1 : chercheur de météo ---
IChatClient fetcherClient = new ChatClientBuilder(
        new OllamaApiClient(ollamaEndpoint, model))
    .UseFunctionInvocation()
    .Build();

AIAgent weatherFetcher = new ChatClientAgent(
    fetcherClient,
    name: "WeatherFetcher",
    instructions: """
        You are a weather data agent. When asked about weather,
        use your tools to get the current conditions.
        Return the raw weather data as-is, without commentary.
        """,
    tools: [.. mcpTools]);

// --- Agent 2 : reformulateur amical ---
IChatClient formatterClient = new OllamaApiClient(ollamaEndpoint, model);

AIAgent friendlyFormatter = new ChatClientAgent(
    formatterClient,
    name: "FriendlyFormatter",
    instructions: """
        You receive raw weather data. Rewrite it as a friendly,
        conversational message in French. Use casual language.
        Add a short clothing suggestion based on the conditions.
        """);

// --- Workflow séquentiel : Fetcher → Formatter ---
var workflow = AgentWorkflowBuilder.BuildSequential(weatherFetcher, friendlyFormatter);

var messages = new List<ChatMessage>
{
    new(ChatRole.User, "What is the weather in Montreal?")
};

var run = InProcessExecution.StreamAsync(workflow, messages);

await foreach (var ev in run.WatchStreamAsync())
{
    if (ev is AgentResponseItem { Message: { } msg })
    {
        Console.WriteLine($"[{msg.AuthorName}] {msg.Text}");
    }
}

await mcpClient.DisposeAsync();

Pourquoi séparer en deux agents?

Responsabilité claire. Le fetcher ne fait que chercher des données. Le formatter ne fait que les réécrire. Si la reformulation ne vous plaît pas, vous changez les instructions du formatter sans toucher au fetcher. Si vous ajoutez un nouvel outil MCP, seul le fetcher est affecté.

Facile à tester. Vous pouvez tester le formatter avec des données météo statiques, sans démarrer Ollama ni le serveur MCP.

Extensible. Ajouter un troisième agent (traducteur, vérificateur de faits, etc.) est une ligne de plus dans BuildSequential().

Ce que j’aurais aimé savoir

Microsoft.Agents.AI vs les vieux packages. Sur NuGet, vous allez trouver Microsoft.SemanticKernel, AutoGen, et Microsoft.Agents.AI. C’est ce dernier qu’il faut utiliser. Semantic Kernel et AutoGen sont les prédécesseurs. Ils fonctionnent encore, mais le développement actif est sur Agent Framework.

Ollama ne parle pas MCP. Il y a une issue ouverte depuis novembre 2024. Ollama a son propre format de tool-calling (compatible OpenAI). Agent Framework comble ce fossé : il traduit les outils MCP en fonctions OpenAI-style que le LLM comprend, et exécute les appels via le protocole MCP côté serveur.

RC = pas encore GA. L’API est stable, mais des ajustements mineurs sont possibles. Épinglez vos versions de packages. Au moment d’écrire, c’est 1.0.0-rc4 pour Microsoft.Agents.AI et Microsoft.Agents.AI.Workflows.

Choix du modèle. Tous les modèles Ollama ne gèrent pas bien le tool-calling. qwen3 est la recommandation actuelle de la communauté pour l’appel d’outils — il est stable, hallucine rarement des appels, et fonctionne bien même pour les workflows multi-outils. llama4:scout est une autre bonne option. Les modèles plus petits comme llama3.2 peuvent fonctionner pour des cas simples mais peinent avec les interactions d’outils complexes.

Conclusion

La série est complète. En quatre posts, on a construit une stack agent .NET fonctionnelle de bout en bout :

  1. Ollama pour l’inférence locale, privée, gratuite, hors ligne
  2. RAG avec Qdrant et LiteLLM pour donner du contexte aux modèles
  3. Agents ReAct maison pour comprendre les fondamentaux
  4. Serveur MCP pour standardiser l’exposition d’outils
  5. Microsoft Agent Framework pour orchestrer le tout proprement

Le code complet des trois exemples est disponible ici : mongeon/code-examples · agent-framework-ollama-mcp

Ressources


Ce billet a été rédigé avec l’aide de l’IA.


Suggestions de lecture :