Meine Aufgabe war, einen Assistenten zu bauen, der Daten in Salesforce CRM findet und analysiert zu einer natürlichsprachlichen Anfrage. Fachleute können beliebige Fragen stellen. Das sind zum Beispiel Fragen, die noch wie Abfragen klingen, aber auch weit darüber hinausgehen und eine mehrstufige Strategie erfordern:

  • «Ich war im Urlaub. Was ist in den letzten zwei Wochen beim Kunden Mustermann geschehen?»
  • «Heute Nachmittag ist ein Besuch beim Unternehmen Mustershop geplant, was soll ich unbedingt berücksichtigen?»
  • «Welche Potenziale in meinem Kundenportfolio sollte ich priorisiert bearbeiten?»

Strategie

Ganz im Sinne meines Blogposts Das Versprechen der Agenten konzentrierte ich mich auf eine Lösung, die keine Vorannahmen darüber trifft, welche Fragen beantwortet werden müssen. Das LLM soll selbst den Lösungsweg finden mit den Tools, die ich ihm zur Seite stelle.

Die Tools greifen auf Endpunkte der Salesforce API zu. Ich implementierte Funktionen für folgende Endpunkte:

  • SOQL Query: SOQL ist die universelle Abfragesprache in Salesforce. Objects sind vergleichbar mit Tabellen. Die SOQL-Syntax ist an SQL angelehnt.
  • Read Object: Objects haben eine eindeutige ID. Die Daten eines konkreten Object können hier ausgelesen werden.
  • Describe Object: Beschafft Metadaten über die Struktur von Objects, also Felddefinitionen, Constraints, Verbindungen zu anderen Objects, usw.

So ausgerüstet ist das LLM in der Lage, sich über die Beschaffenheit der Daten zu informieren und Queries zu produzieren. GPT-5 kennt SOQL in hinreichender Tiefe.

Hindernisse

Customization

Die Objects in Salesforce sind umfangreich customized, auch gibt es Objects, die im Standard-Salesforce gar nicht vorkommen. Die Lösung besteht aus zwei Teilen:

  • Im System-Prompt werden Regeln aufgesammelt, um das LLM anzuleiten, welche Felder für welchen Zweck benutzt werden und wie die Zusammenhänge sind.
  • Das LLM beschafft sich on-demand selbständig Metadaten für Objects mit dem Describe-Object Tool. Die Metadaten werden gecached.

Das klappt sehr gut. Das LLM ignoriert irrelevante Fakten, die es über Salesforce weiß, und hält sich an die speziellen Regeln.

Schwaches SOQL

SOQL hat viele Einschränkungen, die es oft verhindern, Aggregationen zu berechnen. Es gibt berechnete Felder, die nicht sortable, groupable oder filterable sind, obwohl sie fachlich dafür gebraucht würden. Auch Joins sind nicht immer so möglich, wie man sie gerne hätte. In Salesforce müsste man spezialisierte Programme schreiben, die sich um ganz konkrete Anfragen kümmern. Das kam für mich nicht in Frage, weil es der Strategie widersprach, ein universelles System zu bauen.

Lösung: In-Memory-Datenbank als Schweizer Messer

Meine Lösung ist eine In-Memory SQL-Datenbank, die das LLM frei benutzen kann im Rahmen eines Dialogs im Assistenten. Ich wählte DuckDB, weil sie einen praktischen JSON-Loader hat, der in einem Rutsch die SOQL-Resultate in eine Tabelle lädt.

Das LLM kann bei der SOQL-Abfrage den selbstgewählten Namen für die Zieltabelle in DuckDB mitgeben. Die Ergebnisse aus Salesforce werden dann nicht in den LLM-Kontext gesetzt, sondern in die Tabelle kopiert. Das LLM kann danach SQL in der In-Memory-Datenbank ausführen. Die SQL-Abfrage ist ein weiteres Tool für das LLM. Weil das LLM genau weiß, was es aus Salesforce abgeholt hat, kann es zielgenaues SQL generieren, ohne dass alle Daten im Kontext liegen müssen.

Wie sich herausstellte, macht das LLM davon konsequent Gebrauch, wenn es komplizierte, mehrstufige Recherchen plant oder auf Felder trifft, die nicht sortable oder groupable sind. Auch Joins über mehrere Zwischenergebnisse wurden ausgeführt, die mit SOQL unmöglich gewesen wären. Ich war sehr begeistert.

Die In-Memory-Datenbank sitzt in einem zeitbasierten Cache[1] und ist genau einem Dialog zugeordnet. Der Dialog bildet den Scope für die Datenbank. Wir haben hier also einen Datenkontext, der mit dem Dialogkontext assoziiert ist und diesen entlastet, aber trotzdem vom LLM zielgenau verwendet werden kann.

Das ist großartig! Wir können Massendaten präzise, deterministisch(!) und effizient bearbeiten, ohne den LLM-Kontext vollzustopfen und den Modellen Aufgaben aufzubürden, die sie nicht gut können.

Das folgende Bild zeigt den schematischen Ablauf einer SOQL-Query, deren Ergebnis in einer DuckDB-Tabelle landet und am Ende per SQL abgefragt wird.

Flowchart showing a process where data from Salesforce is queried using the SOQL tool, passed to DuckDB for processing, and linked to a dialog context. Steps are labeled 1 through 7, with German terms like 'Aufruf' (call) and 'Tabelle' (table). Start and endpoint are labeled 'Start' and 'Ende.'
SOQL Abfrage mit In-Memory-DB

MCP

Die vorgestellte Lösung würde mit MCP keinen Sinn ergeben. Die In-Memory-DB ist eng mit dem von der Assistant-App verwalteten Dialog verknüpft. Weil das SOQL-Tool die DB befüllt (das LLM bestimmt beim Aufruf, ob es die Daten aus Salesforce kopiert haben möchte), müsste die DB in den MCP-Server wandern und der MCP-Server müsste deren Verwaltung übernehmen. Der Server würde in das Management des Dialogs involviert und die SQL-Ergebnisse aus der DB würden über umständliche Transportwege zur App gelangen. Das wäre grober Unfug. Wenn zwei Komponenten logisch so eng gekoppelt sind, dann ist es eine einzige Komponente.

MCP steht hier nur im Weg. Effiziente Lösungen können Entkopplung verbieten und so einen Fall haben wir hier.

Fazit

Eine In-Memory-Datenbank ist ein sehr nützliches, universelles Tool für LLMs, wenn eine Datenquelle beschränkte Abfragemöglichkeiten hat und Zwischenergebnisse in mehreren Stufen aufgearbeitet werden müssen. Sie gibt dem LLM einen großen Spielraum beim Entwickeln von Strategien.

GPT-5 hat meine Erwartungen mehr als erfüllt. 5-mini findet sich schon beeindruckend gut zurecht in dem doch sehr großen Datenschema. Das große 5 erzeugt erstaunlich tiefe Lösungswege. In einem Beispiel hatte ich satte 15 Tool-Aufrufe mit mehreren Tabellen.

Es ist auch bemerkenswert, wie das Modell Fehlermeldungen aus ungültigem SOQL oder SQL versteht und mit einer korrigierten Query einen neuen Versuch macht.

Man kauft sich mit tiefem Reasoning auch eine entsprechend lange Antwortzeit ein. Ich denke aber, dass die Fachleute es akzeptieren können, wenn sie den gründlichen Lösungsweg sehen und das Ergebnis gut ist.

Ausblick

Die nächste logische Stufe nach den interaktiven Assistenten mit Tools sind Agenten, die asynchron auf Ereignisse reagieren und im Hintergrund (headless) permanent Aufgaben für die Fachleute erledigen. In einem CRM-System sollte es viele Gelegenheiten geben für Agenten, proaktiv Fakten zu finden und Hinweise zu geben. Aber schön der Reihe nach. Es wird einige Zeit dauern, sich an die Arbeitsweise des Assistenten zu gewöhnen, zu lernen, wie die Fachleute ihn benutzen, und Ideen zu finden, was man sonst noch so alles damit anstellen könnte.

Ich sehe die große Innovation nach wie vor in agentischen KI-Systemen, deren Aufgaben nicht im Detail vorherbestimmt sind. Als Konstrukteure solcher Systeme müssen wir es beherrschen, die LLMs mit den passenden Tools auszustatten und sie anleiten, wie sie sich in den Datenquellen zurechtfinden sollen. Dann werden Systeme möglich, die es noch nie gab.

  1. OpenAI mit seiner code interpreter sandbox macht das ähnlich. Man hat 20 Minuten Zeit sie zu benutzen im Dialog, danach ist sie weg.  ↩