· AI & Automation  · 14 min read

AI työkalut osa 3 - Semantic Kernel: AI-Agentit .NET:llä

Hallitse Microsoft Semantic Kernel tuotantovalmiiden AI-agenttien rakentamiseen. Opi moniagenttiorkestrointia, MCP-integraatiota, vektorivarastoja ja yritysratkaisuja aidoilla C# koodiesimerkeillä.

Hallitse Microsoft Semantic Kernel tuotantovalmiiden AI-agenttien rakentamiseen. Opi moniagenttiorkestrointia, MCP-integraatiota, vektorivarastoja ja yritysratkaisuja aidoilla C# koodiesimerkeillä.

Kuinka Semantic Kernel Auttaa Rakentamaan Moniagentti AI-Järjestelmiä .NET:llä

Tämä artikkeli on osa 5-osaista sarjaamme AI-Agentti- ja Työnkulkutyökaluista, jossa tutkimme johtavia alustoja ja kehyksiä tuotantovalmiiden AI-ratkaisujen rakentamiseen.

📚 Sarja: Työkalut Joita Käytämme AI-Kehityksessä

  1. Azure AI Foundry - Kuinka Azure AI Foundry auttaa rakentamaan turvallisia yritystason AI-ratkaisuja
  2. LangChain - Kuinka LangChain auttaa rakentamaan tuotantovalmiita AI-agentteja Pythonilla
  3. Semantic Kernel (tämä artikkeli) - Kuinka Semantic Kernel auttaa rakentamaan moniagentti AI-järjestelmiä .NET:llä
  4. n8n - Kuinka n8n demokratisoi AI-automaation low-code-työnkuluilla
  5. Microsoft Agent Framework - Kuinka Microsoft Agent Framework mahdollistaa skaalautuvat moniagenttityönkulut

Mikä on Microsoft Semantic Kernel?

Semantic Kernel on Microsoftin avoimen lähdekoodin AI-orkestrointikehys, joka tekee .NET-kehittäjille helpommaksi ja nopeammaksi rakentaa yritystason AI-ratkaisuja ja älykkäitä agentteja.

Se toimii “aivoina” ja koordinointikerroksena, joka yhdistää suuret kielimallit (kuten GPT-4 ja GPT-5) organisaatiosi järjestelmiin, dataan ja liiketoimintalogiikkaan. Sen todellinen voima piilee tilattomien tekstigenerointimallien muuntamisessa tilallisiksi, päätteleviksi agenteiksi, jotka voivat olla vuorovaikutuksessa olemassa olevan yritysinfrastruktuurisi kanssa.

Semantic Kernel ratkaisee keskeisen ongelman: todennäköisyyspohjaisen AI-päättelyn ja deterministisen liiketoimintalogiikan (SQL-tietokannat, ERP-järjestelmät, REST API:t) välisen kuilun ylittämisen säilyttäen samalla tyyppiturvalli suuden ja idiomaattiset .NET-mallit.

Miksi moniagenttijärjestelmät?

Varhaiset AI-ratkaisut luottivat usein yhteen, monoliittiseen promptiin - niin sanottuun “God Promptiin” - joka yritti hallita jokaista ohjetta, sääntöä ja poikkeusta kerralla. Tämä lähestymistapa hajoaa nopeasti: sitä on vaikea ylläpitää, vaikea debugata, ja se ylittää helposti mallin kontekstirajoitukset.

Moniagenttijärjestelmät (MAS) ratkaisevat tämän jakamalla monimutkaisen työn erikoistuneisiin rooleihin - aivan kuten todellinen tiimi. Yksi agentti suunnittelee tehtävän. Toinen hakee tietoa. Toinen on vuorovaikutuksessa ydinjärjestelmien kanssa. Toinen validoi laatua tai vaatimustenmukaisuutta.

Jakamalla vastuuta moniagentti AI-järjestelmät tarjoavat:

  • Korkeamman luotettavuuden - agentit tarkistavat ja tasapainottavat toisiaan
  • Paremman ylläpidettävyyden - jokainen agentti on pienempi, selkeämpi ja helpompi parantaa
  • Skaalautuvuuden - useat agentit voivat tehdä yhteistyötä ongelmissa, jotka ovat liian suuria yhdelle mallille
  • Vahvemman tarkkuuden ja johdonmukaisuuden - erikoistuminen parantaa tulosteen laatua
  • Suuremman mukautuvuuden - agentteja voidaan vaihtaa, päivittää tai käyttää uudelleen eri ratkaisuissa

Semantic Kernel Ydinarkkitehtuuri .NET-Kehittäjille

Kernel on keskusorkestrointiyksikkösi - muuttuva kontekstisäiliö, joka sisältää AI-palvelut, pluginit ja suodattimet. Toisin kuin staattiset clientit, se on suunniteltu lyhytaikaiseen, pyyntökohtaiseen käyttöön.

Kernelin Elinkaaren Hallinta: Miksi Transient-Rekisteröinti on Tärkeä

Kriittinen: Rekisteröi Kernel aina Transient-tyyppisenä riippuvuusinjektiossa. Kernel.Plugins-kokoelma on muuttuva - jos rekisteröit Singletoniksi, plugin-tila vuotaa samanaikaisten käyttäjien välillä (vakava tietoturvahaavoittuvuus).

Yritystason Semantic Kernel Asennus HostApplicationBuilderilla

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;

var builder = Host.CreateApplicationBuilder(args);

// 1. Rekisteröi AI-palvelut (Singleton - uudelleenkäytä HTTP-clientit)
// ServiceId mahdollistaa monimaллireitityksen (esim. nopeat vs. tarkat mallit)
builder.Services.AddAzureOpenAIChatCompletion(
    deploymentName: "gpt-4o",
    endpoint: Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!,
    apiKey: Environment.GetEnvironmentVariable("AZURE_OPENAI_KEY")!,
    serviceId: "gpt4-fast"
);

builder.Services.AddAzureOpenAIChatCompletion(
    deploymentName: "gpt-4-turbo",
    endpoint: Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!,
    apiKey: Environment.GetEnvironmentVariable("AZURE_OPENAI_KEY")!,
    serviceId: "gpt4-reasoning" // Monimutkaisiin suunnittelutehtäviin
);

// 2. Rekisteröi Kernel (AINA Transient)
builder.Services.AddTransient<Kernel>(sp =>
{
    var kBuilder = Kernel.CreateBuilder();

    // Propagoi lokitus ja telemetria
    kBuilder.Services.AddLogging(l =>
    {
        l.AddConsole();
        l.SetMinimumLevel(LogLevel.Trace); // Näe LLM-päättely kehityksessä
    });

    // Injektoi AI-palvelut host-kontainerista
    kBuilder.Services.AddSingleton(sp.GetRequiredService<IChatCompletionService>());

    return kBuilder.Build();
});

using var host = builder.Build();

Semantic Kernel Pluginit: Yhdistä AI Liiketoimintalogiikkaan

LLM on “aivot purkissa” - se voi päätellä, mutta ei pääse käsiksi tiedostoihin, tietokantoihin tai API:eihin. Semantic Kernel Pluginit kuromivat tämän kuilun paljastamalla C#-metodit “työkaluina”, joita LLM voi kutsua.

Miten Semantic Kernel Pluginit Toimivat

  1. Koristelet metodit [KernelFunction]-attribuutilla
  2. SK käyttää reflektiota luodakseen JSON-skeeman metodistasi
  3. Tämä skeema lähetetään LLM:lle sen järjestelmäpromptissa
  4. LLM tulostaa strukturoituja työkalukutsuja (esim. {"function": "CheckStock", "args": {"sku": "ABC123"}})
  5. SK sieppaa, suorittaa C#-koodisi ja palauttaa tulokset LLM:lle

Vahvasti Tyypitettyjen Semantic Kernel Pluginien Rakentaminen

Älä koskaan käytä primitiivisiä merkkijonoja monimutkaiseen dataan. Hyödynnä C#-recordeja ja LLM:n strukturoitua päättelyä.

using Microsoft.SemanticKernel;
using System.ComponentModel;

// Määrittele sopimus käyttäen recordeja (muuttumaton, tiivis)
public record OrderRequest(
    [Description("Tuotteen SKU-koodi")] string Sku,
    [Description("Tilausmäärä (1-1000)")] int Quantity,
    [Description("Toimitusprioriteetti: Standard, Express, Overnight")] string Priority = "Standard"
);

// Plugin-luokka DI-tuella
public class ERPPlugin
{
    private readonly IErpService _erpService;
    private readonly ILogger<ERPPlugin> _logger;

    public ERPPlugin(IErpService erpService, ILogger<ERPPlugin> logger)
    {
        _erpService = erpService;
        _logger = logger;
    }

    [KernelFunction("create_order")]
    [Description("Lähetä uusi tilaus ERP-järjestelmään. Palauttaa tilaus-ID:n.")]
    public async Task<string> CreateOrderAsync(
        [Description("Tilauksen tiedot")] OrderRequest order,
        CancellationToken ct = default)
    {
        _logger.LogInformation("Luodaan tilausta SKU:lle: {Sku}", order.Sku);

        // SK takaa, että 'order' on täytetty JSON-skeeman perusteella
        var orderId = await _erpService.SubmitAsync(
            order.Sku,
            order.Quantity,
            order.Priority,
            ct
        );

        return $"Tilaus {orderId} luotu onnistuneesti";
    }

    [KernelFunction("check_inventory")]
    [Description("Tarkista tuotteen reaaliaikaiset varastotasot")]
    public async Task<int> CheckStockAsync(
        [Description("Tuotteen SKU")] string sku,
        [Description("Varaston sijaintikoodi")] string location = "MAIN")
    {
        var stock = await _erpService.GetStockLevel(sku, location);
        return stock;
    }
}

// Rekisteröi DI:ssä
builder.Services.AddSingleton<IErpService, ErpService>();
builder.Services.AddSingleton<ERPPlugin>();

// Lisää Kerneliin
var plugin = serviceProvider.GetRequiredService<ERPPlugin>();
kernel.Plugins.AddFromObject(plugin, "ERP");

Keskeiset edut:

  • LLM näkee JSON-skeeman ja “ymmärtää”, että sen on toimitettava Sku, Quantity ja valinnaisesti Priority
  • Tyyppiturvallisuu: saat vahvasti tyypitetyn OrderRequest-olion, ei sanakirjaa
  • Validointi tapahtuu ennen liiketoimintalogiikkasi suorittamista

Model Context Protocol (MCP) Integraatio Semantic Kerneliin

Model Context Protocol (MCP) on avoin standardi, joka eliminoi mukautetun liitinkoodin. Sen sijaan, että kirjoittaisit erilliset Semantic Kernel -pluginit GitHubille, Google Drivelle ja Slackille, muodostat yhteyden olemassa oleviin MCP-palvelimiin, joita toimittajat tarjoavat.

Arkkitehtuuri

  • MCP-palvelin: Itsenäinen prosessi (Node.js, Python, Docker), joka paljastaa työkalut MCP-standardin kautta
  • MCP-client: .NET-sovelluksesi toimii isäntänä
  • Transport: Viestintäkanava (stdio paikallisille, SSE etäisille)

3.1 Ulkoisten MCP-palvelimien käyttäminen

Paketti: Microsoft.SemanticKernel.Plugins.Mcp

using Microsoft.SemanticKernel.Plugins.Mcp;

// Muodosta yhteys GitHub MCP -palvelimeen (vaatii Node.js:n asennuksen)
await using IMcpClient mcpClient = await McpClientFactory.CreateAsync(
    new StdioClientTransport(new()
    {
        Name = "GitHub",
        Command = "npx",
        Arguments = ["-y", "@modelcontextprotocol/server-github"],
        // Välitä halutessasi ympäristömuuttujia
        Environment = new()
        {
            ["GITHUB_TOKEN"] = Environment.GetEnvironmentVariable("GITHUB_TOKEN")
        }
    })
);

// Löydä saatavilla olevat työkalut palvelimelta
var mcpTools = await mcpClient.ListToolsAsync();
Console.WriteLine($"Löydettiin {mcpTools.Tools.Count} työkalua");

// Muunna MCP-työkalut Kernel-funktioiksi (automaattinen skeemamapattaus)
var functions = mcpTools.Tools.Select(tool => tool.AsKernelFunction());
kernel.Plugins.AddFromFunctions("GitHub", functions);

// Agentti voi nyt kutsua: list_issues, create_pull_request, search_code, jne.

Polyglot-etu: Python-tiimi rakentaa MCP-palvelimen datatieteellisille työkaluille. C#-agenttisi käyttävät sitä kirjoittamatta logiikkaa uudelleen .NET:iin.

3.2 MCP-palvelimen rakentaminen C#:lla

Paljasta C#-liiketoimintalogiikkasi MCP-palvelimena Claude Desktopille, Python-agenteille tai muille SK-instansseille.

Paketti: ModelContextProtocol

// Program.cs (Console App)
using Microsoft.Extensions.Hosting;
using Microsoft.SemanticKernel;

var builder = Host.CreateApplicationBuilder(args);

// Rekisteröi pluginisi
builder.Services.AddSingleton<ERPPlugin>();
builder.Services.AddSingleton<InventoryPlugin>();

// Lisää MCP-palvelinominaisuus
builder.Services.AddMcpServer()
    .WithStdioServerTransport() // stdio paikallisille, SSE HTTP-endpointeille
    .WithToolsFromAssembly(typeof(ERPPlugin).Assembly); // Automaattinen [KernelFunction]-löytäminen

var app = builder.Build();
await app.RunAsync(); // Blokkaa ja kuuntelee MCP JSON-RPC-viestejä

Nyt Claude Desktop tai mikä tahansa MCP-client voi löytää ja kutsua create_order- ja check_inventory-funktioitasi.

Semantic Kernel Agenttikehys: Tyypit ja Käyttötapaukset

Paketti: Microsoft.SemanticKernel.Agents

AgenttityyppiSuoritusTilan sijaintiParhaiten
ChatCompletionAgent.NET in-processClient-puoli (muisti/DB)Pieni latenssi, mukautettu historia, ei-OpenAI-mallit
OpenAIAssistantAgentOpenAI APIPalvelinpuoli (OpenAI)Code Interpreter, File Search, pysyvät säikeet
AzureAIAgentAzure AI FoundryPalvelinpuoli (Azure)Yritysturvallisuus, VNET:it, Azure AI Search -integraatio

4.1 ChatCompletionAgent: .NET-natiivi työjuhta

Tilaton suunnittelultaan - sinä hallitset keskusteluhistoriaa. Toimii minkä tahansa IChatCompletionService:n kanssa (Azure OpenAI, Hugging Face, Ollama).

using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Connectors.OpenAI;

// Luo erikoistuneet agentit
ChatCompletionAgent plannerAgent = new()
{
    Name = "Planner",
    Instructions = """
        Olet strateginen suunnittelija. Jaa käyttäjän pyynnöt toiminnallisiin vaiheisiin.
        Tulosta numeroitu suunnitelma. ÄLÄ suorita - vain suunnittele.
        """,
    Kernel = kernel,
    Arguments = new KernelArguments(new OpenAIPromptExecutionSettings
    {
        Temperature = 0.7,
        MaxTokens = 500
    })
};

ChatCompletionAgent coderAgent = new()
{
    Name = "Developer",
    Instructions = """
        Kirjoitat siistiä, idiomaattista C#-koodia käyttäen dependency injectionia.
        Noudata SOLID-periaatteita. Käytä annettua ERP-pluginia tarvittaessa.
        """,
    Kernel = kernel, // Tällä kernelillä on ERPPlugin rekisteröity
    Arguments = new KernelArguments(new OpenAIPromptExecutionSettings
    {
        FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(), // Ota työkalukutsut käyttöön
        Temperature = 0.2 // Alempi deterministiselle koodille
    })
};

ChatCompletionAgent reviewerAgent = new()
{
    Name = "Reviewer",
    Instructions = """
        Tarkista Developerin koodi seuraavien osalta:
        - Tietoturvahaavoittuvuudet (SQL-injektio, XSS)
        - SOLID-periaatteiden rikkomukset
        - Puuttuva virheidenkäsittely
        Jos kelvollinen, tulosta: APPROVED
        Jos ongelmia löytyy, tulosta: REJECTED syineen
        """,
    Kernel = kernel,
    Arguments = new KernelArguments(new OpenAIPromptExecutionSettings
    {
        Temperature = 0.1 // Hyvin deterministinen tarkistukselle
    })
};

4.2 AgentGroupChat: moniagenttiorkestraatio

Yhteistyöajoympäristö - hallitsee vuoronvaihtoa, jaettua historiaa ja lopetuslogiikkaa.

using Microsoft.SemanticKernel.Agents.Chat;

// Luo ryhmäkeskustelu valintastrategialla
AgentGroupChat chat = new(plannerAgent, coderAgent, reviewerAgent)
{
    ExecutionSettings = new()
    {
        // Valintastrategia: Kuka puhuu seuraavaksi?
        SelectionStrategy = new SequentialSelectionStrategy(),
        // Voi käyttää myös KernelFunctionSelectionStrategya dynaamiseen reititykseen

        // Lopetusstrategia: milloin lopetetaan?
        TerminationStrategy = new RegexTerminationStrategy("APPROVED")
        {
            Agents = [reviewerAgent], // Vain reviewer voi hyväksyä
            MaximumIterations = 15 // Turvaraja
        }
    }
};

// Alusta keskustelu
chat.AddChatMessage(new ChatMessageContent(
    AuthorRole.User,
    "Luo OrderService, joka validoi varaston ennen tilausten tekemistä"
));

// Suorita silmukka
await foreach (var message in chat.InvokeAsync())
{
    Console.WriteLine($"[{message.AuthorName}] {message.Content}");

    // Käsittele striimaus tai artefaktit
    if (message.Items.Any(i => i is FileReferenceContent))
    {
        // Käsittele tiedostotulosteet
    }
}

Console.WriteLine($"Keskustelu päättyi {chat.History.Count} viestin jälkeen");

4.3 Edistynyt: dynaaminen valintastrategia (ReAct-malli)

Peräkkäisen sijaan käytä LLM:ää reitittämään dynaamisesti kontekstin perusteella.

// Luo reititysfunktio
KernelFunction selectionFunction = AgentGroupChat.CreatePromptFunctionForStrategy(
    $$$"""
    Analysoi keskustelu ja valitse seuraava puhuva agentti.

    Saatavilla olevat agentit:
    - Planner: Luo strategisia suunnitelmia, jakaa monimutkaiset tehtävät
    - Developer: Kirjoittaa C#-koodia, toteuttaa ratkaisut
    - Reviewer: Tarkistaa koodin laadun, hyväksyy tai hylkää

    Säännöt:
    - Käyttäjän pyynnön jälkeen → Planner
    - Suunnitelman jälkeen → Developer
    - Koodin jälkeen → Reviewer
    - REJECTED-vastauksen jälkeen → Developer (korjaamaan)
    - APPROVED-vastauksen jälkeen → DONE

    Keskusteluhistoria:
    {{$history}}

    Tulosta vain agentin nimi.
    """
);

var strategy = new KernelFunctionSelectionStrategy(selectionFunction, kernel)
{
    // Varajärjestely, jos LLM tulostaa virheellisen nimen
    ResultParser = (result) => result.GetValue<string>() ?? "Planner",

    // Historia lähettää reititys-LLM:lle
    HistoryVariableName = "history",
    HistoryReducer = new ChatHistoryTruncationReducer(10) // Vain viimeiset 10 viestiä
};

chat.ExecutionSettings.SelectionStrategy = strategy;

Tämä mahdollistaa Handoff-mallit: jos käyttäjä kysyy laskutuskysymyksen keskellä keskustelua, reititin voi siirtää BillingAgent:lle dynaamisesti.

Azure AI Foundry Integraatio: Yritystason Semantic Kernel Agentit

Paketti: Microsoft.SemanticKernel.Agents.AzureAI

Tuotantoskenaarioille, jotka vaativat Code Interpreteria (turvallinen Python-hiekkalaatikko), File Searchia (RAG) ja Managed Identity -integraatiota.

5.1 Code Interpreter & File Search -esimerkki

using Microsoft.SemanticKernel.Agents.AzureAI;
using Azure.AI.Projects;
using Azure.Identity;

// 1. Luo Azure AI Project Client (käyttää Managed Identitya tuotannossa)
var projectClient = new AIProjectClient(
    new Uri(Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT")!),
    new DefaultAzureCredential()
);

// 2. Määrittele agentti hallinnoiduilla ominaisuuksilla
var agentDefinition = await AzureAIAgent.CreateAsync(
    kernel,
    client: projectClient,
    definition: new AzureAIAgentDefinition("DataScientist")
    {
        ModelId = "gpt-4-turbo",
        Instructions = """
            Olet data-analyytikko. Käytä Pythonia:
            - Lataa ja puhdista CSV-data
            - Luo tilastollisia yhteenvetoja
            - Luo visualisointeja (matplotlib/seaborn)
            Selitä aina analyysisi ennen koodin näyttämistä.
            """,

        // Ota käyttöön hallinnoidut työkalut (Azure isännöi suorituksen)
        CodeInterpreter = new AzureAICodeInterpreterToolDefinition(),
        FileSearch = new AzureAIFileSearchToolDefinition()
    }
);

// 3. Lataa tiedosto analyysiin (tallennetaan Azureen, ei paikalliseen muistiin)
var agentsClient = projectClient.GetAgentsClient();
var fileInfo = await agentsClient.UploadFileAsync(
    "sales_data.csv",
    AgentFilePurpose.Agents
);
await agentDefinition.AddFileAsync(fileInfo.Id);

// 4. Luo pysyvä säie (tila elää Azuressa)
AgentThread thread = await agentDefinition.CreateThreadAsync();
await agentDefinition.AddChatMessageAsync(
    thread,
    "Analysoi Q4-myyntitrendit ja luo kuukausittainen pylväskaavio"
);

// 5. Suorita (agentti kirjoittaa Pythonia, Azure ajaa sen hiekkalaatikossa)
await foreach (var msg in agentDefinition.InvokeAsync(thread))
{
    Console.WriteLine($"[{msg.AuthorName}]: {msg.Content}");

    // Pura generoidut kuvat (kaaviot)
    foreach (var item in msg.Items)
    {
        if (item is ImageContent imgContent)
        {
            var imageBytes = imgContent.Data!.Value.ToArray();
            await File.WriteAllBytesAsync("sales_chart.png", imageBytes);
            Console.WriteLine("Kaavio tallennettu sales_chart.png:ksi");
        }
    }
}

// 6. Siivoa
await agentDefinition.DeleteAsync();

Keskeiset erot ChatCompletionAgentiin:

  • Tilan hallinta Azuressa, ei sovelluksessasi (säie säilyy uudelleenkäynnistyksien aikana)
  • Turvallinen Python-suoritus Hyper-V-eristetyissä konteissa
  • Natiivi RAG File Searchin kautta (ei manuaalista pilkkomista/upotusta)
  • Managed Identity -tuki (ei API-avaimia koodissa)

Semantic Kernel Muisti: Vektorivarastot ja RAG-Toteutus

Muisti erottaa reaktiiviset chatbotit tilapäisistä AI-assistenteista. Semantic Kernel erottaa:

  • Lyhytaikainen muisti: LLM:n konteksti-ikkuna (keskusteluhistoria)
  • Pitkäaikainen muisti: Vektori-/semanttinen haku (RAG - Retrieval-Augmented Generation)

Paketti: Microsoft.Extensions.VectorData

Uusi abstraktio tarjoaa yhtenäisen rajapinnan Azure AI Searchille, CosmosDB:lle, Qdrantille, Redisille ja muistivarastoille.

6.1 Vektoridatamallin määrittäminen

Käytä attribuutteja C#-ominaisuuksien kartoittamiseen vektorivarasto-skeemaan.

using Microsoft.Extensions.VectorData;

public class ProductDocument
{
    [VectorStoreRecordKey]
    public string ProductId { get; set; } = string.Empty;

    [VectorStoreRecordData]
    public string Name { get; set; } = string.Empty;

    [VectorStoreRecordData]
    public string Description { get; set; } = string.Empty;

    [VectorStoreRecordData]
    public decimal Price { get; set; }

    [VectorStoreRecordData]
    public string Category { get; set; } = string.Empty;

    // Upotus vektori (1536 dimensiota text-embedding-ada-002:lle)
    [VectorStoreRecordVector(1536, DistanceFunction.CosineSimilarity)]
    public ReadOnlyMemory<float> DescriptionEmbedding { get; set; }
}

6.2 CosmosDB:n käyttäminen vektorivarastona

using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Connectors.AzureCosmosDBMongoDB;
using Microsoft.SemanticKernel.Embeddings;

// 1. Rekisteröi upotuspalvelu
builder.Services.AddAzureOpenAITextEmbeddingGeneration(
    deploymentName: "text-embedding-ada-002",
    endpoint: azureOpenAiEndpoint,
    apiKey: azureOpenAiKey
);

// 2. Luo vektorivaarasto-client
var mongoClient = new MongoClient(cosmosConnectionString);
var vectorStore = new AzureCosmosDBMongoDBVectorStore(mongoClient);

// 3. Hae kokoelma (luo automaattisesti tarvittaessa)
var collection = vectorStore.GetCollection<string, ProductDocument>("products");
await collection.CreateCollectionIfNotExistsAsync();

// 4. Generoi upotus ja tallenna
var embeddingService = kernel.GetRequiredService<ITextEmbeddingGenerationService>();

var product = new ProductDocument
{
    ProductId = "SKU-12345",
    Name = "Langaton näppäimistö",
    Description = "Ergonominen langaton näppäimistö mekaanisilla kytkimillä",
    Price = 89.99m,
    Category = "Elektroniikka"
};

// Generoi upotus kuvaukselle
var embedding = await embeddingService.GenerateEmbeddingAsync(product.Description);
product.DescriptionEmbedding = embedding;

// Tallenna vektoritietokantaan
await collection.UpsertAsync(product);

// 5. Semanttinen haku
var queryEmbedding = await embeddingService.GenerateEmbeddingAsync(
    "Tarvitsen mukavan näppäimistön koodaukseen"
);

var searchResults = await collection.VectorizedSearchAsync(
    queryEmbedding,
    new VectorSearchOptions { Top = 5 }
);

await foreach (var result in searchResults.Results)
{
    Console.WriteLine($"Osuma: {result.Record.Name} (Pisteet: {result.Score:F3})");
}

6.3 Muisti-rajatut agentit

Moniagenttijärjestelmissä muistin rajaus estää kontekstin saastumisen:

// Jaettu muisti: Kaikki agentit näkevät saman keskustelun
var sharedHistory = new ChatHistory();
chat.AddChatMessage(sharedHistory);

// Yksityinen muisti: Jokaisella agentilla on eristetty tieto
var menuKernel = kernel.Clone();
menuKernel.Plugins.AddFromObject(new MenuPlugin(vectorStore)); // Menu-data

var kitchenKernel = kernel.Clone();
kitchenKernel.Plugins.AddFromObject(new KitchenPlugin(equipmentDb)); // Laitetieto

ChatCompletionAgent menuAgent = new()
{
    Name = "MenuAgent",
    Kernel = menuKernel, // Sisältää menuvektorivaraston
    Instructions = "Vastaa kysymyksiin menueristä käyttämällä menutietokantaa"
};

ChatCompletionAgent kitchenAgent = new()
{
    Name = "KitchenAgent",
    Kernel = kitchenKernel, // Sisältää laitetietokannan
    Instructions = "Hallitse keittiölaitteita ja varastoa"
};

// Jokainen agentti näkee vain omat työkalunsa ja muistinsa

Kriittinen malli: Käytä kernel.Clone()-metodia tai erillisiä DI-scopeja eristääksesi pluginpääsyn. Ilman tätä kaikki agentit jakavat saman Kernel.Plugins-kokoelman, luoden turvallisuus- ja logiikkaongelmia.

Tuotantovalmis Semantic Kernel: Havainnoitavuus ja Virheidenkäsittely

Semantic Kernelin Monitorointi OpenTelemetrylla

Agenttipäättelyn debuggaus on tunnetusti vaikeaa (“Miksi se valitsi tuon työkalun?”). SK integroituu syvällisesti OpenTelemetryn kanssa.

using OpenTelemetry.Trace;
using OpenTelemetry.Logs;

var builder = Host.CreateApplicationBuilder(args);

// Ota käyttöön OpenTelemetry-jäljitys
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing =>
    {
        tracing
            .AddSource("Microsoft.SemanticKernel*")
            .AddAzureMonitorTraceExporter() // Tai Jaeger, Zipkin
            .AddConsoleExporter(); // Vain kehityksessä
    });

// Lokien integraatio
builder.Logging.AddOpenTelemetry(logging =>
{
    logging.AddAzureMonitorLogExporter();
});

SK lähettää Activities-tapahtumia:

  • Funktion kutsut (mikä plugin, mitkä argumentit)
  • Mallikutsut (prompt, käytetyt tokenit, vastausaika)
  • Suunnittelijan vaiheet (päättelyjäljet)

7.2 Suodattimet: väliohjelmistoputki

Suodattimet sieppaavat suorituksen lokitusta, PII-poistoa tai uudelleenyrityslogiikkaa varten.

using Microsoft.SemanticKernel;

// Funktion kutsusuodatin (lokittaa työkalukutsut)
public class FunctionLoggingFilter : IFunctionInvocationFilter
{
    private readonly ILogger<FunctionLoggingFilter> _logger;

    public FunctionLoggingFilter(ILogger<FunctionLoggingFilter> logger)
        => _logger = logger;

    public async Task OnFunctionInvocationAsync(
        FunctionInvocationContext context,
        Func<FunctionInvocationContext, Task> next)
    {
        _logger.LogInformation(
            "Agentti kutsuu {Plugin}.{Function} argumenteilla: {Args}",
            context.Function.PluginName,
            context.Function.Name,
            context.Arguments
        );

        await next(context); // Suorita funktio

        _logger.LogInformation(
            "Funktio {Function} palautti: {Result}",
            context.Function.Name,
            context.Result?.ToString()
        );
    }
}

// Prompt-suodatin (PII-poisto ennen LLM:lle lähettämistä)
public class PiiRedactionFilter : IPromptRenderFilter
{
    private readonly Regex _ssnRegex = new(@"\b\d{3}-\d{2}-\d{4}\b");
    private readonly Regex _emailRegex = new(@"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b");

    public async Task OnPromptRenderAsync(
        PromptRenderContext context,
        Func<PromptRenderContext, Task> next)
    {
        await next(context); // Renderöi prompt

        // Poista PII ennen LLM:lle lähettämistä
        var renderedPrompt = context.RenderedPrompt!;
        renderedPrompt = _ssnRegex.Replace(renderedPrompt, "***-**-****");
        renderedPrompt = _emailRegex.Replace(renderedPrompt, "***@***.***");

        context.RenderedPrompt = renderedPrompt;
    }
}

// Rekisteröi suodattimet DI:ssä
builder.Services.AddSingleton<IFunctionInvocationFilter, FunctionLoggingFilter>();
builder.Services.AddSingleton<IPromptRenderFilter, PiiRedactionFilter>();

7.3 Virheidenkäsittely & häiriönsietokyky

using Polly;
using Polly.Extensions.Http;

// Uudelleenyritys politiikka tilapäisille virheille (429-rajoitus, verkko-ongelmat)
var retryPolicy = HttpPolicyExtensions
    .HandleTransientHttpError()
    .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

builder.Services.AddHttpClient("AzureOpenAI")
    .AddPolicyHandler(retryPolicy);

// Agenttitason virheidenkäsittely
try
{
    await foreach (var message in chat.InvokeAsync())
    {
        Console.WriteLine(message.Content);
    }
}
catch (HttpOperationException ex) when (ex.StatusCode == 429)
{
    // Rajoitettu - takaisinveto tai siirry toiseen malliin
    _logger.LogWarning("Nopeus rajoitettu. Yritetään uudelleen hitaammalla mallilla...");
}
catch (KernelException ex) when (ex.InnerException is JsonException)
{
    // LLM generoi virheellisen JSON:n funktiokutsulle
    _logger.LogError("Virheellinen työkalukutsumuoto: {Error}", ex.Message);
    // Injektoi virhe keskusteluhistoriaan LLM:n nähtäväksi ja uudelleenyritystä varten
    chat.AddChatMessage(new ChatMessageContent(
        AuthorRole.System,
        $"Virhe: Virheellinen funktiokutsumuoto. Yritä uudelleen."
    ));
}

7.4 Tilan pysyvyys tilattomille hosteille

Agentit Azure Functionsissa tai Kubernetesissa on selvittävä uudelleenkäynnistyksistä.

using System.Text.Json;

// Serialisoi AgentGroupChat-tila
public class AgentChatStateManager
{
    public async Task SaveStateAsync(AgentGroupChat chat, string sessionId)
    {
        var state = new
        {
            History = chat.History.Select(m => new
            {
                m.Role,
                m.Content,
                m.AuthorName
            }).ToList(),
            Iteration = chat.History.Count
        };

        var json = JsonSerializer.Serialize(state);
        await _blobStorage.UploadAsync($"sessions/{sessionId}.json", json);
    }

    public async Task<ChatHistory> LoadStateAsync(string sessionId)
    {
        var json = await _blobStorage.DownloadAsync($"sessions/{sessionId}.json");
        var state = JsonSerializer.Deserialize<dynamic>(json);

        var history = new ChatHistory();
        foreach (var msg in state.History)
        {
            history.AddMessage(
                new ChatMessageContent(msg.Role, msg.Content)
                {
                    AuthorName = msg.AuthorName
                }
            );
        }
        return history;
    }
}

Yhteenveto: Yritystason AI Rakentaminen Semantic Kernelillä

Semantic Kernel on kehittynyt yksinkertaisesta LLM-kääreobjektista kattavaksi kehykseksi yritys-AI-järjestelmien rakentamiseen. Keskeiset opit senior-kehittäjille:

  1. Hajota, älä monoliitti: Jaa monimutkaiset tehtävät erikoistuneisiin agentteihin (Planner, Coder, Reviewer, Data Analyst)
  2. Tyyppiturvallisuu ensin: Käytä vahvasti tyypitettyjä DTO:ita plugineissa. Anna LLM:n päätellä strukturoitua dataa.
  3. Hyödynnä standardit: MCP eliminoi mukautetut integraatiot. Käytä toimittajien tarjoamia työkalupalvelimia.
  4. Muisti = Pitkäaikainen + lyhytaikainen: Vektorivarastot tiedolle, konteksti-ikkuna välittömälle historialle
  5. Tuotantovalmiit mallit:
    • Transient Kernel -rekisteröinti (vältä tilan vuotoja)
    • OpenTelemetry havainnoitavuuteen
    • Suodattimet PII-poistoon ja lokitukseen
    • Tilan pysyvyys tilattomille hosteille (Azure Functions, Kubernetes)
  6. Agenttiorkestraatio:
    • Peräkkäinen deterministisille putkille
    • KernelFunctionSelectionStrategy dynaamiselle reititykselle (ReAct-malli)
    • Lopetusstrategiat estämään päättymättömät silmukat

Tulevaisuus piilee Process Frameworkissa (BPMN-kaltaiset tilakoneet agenteille, tällä hetkellä esikatselussa) ja syvemmässä Azure AI Foundry -integraatiossa. Mutta periaatteet pysyvät: orkestroi tarkasti, työkalut tarkasti ja tarkkaile selkeästi.

Rakenna moniagenttijärjestelmäsi kuten rakennat mikropalvelut - eristettyinä, testattavina ja häiriönsietoisina. Semantic Kernel tarjoaa primitiivit. Sinä tarjoat arkkitehtuurin.


Usein Kysytyt Kysymykset (UKK)

Mihin Semantic Kernel on tarkoitettu?

Semantic Kernel on tarkoitettu tuotantovalmiiden AI-agenttien ja moniagenttijärjestelmien rakentamiseen .NET:llä. Se yhdistää LLM:t kuten GPT-4:n liiketoimintalogiikkaasi, tietokantoihisi ja API:hin, mahdollistaen älykkään automatisoinnin monimutkaisille yritystyönkuluille.

Onko Semantic Kernel ilmainen?

Kyllä, Semantic Kernel on avoimen lähdekoodin ja ilmainen MIT-lisenssillä. Tarvitset kuitenkin API-avaimia AI-palveluille kuten Azure OpenAI tai OpenAI, joilla on omat hinnoittelunsa.

Mikä on ero Semantic Kernelin ja LangChainin välillä?

Semantic Kernel on suunniteltu .NET-kehittäjille vahvalla tyypityksellä, riippuvuusinjektiolla ja yritysmalleilla. LangChain on Python-ensisijainen. SK:lla on myös ensimm äisen luokan tuki Model Context Protocol (MCP) -yhteensopivuudelle ja Azure AI Foundry -integraatiolle.

Voinko käyttää Semantic Kernel paikallisten LLM:ien kanssa?

Kyllä! Semantic Kernel tukee mitä tahansa IChatCompletionService-toteutusta, mukaan lukien Ollama, Hugging Face -mallit ja muut paikalliset LLM-palveluntarjoajat. Et ole lukittu Azure OpenAI:hin.

Miten debuggaan Semantic Kernel -agentteja?

Käytä OpenTelemetry-integraatiota jäljittääksesi funktiokutsuja, mallikutsuja ja päättelyvaiheita. Ota käyttöön yksityiskohtainen lokitus LogLevel.Trace:llä kehityksen aikana nähdäksesi koko LLM-keskustelun kulun.

Mikä on Model Context Protocol (MCP)?

MCP on avoin standardi, joka mahdollistaa Semantic Kernel -agenteille valmiiden työkalupalvelimien (GitHub, Slack, Google Drive) käytön ilman mukautettujen pluginien kirjoittamista. Se mahdollistaa monikieliset AI-järjestelmät, joissa Python, Node.js ja .NET-agentit jakavat työkaluja.

Tukeeko Semantic Kernel moniagenttijärjestelmiä?

Kyllä, AgentGroupChat-kehys mahdollistaa kehittyneen moniagenttiorkestraation peräkkäisillä, dynaamisilla tai mukautetuilla reitit ysstrategioilla. Agentit voivat tehdä yhteistyötä jaetuilla tai eristetyillä muistikonteksteilla.


Seuraavat Askeleet: Hallitse Semantic Kernel

Back to Blog