O295 Semantic Kernel - Farvekategorisering
I denne opgave skal du skabe en konsolapplikation der bruger Semantic Kernel og OpenRouter til at kategorisere farver til standard farver.
Applikationen skal kunne:
- Tage imod en farve som input (f.eks. “lyseblå”, “pink”, “mørkerød”)
- Bruge en LLM til at kategorisere farven til en af de 7 grundfarver: rød, gul, grøn, blå, lilla, orange eller hvid
- Returnere svaret som JSON med felterne
input,categoryogconfidence
Eksempel på kørsel:
Indtast en farve (eller 'exit'): lyseblå
{"input":"lyseblå","category":"blå","confidence":"høj"}
Indtast en farve (eller 'exit'): pink
{"input":"pink","category":"rød","confidence":"medium"}
Indtast en farve (eller 'exit'): himmelblå
{"input":"himmelblå","category":"blå","confidence":"høj"}
Indtast en farve (eller 'exit'): exit
Krav:
- Brug OpenRouter med en valgfri model (f.eks.
mistralai/mistral-small-3.2-24b-instructelleropenai/gpt-4o-mini) - få API nøgle fra instruktøren. - Brug en system message til at instruere LLM’en om at returnere JSON
- JSON skal være valid og kunne deserialiseres til en C# record
- Confidence skal være enten “høj”, “medium” eller “lav”
Tips:
- Husk at instruere LLM’en om IKKE at inkludere markdown formatering (```json) i outputtet
- Brug
JsonSerializer.Deserialize<ColorResponse>()til at parse svaret - Hvis farven er ukendt eller svær at kategorisere, kan LLM’en vælge den nærmeste farve med lav confidence
Ekstra udfordring:
Udvid programmet til også at returnere en kort forklaring på hvorfor farven blev kategoriseret sådan (tilføj et explanation felt i JSON’en).
Klik for at se et forslag til en løsning
using System.Text.Json;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
// Konfiguration
const int MAX_RETRY_ATTEMPTS = 2;
/// <summary>
/// Farve kategorisering program der bruger AI til at klassificere farver.
/// Programmet tager brugerens farve input og kategoriserer det til en af 7 grundfarver
/// med retry-logik for robust JSON parsing.
/// </summary>
// Opret Semantic Kernel med OpenRouter AI service
var builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion(
modelId: "mistralai/mistral-small-3.2-24b-instruct",
apiKey: Environment.GetEnvironmentVariable("OpenRouterKey", EnvironmentVariableTarget.Machine)!,
endpoint: new Uri("https://openrouter.ai/api/v1"));
Kernel kernel = builder.Build();
var chatService = kernel.GetRequiredService<IChatCompletionService>();
ChatHistory chat = new ChatHistory();
// System prompt der definerer AI'ens rolle og outputformat
chat.AddSystemMessage("""
Du er en farveekspert der kategoriserer farver til en af følgende 7 grundfarver:
rød, gul, grøn, blå, lilla, orange eller hvid.
Du skal returnere et JSON objekt med følgende struktur:
{
"input": "den originale farve brugeren skrev",
"category": "en af de 7 grundfarver",
"confidence": "høj, medium eller lav"
}
Regler:
- Lyse/mørke varianter kategoriseres til grundfarven (lyseblå -> blå, mørkerød -> rød)
- Pastelfarver kategoriseres til deres grundfarve (pink -> rød, mint -> grøn)
- Brug "høj" confidence for klare farver, "medium" for pastelfarver, "lav" for sjældne/uklare farver
- Returner UDELUKKENDE valid JSON uden markdown formatering (ingen ```json tags)
Eksempler:
Input: "lyseblå" -> {"input":"lyseblå","category":"blå","confidence":"høj"}
Input: "pink" -> {"input":"pink","category":"rød","confidence":"medium"}
Input: "turkis" -> {"input":"turkis","category":"blå","confidence":"medium"}
""");
// JSON deserialisering indstillinger
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
// Hovedloop for brugerinteraktion
while (true)
{
Console.Write("Indtast en farve (eller 'exit'): ");
var input = Console.ReadLine() ?? "";
if (input.ToLower() == "exit")
break;
// Tilføj brugerens input til chat historik
chat.AddUserMessage(input);
// Forsøg at få et gyldigt farve-svar med retry-logik
var colorResponse = await TryGetColorResponseAsync(chatService, chat, options);
// Vis det kategoriserede resultat
Console.WriteLine($"Kategoriseret: {colorResponse.Input} -> {colorResponse.Category} (confidence: {colorResponse.Confidence})");
// Nulstil chat historik for næste farve (behold kun system message)
while (chat.Count > 1)
{
chat.RemoveAt(chat.Count - 1);
}
}
/// <summary>
/// Forsøger at få et gyldigt ColorResponse fra AI service med retry-logik.
/// Hvis JSON parsing fejler, prøves igen op til MAX_RETRY_ATTEMPTS gange.
/// Hvis alle forsøg fejler, returneres en ColorResponse med null værdier.
/// </summary>
/// <param name="chatService">Chat completion service til AI kommunikation</param>
/// <param name="chat">Chat historik med system message og bruger input</param>
/// <param name="options">JSON serialisering indstillinger</param>
/// <returns>ColorResponse objekt - enten parsed fra AI eller med null værdier</returns>
static async Task<ColorResponse> TryGetColorResponseAsync(IChatCompletionService chatService, ChatHistory chat, JsonSerializerOptions options)
{
for (int attempt = 1; attempt <= MAX_RETRY_ATTEMPTS; attempt++)
{
// Få svar fra AI service
var response = await chatService.GetChatMessageContentAsync(chat);
var responseString = response.ToString();
try
{
// Forsøg at parse JSON response
var colorResponse = JsonSerializer.Deserialize<ColorResponse>(responseString, options);
// Vis succesfuldt svar med attempt nummer hvis relevant
Console.WriteLine($"Svar{(attempt > 1 ? $" (forsøg {attempt})" : "")}: {responseString}");
return colorResponse!;
}
catch (Exception ex)
{
// Log parsing fejlt med attempt nummer
Console.WriteLine($"Forsøg {attempt} fejlede med JSON parsing: {ex.Message}");
// Hvis dette var sidste forsøg, returner fallback
if (attempt == MAX_RETRY_ATTEMPTS)
{
Console.WriteLine("Returnerer JSON med null værdier");
return new ColorResponse(null, null, null);
}
}
}
// Denne linje nås aldrig, men compiler kræver return statement
return new ColorResponse(null, null, null);
}
/// <summary>
/// Repræsenterer et farve kategorisering svar fra AI systemet.
/// Alle felter er nullable for at håndtere parsing fejl.
/// </summary>
/// <param name="Input">Den originale farve som brugeren indtastede</param>
/// <param name="Category">Kategoriseret grundfarve (rød, gul, grøn, blå, lilla, orange, hvid)</param>
/// <param name="Confidence">Confidence niveau (høj, medium, lav)</param>
public record ColorResponse(string? Input, string? Category, string? Confidence);