🤖 Agents IA

agent-semantic-kernel-guide

Développement d'agents IA avec Microsoft Semantic Kernel en .NET/C# et Python. Plugins natifs, plugins prompts, planners, filters, AgentGroupChat et intégration enterprise Azure.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- agent-semantic-kernel-guide --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } agent-semantic-kernel-guide -Launch"

🚀 Déjà installé ?

claude "/agent-semantic-kernel-guide"

Ou tapez /agent-semantic-kernel-guide dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

Semantic KernelSKMicrosoft Semantic Kernelkernel pluginplanneragent .NETC# agententerprise AIAzure OpenAI agentkernel function

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/agent-semantic-kernel-guide ~/.claude/skills/

Payload du plugin : skills/agent-semantic-kernel-guide · source éditable : agent-skills/semantic-kernel-guide

📖 Manuel

Semantic Kernel Guide — Agents IA Enterprise Microsoft

Quand utiliser ce skill

Utiliser quand l'utilisateur développe des applications IA en .NET/C# ou Python avec un besoin d'architecture structurée : plugins typés, planification automatique, injection de dépendances, tests unitaires, ou intégration Azure (Azure OpenAI, Azure AI Search, Cosmos DB). SK est le choix naturel pour les équipes .NET adoptant l'IA générative en production.

Ne pas utiliser SK si : projet Python pur sans besoin enterprise → LangChain ou LlamaIndex suffisent. Script one-shot sans plugins → appel API direct suffit.

Workflow en étapes

1. Installation et structure de projet

# .NET (recommandé : toujours figer la version)
dotnet add package Microsoft.SemanticKernel --version 1.30.0
dotnet add package Microsoft.SemanticKernel.Agents.Core
dotnet add package Microsoft.SemanticKernel.Plugins.Memory  # si RAG

# Python
pip install "semantic-kernel==1.14.0"

Structure .NET recommandée :

MyAIApp/
├── Plugins/
│   ├── WeatherPlugin.cs
│   └── Prompts/
│       └── Summarize/
│           ├── skprompt.txt
│           └── config.json
├── Filters/
│   └── LoggingFilter.cs
├── Program.cs
└── appsettings.json

2. Configuration du Kernel

using Microsoft.SemanticKernel;

var builder = Kernel.CreateBuilder();

// Azure OpenAI avec Managed Identity (recommandé production — pas de clé API en dur)
builder.AddAzureOpenAIChatCompletion(
    deploymentName: "gpt-4o",
    endpoint: config["AzureOpenAI:Endpoint"]!,
    credential: new DefaultAzureCredential()  // Managed Identity
);

// Fallback : clé API (dev/test seulement)
// builder.AddOpenAIChatCompletion("gpt-4o", Environment.GetEnvironmentVariable("OPENAI_API_KEY")!);

builder.Services.AddLogging(c => c.AddConsole().SetMinimumLevel(LogLevel.Warning));

var kernel = builder.Build();

ASP.NET Core — ne jamais instancier Kernel manuellement :

// Program.cs
builder.Services.AddKernel()
    .AddAzureOpenAIChatCompletion(deploymentName, endpoint, credential);
builder.Services.AddSingleton<WeatherPlugin>();
builder.Services.AddFromType<WeatherPlugin>("Weather");

3. Plugins natifs — règles critiques

Les [Description] sont lues par le LLM pour choisir quelle fonction appeler. Des descriptions vagues = appels incorrects.

using Microsoft.SemanticKernel;
using System.ComponentModel;

public class WeatherPlugin
{
    private readonly IHttpClientFactory _httpFactory;
    public WeatherPlugin(IHttpClientFactory httpFactory) => _httpFactory = httpFactory;

    [KernelFunction("get_current_weather")]
    [Description("Obtient la météo actuelle (température, conditions) pour une ville. N'utiliser que pour des informations météo en temps réel.")]
    public async Task<string> GetWeatherAsync(
        [Description("Nom de la ville, ex: 'Paris', 'Lyon'")] string city,
        [Description("Unité de température : 'celsius' (défaut) ou 'fahrenheit'")] string unit = "celsius")
    {
        try
        {
            // Appel API réel
            var client = _httpFactory.CreateClient("weather");
            var response = await client.GetStringAsync($"/weather?city={city}&unit={unit}");
            return response;
        }
        catch (HttpRequestException ex)
        {
            // Toujours retourner une string — ne jamais lever une exception vers le LLM
            return $"Impossible d'obtenir la météo pour {city} : {ex.Message}";
        }
    }
}

// Enregistrement
kernel.Plugins.AddFromType<WeatherPlugin>("Weather");
// Ou depuis une instance (avec DI)
kernel.Plugins.AddFromObject(new WeatherPlugin(httpFactory), "Weather");

4. Plugins prompts — template fichier

Plugins/Prompts/Summarize/skprompt.txt :

Résumez le texte suivant en {{$max_words}} mots maximum. Conservez les points clés et le ton original.

TEXTE :
{{$input}}

RÉSUMÉ :

Plugins/Prompts/Summarize/config.json :

{
  "schema": 1,
  "name": "Summarize",
  "description": "Résume un texte en un nombre maximum de mots",
  "execution_settings": {
    "default": { "max_tokens": 500, "temperature": 0.3 }
  },
  "input_variables": [
    {"name": "input", "description": "Texte à résumer", "is_required": true},
    {"name": "max_words", "description": "Nombre de mots maximum", "default": "100"}
  ]
}

Chargement :

kernel.ImportPluginFromPromptDirectory("./Plugins/Prompts");
var result = await kernel.InvokeAsync("Summarize", "Summarize",
    new KernelArguments { ["input"] = longText, ["max_words"] = "50" });

5. Function Calling — deux modes

var chatService = kernel.GetRequiredService<IChatCompletionService>();
var history = new ChatHistory("Vous êtes un assistant expert.");
history.AddUserMessage("Quelle est la météo à Paris et Lyon ?");

// Mode AUTO : le LLM choisit et exécute les fonctions automatiquement
var autoSettings = new OpenAIPromptExecutionSettings
{
    ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions,
    Temperature = 0.1,
    MaxTokens = 1000,
};
var response = await chatService.GetChatMessageContentAsync(history, autoSettings, kernel);

// Mode MANUEL : récupérer les tool calls et les traiter soi-même
var manualSettings = new OpenAIPromptExecutionSettings
{
    ToolCallBehavior = ToolCallBehavior.EnableKernelFunctions,
};

Critère de choix : utiliser AutoInvoke pour les agents conversationnels. Utiliser EnableKernelFunctions (manuel) si besoin de validation, d'audit, ou de contrôle des coûts par appel.

6. Agents et AgentGroupChat

using Microsoft.SemanticKernel.Agents;

var agent = new ChatCompletionAgent
{
    Name = "AnalystAgent",
    Instructions = "Vous êtes un analyste financier. Analysez les données avec précision et citez vos sources.",
    Kernel = kernel,
    Arguments = new KernelArguments(new OpenAIPromptExecutionSettings
    {
        ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
    }),
};

// Invocation streaming
var thread = new ChatHistory();
thread.AddUserMessage("Analysez ces résultats : ...");
await foreach (var chunk in agent.InvokeStreamingAsync(thread))
    Console.Write(chunk.Content);

AgentGroupChat — plusieurs agents collaborant :

var chat = new AgentGroupChat(writerAgent, reviewerAgent)
{
    ExecutionSettings = new AgentGroupChatSettings
    {
        SelectionStrategy = new SequentialSelectionStrategy(),
        TerminationStrategy = new RegexTerminationStrategy("[APPROUVÉ]") { MaximumIterations = 6 },
    }
};
await chat.AddChatMessageAsync(new ChatMessageContent(AuthorRole.User, "Rédigez un article sur..."));
await foreach (var msg in chat.InvokeAsync())
    Console.WriteLine($"[{msg.AuthorName}] {msg.Content}");

7. Filters — middleware d'interception

// Logging + sécurité sur chaque appel de fonction
public class SafetyFilter : IFunctionInvocationFilter
{
    public async Task OnFunctionInvocationAsync(
        FunctionInvocationContext context,
        Func<FunctionInvocationContext, Task> next)
    {
        var fnName = context.Function.PluginName + "." + context.Function.Name;
        Console.WriteLine($"[CALL] {fnName} — args: {JsonSerializer.Serialize(context.Arguments)}");

        await next(context);  // exécution effective

        Console.WriteLine($"[DONE] {fnName} — result: {context.Result?.GetValue<string>()?.Substring(0, 100)}");
    }
}

kernel.FunctionInvocationFilters.Add(new SafetyFilter());
// Également disponible : IPromptRenderFilter (intercepte avant rendu du prompt)

8. Memory et RAG

// dotnet add package Microsoft.SemanticKernel.Plugins.Memory
var memoryBuilder = new MemoryBuilder();
memoryBuilder.WithAzureOpenAITextEmbeddingGeneration(
    "text-embedding-3-small", endpoint, credential);

// Dev : in-memory. Production : AzureAISearchMemoryStore, QdrantMemoryStore
memoryBuilder.WithMemoryStore(new VolatileMemoryStore());
var memory = memoryBuilder.Build();

await memory.SaveInformationAsync("docs", id: "doc1", text: "Contenu du document...");
var results = await memory.SearchAsync("docs", "question utilisateur", limit: 3, minRelevanceScore: 0.7);
foreach (var r in results)
    Console.WriteLine($"Score: {r.Relevance:F2} — {r.Metadata.Text}");

Stores production recommandés : Azure AI Search (intégration native Azure), Qdrant (self-hosted open-source), Redis (faible latence).

9. Intégration enterprise

BesoinSolution SK
Auth sans clé APIDefaultAzureCredential + Managed Identity
Persistance historiqueCosmos DB + ISemanticTextMemory
RAG vectorielAzure AI Search AzureAISearchMemoryStore
ObservabilitéIFunctionInvocationFilter + OpenTelemetry
Tests unitairesMock IChatCompletionService avec Moq

Test unitaire sans appel LLM réel :

var mockChat = new Mock<IChatCompletionService>();
mockChat.Setup(s => s.GetChatMessageContentsAsync(It.IsAny<ChatHistory>(), It.IsAny<PromptExecutionSettings>(), It.IsAny<Kernel>(), It.IsAny<CancellationToken>()))
    .ReturnsAsync([new ChatMessageContent(AuthorRole.Assistant, "réponse mockée")]);

var kernel = Kernel.CreateBuilder()
    .Build();
kernel.GetAllServices<IChatCompletionService>(); // injecter le mock

Garde-fous et anti-patterns

Bonnes pratiques 2026