Geben Sie einer 30 Jahre alten 4D-Anwendung AI

Automatisch übersetzt von Deepl

In nur wenigen Jahren hat sich die künstliche Intelligenz von einem aufkommenden Trend zu einem wesentlichen Bestandteil moderner Software entwickelt. ChatGPT, Grok, Gemini und andere KI-Assistenten spielen heute eine wichtige Rolle im täglichen Leben, sowohl beruflich als auch privat.
Deshalb stellt 4D 21 die 4D.Vectors und das 4D AI Kit vor: 4D Entwickler erhalten damit einfache und effektive Werkzeuge, um ihre Anwendungen um KI-gestützte Funktionen zu erweitern.
Wir haben bereits viele Beispiele, Tutorials und Webinare zum Thema KI veröffentlicht, aber ich habe mich kürzlich gefragt: Was müsste man tun, um KI in eine 30 Jahre alte 4D Anwendung zu bringen?
Könnte man eine solche Anwendung einfach nach den 10 wichtigsten Kunden fragen und sofort ein schönes Diagramm zurückerhalten?

Nun, raten Sie mal? Es stellte sich heraus, dass es so einfach ist, dass es einen eigenen Blogbeitrag verdient.

Beginnen wir mit dem Link zu den Projektquellen auf Github und einem kurzen Demo-Video

Projekt-Quellen

 

Die 4D Invoice Anwendung

Die Anwendung 4D Invoice ist bereits seit einiger Zeit im 4D Depot verfügbar. Sie dient als solides Beispiel dafür, wie man Produkte, Kunden und Rechnungen sauber und strukturiert verwalten kann. Obwohl sie bereits den Projektmodus verwendet (eine Voraussetzung für die Nutzung der neuesten 4D AI Funktionen), nutzt sie noch keine DataClasses, und ihre Formulare sind älter als die neuere Form-Klasse. Die Codebasis ist recht umfangreich, verwendet generische Entwurfsmuster und enthält mehrere nicht-triviale Geschäftsregeln.

Mein Ziel für dieses Experiment war es, ein neues Formular hinzuzufügen, das eine KI-gestützte Interaktion mit der Anwendung ermöglicht. Ich wollte, dass die Benutzer mit einem KI-Assistenten kommunizieren und alles von einfachen Fragen bis hin zu komplexeren analytischen Abfragen stellen können. In der Praxis würde dies einer eher „altmodischen“ Anwendung sofort ein modernes Aussehen verleihen, das den heutigen KI-gesteuerten Nutzererwartungen entspricht. Das ist in der Tat sehr spannend!

Ein weiteres Ziel war es, keine Änderungen an der Datenstruktur vorzunehmen und die bestehenden UI-Mechanismen nicht zu verändern. Mit anderen Worten: Das KI-Upgrade sollte hochflexibel sein, möglichst wenig in das System eingreifen und idealerweise in anderen Legacy-Anwendungen wiederverwendet werden können.

Aus diesem Grund basiert dieses Upgrade nicht auf 4D.Vectors oder Embeddings. Wir werden später darauf zurückkommen, aber es lohnt sich jetzt schon zu betonen, dass die Integration von KI in Ihre 4D Anwendung nicht unbedingt Embeddings oder semantische Suche erfordert. Das sind getrennte Konzepte.

Vorbereitet sein

Bei 4D haben wir bereits mehrere KI-basierte Beispiele und Webinare veröffentlicht, darunter auch die jüngsten Demonstrationen zum Aufbau eines RAG-Systems mit Tool Calling. Für dieses Projekt habe ich beschlossen, das Chat-UI-Formular aus der People & Skills-Demo zu extrahieren und es allgemeiner und wiederverwendbar zu machen.

Die Chat-Benutzeroberfläche besteht aus den folgenden Komponenten:

  • Das AIChat-Formular, zusammen mit seiner Formularklasse formAIChat.4dm. Dieses Formular bietet:
    • eine einfache Texteingabe für die Eingabeaufforderung des Benutzers
    • einen Webbereich, der die Konversation mit dem Modell anzeigt
  • Die Klasse AI_ChatWithTools, zuständig für:
    • die Instanziierung eines KI-Bots unter Verwendung der Chat-Hilfe des 4D AI Kits, basierend auf dem in Resources/AIProvider.json konfigurierten Inferenzserver und Modell
    • das Laden der in Resources/AITools.json definierten Tools
    • Hosting der Implementierung dieser Werkzeuge

Die Klasse läuft vollständig im Streaming-Modus, so dass der Benutzer ein ChatGPT-ähnliches Erlebnis hat, bei dem die Antworten nach und nach erscheinen.

  • DasRendern der Konversation wird durch das Singleton ChatHTMLRenderer gehandhabt.

Es nimmt die Sammlung von Nachrichten, die im AIBot gespeichert sind, und wandelt sie in HTML um, indem es die Vorlagen verwendet, die sich im Ordner Resources befinden:

    • chat-template.html
    • chat-template.css
    • tool-icon.svg

 

Ich will ehrlich sein: Das HTML-Rendering war im Wesentlichen „vibe-coded“ mit Hilfe des GitHub-Agenten von VS Code und Claude Sonnet 4.5. Die größte Herausforderung bestand darin, das korrekte Rendering während des Streamings sicherzustellen, insbesondere für Elemente wie Tabellen, Tool-Aufrufe und Diagramme.

AI-Tool-Aufrufe

Wie Sie wahrscheinlich wissen, weiß ein KI-Modell von Haus aus nichts über Ihre Daten. Es erhält nur über Tools, die Sie explizit zur Verfügung stellen, Zugang zu diesen Daten. In diesem Abschnitt erkläre ich, welche Tools ich implementiert habe und wie sie funktionieren.

tool_getProducts, tool_getClients, tool_getInvoices, tool_getInvoiceLines

Alle diese Werkzeuge sind für die Abfrage der Datenbank zuständig. Sie führen jeweils eine einfache ORDA-Abfrage auf der Grundlage der vom Modell angeforderten Felder durch.

Natürlich gibt es bei diesen Tool-Funktionen noch viel zu verbessern. Dank der nativen Funktionen von 4D 21 AI können wir uns eine semantische Suche vorstellen, bei der 4D.Vector und Einbettungen verwendet werden, um die Suche nach Kunden zu verbessern. Da dies tiefgreifende Änderungen in der Struktur bedeuten würde, habe ich einen einfacheren Weg gewählt.

Lassen Sie uns tool_getClients aufschlüsseln, denn das gleiche Muster gilt für alle anderen „Getter“-Tools:

Function tool_getClients($input : Object) : Object

Diese Funktion empfängt ein Objekt als Eingabe und gibt ein Objekt als Ausgabe zurück. Die Eingabe beschreibt die Suchparameter; die Ausgabe enthält die resultierenden Daten.

Validierung der Eingabe

var $validation; $returnObject : Object	
var $entities : cs.CLIENTSSelection:=ds.CLIENTS.all()

$validation:=JSON Validate($input; This._getToolArgumentsSchema(This._functionName(Call chain)))
If (Not($validation.success))
	return {error: "Could not validate input parameters against JSON Schema, call the tool again with proper input parameters"}
End if 

Der erste Schritt ist die Überprüfung, ob die Eingabe mit dem in AITools.json definierten Schema übereinstimmt.

Die meisten modernen Modelle erzeugen gut strukturierte Toolaufrufe, aber je nach Modell ist eine Validierung dennoch eine gute Sicherheitspraxis.

Wenn die Validierung fehlschlägt, gibt das Tool ein einfaches Objekt zurück, das eine Fehlereigenschaft enthält. Es ist wichtig zu wissen, dass das Modell diesen Wert liest, daher sollten Sie explizit angeben, was falsch gelaufen ist.

Einrichten von Standard-Eingabewerten

$input.ID:=($input.ID) || "any"
$input.Name:=($input.Name) || "@"
$input.Contact:=($input.Contact) || "@"
$input.Total_Sales:=$input.Total_Sales || {}
$input.Total_Sales.min:=$input.Total_Sales.min || 0
$input.Total_Sales.max:=$input.Total_Sales.max || 9999999
$input.orderBy:=($input.orderBy) || {}
$input.orderBy.field:=($input.orderBy.field) || "Name"
$input.orderBy.order:=($input.orderBy.order) || "asc"
$input.top:=($input.top) || This.defaultTop
$input.countOnly:=($input.countOnly) || False

Standardwerte gewährleisten sichere ORDA-Abfragen, haben aber auch einen interessanten Nebeneffekt: Das Schreiben eines vollständigen JSON-Schemas in AITools.json kann mühsam sein. Stattdessen habe ich GitHub Copilot das Schema aus dem Code und der Standardstruktur ableiten lassen, und das Ergebnis war hervorragend. Copilot erstellte eine genaue Schemadefinition, die allein auf der obigen Logik basierte.

Zu beachtende Parameter

  • orderBy und top reduzieren die Ausgabegröße (und damit die Verwendung von Token).
  • countOnly ermöglicht es dem Modell, nur Datensatzzählungen anzufordern, ohne Daten abzurufen.

 

Praktische Beispiele:

  • Wenn das Modell die Anzahl der Kunden benötigt → countOnly = true
  • Wenn es die 5 wichtigsten Kunden benötigt → top = 5 und orderBy: {field: „Total_Sales“, order: „desc“}

 

Initialisierung des Ausgabeobjekts

$returnObject:={}
$returnObject.form:="Clients"
$returnObject.dataClass:="CLIENTS"
$returnObject.counts:={}
$returnObject.counts.total:=$entities.length
  • form gibt an, welches UI-Formular zur Anzeige der Ergebnisse verwendet werden kann – wir werden das später sehen.
  • dataClass identifiziert die beteiligte Datenklasse, wichtig für die Abfrage über mehrere Tabellen hinweg – auch das werden wir später sehen.
  • counts.total ist die Anzahl der Datensätze, bevor ein Filter angewendet wird.

 

Ausführen der Abfrage

If ($input.ID#"any")
	$entities:=$entities.query("ID = :1"; $input.ID)
End if 

$entities:=$entities.query("Name = :1 and Contact = :2 and Total_Sales >= :3 and Total_Sales <= :4 order by "+$input.orderBy.field+" "+$input.orderBy.order; $input.Name; $input.Contact; $input.Total_Sales.min; $input.Total_Sales.max)

Dieser Teil ist einfach und könnte sicherlich noch generischer gestaltet werden, aber das war nicht mein Ziel hier.

Fertigstellung des Ergebnisses

$returnObject.counts.totalFiltered:=$entities.length
If ($returnObject.counts.totalFiltered>$input.top)
	$entities:=$entities.slice(0; $input.top)
End if 

$returnObject.counts.totalSent:=$entities.length
$returnObject.entities:=($input.countOnly) ? [] : $entities.toCollection("ID, Name, Contact, City, State, Country, Discount_Rate, Total_Sales, Comments")

return $returnObject

Aufschlüsselung

  • counts.totalFiltered: Anzahl der Datensätze nach der Filterung
  • counts.totalSent: Anzahl der tatsächlich zurückgegebenen Datensätze (nach Anwendung von top)
  • entities: die endgültige Datensammlung (oder leer, wenn countOnly = true)

 

Sie werden feststellen, dass das Tool genau steuert , welche Attribute an das Modell gesendet werden. Es ist wichtig, das richtige Gleichgewicht zu finden.

Was zu beachten ist

  • Qualität der Konversation: mehr Daten → bessere Erkenntnisse
  • Leistung: mehr Daten → längere Verarbeitung
  • Kontextfenster: insbesondere lokale Modelle können bei Überlastung beeinträchtigt werden
  • Kosten: mehr Token → höhere Auslastung der Cloud-Inferenzserver
  • Vertraulichkeit: Berücksichtigen Sie bei der Auswahl der Felder immer GDPR und die Sensibilität der Daten

 

Die Quintessenz

Welches Objekt das Tool auch immer zurückgibt, 4D AI Kit serialisiert es transparent und liefert es an das Modell. Ziemlich praktisch, oder?

 

Tabellenübergreifende Abfragen und das frühe System Prompt

Eine weitere interessante Entdeckung während dieses Projekts war, dass das Modell die Beziehungen zwischen den Tabellen nicht automatisch versteht. Zum Beispiel, Aufforderungen wie:

Gib mir die 5 wichtigsten Kunden, ihre höchste Rechnung und ihr meistbestelltes Produkt

führten nicht immer zu zuverlässigen Ergebnissen.

Das Problem war einfach: Das Modell erkannte nicht, dass die ID in der Tabelle “ Kunden“ für die Abfrage der Tabelle “ Rechnungen“ verwendet werden sollte, oder dass Rechnungszeilen sich auf Produkte beziehen, und so weiter.

Mit anderen Worten: Ich musste dem Modell ein gewisses Wissen über die Struktur vermitteln, ohne jedoch zu weit zu gehen. Meine Anforderungen waren:

  • Keine hart kodierte Systemabfrage: Ich möchte die Eingabeaufforderung nicht manuell aktualisieren, wenn sich die Struktur ändert.
  • Kein vollständiger Strukturkatalog: Das Modell braucht nicht das gesamte Schema, sondern nur die relevanten Beziehungen.

 

Um das zu erreichen, habe ich eine sehr praktische Klasse von Thomas Maul wiederverwendet: StructureInfo.4dm, die nur die Beziehungen zwischen den Tabellen extrahiert.

Daraus habe ich meine ursprüngliche System-Eingabeaufforderung erstellt:

var $relations : Collection:=This._relationsInfos()	
$systemPrompt:="You are a helpful assistant. I need your help to answer questions data stored in my application.\n"+\	
	"**CONTEXT**\n"+\
	"The application stores data about invoices, products and clients"+\
	"In some cases, you'll need to cross query several tables (dataClasses) in order to answer."+\
	"To help you, here are the application relations between tables (dataClasses):\n"+\
	JSON Stringify($relations)+"\n"+\
	"**INSTRUCTIONS**\n"+\
	"Analyze questions and answer step by step.\n"+\
	"Use the tools at your disposal to answer everytime you think they are relevant.\n"+\
	"**FORMATING**\n"+\
	"Use HTML everytime.\n"+\
	"Use bullet lists and Tables everytime everytime necessary\n"+\
	"**IMPORTANT**\n"+\
	"When calling tools, always include all required arguments in valid JSON.\n"+\
	"Do not call a tool with empty arguments. If a value is missing, choose a reasonable default.\n"+\
	"Always double check tools results before answering. Especially when they rely on vector search. \n"+\
	"Indeed they may return results not matching with your search intention.\n"+\
	"When tool calling returns data not related with the initial question, or that you cannot use to answer,\n"+\
	"avoid detailing such results too much and stay short.\n"

Durch die Kombination dieser Beziehungs-Metadaten mit den dataClass-Informationen, die von jedem Tool zurückgegeben wurden, war das Modell schließlich in der Lage zu verstehen, wie Tool-Aufrufe über Tabellen hinweg verkettet werden können.

Dies verbesserte die Qualität und Genauigkeit der Antworten des Modells erheblich, insbesondere bei Analysen mit mehreren Tabellen, wie z. B.:

Top-Kunden nach Umsatz

oder

am häufigsten bestellte Produkte

oder

größte Rechnungen pro Kunde

Benutzererfahrung: Öffnen Sie ein 4D Formular direkt aus der Conversational UI

Bei meinen früheren Experimenten mit RAG habe ich die Ergebnisse oft in einem separaten Listenfeld angezeigt. Dieser Ansatz funktionierte, hatte aber einige Nachteile:

  • Das Modell musste in einem separaten versteckten Abschnitt die Liste der Entitäts-IDs bereitstellen, die in der Listbox angezeigt werden sollten. Das bedeutete mehr Token, langsamere Antworten und zusätzliche HTML-Tricks (wie das Verstecken der ID-Liste innerhalb eines kommentierten Blocks).
  • Es erforderte zusätzliche Arbeit, um die Listbox generisch genug zu machen, um verschiedene Entitätstypen zu behandeln (Kunden, Produkte, Rechnungen, …).
  • Sie schränkte die Benutzeroberfläche ein und fühlte sich weniger in die Anwendung integriert an.

 

Für dieses Projekt wollte ich etwas einfacheres, eleganteres und natürlicheres für den Benutzer.

Also wählte ich eine neue Strategie: Jedes Mal, wenn die KI eine Entität erwähnt, erzeugt sie einen benutzerdefinierten Hyperlink, der direkt das entsprechende 4D Formular öffnet, gefiltert nach der ausgewählten Entität.

Dies erwies sich als erstaunlich einfach. Ich habe einfach die folgenden Anweisungen in die Eingabeaufforderung des Systems eingefügt:

"**CUSTOM URL HANDLING**\n"+\	
"Tools responses give information about the form to open when available, the dataClass and entities ID\n"+\
"When you display any element coming from a tool response, you must use a custom url so that the user can open the corresponding form\n"+\
"Such custom url must follow the following syntax examples:\n"+\
"<a href=\"myapp://openform?form=Products&dataClass=PRODUCTS&entities=989511\">A single product</a>\n"+\
"<a href=\"myapp://openform?form=Invoices&dataClass=INVOICESS&entities=654KJY,6467HGS,79864JSD\">A list of invoices</a>\n"

Da meine Tools immer das entsprechende Formular, die dataClass und die Liste der Entitäten zurückgeben, hat das Modell alles, was es braucht, um diese Links korrekt zu erzeugen. KI-Modelle sind sehr gut in dieser Art der strukturierten Ausgabe.

Handhabung der benutzerdefinierten URLs in 4D

Alles, was ich auf der 4D Seite brauchte, war ein kleiner URL-Filtermechanismus im Webbereich, um myapp://links abzufangen und das richtige Formular mit der richtigen Entitätsauswahl zu öffnen:

Function webAreaEventHandler($formEventCode : Integer)
	var $formToOpen : Text
	var $entitySelectionToShow : 4D.EntitySelection
	var $queryObject : Object

	Case of 
		: ($formEventCode=On Load)
			ARRAY TEXT($filters; 0)
			ARRAY BOOLEAN($allowDeny; 0)
			APPEND TO ARRAY($filters; "myapp://*")  // Intercept all URLs starting with myapp://
			APPEND TO ARRAY($AllowDeny; False)  //Allow
			WA SET URL FILTERS(*; "Web Area"; $filters; $allowDeny)

		: ($formEventCode=On URL Filtering)
			$url:=WA Get last filtered URL(*; "Web Area")

			// Parse the URL to determine what to do
			Case of 
			: ($url="myapp://openform?@")
				$queryObject:=This.queryObjectFromUrl($url)
				If ($queryObject=Null)
					return 
				End if 

				If ($queryObject.entitiesCollection.length>0)
					$entitySelectionToShow:=ds[$queryObject.dataClass].query("ID in :1"; $queryObject.entitiesCollection)
					CALL WORKER("Generic"; "W_Generic"; $queryObject.form; True; $entitySelectionToShow)
				Else 
					CALL WORKER("Generic"; "W_Generic"; $queryObject.form; False)
				End if 
			End case 
	End case

Das Ergebnis

Das Endergebnis ist eine sehr reibungslose Benutzererfahrung, bei der sich die dialogorientierte Benutzeroberfläche nahtlos in den Rest der 4D Anwendung einfügt.

Benutzer können mit der KI chatten, Daten erforschen und sofort native 4D Formulare öffnen, ohne die Kernlogik oder Struktur der Anwendung zu verändern.

Ein modernes Interaktionsmodell, das direkt auf einer klassischen 4D Anwendung aufsitzt… und das fast ohne Eingriffe.

blank

Ein zusätzliches Werkzeug: tool_createInvoice

Die Beispieldatenbank im GitHub-Projekt enthielt nur eine Handvoll Rechnungen, nicht annähernd genug, um Interaktionen mit der KI interessant zu machen. Ich brauchte mehr Daten.

Die Erstellung eines benutzerdefinierten Formulars oder das Schreiben einer weiteren Routine zur Rechnungserstellung erschien mir sowohl mühsam als auch irrelevant für den Zweck dieser Demo. Und dann fiel es mir ein: Ich hatte bereits alles, was ich brauchte.

  • Eine konversationelle Benutzeroberfläche.
  • Ein KI-Agent, der mein Datenmodell kennt.
  • Wissen über Kunden, Produkte, Preise, Beziehungen…

Warum sollte die KI also nicht direkt von der Chat-Oberfläche aus Rechnungen erstellen können?

Alles, was ich tun musste, war, ein neues Tool hinzuzufügen: tool_createInvoice.

Mein Ansatz war ganz einfach:

  • Implementieren Sie eine einfache Funktion zur Rechnungserstellung innerhalb von AI_ChatWithTools.
  • Den gesamten Prozess in eine Transaktion verpacken:
    • Im Fehlerfall: Rollback und Rücksendung einer eindeutigen Fehlermeldung an das Modell.
    • Bei Erfolg: Übertragen Sie die Rechnung und geben Sie ihre Details zurück.
  • Dokumentieren Sie das Schema des Tools sorgfältig, insbesondere seine Eingabeparameter.
  • Dann… lassen Sie GitHub Copilot das JSON-Schema in AITools.json generieren.

 

Das Ergebnis?

Ich kann jetzt die KI bitten, eine brandneue Rechnung ganz allein zu erstellen. Sie findet einen relevanten Kunden, wählt Produkte aus, berechnet die Summen und ruft das Tool auf – und das alles über dieselbe konversationelle Benutzeroberfläche, die ich zuvor erstellt habe.

Es stellte sich heraus, dass dies ein überraschend eleganter Weg ist, um realistische Testdaten zu erzeugen.

blank

Eine interessante Beobachtung: Einige Modelle (insbesondere OpenAI GPT-4.1) neigen dazu, um eine Bestätigung oder zumindest ausreichende Eingabedetails zu bitten, bevor sie eine Rechnung erstellen… es sei denn, man weist sie ausdrücklich an, dies nicht zu tun.

blank

HTML-Rendering von OpenAI-Nachrichten

Wie bereits erwähnt, wurde dieser Teil vollständig von Vibe codiert. Verwenden Sie ihn weiter, passen Sie ihn an oder ignorieren Sie ihn, je nachdem, was Ihren Bedürfnissen entspricht. Die Idee ist einfach: Man nimmt eine Sammlung von OpenAI-Nachrichten und rendert sie schön in HTML.

Aber natürlich verdienen unsere Endbenutzer immer mehr als nur einen einfachen Textdump. Also habe ich ein paar Qualitätsmerkmale hinzugefügt:

  • Ein sauberes, strukturiertes Layout für Tool-Aufrufe, einschließlich einer visuellen Anzeige, während ein Tool läuft.

 

  • Eine „Kopieren“-Schaltfläche, mit der sich jede Assistenten-Nachricht miteinem Klick kopieren und in ein Dokument einfügen lässt, sei es Microsoft Word, Google Docs oder eine E-Mail.

Dadurch wirkt die gesamte Konversation ausgefeilt und professionell, ist aber dennoch schnell und einfach zu implementieren.

blank

  • Eine Kopierschaltfläche für jede Tabelle, die es dem Benutzer ermöglicht, die Rohdaten der Tabelle sofort zu extrahieren und direkt in eine Excel-ähnliche Tabelle einzufügen.

Dies ist äußerst praktisch, wenn der Benutzer Daten außerhalb der Anwendung bearbeiten oder vergleichen möchte, ohne etwas zu exportieren.

blank

Diagrammfunktionen direkt in der Benutzeroberfläche

Wenn man sich mit einer KI über Rechnungen, Kunden oder Produkte unterhält, erwarten die Benutzer natürlich Diagramme. Rankings, Vergleiche, Trends… visuelle Einblicke sind heute Teil jeder modernen Erfahrung.

Also beschloss ich, das Rendering von Inline-Diagrammen in die Chat-Benutzeroberfläche zu integrieren, und es erwies sich als überraschend einfach, dank ein wenig Vibe-Coding mit GitHub Copilot.

Ich habe es in drei Schritten implementiert:

1) Importieren Sie Chart.js in chat-template.html und erweitern Sie meine HTML-Rendering-Engine, um <chart>…</chart>-Blöcke zu erkennen.

Während die KI ihre Antwort überträgt, zeigt eine kleine CSS-Animation einen Diagrammplatzhalter an und sorgt so für ein ausgefeiltes UX-Gefühl.

2) Erweitern Sie die System-Eingabeaufforderung, um der KI explizit beizubringen, wie sie Diagramme anfordern soll. Ich habe Anweisungen wie die folgenden hinzugefügt:

"**CHARTS**\n"+\	
"Create charts for rankings, comparisons, trends, or distributions. Format: <chart>{...JSON...}</chart>\n"+\
"Available types: bar, line, pie, doughnut, radar, polarArea. Always include:\n"+\
"- \"type\": chart type\n"+\
"- \"data.labels\": array of x-axis labels\n"+\
"- \"data.datasets\": array with \"label\", \"data\" (numeric array), \"backgroundColor\" (color array)\n"+\
"- \"options.responsive\": true\n"+\
"- \"options.plugins.title\": {\"display\": true, \"text\": \"Chart Title\"}\n"+\
"- \"options.scales.y.beginAtZero\": true (for bar/line charts)\n"+\
"Use distinct vibrant colors (e.g., #4caf50, #2196f3, #ff9800, #e91e63, #9c27b0). Set \"legend.display\" to false for single datasets, true for multiple.\n"

3) Lassen Sie die KI Diagrammdefinitionen in JSON generieren, die der Webbereich sofort mit Chart.js rendert.

blank

Das Ergebnis ist wirklich beeindruckend: Das Modell erzeugt aussagekräftige Grafiken direkt im Gesprächsfluss und bereichert das Erlebnis erheblich.

Allerdings würde ich mich bei komplexen Berechnungen nicht ausschließlich auf das Modell verlassen. Für den produktiven Einsatz wäre es ratsam, eine Reihe von Tools hinzuzufügen, die sich mit:

  • Summen und Kumulierung
  • Gruppierung und Aggregierung
  • Zeitbasierte Zusammenfassungen
  • Periodenvergleiche
  • KPI-Extraktion

 

4D führt die schwierigen, genauen Berechnungen durch, und die KI fordert sie einfach an und zeichnet die Diagramme auf der Grundlage präziser, validierter numerischer Daten.

Eine perfekte Kombination aus 4D-Zuverlässigkeit und KI-gestützter Benutzeroberfläche.

Fazit

Und was nun?

Wir haben eine etwas altmodische Geschäftsanwendung mit einer modernen, konversationellen, KI-gestützten Erfahrung ausgestattet.

Aber es einfach als „eine weitere Möglichkeit, Daten abzurufen“ zu betrachten, würde völlig am Thema vorbeigehen.

Sicher, Sie brauchen keine konversationelle Benutzeroberfläche, um „die 5 umsatzstärksten Kunden im Jahr 2025“ zu ermitteln.

Ein einfacher Bildschirm mit ein paar Filtern kann das leisten.

Aber man merkt sehr schnell, dass es hier um etwas anderes geht.

Dies ist eine neue Art, Ihre Daten zu erforschen.

Mit einem einzigen Formular, der Chat-Schnittstelle, können die Benutzer alles abfragen: Rechnungen, Produkte, Kunden… egal, ob sie eine Tabelle, ein Diagramm oder beides wollen.

Damit entfällt die Notwendigkeit, zahllose spezialisierte Bildschirme für leicht unterschiedliche Berichtsanforderungen zu erstellen.

Und wenn Sie das sehen, verstehen Sie auch, dass dies weit über die Abfrage und Anzeige von Daten hinausgeht.

Der wahre Wert liegt nicht in der Beantwortung der Frage „Zeigen Sie mir das“.

Der wahre Wert liegt in der Antwort „Hilf mir, das zu verstehen“.

Ihre Aufforderung sollte nicht mehr lauten:

Zeichne ein Diagramm, das 2024 und 2025 vergleicht

sondern stattdessen:

Legen Sie bitte einen detaillierten Umsatzbericht für 2025 vor, einschließlich des Gesamtumsatzes, der 5 umsatzstärksten Produkte, der 5 umsatzstärksten Kunden, der Umsatzentwicklung im Jahresverlauf und der unbezahlten Rechnungen. Zeigen Sie relevante Diagramme und Tabellen und erläutern Sie bemerkenswerte Trends, Chancen und Risiken. Vergleichen Sie außerdem die Produktleistung mit dem Jahr 2024 und schlagen Sie umsetzbare Erkenntnisse zur Verbesserung von Umsatz und Cashflow vor. Fügen Sie eine Leistungsübersicht für jeden Kunden und jedes Produkt mit den wichtigsten Kennzahlen bei. Ich möchte sowohl Zahlen als auch Erklärungen und umsetzbare Erkenntnisse. Ihr Bericht wird Vergleiche zwischen 2024 und 2025 enthalten. Die Ziele eines solchen Berichts sind: Wie kann der Umsatz gesteigert werden, welche Kunden sollen angesprochen werden, wie kann die Produktleistung erhöht werden.

Und genau diese Art von Antwort werden Sie – und Ihre Nutzer – erhalten:

blank

Eine einzige Dialogschnittstelle, die nahtlos in Ihre 4D-Anwendung integriert ist und Einblicke, Schlussfolgerungen, Visualisierungen, Kreationen… ermöglicht.

Dies ist keine Funktion.

Es ist ein Schritt in Richtung einer neuen Generation von Geschäftsanwendungen.

Wie können Sie dies in Ihrem eigenen Projekt wiederverwenden?

Wenn das Lesen dieses Beitrags und das Herumspielen mit der App Ihr Interesse geweckt hat, können Sie dies ganz einfach tun:

  • Kopieren Sie die folgenden Dateien in Ihr Projekt:
    • Klassen
      • AI_ChatWithTools.4dm
      • ChatHTMLRenderer.4dm
      • formAIChat.4dm
      • StrukturInfo.4dm
    • Formular
      • AIChat
    • Ressourcen
      • AIprovider.json
      • AITools.json
      • chat-vorlage.html
      • chat-vorlage.css
      • werkzeug-ikon.svg
    • Nehmen Sie die notwendigen Anpassungen vor
      • System-Eingabeaufforderung und Werkzeug-Implementierung in AI_ChatWithTools.4dm
      • Nachfolgende Werkzeugdefinition in AITools.json (verwenden Sie hierfür einfach AI!)
      • Anpassung der Formularöffnung an Ihre Anwendung in formAIChat.webAreaEventHandler()
      • AI-Anbieter-Einstellungen in AIprovider.json

 

Und das war’s auch schon!

Zum Schluss noch ein paar Anmerkungen:

In diesem Beispiel ist die gesamte Tool-Logik in der Klasse AI_ChatWithTools implementiert. Ich habe dies getan, weil ich so wenig wie möglich eingreifen wollte, und weil das Projekt keine DataClasses implementiert. Abhängig von der Architektur Ihrer Code-Basis könnte es eine bessere Praxis sein, solche Tools auf DataClasses-Funktionen auszurichten.

Das gesamte Projekt funktioniert perfekt mit OpenAI und dem gpt-4.1-Modell oder höher. Die Arbeit mit einem lokalen Modell wirft zusätzliche Herausforderungen auf, die im 4D Forum diskutiert werden können!

 

Mathieu Ferry
4D Product Team Leader -Mathieu kam 2020 als Product Team Leader zu 4D. Sein Team besteht aus Product Ownern, der Stimme der User von 4D. Sie arbeiten Hand in Hand mit dem technischen Team und müssen Prioritäten setzen, die Reichweite festlegen und überprüfen, ob neue Funktionen den Erwartungen der 4D User entsprechen. Mathieu war zuvor als Projektleiter und Teammanager in verschiedenen IT-Abteilungen führender Branchen tätig - Automobil, Sicherheit, Werbung, spezialisiert auf internationale Kontexte und Cloud-orientierte Dienste.