Skip to content

Semantic Kernel Integration

This document explains how Microsoft Semantic Kernel is integrated into the GridLab.Gmss.Cim module to enable natural language querying of CIM (Common Information Model) documents.


What is Semantic Kernel?

Microsoft Semantic Kernel is an open-source SDK that enables developers to integrate Large Language Models (LLMs) with conventional programming languages like C#, Python, and Java. It acts as an orchestration layer that:

  • Connects LLMs to Your Code: Allows AI models to call your application functions
  • Plugin Architecture: Exposes application capabilities as "plugins" that AI can discover and invoke
  • Multi-Model Support: Works with OpenAI, Azure OpenAI, Ollama, HuggingFace, and other AI services
  • Agentic Behavior: Enables AI agents to reason, plan, and execute tasks using your code
  • Memory & Context Management: Maintains conversation history and context across interactions

In essence, Semantic Kernel bridges the gap between natural language understanding (via LLMs) and structured code execution.


Semantic Kernel vs MCP Server

While both technologies enable AI-powered interactions with application data, they serve different purposes and use different architectures:

Aspect Semantic Kernel MCP (Model Context Protocol) Server
Purpose Orchestration SDK for integrating LLMs into applications Standardized protocol for exposing application context to AI assistants
Architecture Embedded SDK within your application External server process that communicates via stdio/HTTP
Integration Code-first: Define functions in C#/Python/Java Protocol-first: Implement MCP server specification
LLM Control You host/manage LLM connections (OpenAI, Ollama, etc.) AI client (like Claude Desktop) manages the LLM
Execution Functions execute in your application process Tools execute in MCP server process, results sent to client
Use Case Building AI-powered features within your app (chatbots, agents) Exposing app capabilities to external AI assistants (Claude, VS Code Copilot)
Conversation Full control over chat flow and history AI client controls conversation flow
Deployment Deployed as part of your application Deployed as a separate service/binary

When to Use Each:

Use Semantic Kernel when:

  • You want to embed AI capabilities directly into your application
  • You need full control over the LLM, prompts, and execution flow
  • You're building custom chatbots, AI agents, or intelligent features
  • You want to maintain conversation context within your app

Use MCP Server when:

  • You want external AI assistants (Claude Desktop, VS Code Copilot) to access your app's data
  • You're exposing read-only or utility functions to AI tools
  • You want a standardized protocol for AI assistant integration
  • You don't need to manage LLM infrastructure yourself

In GridLab.Gmss.Cim:

  • Semantic Kernel powers the integrated chat interface for querying CIM documents via natural language

Architecture Overview

The Semantic Kernel integration in this module follows a clean architecture pattern:

graph TB
    subgraph "User Interface Layer"
        A[Chat UI<br/>Razor Page]
        B[SignalR Hub<br/>CimChatHub]
    end

    subgraph "Service Layer"
        C[CimChatService]
        D[Semantic Kernel]
    end

    subgraph "Plugin Layer"
        E[CimDocumentQueryPlugin]
    end

    subgraph "Application Layer"
        F[CimDocumentQueryAppService]
    end

    subgraph "Domain Layer"
        G[CimDocumentManager]
        H[RDF Graph Store]
    end

    subgraph "AI Infrastructure"
        I[Ollama<br/>Local LLM]
    end

    A -->|WebSocket| B
    B -->|Chat Request| C
    C -->|Kernel.InvokeAsync| D
    D -->|Function Calling| E
    E -->|Query Documents| F
    F -->|Read Graph| G
    G -->|LINQ| H
    D <-->|HTTP API| I

Implementation in GridLab.Gmss.Cim

The Semantic Kernel integration enables users to query CIM documents using natural language through a conversational AI interface. The implementation consists of:

  1. Kernel Factory - Creates and configures Semantic Kernel instances
  2. Chat Service - Manages conversation flow and LLM interactions
  3. Query Plugin - Exposes CIM document query capabilities to the AI
  4. SignalR Hub - Provides real-time communication with the UI
  5. Chat UI - User-facing interface for natural language queries

How It Works

1. User Asks a Question

User: "How many SynchronousMachines are in the document?"

2. Chat Service Sends to LLM

The CimChatService sends the user's message to the LLM (Ollama) with:

  • System Prompt: Instructions on how to use available functions
  • Chat History: Previous conversation context
  • Function Definitions: Metadata about available CIM query functions

3. LLM Decides to Call a Function

The LLM reasons:

  • "The user wants to count SynchronousMachine instances"
  • "I should use search_definitions with searchTerm='SynchronousMachine'"

It generates a function call request:

{
  "function": "search_definitions",
  "arguments": {
    "searchTerm": "SynchronousMachine",
    "maxResults": 100
  }
}

4. Semantic Kernel Executes the Plugin Function

Semantic Kernel intercepts the function call and invokes:

CimDocumentQueryPlugin.SearchDefinitionsAsync(
    searchTerm: "SynchronousMachine",
    maxResults: 100
)

5. Plugin Queries CIM Document

The plugin calls the application service:

var definitions = await _queryService.SearchDefinitionsAsync(
    documentId, 
    "SynchronousMachine"
);

This executes a bultin query against the RDF graph store.

6. Results Return to LLM

The plugin returns formatted results:

Found 12 results for 'SynchronousMachine':

1. cim:SynchronousMachine (ID: _72cb1d28-c3ce-11f0-988b-f8edfcb6b192)
2. cim:SynchronousMachine (ID: _8f3a4b12-d4ef-22c1-899c-a9fedcb7c203)
...

7. LLM Generates Human-Friendly Response

The LLM processes the function result and responds:

I found **12 SynchronousMachines** in the document. Here's a summary:

1. **_72cb1d28-c3ce-11f0-988b-f8edfcb6b192** - SynchronousMachine
2. **_8f3a4b12-d4ef-22c1-899c-a9fedcb7c203** - SynchronousMachine
...

Would you like details about any specific machine?

8. User Sees the Answer

The response is streamed back through SignalR to the chat UI in real-time.


Key Components

1. CimSemanticKernelFactory

Location: host/GridLab.Gmss.Cim/SemanticKernel/CimSemanticKernelFactory.cs

Factory class for creating and configuring Semantic Kernel instances with Ollama LLM support.

Key Methods:

// Create kernel with Ollama LLM and CIM query plugin
public static (Kernel kernel, CimDocumentQueryPlugin plugin) CreateKernelWithPlugin(
    ICimDocumentQueryAppService queryService,
    string ollamaEndpoint,
    string modelId)

// Get execution settings for automatic function calling
public static OllamaPromptExecutionSettings GetOllamaExecutionSettings()

Configuration:

  • Connects to Ollama (local LLM runtime)
  • Registers CimDocumentQueryPlugin as "CimDocument"
  • Enables automatic function calling (temperature=0.0 for deterministic behavior)

2. CimChatService

Location: host/GridLab.Gmss.Cim/SemanticKernel/Services/CimChatService.cs

Service that manages conversation flow between users and the LLM.

Responsibilities:

  • Maintains chat history with system prompt
  • Sends user messages to LLM via Semantic Kernel
  • Handles automatic function invocation
  • Returns AI-generated responses

System Prompt Highlights:

You are an expert assistant for querying CIM documents...

Available functions:
1. set_document_context - Set active document
2. get_definition - Get specific definition by ID
3. get_all_definitions - Get all definitions
4. search_definitions - Search by term
5. list_class_types - List all CIM classes
6. find_content_in_document - Search text patterns

ALWAYS use functions to query the RDF graph!

Key Methods:

// Process user message and return AI response
public async Task<string> ChatAsync(string userMessage)

// Set the active CIM document for queries
public Task SetDocumentContextAsync(Guid documentId)

// Clear conversation history
public void ClearHistory()

3. CimDocumentQueryPlugin

Location: host/GridLab.Gmss.Cim/SemanticKernel/Plugins/CimDocumentQueryPlugin.cs

Semantic Kernel plugin that exposes CIM document query capabilities as callable functions.

Available Functions:

Function Description Parameters
set_document_context Set active document for queries documentId (GUID)
get_definition Retrieve specific definition by instance ID instanceId, documentId (optional)
get_all_definitions Get all definitions in document documentId (optional), maxResults
search_definitions Search definitions by term searchTerm, documentId (optional), maxResults
list_class_types List all CIM class types documentId (optional)
find_content_in_document Search text patterns pattern, documentId (optional), maxResults

Example Function Definition:

[KernelFunction("search_definitions")]
[Description("Searches CIM definitions by term. Matches IDs, class names, property values.")]
public async Task<string> SearchDefinitionsAsync(
    [Description("Search term (e.g., 'SynchronousMachine', 'Generator')")] 
    string searchTerm,

    [Description("Optional document ID. Uses current context if not provided.")] 
    string? documentId = null,

    [Description("Max results to return (default: 10)")] 
    int maxResults = 10,

    CancellationToken cancellationToken = default)

How Functions Are Discovered:

  • [KernelFunction] attribute marks methods as callable by LLM
  • [Description] attributes provide semantic information to the AI
  • Parameter descriptions help the LLM understand how to call functions

4. CimChatHub (SignalR)

Location: host/GridLab.Gmss.Cim/Hubs/CimChatHub.cs

SignalR hub for real-time chat communication between browser and server.

Client-to-Server Methods:

// Send user message to AI
public async Task SendMessage(string message, Guid? documentId = null)

// Clear conversation history
public async Task ClearHistory()

Server-to-Client Events:

"ReceiveMessage"  // AI response text
"ReceiveStatus"   // Processing status (e.g., "thinking")
"ReceiveError"    // Error messages
"HistoryCleared"  // Confirmation of history reset

5. Chat UI

Location: host/GridLab.Gmss.Cim/Pages/Cim/Chat/Index.cshtml

Razor page providing the chat interface:

  • Document selector dropdown
  • Message input field
  • Chat history display with markdown rendering
  • Real-time updates via SignalR
  • Status indicators (thinking, error)

JavaScript Integration:

// Connect to SignalR hub
const connection = new signalR.HubConnectionBuilder()
    .withUrl("/cim-chat-hub")
    .build();

// Send message
connection.invoke("SendMessage", message, documentId);

// Receive response
connection.on("ReceiveMessage", (response) => {
    // Display formatted message
});

Configuration

Application Settings

File: host/GridLab.Gmss.Cim/appsettings.json

{
  "SemanticKernel": {
    "OllamaEndpoint": "http://localhost:7869",
    "ModelId": "qwen2.5:14b-instruct"
  }
}

Configuration Options:

Setting Description Default
OllamaEndpoint URL of Ollama server http://localhost:7869
ModelId LLM model to use qwen2.5:14b-instruct

Supported Models:

  • qwen2.5:14b-instruct (recommended for function calling)
  • llama3.2:latest
  • mistral:latest
  • deepseek-r1:14b
  • Any Ollama-compatible model with function calling support

Module Registration

File: host/GridLab.Gmss.Cim/CimWebHostModule.cs

private void ConfigureSemanticKernel(ServiceConfigurationContext context)
{
    var configuration = context.Services.GetConfiguration();

    // Create shared kernel container with plugin
    context.Services.AddSingleton(sp =>
    {
        var queryService = sp.GetRequiredService<ICimDocumentQueryAppService>();
        var ollamaEndpoint = configuration["SemanticKernel:OllamaEndpoint"] 
            ?? "http://localhost:7869";
        var modelId = configuration["SemanticKernel:ModelId"] 
            ?? "qwen2.5:14b-instruct";

        return CimSemanticKernelFactory.CreateKernelContainer(
            queryService, ollamaEndpoint, modelId);
    });

    // Register Kernel and Plugin as separate services
    context.Services.AddSingleton(sp => sp.GetRequiredService<KernelContainer>().Kernel);
    context.Services.AddSingleton(sp => sp.GetRequiredService<KernelContainer>().Plugin);
}

Dependency Injection:

  • Kernel - Singleton instance shared across requests
  • CimDocumentQueryPlugin - Singleton plugin instance
  • CimChatService - Scoped service per user session

Usage Example

Scenario: Query Equipment in a CIM Document

Step 1: User selects a document

Document: "Nordic44-HV_EQ.xml" (Selected from dropdown)

Step 2: User asks about equipment

User: "What types of equipment are in this document?"

Step 3: LLM calls list_class_types function

{
  "function": "list_class_types",
  "arguments": {}
}

Step 4: Plugin queries RDF graph

var definitions = await _queryService.GetDefinitionsAsync(documentId);
var classTypes = definitions
    .GroupBy(d => d.ClassName)
    .Select(g => new { ClassName = g.Key, Count = g.Count() })
    .OrderByDescending(x => x.Count);

Step 5: Function returns results

Found 15 class types in document:

1. cim:Terminal (120 instances)
2. cim:SynchronousMachine (12 instances)
3. cim:ACLineSegment (45 instances)
4. cim:PowerTransformer (8 instances)
...

Step 6: LLM generates friendly response

The document contains **15 different equipment types**:

**Most Common:**
- **Terminal** (120 instances) - Connection points
- **ACLineSegment** (45 instances) - Transmission lines
- **SynchronousMachine** (12 instances) - Generators

**Other Equipment:**
- PowerTransformer (8)
- Breaker (22)
- Load (18)
...

Would you like details about any specific equipment type?


Demo

The following demonstration showcases the natural language chat interface in action:

Semantic Kernel Chat Demo

What's happening in the demo:

  1. User selects a CIM document from the dropdown
  2. User types natural language questions about the document
  3. AI assistant uses Semantic Kernel to:
    • Understand the intent
    • Call appropriate query functions
    • Access the RDF graph store
    • Format results in markdown
  4. Responses appear in real-time via SignalR
  5. Conversation context is maintained across multiple questions

Example Queries Shown:

  • "How many generators are in this document?"
  • "Show me the properties of the first generator"
  • "What is the rated power of generator XYZ?"
  • "List all substations"

Benefits of This Approach

1. Natural Language Interface

Users can query complex CIM data without knowing SPARQL or GraphQL syntax.

2. Contextual Conversations

The AI maintains conversation history, allowing follow-up questions:

User: "How many generators?"
AI: "I found 12 generators."
User: "Show me the first one"  // AI remembers "generators" from context

3. Automatic Function Orchestration

The LLM decides which functions to call and in what order:

User: "Compare the rated power of all generators"
AI calls:
1. search_definitions(searchTerm="SynchronousMachine")
2. get_definition(instanceId=...) for each result
3. Analyzes and compares power ratings

4. Flexible Querying

Users can ask questions in many ways:

  • "How many SynchronousMachines?"
  • "List all generators"
  • "Count the power generation equipment"

5. Developer-Friendly

Adding new query capabilities is simple:

[KernelFunction("get_voltage_levels")]
[Description("Get all voltage levels in the network")]
public async Task<string> GetVoltageLevelsAsync()
{
    // Implementation
}

The LLM automatically discovers and uses new functions!


Future Enhancements

1. Streaming Responses

Implement token-by-token streaming for faster perceived response times.

2. Multi-Document Queries

Enable queries across multiple CIM documents simultaneously.

3. Advanced Analytics

Add plugins for:

  • Power flow calculations
  • Network topology analysis
  • Compliance checking

4. Visualization Generation

Generate diagrams and charts based on natural language requests:

User: "Show me a network diagram of all substations"
AI: Generates SVG/PNG diagram

5. Memory Persistence

Store conversation history in database for: - Session recovery - Audit trails - Learning from user patterns


Troubleshooting

Issue: "No document context set"

Cause: User asked a question without selecting a document.

Solution: Either: - Select document from dropdown before chatting - Ask with explicit document ID: "Query document ABC123..."


Issue: "Ollama connection failed"

Cause: Ollama is not running or wrong endpoint.

Solution:

  1. Start Ollama: ollama serve
  2. Pull model: ollama pull qwen2.5:14b-instruct
  3. Verify endpoint in appsettings.json

Issue: "Function calls not working"

Cause: Model doesn't support function calling or wrong settings.

Solution:

  1. Use a function-calling capable model (qwen2.5, llama3, mistral)
  2. Ensure FunctionChoiceBehavior.Auto() is set
  3. Check model supports OpenAI function calling format

Issue: "Responses are generic, not using functions"

Cause: System prompt might be ignored or model temperature too high.

Solution:

  1. Verify system prompt includes function instructions
  2. Set temperature to 0.0 for deterministic function calling
  3. Add explicit instruction in user message: "Use the available functions to answer this"

References


Summary

The Semantic Kernel integration in GridLab.Gmss.Cim demonstrates how modern AI orchestration can transform complex domain-specific queries into natural conversations. By combining:

  • Semantic Kernel for AI orchestration
  • Ollama for local LLM execution
  • Custom Plugins for domain-specific operations
  • SignalR for real-time communication

We've created an intuitive interface that makes CIM document querying accessible to non-technical users while maintaining the full power and precision of structured queries under the hood.