Meiner Meinung nach sollte jedes versendete Email 1 Cent kosten und dafür die absurden Regeln bezüglich Spam fallen. Das haben sich Microsoft und andere Cloud Anbieter auch gedacht. Weil aber die Rechenzentrum leer liefen, hat man sich einen Workload gesucht und in AI gefunden. Sicherheitshalber bei OpenAI, die eigentlich einen Open Gründungsgedanken hatten, dicke eingekauft.
So hat man heute die Wahl zwischen der Azure API und OpenAI Api. Den Standard haben letztere gesetzt,
Nun muss man das Zeugs auch nutzen können und da geht es zu wie im wildem Westen. Erinnert mich an die Ajax Zeit. Jeder will dir morgens um halb 10, zum Knoppers, ein neues Framework platzieren. Microsoft ist mit Semantic Kernel dabei. Eine Art Klon von Langchain aber für .NET Entwickler.
Leider oder Gott sei Dank, erstreckt sich der Wildwuchs auch über die Modelle und so muss Semantic Kernel eine Unzahl an Providern bereit stellen für den Zugriff auf das LLM.
Unter meinem Radar wurde vor ein paar Wochen nun ein neuer Ansatz für Function Calling implementiert. Müsste ab Version 1.21 sein. Zum Zeitpunkt des Blog Artikel ist 1.27 von Microsoft.SemanticKernel aktuell.
Was ist Function Calling
Large Language Models sind statische, statuslose Rechenmodelle mit Input und Output. Im Sinne von 1+1=2. Das was wir heute von ChatGPT als LLM kennen geht aber weit über das hinaus. Wie sie es machen, keine Ahnung. Wenn nun dem LLM eine Frage gestellt wird oder eine Problem zur Lösung vorgelegt wird, für das Modell weitere Infos braucht, dann ist Functions ein Lösungsansatz.
Wenn das LLM eine Frage erkennt, versucht es die Lables zu extrahieren, die Funktion aufzurufen und in Antwort einzubetten.
Ich habe hier OpenAI genutzt. Für den API Key braucht es einen Bezahlaccount,
Wir erstellen innerhalb einer Klasse eine oder mehrere Functions. Unser fikties Problem ist das Wetter an einem bestimmten Ort zu klären. Das kann ein LLM nicht wissen.
Über den Namensraum using Microsoft.SemanticKernel steht als Attribut KernelFunction bereit. Diesem übergeben wir einen Beschreibungstext, ebenso den Parametern. LLM löst diese Texte über seinen Token Vektorisierung auf. Für uns ist nur wichtig, das die Beschreibung gut genug ist.
1: public class WeatherPlugin
2: {
3: [KernelFunction, Description("liefert das Wetter für einen bestimmten Ort")]
4: public async Task<string> GetWeatherAsync([Description("der Ort")] string Ort)
5: {
6: // Optional: JSON verarbeiten und Daten auslesen
7: return $"Das Wetter in Wien ist 10° bei Schneefall und Sonnenschein ";
8: }
9: }
Klappt das auch mit PHI-3.5 offline
leider heute nicht. Man kann ein LLM in den Adressraum der .NET Anwendung laden. Wahrscheinlicher aber wird man eine Runtime wie Ollama nutzen um das LLM zu laden und per API zu befragen.
AI Connector |
FunctionChoiceBehavior |
ToolCallBehavior |
Anthropic |
Planned |
❌ |
AzureAIInference |
Coming soon |
❌ |
AzureOpenAI |
✔️ |
✔️ |
Gemini |
Planned |
✔️ |
HuggingFace |
Planned |
❌ |
Mistral |
Planned |
✔️ |
Ollama |
Coming soon |
❌ |
Onnx |
Coming soon |
❌ |
OpenAI |
✔️ |
✔️ |
Chat with .NET
Ich beginne mit dem was wir nicht mehr benötigen : using Microsoft.SemanticKernel.Connectors.OpenAI;. Der Grund, wenn man nach Source Code sucht, ist es kaum mögllich herauszufinden auf welche Nuget Paket Versionen dieser sich bezieht.
Der Rest ist üblicher Semnatic Kernel C# Sample Code
1:
2: IKernelBuilder builderOpenAI = Kernel.CreateBuilder()
3: .AddOpenAIChatCompletion("gpt-4", "key");
4: Kernel kernelOpenAI = builderOpenAI.Build();
Nun kann das Plugin geladen werden. In der Praxis wird man nicht nur eines benötigen um Zugriff auf SQL Tabellen, PDF oder was auch immer umzusetzen.
Die eigentliche Neuerung passiert ab Zeile 3. Auto bedeutet das das LLM selbst entscheidet ob die Funktion aufgerufen werden soll. Daneben existiert Required und None. Optional kann man auch eine Liste von KernelFunctions übergeben und spezifische AutoInvoke festlegen.
Da Microsoft dieses Paket als Experimentell bezeichnet und sich dann der Compiler weigert dies zu kompilieren, muss man dieses Pragma Dingens in den Code einfügen. Was für ein Unsinn.
1: kernelOpenAI.Plugins.AddFromType<WeatherPlugin>();
2: #pragma warning disable SKEXP0001
3: PromptExecutionSettings settings = new()
4: {
5: FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
6: };
Ist wirklich einfach geworden, wenn man weis wie.
Nun kommen wir zum Teil wie das Wetter in Wien ist. Aber ich stelle die Frage ganz anders
var result0 = await kernelOpenAI.InvokePromptAsync(
"brauche ich eine Jacke in Wien heute",
new KernelArguments(settings)
Das Ergebnis per Console und Writeline
Um zu meinem Eingangsstatement zu kommen. Was hats gekostet? Drei Cent, verrechnet Open AI für den Api Call.
Nicht nur aus diesem Grund forsche ich auf daran, wie man das ganze lokal betreiben kann.