Format: Practical demo-oriented course focused on evaluating and leveraging generative AI
Table of Contents
- Introduction
- Module 1 — Evaluating and Leveraging Generative AI
- Module 2 — Creating an Agent with Semantic Kernel and the OpenAI Chat Completions API
- Module 3 — Extending Agentic Behavior with Plugins and Native Functions
- Module 4 — Enhancing Agent Knowledge with RAG, InMemory Vector Store, OpenAI Embeddings and Semantic Kernel
- Overall Course Architecture
- Summary and Key Points
Introduction
This course shows how to evaluate and leverage generative AI in real-world contexts. It covers four main areas:
- Understanding what generative AI means for developers and organizations
- Creating a basic AI agent with Semantic Kernel and the OpenAI Chat Completions API
- Extending agent intelligence via plugins and native functions
- Enhancing agent knowledge by referencing contextual and accurate data through RAG
flowchart LR
A[Evaluate use cases] --> B[Create an agent]
B --> C[Extend with plugins]
C --> D[Enrich with RAG]
D --> E[Intelligent agent grounded in your data]
Module 1 — Evaluating and Leveraging Generative AI
What Generative AI Means for Developers
This is an exceptional time to be a developer. Recent AI advances — particularly over the past 24 months — have transformed development practices. Generative AI offers several concrete benefits:
Optimizing the Development Workflow
| Benefit | Description |
|---|---|
| Boilerplate code generation | A concise set of prompts is enough for a model to produce 50–60% of required boilerplate code |
| Feature implementation | By precisely expressing a feature and its context, AI can generate 70–80% of it |
| Real-time pair programming | Instant suggestions, code snippets, explanations — without waiting for a forum response |
| Test data generation | Rather than hand-coding every combination, instruct the model to generate request combinations with their parameters |
| Automated code reviews | GitHub Copilot can improve code quality by offering automated reviews |
| Automatic documentation | Generate Markdown documentation from automatically generated code |
| Technical summaries | Synthesize an existing codebase to navigate hundreds of lines of code |
Concrete example: For a settings screen in a .NET Core application — input fields, business logic, HTML view, .NET controller, JavaScript to toggle API key field visibility — a single prompt was enough to generate 70–80% of the required code, saving several hours of development.
Generative AI as an Internal Knowledge Base
Information assets produced by generative AI — code documentation, technical summaries, API definitions — can be ingested into an information store like Azure Search or Elasticsearch to form an internal knowledge base.
flowchart TD
A[Source code] --> B[Generative AI]
B --> C[Automatic documentation]
B --> D[Technical summaries]
B --> E[API definitions]
C --> F[Azure Search / Elasticsearch]
D --> F
E --> F
F --> G[Internal knowledge base]
Identifying and Prioritizing Use Cases
Key Evaluation Metrics
Prioritize use cases that closely align with business objectives or current pain points:
mindmap
root((Evaluation Metrics))
Cost Reduction
Labor reduction
Process optimization
Improved decision-making
Revenue Growth
Improved customer satisfaction
Higher conversion rates
Market expansion
Risk Management
Fraud and anomaly detection
Regulatory compliance
Customer churn reduction
Cost reduction: Compare the current cost of processes versus an AI approach.
Revenue growth: Use generative AI to detect patterns in customer correspondence and respond accordingly. Smart models can reveal patterns in customer behavior to boost conversion rates.
Risk management: Generative AI can detect fraudulent patterns and anomalies by analyzing large datasets. It can also measure and mitigate customer churn by automating trend detection and providing predictive analytics.
Pilot Program Approach
The best way to evaluate the ROI of a generative AI solution is to implement a pilot program:
flowchart LR
A[Identify use cases] --> B[Define clear objectives]
B --> C[Define measurable metrics]
C --> D[Start small]
D --> E[Collect data]
E --> F[Iterate]
F --> G[Scale]
style A fill:#e8f4f8
style D fill:#fff3cd
style G fill:#d4edda
Key steps:
- Identify use cases through traditional business analysis, inventory of existing data sources, or identifying current pain points
- Interact with a model — explain your current challenges and ask for suggestions
- Target low-hanging fruit at first to minimize risk
- Set clear objectives — manage stakeholder expectations, define measurable outcomes
- Start small — minimize risk and resource management
- Adopt an iterative approach — refine before scaling
Tools for Implementing Generative AI
Overview of Main Tools
mindmap
root((Gen AI Tools))
Microsoft
Azure AI Foundry
Azure AI Services
GitHub Copilot
Semantic Kernel
OpenAI
GPT-4 / GPT-4o
Embeddings ada-002
Others
Google Gemini
Hugging Face
Midjourney
Toolhouse
Audio Notes
Azure AI Foundry
New Microsoft product — an end-to-end solution for developing, deploying, and optimizing generative AI models tailored to business needs:
- Custom model development (Bring Your Own Data)
- Access to leading AI models and additional AI services
- Built-in governance and compliance tools to ensure responsible AI practices
Azure AI Services
General term for many AI tools:
- Access to small and large language models
- Accessible via containers, SDKs and APIs
- Capabilities: reading, comprehension, listening, searching, data processing
- Enable augmenting existing software with AI capabilities
GitHub Copilot
Powered by generative AI, Copilot:
- Produces automated code suggestions
- Completes functions and automates repetitive tasks in real time
- Coupled with Microsoft Graph connectors, enables integrations with Teams, Outlook, Word
- Reduces the need to memorize obscure syntax in Visual Studio
Semantic Kernel
Open-source SDK designed to simplify creating agents that can interface with existing code:
| Feature | Detail |
|---|---|
| Type | Open-source SDK |
| Supported models | OpenAI, Azure OpenAI, Hugging Face, and more |
| Goal | Rapid agent creation with language model integrations |
| Key advantage | No need to learn the internals of LLM providers, APIs, or low-level function calling |
Other Notable Tools
| Tool | Usage |
|---|---|
| Audio Notes | Creating concise notes from spoken words, video transcription |
| Google Gemini | Multimodal inputs, text generation, image creation, complex data analysis |
| Midjourney | Image generation for founders, designers, marketers and creators |
| Toolhouse | Platform to simplify LLM integration, letting developers focus on agents without managing complex integrations |
Key principles: Start small, implement the strict minimum, collect data throughout the pilot program, and iterate.
Module 2 — Creating an Agent with Semantic Kernel and the OpenAI Chat Completions API
Introduction to AI Agents
An AI agent is a system capable of understanding natural language instructions, maintaining conversation history, and generating contextual responses by interacting with a large language model (LLM).
sequenceDiagram
participant U as User
participant A as Agent (console)
participant SK as Semantic Kernel
participant LLM as OpenAI GPT-4
U->>A: Types a question
A->>SK: Adds to ChatHistory
SK->>LLM: Sends history + prompt
LLM-->>SK: Generates a response
SK-->>A: Returns the response
A->>A: Adds response to ChatHistory
A-->>U: Displays the response
Prerequisites: Obtain OpenAI API keys at platform.openai.com
Demo — Creating a Minimal Agent
C# Code Structure
// Required Semantic Kernel namespaces
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
// Configuration
const string apiKey = "your-openai-api-key";
const string modelId = "gpt-4o";
// 1. Create the kernel — orchestrator for LLM interactions
var builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion(modelId, apiKey);
Kernel kernel = builder.Build();
// 2. Initialize chat history with a meta-prompt (system prompt)
var chatHistory = new ChatHistory();
chatHistory.AddSystemMessage(
"You are an enthusiastic and helpful assistant. Always respond with positivity."
);
// 3. Get the chat completion service
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
// 4. Conversational loop
while (true)
{
Console.Write("You: ");
string userInput = Console.ReadLine()!;
// Add user message to history
chatHistory.AddUserMessage(userInput);
// Invoke the chat completion service
var response = await chatCompletionService.GetChatMessageContentAsync(
chatHistory,
kernel: kernel
);
// Display and record the response
Console.WriteLine($"Assistant: {response.Content}");
chatHistory.AddAssistantMessage(response.Content!);
}
Key Points
- The kernel is responsible for orchestrating all interactions with the language model
- ChatHistory is the object that maintains conversation context — human and assistant messages
- The meta-prompt (system message) defines the agent’s tone and behavior
- Changing the meta-prompt radically changes agent behavior (enthusiastic response vs. formal response)
In summary: In just a few lines of code, Semantic Kernel connects to an LLM via OpenAI and creates a complete conversational experience.
Module 3 — Extending Agentic Behavior with Plugins and Native Functions
Semantic Kernel Core Concepts
The kernel is composed of three main components:
flowchart TD
K[Kernel — Central Orchestrator] --> AC[AI Connectors]
K --> DC[Data Connectors]
K --> P[Plugins]
AC --> |"Azure OpenAI, Phi-3, custom models"| LLM[Language Models]
AC --> |"Common abstraction"| TG[Text Generation & Embeddings]
DC --> |"Vector databases"| VDB[Vector Databases]
VDB --> |"In-memory (prototypes)"| IM[InMemory Store]
VDB --> |"Enterprise"| ES[Azure AI Search / Elasticsearch]
P --> |"Prompts + business logic"| NF[Native Functions]
NF --> |"Decorated in natural language"| AUTO[Automatic Function Calling]
AI Connectors
- Facilitate integration with AI models (Azure OpenAI, Phi-3, custom models)
- Provide a common abstraction for text generation and embeddings
- Unified developer experience regardless of the underlying model
Data Connectors
- Enable interaction with vector databases required by the application
- The kernel does not use any registered vector database by default — this is the developer’s responsibility
- For rapid prototypes: in-memory store; for enterprise: Azure AI Search, Elasticsearch, etc.
Plugins and Native Functions
- Plugin: encapsulates multiple prompts or business logic into a single reusable component
- A native function is an ordinary .NET method decorated with natural language
- In a single line of code, a plugin becomes discoverable by the kernel
- The kernel automatically identifies and selects the most relevant plugin based on the prompt
Automatic Function Calling — How It Works
sequenceDiagram
participant U as User
participant SK as Semantic Kernel
participant LLM as AI Model
participant P as Plugin / Native Function
U->>SK: Submits a prompt
SK->>LLM: Transmits prompt + list of available functions
LLM->>LLM: Analyzes user intent
LLM->>LLM: Extracts required parameters
LLM->>LLM: Determines if a function call is required
alt Function call required
LLM->>SK: Function call request with parameters
SK->>P: Invokes native function
P-->>SK: Returns result
SK->>LLM: Provides result
LLM->>SK: Generates enriched response
else No function call
LLM->>SK: Generates normal response
end
SK-->>U: Final response
Semantic Kernel handles all low-level orchestration — the developer does not need to implement function calling manually.
Demo — Extending Agent Behavior
Use case: Health and fitness agent that suggests exercises based on the user’s goals.
Plugin Architecture
Project/
├── program.cs ← Agent entry point
└── Plugins/
├── CardioPlugin.cs ← Cardio exercises (low impact + regular)
└── StrengthTrainingPlugin.cs ← Strength exercises by muscle group
CardioPlugin — Native Functions
public class CardioPlugin
{
[KernelFunction("GetLowImpactCardioActivities")]
[Description("Suggests low-impact cardio activities suitable for people " +
"with physical limitations or seeking gentle exercise.")]
public string GetLowImpactCardioActivities()
{
return """
Available low-impact cardio activities:
1. Walking
2. Swimming
3. Cycling
4. Rowing
5. Elliptical training
""";
}
[KernelFunction("GetRegularCardioActivities")]
[Description("Suggests regular cardio activities to improve " +
"cardiovascular endurance.")]
public string GetRegularCardioActivities()
{
return """
Available regular cardio activities:
1. Running
2. Jumping rope
3. HIIT (High-Intensity Interval Training)
4. Aerobics
5. Dancing
""";
}
}
StrengthTrainingPlugin — With Parameter
public class StrengthTrainingPlugin
{
[KernelFunction("GetStrengthExercises")]
[Description("Suggests strength exercises based on the muscle group " +
"the user wants to target.")]
public string GetStrengthExercises(
[Description("The muscle group to target. " +
"Possible values: chest, back, shoulders, legs, arms")]
string muscleGroup)
{
return muscleGroup.ToLower() switch
{
"chest" => "Bench Press, Push-ups, Cable Fly",
"back" => "Pull-ups, Barbell Row, Deadlift",
"shoulders" => "Overhead Press, Lateral Raises, Front Raises",
"legs" => "Squat, Lunges, Leg Press",
"arms" => "Bicep Curl, Tricep Extension, Hammer Curl",
_ => "Muscle group not recognized. Try: chest, back, shoulders, legs, arms"
};
}
}
Configuration in program.cs
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
const string apiKey = "your-openai-api-key";
const string modelId = "gpt-4o";
// 1. Create the kernel and register plugins
var builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion(modelId, apiKey);
// Make plugins discoverable by the kernel and the LLM
builder.Plugins.AddFromType<CardioPlugin>();
builder.Plugins.AddFromType<StrengthTrainingPlugin>();
Kernel kernel = builder.Build();
// 2. Configure automatic function calling
var executionSettings = new OpenAIPromptExecutionSettings
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};
// 3. Initialize history with the meta-prompt
var chatHistory = new ChatHistory();
chatHistory.AddSystemMessage(
"You are a health and fitness assistant. Help users reach their " +
"goals by suggesting appropriate exercises."
);
var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
// 4. Conversational loop
while (true)
{
Console.Write("You: ");
string userInput = Console.ReadLine()!;
chatHistory.AddUserMessage(userInput);
var response = await chatCompletionService.GetChatMessageContentAsync(
chatHistory,
executionSettings,
kernel
);
Console.WriteLine($"Assistant: {response.Content}");
chatHistory.AddAssistantMessage(response.Content!);
}
Results Observed in Demo
| User Prompt | Plugin Invoked | Result |
|---|---|---|
| ”What low-impact cardio activities are available?” | CardioPlugin.GetLowImpactCardioActivities | Walking, Swimming, Cycling, Rowing, Elliptical + additional LLM-generated info |
| ”Regular cardio activities?” | CardioPlugin.GetRegularCardioActivities | Running, Jumping rope, HIIT, Aerobics, Dancing + enriched context |
| ”Exercises for the back?” | StrengthTrainingPlugin.GetStrengthExercises(muscleGroup: "back") | Pull-ups, Rows, Deadlifts — the SDK automatically extracts "back" from the prompt |
RAG in action: The LLM augments the plugin response with additional contextual information, creating an enriched experience without the plugin containing all the data.
Module 4 — Enhancing Agent Knowledge with RAG, InMemory Vector Store, OpenAI Embeddings and Semantic Kernel
RAG Core Concepts
RAG (Retrieval-Augmented Generation) combines AI generation with existing information you already have access to — data the model has not yet been trained to know, but that you want to include in processing.
flowchart LR
U[User] --> |Prompt| R[Retriever]
R --> |Vectorizes the prompt| VS[Vector Store]
VS --> |Results by similarity| G[Generator LLM]
DB[(Existing data\ne.g. last 30 days feedback)] --> VS
G --> |Enriched and accurate response| U
style VS fill:#fff3cd
style G fill:#d4edda
Key components:
| Component | Role |
|---|---|
| Retriever | Service that accepts input and fetches existing information to complete the prompt |
| Vector Embeddings | Numerical representation of the semantic meaning of text |
| Vector Database | Stores and enables efficient retrieval of embeddings |
| Generator | Uses retrieved information to produce responses |
Vector Embeddings — Understanding Semantic Similarity
Vector embeddings represent the semantic meaning of text in numerical format. They enable searches based on meaning rather than exact text.
flowchart TD
T["Text: 'Hello World'"] --> E[Embeddings model\nada-002]
E --> V["[0.0023, -0.0156, 0.0891, ...]\n(truncated vector for example)"]
V --> DB[(Vector Database\nEx: Elasticsearch)]
Cosine Similarity — Search Algorithm
The cosine similarity algorithm measures the angle between two vectors:
flowchart LR
A["Value = 1"] --> |"Identical vectors"| B[Perfect match]
C["Value = 0"] --> |"No similarity"| D[No relevant results]
E["0 < Value < 1"] --> |"Partial similarity"| F[Results ranked by relevance]
Typical processing workflow:
sequenceDiagram
participant U as User
participant A as Application
participant E as Embeddings API (ada-002)
participant VS as Vector Store
participant LLM as GPT-4o
U->>A: Submits a prompt
A->>E: Vectorizes the prompt
E-->>A: Prompt embedding
A->>VS: Cosine similarity search
VS-->>A: Top N results with scores
A->>LLM: Prompt + retrieved data (context)
LLM-->>A: Enriched and accurate response
A-->>U: Final response
Demo — Implementing a Complete RAG Agent
Use case: Strength training advisory agent that retrieves exercises from a vector database.
Required NuGet Package:
Microsoft.SemanticKernel.Connectors.InMemory (preview)
Project Structure
Project/
├── program.cs ← Entry point and orchestration
├── VectorModel/
│ └── ExerciseFact.cs ← Vector data model
├── Services/
│ └── VectorStoreService.cs ← Ingestion and vector store interaction
└── Plugins/
└── StrengthTrainingPlugin.cs ← RAG plugin with vector search
VectorModel — ExerciseFact.cs
using Microsoft.Extensions.VectorData;
public class ExerciseFact
{
[VectorStoreRecordKey]
public Guid Id { get; set; }
[VectorStoreRecordData]
public string Name { get; set; } = string.Empty;
[VectorStoreRecordData]
public string Description { get; set; } = string.Empty;
[VectorStoreRecordVector(Dimensions: 1536)]
public ReadOnlyMemory<float> DescriptionEmbedding { get; set; }
}
Decoration attributes:
[VectorStoreRecordKey]— unique record key[VectorStoreRecordData]— text data (Name, Description)[VectorStoreRecordVector]— numerical vector representation (DescriptionEmbedding)
ExerciseHelper — Training Data
public static class ExerciseHelper
{
public static List<ExerciseFact> GetExerciseFacts() => new()
{
new ExerciseFact
{
Id = Guid.NewGuid(),
Name = "Deadlift",
Description = "Compound exercise targeting the back, legs and core. " +
"Excellent for overall strength and muscle development."
},
new ExerciseFact
{
Id = Guid.NewGuid(),
Name = "Bench Press",
Description = "Horizontal push exercise primarily targeting the " +
"pectorals, anterior deltoids and triceps."
},
new ExerciseFact
{
Id = Guid.NewGuid(),
Name = "Squat",
Description = "Fundamental lower body exercise targeting " +
"quadriceps, hamstrings and glutes."
},
new ExerciseFact
{
Id = Guid.NewGuid(),
Name = "Pull-Up",
Description = "Pulling exercise targeting the latissimus dorsi, biceps and " +
"back muscles. Ideal for back strengthening."
},
new ExerciseFact
{
Id = Guid.NewGuid(),
Name = "Overhead Press",
Description = "Military press targeting the deltoids, triceps and " +
"core stability. Key exercise for shoulder development."
}
};
}
VectorStoreService — Data Ingestion
#pragma warning disable SKEXP0001, SKEXP0010
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.Extensions.VectorData;
public class VectorStoreService
{
private const string EmbeddingModelId = "text-embedding-ada-002";
private const string ApiKey = "your-openai-api-key";
private readonly OpenAITextEmbeddingGenerationService _embeddingService;
public VectorStoreService()
{
_embeddingService = new OpenAITextEmbeddingGenerationService(EmbeddingModelId, ApiKey);
}
public async Task IngestDataIntoVectorStore(
IVectorStoreRecordCollection<Guid, ExerciseFact> collection)
{
var exerciseFacts = ExerciseHelper.GetExerciseFacts();
foreach (var fact in exerciseFacts)
{
// Generate embedding for the description
var embeddings = await _embeddingService.GenerateEmbeddingsAsync(
new[] { fact.Description }
);
fact.DescriptionEmbedding = embeddings[0];
// Insert into vector store
await collection.UpsertAsync(fact);
}
}
}
StrengthTrainingPlugin — With RAG Vector Search
#pragma warning disable SKEXP0001
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.InMemory;
using Microsoft.Extensions.VectorData;
public class StrengthTrainingPlugin
{
private readonly InMemoryVectorStore _vectorStore;
private readonly OpenAITextEmbeddingGenerationService _embeddingService;
private readonly IChatCompletionService _chatCompletionService;
public StrengthTrainingPlugin(
InMemoryVectorStore vectorStore,
OpenAITextEmbeddingGenerationService embeddingService,
IChatCompletionService chatCompletionService)
{
_vectorStore = vectorStore;
_embeddingService = embeddingService;
_chatCompletionService = chatCompletionService;
}
[KernelFunction("GetStrengthExercises")]
[Description("Suggests a strength exercise based on the muscle group " +
"the person wants to target.")]
public async Task<string> GetStrengthExercisesAsync(
[Description("The muscle group to target (e.g.: chest, back, shoulders, legs, arms)")]
string muscleGroup)
{
// 1. Get the collection from the vector store
var collection = _vectorStore.GetCollection<Guid, ExerciseFact>("exercises");
// 2. Vectorize the search parameter (muscleGroup)
var queryEmbeddings = await _embeddingService.GenerateEmbeddingsAsync(
new[] { muscleGroup }
);
// 3. Perform vector search (top 1 result)
var searchResults = await collection.VectorizedSearchAsync(
queryEmbeddings[0],
new VectorSearchOptions { Top = 1 }
);
// 4. Collect results
var results = new List<ExerciseFact>();
await foreach (var result in searchResults.Results)
{
results.Add(result.Record);
}
// 5. Build RAG context for the LLM
var exerciseContext = string.Join("\n", results.Select(r =>
$"- {r.Name}: {r.Description}"
));
// 6. Ask the LLM to enrich with an exercise recommendation
var enrichmentPrompt = $"""
Based on the following exercise data:
{exerciseContext}
Provide a helpful recommendation for someone targeting their {muscleGroup}.
Include tips on proper form and how to get started.
""";
var chatHistory = new ChatHistory();
chatHistory.AddUserMessage(enrichmentPrompt);
var response = await _chatCompletionService.GetChatMessageContentAsync(chatHistory);
return response.Content ?? "No recommendation available.";
}
}
Overall Course Architecture
flowchart TD
subgraph M1["Module 1 — Evaluation"]
UC[Use case identification]
TOOLS[Tool selection]
end
subgraph M2["Module 2 — Basic Agent"]
KERNEL[Kernel creation]
HIST[ChatHistory]
LOOP[Conversational loop]
end
subgraph M3["Module 3 — Plugins"]
PLUGIN[Native functions]
AFC[Automatic Function Calling]
META[Meta-prompt]
end
subgraph M4["Module 4 — RAG"]
EMBED[Vector embeddings]
VS[Vector Store]
RAG[Contextual retrieval]
end
M1 --> M2 --> M3 --> M4
style M1 fill:#e8f4f8
style M2 fill:#e8f8e8
style M3 fill:#fff3cd
style M4 fill:#f3e8ff
Summary and Key Points
| Concept | Key Takeaway |
|---|---|
| GenAI for Developers | Saves 50–80% development time on boilerplate and common features |
| Pilot Program | Start small, measure ROI, iterate before scaling |
| Semantic Kernel | Open-source SDK that abstracts LLM complexity |
| Kernel | Central orchestrator for all LLM interactions |
| ChatHistory | Maintains conversational context across turns |
| Meta-prompt | System message defining agent tone and behavior |
| Plugins | Reusable components grouping native functions |
| Automatic Function Calling | LLM selects and invokes the right function automatically |
| RAG | Grounds responses in your existing, current data |
| Vector Embeddings | Numerical representations enabling semantic search |
| Cosine Similarity | Algorithm measuring semantic similarity between vectors |
Core message: Generative AI is most valuable when aligned with concrete business objectives. Start with a well-defined use case, measure impact, and iterate — the technology will amplify your efforts only if it addresses a real need.
Search Terms
aligning · generative · ai · business · cases · llm · application · development · artificial · intelligence · agent · semantic · kernel · rag · data · functions · native · tools · vector · architecture · azure · behavior · concepts · connectors