Wie Large Language Models den Kundenservice in Dynamics 365 unterstützen können - exemplarisch am Beispiel von Ollama

Geschrieben von Alan Rachid am 07.04.2025

Large Language Models (LLMs) sind in aller Munde und ich dachte mir, dass es Zeit wird ein wenig mehr mit diesen zu experimentieren und abseits der täglichen Nutzung in meinen Arbeitsalltag herauszufinden, wie diese eingesetzt werden können.

Hierbei springe ich bewusst nicht auf dem Zug auf, der uns allen erzählt, wie bunt und toll die Welt wird, wenn uns autonome KI-Agenten in „nicht absehbarer“ Zeit ersetzen und unsere Arbeit übernehmen, sondern habe mir ein Anwendungsszenario überlegt, bei dem ein LLM eine Benutzer:in einer Geschäftsanwendung unterstützt. Wichtig war es mir hierbei auch herauszufinden, inwieweit man bei dem Einsatz von LLMs auch gewisse datenschutzrelevante Spannungsfelder berücksichtigen kann. Genau gesagt wollte ich herausfinden, ob man mit selbst gehosteten LLMs die Modelle der großen Technologieanbieter wie ChatGPT, Microsoft Copilot etc., ersetzen kann.

Zusammengefasst: In diesem Blogbeitrag beschreibe ich, wie ein Large Language Model mit Hilfe von Ollama als Docker Container „lokal“ in Form einer Azure Container Instance gehostet und mit einer Azure Function aufgerufen wird, um eine Serviceanfrage aus Microsoft Dynamics 365 Customer Service mit Schlagworten zu versehen, so dass die Anfrage nachgelagert z.B. in eine entsprechende Queue vorsortiert werden kann. Hierbei gehe ich kurz auf Large Language Models ein, beschreibe was Ollama ist und zeige Schritt für Schritt auf, wie ich mein Anwendungsszenario umgesetzt habe.

Was sind Large Language Model (LLM)?

Large Language Models sind eine Unterkategorie der natürlichen Sprachverarbeitung (Natural Language Processing, NLP), die es Computern ermöglichen soll, menschliche Sprache zu verstehen, zu interpretieren und zu erzeugen. Die Large Language Models haben das Ziel menschenähnliche Textantworten zu generieren. Um Ihnen dies zu ermöglichen, wurden sie mit einer großen Menge an Texten trainiert. Hierdurch sind die Modelle in der Lage Muster, Zusammenhänge und Bedeutungen in der Sprache zu erkennen.

Im Zusammenhang mit LLMs wird auch oft der Begriff der generativen KI genutzt. LLMs sind nicht gleichzusetzen mit generativer KI, sondern sind ein Bauteil dieser. Generative KI umfasst alle Technologien, die Inhalte (Text, Bild, Musik) eigenständig erzeugen können. Microsoft Copilot, ChatGPT und andere sind generative und vortrainierte Modelle, die als cloudbasierte Services laufen und Daten an externe Server zur Verarbeitung schicken können. Um die externe Verarbeitung von kritischen Daten zu verhindern, kann man auf Dienste zurückgreifen, die LLMs lokal auf einem Rechner ausführen, ohne hierbei Daten an Dritte zu verschicken. Ollama ist solch ein Dienst. Mithilfe von Ollama können eine Vielzahl von LLMs wie Llama oder Phi genutzt werden, ohne hierbei die Komplexität der Installation und Konfiguration der Modelle zu haben. Die Modelle können einfach als Docker-Container lokal ausgeführt werden.

Das Anwendungsszenario: Automatisierte Verschlagwortung einer Serviceanfrage in Dynamics 365 Customer Service mithilfe von Large Language Models

Bei der Nutzung von Microsoft Dynamics 365 Customer Service helfen Warteschlangen bei der schnellen Bearbeitung von Serviceanfragen, indem Anfragen unter anderem thematisch vorsortiert werden können. Das Vorsortieren kann je nach Reifegrad eines Serviceprozesses entweder manuell durch eine Mitarbeiter:in vorgenommen werden oder automatisch durch Routing-Regelsätze, die nach einfachen Suchkriterien („Betreff enthält Wort „X“) eine Anfrage automatisch zuordnen. Wir möchten nun mithilfe eines LLMs das automatische Routing verbessern, indem wir den Anfragentext mithilfe des LLMs nach Schlagwörtern durchsuchen, um diese dann nachgelagert für ein Routing zu nutzen.

  • Microsoft Dynamics 365 Customer Service: Die Serviceanfrage ist Teil der First-Party App zur Verwaltung von Serviceprozessen. In unserem Szenario werden wir auf diese Tabelle zurückgreifen. Damit eine Verschlagwortung der Serviceanfrage möglich ist, legen wir die neue Tabelle „Kategorie“ an. Diese Tabelle hat nur ein relevantes Feld „Name“ und eine N:M-Beziehung zu der Serviceanfrage. Wir möchten es ermöglichen, dass eine Serviceanfrage zu mehreren Kategorien zugeordnet werden kann und eine Kategorie mit mehreren Serviceanfragen.
  • Azure Functions: Die Kommunikation mit dem Large Language Model wird über eine Azure Function abgebildet. Die Azure Function wird mithilfe eines http-Triggers aus dem CRM aufgerufen. Dies passiert nach der Anlage der Serviceanfrage. Sobald diese erstellt wurde, wird die Azure Function mit dem Query-Parameter caseId aufgerufen. Die caseId enthält die Guid der Serviceanfrage. Innerhalb der Azure Function erstellen wir einen Prompt und schicken diesen an unser selbst gehostetes LLM.
  • Azure Container Registry: Hier legen wir unser Docker Image ab, um daraus einen Container zu erstellen.
  • Azure Container Instances: Dies ist ein Service von Microsoft Azure, der es ermöglicht, Container-Anwendungen direkt in der Cloud auszuführen. Wir werden das Docker-Image von Ollama hier hosten, sodass die Azure Function die Prompts gegen diese Container Instance schickt.

Der generelle Ablauf ist also wie folgt: In Dynamics 365 Customer Service pflegen wir Kategorien, zu denen Serviceanfragen zugeordnet werden können. Wenn eine Serviceanfrage angelegt wird, rufen wir automatisch eine Azure Function auf. Diese Azure Function holt sich die Beschreibung der Serviceanfrage sowie alle Kategorien und erstellt hieraus einen Prompt. Dieser Prompt wird an ein LLM geschickt, welches wir mithilfe von Ollama in einer Azure Container Instance laufen lassen. Zu guter Letzt schickt die Azure Function identifizierte Kategorien an das CRM zurück, sodass ein Routing der Anfrage vorgenommen werden kann.

Hands on: Dynamics 365 Customer Service erweitern und neue Tabelle anlegen

Nachfolgend zeige ich die Schritte auf, die ich durchgefüht habe, um das oben beschriebene Szenario umzusetzen. Zunächst erweitern wir Dynamics 365 Customer Service.

Wir legen unsere neue Entität „Kategorie“ an. Hierfür öffnen wir make.powerapps.com und klicken in der Navigation auf „Solutions/Lösungen“. Nachdem wir eine neue Lösung „LLMPlayground“ angelegt haben, fügen wir dieser eine neue Tabelle hinzu. Die Tabelle nennen wir „Kategorie“ und stellen sicher, dass auf dem Hauptformular das Namensfeld angezeigt wird. Nach der Anlage der Tabelle erstellen wir eine neue N:M-Beziehung zwischen der Kategorie und der Anfrage. Als letzten Schritt passen wir das Anfragenformular an und fügen ein Subgrid auf die Kategorien hinzu. Hierdurch können nun Kategorien, die durch unsere Azure Function identifiziert worden sind, direkt mit der Anfrage verknüpft werden.

Azure Container Instances aufsetzen und Ollama-Image mit dem LLM Phi3.5 deployen

Die Microsoft Dynamics 365 Customer Service App ist so weit vorbereitet, dass Anfragen automatisch mit Kategorien verschlagwortet werden können. Nun erstellen wir unseren Docker Container in Microsoft Azure. Hierfür muss zunächst ein Azure Container Registry angelegt werden. Dies ist ein Service aus der Azure Cloud, der es einem ermöglicht Container-Images und andere Artefakte privat und zentral zu verwalten. Um ein Azure Container Registry zu erstellen, nutzen wir die Azure CLI. Folgende Befehle müssen nacheinander ausgeführt werden:
Create Azure Container Registry with Azure CLI commads
Nun sollet ihr in der spezifizierten Ressourcengruppe ein neues Element vom Typ “Container Registry” sehen können. Als nächste bereiten wir unser Docker Image lokal vor. Ihr müsst also auf eurem Rechner Docker installiert haben. Hierfür empfiehlt sich Docker Desktop. Wenn ihr Docker Desktop bereits installiert habt, könnt ihr nun das offizielle Docker Image von Ollama laden und einen Container erstellen:
Create Docker Image with Ollama
In unserem Beispiel verwenden wir das LLM Phi3.5, welches von Ollama bereitgestellt wird. Phi3.5 wurde von Microsoft entwickelt und eignet sich nach Angaben von Microsoft für Anwendungen mit begrenztem Arbeitsspeicher und Rechenleistung. Mehr zu Phi3.5 findet ihr hier. Nachdem wir nun unseren Docker Container lokal aufgesetzt haben, müssen wir diesen jedoch noch in Richtung Azure Container Instances deployen. Als nächstes müssen wir unser Docker Image taggen und in unser Container Registry hochladen.
Push Docker Image to Azure Container Registry
Mit dem Befehl "docker commit" erstellt ihr ein neues Image mit dem Namen "newtestllama", welches ein Snapshot aller Änderungen umfasst, die auf dem Filesystem des Containers vorgenommen wurden. Ausgeschlossen hierbei sind Daten, die auf einem Volume gespeichert sind. Mit dem Befehl "docker tag" geben wir dem existierenden Image newtestllama eine neue Referenz, damit wir das Image in ein Registry pushen können. Der Befehl "docker push" lädt dann schlussendlich das Image in das Registry-Repository ollama hoch.

Unser Docker Image liegt nun in der Container Registry und wir können eine Azure Container Instance auf Grundlage dessen erzeugen. Hierfür öffnen wir portal.azure.com, navigieren in unsere Ressourcengruppe und erstellen eine neue Container Instances. Bei der Anlage der Container Instances wählen wir bei der Image Source "Azure Container Registry" aus und nutzen das soeben hochgeladene Image. Bei der Size belassen wir die CPU so wie die Default-Einstellungen sind, jedoch müssen wir die Memory auf 8 GiB erhöhen, da ansonsten nicht genug Platz für das LLM vorhanden ist. In den Netzwerkeinstellungen geben wir den Port 11434 frei.

Nach erfolgreichen Deployment der Container Instance, könnt ihr die Container Instance öffnen. Für einen späteren Schritt benötigen wir die öffentliche IP-Adresse, da wir so das LLM ansprechen können.

Anlegen unseres Azure Functions Projekt und Aufruf des LLMs mit Microsoft.Extensions.Ai

Nachdem wir nun unseren Docker Container mit dem Image von Ollama in der Azure Cloud gehostet haben, widmen wir uns dem Schreiben unserer Azure Function, die eine Anfragen von Dynamics 365 Customer Service entgegennimmt, die Beschreibung der Anfrage sowie alle Kategorien abruft und diese an das LLM schickt.

Als erstes legen wir und Azure Functions Projekt mithilfe von Visual Studio Code und der den Azure Functions Core Tools an. Da ich bereits in vorherigen Blog Posts im Detail darauf eingangen bin, wie wir mit den Core Tools ein Functions Project anlegen und wie wir uns zu Dataverse verbinden, gehe ich in diese Post nicht mehr im Detail darauf ein. Nachfolgend die Links zum Nachlesen:

Nachdem wir das Functions Projekt aufgesetzt haben und unsere Verbindung zu Dataverse hergestellt haben, installieren wir als nächstes das Nuget-Package Microsoft.Extensions.Ai. Die Bibliothek Microsoft.Extensions.Ai bietet .Net-Entwicklern einheitliches Abstraktionen, die von unterschiedlichen LLM-Anbietern implementiert werden können. So könnten Entwickler:innen einfach das zugrunde liegende Large Language Model austauschen, ohne hierbei Code umschreiben zu müssen.

Um loslegen zu können, müssen wir die relvanten Nuget-Packages installieren:
Install nuget packages
Danach müssen wir in der Program.cs der Azure Function unseren OllamaChatClient zum IoC-Container hinzufügen, damit wir diesen über Konstruktor-Injection in unserer eigentlichen Azure Function nutzen können:
Constructor injection of OllamaChatClient

Unser appsettings-Eintrag "OllamaURl" enthält die URL, die wir bei der Erstellung der Container Instance erhalten haben. Diese URL enthält die öffentliche IP-Adresse der Container Instance und den Port 11434. Die local.settings.json sehen wie folgt aus:
adjust local.settings.json

Sobald die Azure Function in die Cloud gepushed wurde, müssen die von uns angelegten Einträge in der local.settings.json noch im Bereich der Umgebungsvariablen in der Azure Function App hinzugefügt werden.

Unsere eigentliche Function benennen wir CaseTagging.cs und in einem ersten Schritt reichen wir über den Konstruktor unsere relevanten Abhängigkeiten hinein. Dies sind der IOrganizationService, um mit dem Dynamics 365 zu kommunizieren sowie der IChatClient, um ein Gespräch mit unserem LLM zu führen.
Die Azure Function wird über einen HTTP-Trigger aufgerufen und bekommt als Query-Parameter die Id der Serviceanfrage aus dem CRM mitgegeben. Diese Id speichern wir in der Variablen "caseId". Anschließend holen wir uns die Serviceanfrage sowie die Kategorien mithilfe des IOrganizationService und bauen unseren Prompt.
Azure Function to call LLM
Der wohl interessanteste Teil des Code-Schnipsel ist die Zeile mit dem Aufruf des LLMs. Hierbei sagen wir dem Chat-Client, dass er uns eine strongly-typed Antwort vom Typ CategoryList zurück geben soll. Damit erreichen wir eine gewissen Standardisierung der Antwort, sodass wir die Antwort immer gleich verarbeiten können. Die CategoryList hat der Einfacheit halber nur eine Eigenschaft "Categories" vom Typ Liste von Strings.
DTO for CategoryLists

Damit das LLM jedoch auch immer eine Antwort zurückgibt, die in unseren Type CategoryList konvertiert werden kann, muss unser Prompt richtig entworfen werden. Dies tun wir in der Methode GeneratePrompt. Unser Prompt setzt sich zum Teil aus standardisiertem Text und zum Teil aus dynamischem Inhalt zusammen, den wir aus der Anfrage laden. In dem Prompt lassen wir das LLM auch wissen, in welchem Format wir die Antwort erwarten.
Building prompt

Nachdem die Azure Function erfolgreich durchgelaufen ist, sollte die Serviceanfrage in Dynamics 365 Customer Service nun mit relevanten Kategorien versehen sein. Diese Kategorien können dann für ein Routing oder andere nachgelagerte Prozessschritte genutzt werden.

Recap: Wie Large Language Models den Kundenservice in Dynamics 365 unterstützen können

In diesem Blogartikel haben wir uns angeschaut, wie wir Large Language Models mithilfe von Ollama lokal deployen können und diese mithilfe einer Azure Function aufrufen, um Prozesse in Dynamics 365 Customer Service zu unterstützen. Wir haben uns ein Beispiel überlegt, bei dem eine Serviceanfrage durch ein LLM automatisch mit Kategorien versehen wird, um diese dann für ein Routing zu nutzen.

Das Deployen des LLMs in einer Azure Container Instance ist relativ einfach und schnell. Ollama bietet uns eine Alternative zu den LLMs der großen Technologieanbieter. Somit haben wir deutlich mehr Kontrolle über die Weiterverarbeitung unternehmensrelevanter Daten.

Die Bibliothek Microsoft.Extensions.Ai bietet uns eine einfache Möglichkeit, LLMs in .Net Anwendungen zu integrieren. Ohne viel Code zu ändern, könnte man das genutzte LLM mithilfer dieser Bibliothek einfach austauschen.

Ohne die nachfolgenden zwei Blogartikel wäre es mir nicht so einfach gefallen, dieses Thema zu behandeln. Der komplette Source Code kann auf meinen Github-Profil eingesehen werden:
Ollama-Agent for Dynamics 365 Customer Service

Wie immer freue ich mich über Feedback von eurer Seite. Wenn ihr Fragen zu dem Thema habt, dann schreibt mir einfach!

Wenn Sie Fragen zu unseren Best Practices haben oder Unterstützung bei der Einführung der Microsoft Power Platform oder Dynamics 365 benötigen, sprechen Sie uns gerne an. Wir freuen uns auf den Austausch mit Ihnen.

Nachricht senden