En l’espace de quelques années, l’intelligence artificielle est passée du statut de tendance émergente à celui de composante essentielle des logiciels modernes. ChatGPT, Grok, Gemini et autres assistants IA jouent désormais un rôle majeur dans la vie quotidienne de chacun, tant sur le plan professionnel que personnel.
C’est pourquoi 4D 21 propose 4D.Vectors et 4D AI Kit: pour donner aux développeurs 4D des outils simples et efficaces pour ajouter des fonctionnalités d’IA à leurs applications.
Nous avons déjà partagé de nombreux exemples, tutoriels et webinaires sur l’IA, mais je me suis récemment demandé ce qu’il faudrait faire pour intégrer l’IA dans une application 4D vieille de 30 ans.
Pourriez-vous simplement demander à une telle application de vous indiquer vos 10 principaux clients et obtenir instantanément un joli graphique en retour ?
Et bien, devinez quoi ? La démarche s’est avérée si simple qu’elle mérite son propre article de blog.
Commençons par le lien vers les sources du projet sur Github et une rapide vidéo de démonstration.
L’application 4D Invoice
L’application 4D Invoice est disponible dans 4D Depot depuis un certain temps. C’est un exemple solide de la façon de gérer les produits, les clients et les factures d’une manière propre et structurée. Bien qu’elle utilise déjà le mode projet (une exigence pour profiter des dernières fonctionnalités IA de 4D), elle n’utilise pas encore les DataClasses, et ses formulaires sont antérieurs à l’emploi de classes de Formulaires, plus récentes. La base de code est assez importante, utilise des modèles de conception génériques et inclut plusieurs règles de gestion non triviales.
Pour cette expérience, mon objectif était d’ajouter un nouveau formulaire permettant une interaction avec l’application alimentée par l’IA. Je voulais que les utilisateurs puissent converser avec un assistant IA et poser des questions simples ou des requêtes analytiques plus complexes. Dans le monde réel, cela donnerait instantanément à une application plutôt « old school » une touche de modernité, alignée sur les attentes des utilisateurs d’aujourd’hui, guidés par l’IA. C’est vraiment passionnant !
Un autre objectif était d’éviter toute modification de la structure des données et de ne pas altérer les mécanismes existants de l’interface utilisateur. En d’autres termes, la mise à niveau de l’IA devait être très flexible, peu intrusive et idéalement réutilisable dans d’autres applications existantes.
Par conséquent, cette mise à jour ne s’appuie pas sur les 4D.Vectors ou les embeddings. Nous y reviendrons plus tard, mais il est utile de le souligner dès à présent : l’intégration de l’IA dans votre application 4D ne nécessite pas nécessairement des embeddings ou une recherche sémantique. Il s’agit de concepts distincts.
Se préparer
Chez 4D, nous avons déjà partagé plusieurs exemples et webinaires basés sur l’IA, y compris des démonstrations récentes sur la construction d’un système RAG utilisant l’appel d’outils. Pour ce projet, j’ai décidé d’extraire le formulaire de l’interface de discussion de la démo People & Skills et de le rendre plus générique et réutilisable.
L’interface de chat se compose des éléments suivants :
- Le formulaire AIChat, avec sa classe de formulaire formAIChat.4dm. Ce formulaire fournit
- une simple entrée de texte pour l’invite de l’utilisateur
- une zone web qui affiche la conversation avec le modèle
- La classe AI_ChatWithTools, responsable de :
- l’instanciation d’un bot d’intelligence artificielle à l’aide de l’assistant de conversation du 4D AI Kit, sur la base du serveur d’inférence et du modèle configurés dans Resources/AIProvider.json
- charger les outils définis dans Resources/AITools.json
- l’hébergement de l’implémentation de ces outils
La classe fonctionne entièrement en mode streaming, de sorte que l’utilisateur bénéficie d’une expérience de type ChatGPT, avec des réponses apparaissant progressivement.
- Le rendu de la conversation est géré par le singleton ChatHTMLRenderer.
Il prend la collection de messages stockés dans l’AIBot et les reflète en HTML en utilisant les modèles situés dans le dossier Resources :
-
- chat-template.html
- chat-template.css
- tool-icon.svg
Je vais être honnête : le rendu HTML a été essentiellement « vibe-codé » avec l’aide de l’agent GitHub de VS Code et de Claude Sonnet 4.5. La partie la plus difficile a été d’assurer un rendu correct pendant le streaming, en particulier pour les éléments tels que les tableaux, les appels d’outils et les graphiques.
Appel d’outils d’IA
Comme vous le savez probablement, un modèle d’IA ne connaît pas intrinsèquement vos données. Il n’y accède que par l’intermédiaire d’outils que vous lui fournissez explicitement. Dans cette section, j’expliquerai quels outils j’ai mis en œuvre et comment ils fonctionnent.
tool_getProducts, tool_getClients, tool_getInvoices, tool_getInvoiceLines
Tous ces outils sont chargés d’interroger la base de données. Chacun d’entre eux effectue une simple requête ORDA sur la base des champs demandés par le modèle.
Bien entendu, il existe un vaste champ d’amélioration pour les fonctions de ces outils. Grâce aux fonctionnalités natives de 4D 21 AI, nous pourrions imaginer une recherche sémantique utilisant 4D.Vector et les embeddings pour améliorer la recherche des clients. Comme cela impliquerait des changements plus profonds dans la structure, j’ai choisi une voie plus simple.
Décortiquons tool_getClients, car le même schéma s’applique à tous les autres outils « getter » :
Function tool_getClients($input : Object) : Object
Cette fonction reçoit un objet en entrée et renvoie un objet en sortie. L’entrée décrit les paramètres de recherche ; la sortie contient les données résultantes.
Validation de l’entrée
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
La première étape consiste à valider que l’entrée correspond au schéma défini dans AITools.json.
La plupart des modèles modernes produisent des appels d’outils bien structurés, mais selon le modèle, la validation reste une bonne pratique de sécurité.
Si la validation échoue, l’outil renvoie un simple objet contenant une propriété d’erreur. Il est important de savoir que le modèle lit cette valeur, alors n’hésitez pas à être explicite sur ce qui n’a pas fonctionné.
Mise en place de valeurs d’entrée par défaut
$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
Les valeurs par défaut assurent la sécurité des requêtes ORDA, mais elles ont aussi un avantage intéressant : écrire un schéma JSON complet dans AITools.json peut être fastidieux. Au lieu de cela, j’ai laissé GitHub Copilot déduire le schéma à partir du code et de la structure par défaut et le résultat a été excellent. Copilot a produit une définition précise du schéma en se basant uniquement sur la logique ci-dessus.
Paramètres à noter
- orderBy et top réduisent la taille de la sortie (et donc l’utilisation de jetons).
- countOnly permet au modèle de demander uniquement le nombre d’enregistrements sans récupérer les données.
Exemples pratiques :
- Si le modèle a besoin du nombre de clients → countOnly = true
- S’il veut les 5 premiers clients → top = 5 et orderBy : {field : « Total_Sales », order : « desc »}
Initialisation de l’objet de sortie
$returnObject:={}
$returnObject.form:="Clients"
$returnObject.dataClass:="CLIENTS"
$returnObject.counts:={}
$returnObject.counts.total:=$entities.length
- form indique quel formulaire d’interface utilisateur peut être utilisé pour afficher les résultats – nous verrons cela plus tard.
- dataClass identifie la classe de données concernée, ce qui est important pour les requêtes portant sur plusieurs tables – nous verrons cela également plus tard.
- counts.total est le nombre d’enregistrements avant l’application d’un filtre.
Exécution de la requête
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)
Cette partie est simple et pourrait certainement être rendue plus générique, mais ce n’était pas mon objectif ici.
Finalisation du résultat
$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
Décomposition
- counts.totalFiltered: nombre d’enregistrements après filtrage
- counts.totalSent: nombre d’enregistrements renvoyés (après application du top)
- entities: la collection de données finale (ou vide si countOnly = true)
Vous remarquerez que l’outil contrôle exactement quels attributs sont envoyés au modèle. Il est important de trouver le bon équilibre.
Ce qu’il faut prendre en compte
- Qualité de la conversation: plus de données → meilleures informations
- Performance: plus de données → traitement plus long
- Fenêtre contextuelle: les modèles locaux peuvent notamment se dégrader lorsqu’ils sont surchargés
- Coûts: plus de jetons → utilisation plus importante des serveurs d’inférence en nuage
- Confidentialité: tenez toujours compte du GDPR et de la sensibilité des données lors du choix des champs.
Le résultat
Quel que soit l’objet retourné par l’outil, 4D AI Kit le sérialise de manière transparente et le livre au modèle. Plutôt pratique, non ?
Interrogation entre tables et première invite du système
Une autre découverte intéressante faite au cours de ce projet a été que le modèle ne comprenait pas automatiquement les relations entre les tables. Par exemple, des prompts tels que :
Donne-moi les 5 meilleurs clients, leur facture la plus élevée et le produit le plus commandé
ne produisaient pas toujours des résultats fiables.
Le problème était simple : le modèle ne comprenait pas que l’ID de la table Clients devait être utilisé pour interroger la table Factures, ou que les lignes de facture étaient liées aux produits, etc.
En d’autres termes, je devais donner au modèle une certaine connaissance de la structure, mais sans aller trop loin. Mes exigences étaient les suivantes
- Pas de prompt système codé en dur : Je ne veux pas mettre à jour manuellement le prompt chaque fois que la structure change.
- Pas de catalogue de structure complet : Le modèle n’a pas besoin de tout le schéma, mais seulement des relations pertinentes.
Pour y parvenir, j’ai réutilisé une classe très pratique de Thomas Maul : StructureInfo.4dm, dont je n’ai extrait que les relations entre les tables.
C’est à partir de cette classe que j’ai généré mon prompt système initial :
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"
En combinant ces métadonnées de relations avec les informations dataClass renvoyées par chaque outil, le modèle a finalement été en mesure de comprendre comment enchaîner les appels d’outils à travers les tables.
Cela a considérablement amélioré la qualité et la précision des réponses du modèle, en particulier pour les analyses multi-tables telles que :
les meilleurs clients en fonction de leur chiffre d’affaires
ou
les produits les plus fréquemment commandés
ou
les factures les plus importantes par client
Expérience utilisateur : ouvrir un formulaire 4D directement à partir de l’interface conversationnelle
Lors de mes précédentes expériences avec le RAG, j’ai souvent affiché les résultats dans une liste séparée. Cette approche fonctionnait, mais elle présentait plusieurs inconvénients :
- J’avais besoin que le modèle fournisse, dans une section cachée séparée, la liste des ID d’entités à afficher dans la zone de liste. Cela signifiait plus de jetons, des réponses plus lentes et des astuces HTML supplémentaires (comme cacher la liste des ID dans un bloc commenté).
- Cela aurait nécessité un travail supplémentaire pour rendre la listbox suffisamment générique pour gérer différents types d’entités (Clients, Produits, Factures, …).
- Cela limitait l’interface utilisateur et donnait l’impression d’être moins intégré dans l’application.
Pour ce projet, je voulais quelque chose de plus simple, de plus élégant et de plus naturel pour l’utilisateur.
J’ai donc adopté une nouvelle stratégie : chaque fois que l’IA mentionne une entité, elle génère un lien hypertexte personnalisé qui ouvre directement le formulaire 4D correspondant, filtré sur l’entité sélectionnée.
Cela s’est avéré étonnamment facile. J’ai simplement ajouté les instructions suivantes au prompt système :
"**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"
Étant donné que mes outils renvoient toujours le formulaire approprié, la classe de données et la liste des entités, le modèle dispose de tous les éléments nécessaires pour générer ces liens correctement. Les modèles d’IA sont très performants pour ce type de sortie structurée.
Gestion des URL personnalisées dans 4D
Tout ce dont j’avais besoin du côté de 4D était un petit mécanisme de filtrage d’URL dans la zone web pour intercepter les liens myapp:// et ouvrir le bon formulaire avec la bonne sélection d’entités :
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
Le résultat
Le résultat final est une expérience utilisateur très fluide, où l’interface conversationnelle s’intègre parfaitement au reste de l’application 4D.
Les utilisateurs peuvent discuter avec l’IA, explorer des données et ouvrir instantanément des formulaires 4D natifs, le tout sans modifier la logique ou la structure de base de l’application.
Une interface d’interaction moderne, qui vient se greffer sur une application 4D classique… presque sans aucune intrusion.
Un outil supplémentaire : tool_createInvoice
L’exemple de base de données fourni dans le projet GitHub ne comprenait qu’une poignée de factures, pas assez pour rendre les interactions avec l’IA intéressantes. J’avais besoin de plus de données.
Créer un formulaire personnalisé ou écrire une autre routine de génération de factures me semblait à la fois fastidieux et hors de propos pour l’objectif de cette démo. C’est alors que j’ai compris : J’avais déjà tout ce dont j’avais besoin.
- Une interface utilisateur conversationnelle.
- Un agent d’intelligence artificielle connaissant mon modèle de données.
- La connaissance des clients, des produits, des prix, des relations…
Alors pourquoi ne pas laisser l’IA créer des factures directement à partir de l’interface de chat ?
Il me suffisait d’ajouter un nouvel outil : tool_createInvoice.
Mon approche était simple :
- Implémenter une fonction simple de création de factures dans AI_ChatWithTools.
- Envelopper l’ensemble du processus dans une transaction :
- En cas d’erreur : revenir en arrière et renvoyer un message d’erreur clair au modèle.
- En cas de succès : valider la facture et renvoyer ses détails.
- Documenter soigneusement le schéma de l’outil, en particulier ses paramètres d’entrée.
- Puis… laissez GitHub Copilot générer le schéma JSON dans AITools.json.
Le résultat ?
Je peux maintenant demander à l’IA de générer une toute nouvelle facture de manière entièrement autonome. Elle trouve un client pertinent, sélectionne les produits, calcule les totaux et appelle l’outil, le tout via la même interface conversationnelle que j’ai construite précédemment.
Cette méthode s’est avérée étonnamment élégante pour générer des données de test réalistes.
Une observation intéressante : certains modèles (notamment OpenAI GPT-4.1) ont tendance à demander une confirmation, ou au moins suffisamment de détails d’entrée, avant de créer une facture… à moins que vous ne leur demandiez explicitement de ne pas le faire.
Rendu HTML des messages OpenAI
Comme mentionné plus haut, cette partie a été entièrement « vibe-codée ». Réutilisez-la, adaptez-la ou ignorez-la, selon vos besoins. L’idée est simple : prendre une collection de messages OpenAI et les rendre joliment en HTML.
Mais bien sûr, nos utilisateurs finaux méritent toujours plus qu’une simple décharge de texte. J’ai donc ajouté quelques fonctionnalités de confort :
- Une mise en page propre et structurée pour les appels d’outils, y compris une indication visuelle lorsqu’un outil est en cours d’exécution.
- Un bouton « Copier » permettant de copier facilement n’importe quel message de l’assistant et de le coller dans un document, qu’il s’agisse de Microsoft Word, de Google Docs ou d’un courrier électronique.
Cela donne à l’ensemble de l’expérience conversationnelle un aspect poli et professionnel, tout en étant rapide et léger à mettre en œuvre.
- Un bouton « copier » pour chaque tableau, permettant à l’utilisateur d’extraire instantanément les données brutes du tableau et de les coller directement dans une feuille de calcul de type Excel.
Cette fonction est extrêmement pratique lorsque les utilisateurs souhaitent manipuler ou comparer des données en dehors de l’application sans rien exporter.
Capacités graphiques directement dans l’interface conversationnelle
Lorsqu’ils conversent avec une IA au sujet de factures, de clients ou de produits, les utilisateurs s’attendent naturellement à voir apparaître des graphiques. Classements, comparaisons, tendances… les informations visuelles font désormais partie de toute expérience moderne.
J’ai donc décidé d’intégrer le rendu des graphiques en ligne dans l’interface de chat et cela s’est avéré étonnamment facile, grâce à un peu de vibe-coding avec GitHub Copilot.
Je l’ai implémenté en trois étapes:
1) Importer Chart.js dans chat-template.html et étendre mon moteur de rendu HTML pour reconnaître les blocs <chart>…</chart>.
Pendant que l’IA diffuse sa réponse, une petite animation CSS affiche un espace réservé pour le graphique, ce qui donne une impression d’élégance à l’interface utilisateur.
2) Étendre l’invite du système pour enseigner explicitement à l’IA comment demander des graphiques. J’ai ajouté des instructions telles que
"**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) Laisser l’IA générer des définitions de graphiques en JSON, que la zone web rend instantanément à l’aide de Chart.js.
Le résultat est vraiment impressionnant : le modèle produit des images significatives directement dans le flux de la conversation, ce qui enrichit considérablement l’expérience.
Cela dit, je ne me fierais pas entièrement au modèle pour les calculs complexes. Pour une utilisation en production, il serait judicieux d’ajouter une série d’outils dédiés aux :
- les totaux et les cumuls
- le regroupement et l’agrégation
- résumés temporels
- comparaisons de périodes
- l’extraction des indicateurs clés de performance
4D effectuerait les calculs difficiles et précis, et l’IA se contenterait de les demander et de dessiner les graphiques sur la base de données numériques précises et validées.
Une combinaison parfaite entre la fiabilité de la technologie 4D et l’interface utilisateur pilotée par l’IA.
Conclusion
Alors… et maintenant ?
Nous avons essentiellement pris une application business quelque peu démodée et lui avons insufflé une expérience moderne, conversationnelle et alimentée par l’IA.
Mais considérer cela simplement comme « une autre façon de récupérer des données » serait passer à côté de l’essentiel.
Bien sûr, vous n’avez pas besoin d’ une interface conversationnelle pour obtenir « les 5 premiers clients par chiffre d’affaires total en 2025 ».
Un écran basique avec quelques filtres peut faire l’affaire.
Mais très vite, on se rend compte qu’il s’agit d’autre chose.
Il s’agit d’une nouvelle façon d’explorer vos données.
Avec un seul formulaire, l’interface de chat, les utilisateurs peuvent demander n’importe quoi: factures, produits, clients… qu’ils veuillent un tableau, un graphique ou les deux.
Il n’est donc plus nécessaire de créer d’innombrables écrans spécialisés pour des besoins de reporting légèrement différents.
Une fois que l’on a compris cela, on comprend également que cela va bien au-delà de l’interrogation et de l’affichage de données.
La valeur réelle ne réside pas dans la réponse à la question « montre-moi ceci ».
La véritable valeur réside dans la réponse à la question « aide-moi à comprendre cela ».
Votre question ne devrait plus être :
Dessine un graphique comparant 2024 et 2025
mais plutôt :
Merci de fournir un rapport de vente détaillé pour 2025, y compris les ventes totales, les 5 meilleurs produits par chiffre d’affaires, les 5 meilleurs clients par chiffre d’affaires, l’évolution des ventes au cours de l’année et les factures impayées. Présente les graphiques et les tableaux pertinents et explique les tendances, les opportunités et les risques notables. Compare également les performances des produits par rapport à 2024 et propose des pistes d’action pour améliorer les ventes et la trésorerie. Inclue une analyse des performances par client et par produit avec des indicateurs clés. Je veux à la fois des chiffres, des explications et des idées pratiques. Ton rapport comprendra des comparaisons entre 2024 et 2025. Les objectifs de ce rapport sont les suivants : comment augmenter les ventes, quels clients cibler, comment augmenter la performance des produits.
Voici le type de réponse que vous – et vos utilisateurs – obtiendrez :
Une interface conversationnelle unique, parfaitement intégrée à votre application 4D, capable de comprendre, de raisonner, de visualiser, de créer…
Il ne s’agit pas d’une fonctionnalité.
C’est une étape vers une nouvelle génération d’applications professionnelles.
Comment réutiliser ceci dans votre propre projet ?
Si la lecture de cet article et l’utilisation de l’application vous ont intéressé, vous pouvez simplement :
- Copier les fichiers suivants dans votre projet :
- Classes
- AI_ChatWithTools.4dm
- ChatHTMLRenderer.4dm
- formAIChat.4dm
- StructureInfo.4dm
- Formulaire
- AIChat
- Ressources
- AIprovider.json
- AITools.json
- modèle-de-chat.html
- chat-template.css
- tool-icon.svg
- Effectuer les adaptations nécessaires
- Adaptez le prompt et l’implémentation des outils dans AI_ChatWithTools.4dm
- Définissez des outils ultérieurs dans AITools.json (utilisez de l’IA pour cela !)
- Adaptez l’ouverture de formulaires à votre application dans formAIChat.webAreaEventHandler()
- Paramétrez le fournisseur d’IA dans AIprovider.json
- Classes
Et c’est tout !
Je terminerai par quelques remarques supplémentaires :
Dans cet exemple, toute la logique des outils est mise en œuvre dans la classe AI_ChatWithTools. Je l’ai fait ainsi parce que mon but était d’être aussi peu intrusif que possible, et parce que le projet n’implémente pas les DataClasses. En fonction de l’architecture de votre base de code, une meilleure pratique pourrait être d’avoir de tels outils ciblant les fonctions DataClasses.
Tout ce projet fonctionne parfaitement avec OpenAI et le modèle gpt-4.1 ou supérieur. Travailler avec un modèle local soulève des défis supplémentaires qui peuvent être discutés dans le forum 4D!


