Dans le dernier article, nous avons construit la version ColdFusion AI de « Hello World ». Nous avons configuré un ChatModel(), envoyé une invite avec .chat(), lu response.message et affiché le résultat de façon sécuritaire. C’était simple, utile et volontairement limité.
Cette limitation est importante.
ChatModel() est sans état. Chaque appel se tient par lui-même. Il ne se souvient pas de ce que l’utilisateur a dit il y a cinq secondes. Il ne se souvient pas de son nom. Il ne se souvient pas qu’il préfère les exemples en CFScript. Il ne se souvient pas qu’il pose actuellement une question sur le scope de session et non, par exemple, sur l’entretien d’un levain. Ce n’est pas un bogue. C’est la couche qui fait exactement ce qu’elle est censée faire.
Mais si nous voulons créer quelque chose qui donne l’impression d’être un véritable assistant plutôt qu’un point de terminaison d’autocomplétion très coûteux, nous avons besoin de mémoire.
Cet article explique comment ajouter une mémoire de conversation à ColdFusion AI à l’aide de Agent(), comment comprendre les fenêtres de mémoire, comment utiliser PERUSER correctement, et comment séparer l’historique temporaire de conversation des préférences durables de l’utilisateur. Parce qu’il y a une grande différence entre :
« L’assistant s’est souvenu de ce que je venais de demander. »
Et :
« L’assistant a dit à Janet de la comptabilité que son nom est Bob et qu’elle habite à Paris. »
L’un est de la mémoire. L’autre est une rencontre avec les RH et/ou la sécurité.
Où nous en sommes dans la série
Dans le préambule, nous avons couvert le vocabulaire de l’IA : les LLM, les invites, les jetons, les fenêtres de contexte, la température, les hallucinations, les outils, le RAG, le MCP et les garde-fous. Dans l’article précédent, nous avons utilisé ChatModel() pour une requête simple sans état :
chatModel = ChatModel( {
provider : "openAI",
modelName : "gpt-5-nano",
apiKey : application.aiApiKey,
temperature : 0.3,
maxTokens : 500,
timeout : 30
} );
response = chatModel.chat(
"Explain ColdFusion session scope in one short paragraph."
);
writeOutput( encodeForHtml( response.message ) );
Cela fonctionne bien pour des tâches simples et ponctuelles :
- résumer ce texte
- réécrire ce paragraphe
- classer ce message
- expliquer cette erreur
- générer un court brouillon
- traduire ce contenu
Mais ça échoue au test de conversation le plus élémentaire. Si l’utilisateur dit « Je m’appelle David », puis demande « Comment je m’appelle ? », un simple appel ChatModel() n’en a aucune idée à moins que votre application réinjecte le message précédent. C’est là qu’entre en jeu Agent().
ChatModel() versus Agent()
La façon la plus simple d’y penser est la suivante : ChatModel() est la connexion au modèle. Agent() est l’enveloppe conversationnelle autour du modèle. Un ChatModel() envoie une invite à un LLM et reçoit une réponse. Un Agent() peut s’appuyer sur ce modèle et ajouter des éléments comme :
- la gestion de conversations à plusieurs tours
- la mémoire
- des instructions système persistantes
- du contexte par utilisateur
- l’appel d’outils
- des structures de requêtes de clavardage plus riches
Dans cet article, nous nous concentrons sur la mémoire. Nous n’utilisons pas encore d’outils. Nous ne nous connectons pas encore au MCP. Nous ne faisons pas encore de RAG. Nous ne construisons pas Skynet, Clippy 2.0 ni un chatbot qui insiste pour dire qu’il est « presque terminé » tout en générant du JSON invalide pendant onze minutes. Nous donnons seulement à l’assistant assez de mémoire à court terme pour tenir une conversation utile.
La configuration de base d’Agent
Commençons avec un ChatModel() de base et enveloppons-le dans un Agent().
chatModel = ChatModel( {
provider : "openAI",
modelName : "gpt-5-nano",
apiKey : application.aiApiKey,
temperature : 0.3,
maxTokens : 500,
timeout : 30
} );
agent = Agent( {
CHATMODEL : chatModel,
CHATMEMORY : {
TYPE : "messageWindowChatMemory",
MAXMESSAGES : 20,
PERUSER : true
}
} );
response1 = agent.chat(
"My name is David.",
session.sessionId
);
response2 = agent.chat(
"What is my name?",
session.sessionId
);
writeOutput( encodeForHtml( response2.message ) );
La partie importante est la configuration CHATMEMORY :
CHATMEMORY : {
TYPE : "messageWindowChatMemory",
MAXMESSAGES : 20,
PERUSER : true
}Cela indique à ColdFusion :
- d’utiliser une mémoire basée sur les messages
- de conserver les 20 derniers messages
- d’isoler la mémoire par utilisateur
Ce dernier point n’est pas optionnel dans toute application destinée à de vrais utilisateurs, à moins de vouloir délibérément créer une conversation de groupe partagée. Pour une conversation normale dans une application, PERUSER : true fait toute la différence entre « assistant » et « incident de confidentialité avec une boîte de texte ».
Pourquoi la mémoire appartient à Agent(), pas à ChatModel()
C’est un point architectural clé. La mémoire ne fait pas partie de ChatModel() lui-même. Un ChatModel() sans état ne conserve pas l’historique de conversation. Il envoie une invite, reçoit une réponse, puis poursuit sa vie. Il n’est pas disponible émotionnellement, mais il est fiable. La mémoire est gérée par la couche Agent().
Cela a du sens, parce que la mémoire n’est pas vraiment une responsabilité du modèle. C’est une responsabilité de l’application. Votre application doit décider :
- de qui est cette conversation
- quelle quantité d’historique conserver
- où la stocker
- quand l’oublier
- si elle survit aux redémarrages du serveur
- si elle est isolée par utilisateur
- si les préférences doivent être stockées séparément
- si la mémoire doit être incluse dans les futures invites
Le modèle ne sait rien de tout ça. Le modèle reçoit du contexte. ColdFusion et votre application décident quel contexte est envoyé. C’est exactement le même principe que nous répétons depuis le premier article : le LLM n’est pas votre application. C’est un moteur de raisonnement que votre application supervise. Maintenant, nous supervisons ce dont il se souvient.
Un test de mémoire de base
Voici un test simple que vous pouvez exécuter.
userId = session.sessionId;
agent.chat(
"My favorite ColdFusion style is CFScript.",
userId
);
response = agent.chat(
"What ColdFusion style do I prefer?",
userId
);
writeOutput( encodeForHtml( response.message ) );
Avec la mémoire configurée et le même userId transmis aux deux appels, l’assistant devrait pouvoir répondre en se basant sur le message précédent. Quelque chose comme :
You prefer CFScript.Cela ne veut pas dire que le modèle a magiquement acquis des connaissances permanentes. Cela veut dire que le Agent() a inclus l’historique de conversation pertinent dans la nouvelle requête. Cette distinction est importante. La mémoire n’est pas de la télépathie. La mémoire, c’est la construction d’une invite avec une meilleure plomberie.
L’argument userId
Remarquez cette partie :
response = agent.chat(
"What ColdFusion style do I prefer?",
userId
);Lorsque PERUSER : true, chaque userId unique obtient son propre contexte de mémoire. Cela signifie que ce userId peut être :
session.sessionId- l’ID de base de données de l’utilisateur connecté
- une clé utilisateur à portée de locataire
- un ID de conversation généré
- un autre identifiant stable qui a du sens dans votre application
Pour les applications avec connexion, je préférerais généralement un véritable ID d’utilisateur authentifié, possiblement combiné avec le contexte de locataire/groupe/compte. Par exemple :
userMemoryKey = "account-" & session.accountId & ":user-" & session.userId;Cela évite les collisions et indique très clairement à qui appartient quelle mémoire. Utiliser seulement session.sessionId peut convenir pour une discussion anonyme de courte durée, mais cela peut ne pas survivre d’un appareil à l’autre, d’un navigateur à l’autre ou d’une nouvelle session. C’est peut-être exactement ce que vous voulez. L’essentiel est de faire un choix intentionnel. N’utilisez pas à la légère quelque chose comme :
userId = "user";Ce n’est pas une mémoire par utilisateur. C’est un journal partagé avec des illusions de confidentialité.
PERUSER compte
Parlons de PERUSER. Lorsque vous définissez :
PERUSER : trueColdFusion limite la mémoire au userId que vous transmettez à agent.chat(). Cela signifie que ceci :
agent.chat( "My name is Alice.", "user-alice" );
agent.chat( "My name is Bob.", "user-bob" );
response = agent.chat( "What is my name?", "user-alice" );
writeOutput( encodeForHtml( response.message ) );
Devrait répondre Alice, parce que le troisième appel utilise le contexte de mémoire d’Alice. C’est ce que vous voulez.
Maintenant, imaginez que vous omettez PERUSER. Tous les appels partagent un seul contexte de mémoire global. Cela peut convenir pour un seul bot partagé dans une seule salle partagée. Ce n’est pas approprié pour une application normale où plusieurs utilisateurs discutent de façon indépendante.
Sans isolation par utilisateur, vous pouvez avoir une contamination croisée entre utilisateurs. Alice dit au bot :
My name is Alice and I live in Paris.Bob demande :
Where do I live?Le bot dit :
You live in Paris.Félicitations. Vous avez inventé la confusion distribuée. Aussi, possiblement, un bogue de confidentialité. Pour des expériences d’assistant propres à chaque utilisateur, utilisez PERUSER : true. Ensuite, transmettez une vraie clé utilisateur à chaque fois. Aucune exception, sauf si vous avez une raison très précise et que vous l’avez notée quelque part où votre futur vous pourra la retrouver.
Mémoire de fenêtre de messages
ColdFusion prend en charge une stratégie de mémoire de fenêtre de messages avec :
TYPE : "messageWindowChatMemory"Avec cette stratégie, vous précisez le nombre de messages à conserver. Par exemple :
CHATMEMORY : {
TYPE : "messageWindowChatMemory",
MAXMESSAGES : 20,
PERUSER : true
}Cela conserve les 20 derniers messages de l’historique de conversation. Lorsque la conversation dépasse cette limite, les messages les plus anciens sont supprimés. C’est simple et prévisible. Pour de nombreuses applications, c’est le meilleur point de départ. Vous pouvez facilement le raisonner :
- conserver les 10 derniers messages pour une discussion légère
- conserver les 20 derniers messages pour un comportement normal de l’assistant
- en conserver davantage si les conversations sont plus longues et que le modèle/le budget de contexte le permet
Il n’existe pas de nombre parfait. Si la fenêtre est trop petite, l’assistant oublie les choses trop vite. Si la fenêtre est trop grande, vous risquez d’envoyer trop de contexte, d’augmenter l’utilisation de jetons, d’augmenter les coûts, de ralentir les requêtes et de forcer le modèle à trier un historique de conversation qui comprend trois changements de sujet et quelqu’un qui demande si un hot-dog est un sandwich.
Pour une première implémentation, commencez avec quelque chose comme 10 à 20 messages. Ensuite, testez avec de vraies conversations. Ennuyeux, observable, mesurable. La sainte trinité peu glamour du logiciel de production.
Mémoire de fenêtre de jetons
ColdFusion prend aussi en charge la mémoire de fenêtre de jetons avec :
TYPE : "tokenWindowChatMemory"Avec cette stratégie, vous précisez un budget de jetons plutôt qu’un nombre de messages. Par exemple :
CHATMEMORY : {
TYPE : "tokenWindowChatMemory",
MAXTOKENS : 4000,
PERUSER : true
}Cela conserve les messages jusqu’à la limite de jetons configurée. Les messages plus anciens sont supprimés au besoin pour rester dans le budget de jetons. C’est utile lorsque vous vous souciez davantage des limites de contexte du fournisseur que du nombre de messages. Par exemple, dix courts messages peuvent être minuscules. Dix longs messages peuvent représenter une novella entière, une trace de pile et la configuration XML collée par quelqu’un en 2009.
Le nombre de messages ne vous indique pas toujours la taille de l’invite. La mémoire de fenêtre de jetons vous donne un contrôle plus serré sur la quantité d’historique de conversation incluse. Le compromis, c’est que c’est un peu plus abstrait. Les développeurs peuvent compter les messages facilement. Les jetons sont moins intuitifs.
Ma recommandation pratique :
Utilisez d’abord messageWindowChatMemory. Utilisez tokenWindowChatMemory quand :
- les conversations peuvent contenir des messages très longs
- le contrôle des coûts est important
- les limites de contexte du fournisseur sont une préoccupation
- vous avez besoin d’une gestion plus serrée de la taille des invites
- les utilisateurs collent des documents, des journaux, des rapports ou d’autres gros blocs de texte
En d’autres termes, utilisez des fenêtres de messages lorsque les conversations sont normales. Utilisez des fenêtres de jetons lorsque les utilisateurs commencent à coller tout le journal d’erreurs de production et demandent : « Des idées? »
Stockage en mémoire
Si vous ne configurez pas de stockage persistant, la mémoire de clavardage est stockée dans la mémoire JVM du serveur. C’est rapide et facile. C’est aussi temporaire. Le stockage en mémoire convient bien pour :
- le développement local
- les démos
- les sessions de courte durée
- les prototypes
- les fonctionnalités à faible risque
- « voyons si ça fonctionne avant de compliquer les choses »
Mais il a des limites :
- la mémoire est perdue lorsque le serveur redémarre
- la mémoire peut ne pas être disponible sur plusieurs nœuds ColdFusion
- la mémoire peut disparaître lorsque l’application se recharge ou que la session prend fin
- ce n’est pas un historique de conversation durable
Si vous exécutez un seul serveur ColdFusion local et testez un assistant, la mémoire en mémoire est idéale. Si vous exécutez une production derrière un répartiteur de charge avec plusieurs nœuds, la mémoire en mémoire peut produire un comportement étrange.
L’utilisateur envoie un premier message. Le nœud A s’en souvient. L’utilisateur envoie un deuxième message. Le répartiteur de charge les envoie au nœud B. Le nœud B dit :
Nice to meet you, stranger.Ce n’est pas le genre de personnalisation que quiconque a demandé.
Stockage persistant
Pour les applications de production, surtout les applications en grappe, vous devriez envisager un stockage persistant de la mémoire. ColdFusion prend en charge des magasins de cache persistants comme :
- Redis
- Memcache
- Ehcache
Un magasin persistant permet à l’historique des conversations de survivre au-delà de la mémoire JVM d’un seul serveur. Cela peut être important pour les redémarrages, le clustering et une expérience utilisateur plus fiable.Par exemple :
agent = Agent( {
CHATMODEL : chatModel,
CHATMEMORY : {
TYPE : "messageWindowChatMemory",
MAXMESSAGES : 20,
PERUSER : true,
PERSISTENTSTORE : "myRedisCache"
}
} );Le magasin persistant doit d’abord être configuré dans l’Administrateur ColdFusion. Ensuite, vous référencez le nom du cache configuré dans PERSISTENTSTORE. En production, Redis est généralement le choix évident pour les déploiements en grappe. Memcache peut être rapide, mais il est volatil et n’est pas durable après les redémarrages. Ehcache peut être utile pour les déploiements sur un seul serveur.
Le point principal est le suivant : si votre application s’exécute sur plusieurs nœuds, ne présumez pas à la légère que l’historique de conversation en mémoire est suffisant. Les répartiteurs de charge ne se soucient pas de la continuité émotionnelle de votre assistant.
La mémoire n’est pas la même chose que les préférences
Nous devons maintenant distinguer deux concepts qui sont souvent confondus :
- la mémoire de conversation
- les préférences de l’utilisateur
Ils sont liés, mais ce n’est pas la même chose. La mémoire de conversation correspond à ce que l’utilisateur et l’assistant ont dit récemment. Par exemple :
My name is David.I am working on a ColdFusion AI article.The code sample is using ChatModel().Make the next answer shorter.Ce type de mémoire aide l’assistant à maintenir le contexte d’une conversation. Les préférences sont des paramètres plus durables, propres à l’utilisateur.
Exemples :
- préfère des exemples CFScript
- préfère des réponses concises
- veut des exemples de code avec des tabulations
- travaille dans une application SaaS multitenant
- préfère des explications pour développeurs expérimentés
- veut des avertissements sur les risques de production
- utilise Adobe ColdFusion 2025
- veut des exemples avec des variables à portée
Les préférences peuvent survivre à la conversation. Cela signifie qu’elles devraient probablement se trouver dans la base de données de votre application, et pas seulement dans la mémoire de clavardage. Ne comptez pas sur une fenêtre de mémoire glissante pour conserver des préférences importantes. Si un utilisateur dit :
Always show me CFScript examples instead of tag syntax.Et si cette préférence est importante pour votre application, enregistrez-la volontairement, puis injectez-la dans l’invite ou le message système au besoin. La mémoire, c’est « ce dont on parlait à l’instant ». Les préférences, c’est « la façon dont cet utilisateur veut que l’application se comporte ». Traitez-les différemment.
Une stratégie simple pour les préférences
Imaginons que votre application stocke les préférences IA des utilisateurs dans une table. Vous pourriez avoir des préférences comme :
- style de réponse
- style de code préféré
- niveau de détail souhaité
- faut-il inclure des explications pour débutants
- faut-il inclure des avertissements de production
Pour l’article, nous n’avons pas besoin de concevoir un schéma de base de données complet. Nous pouvons supposer que nous avons déjà chargé une struct :
userPreferences = {
codeStyle : "CFScript",
answerLength : "concise",
experienceLevel : "experienced web developer new to ColdFusion AI"
};Nous pouvons maintenant construire une invite qui inclut ces préférences. Avec Agent(), vous pouvez utiliser un message système ou une struct de requête de clavardage selon la façon dont vous voulez structurer l’appel. Pour un exemple simple :
userPreferences = {
codeStyle : "CFScript",
answerLength : "concise",
experienceLevel : "experienced web developer new to ColdFusion AI"
};
chatRequest = {
SYSTEMMESSAGE : "
You are a helpful ColdFusion AI assistant.
The user prefers #userPreferences.codeStyle# examples.
Keep answers #userPreferences.answerLength#.
Assume the user is an #userPreferences.experienceLevel#.
",
USERMESSAGE : {
MESSAGE : "Explain messageWindowChatMemory."
}
};
response = agent.chat(
chatRequest,
session.sessionId
);
writeOutput( encodeForHtml( response.message ) );
Cela donne à l’assistant un contexte de préférences durable sans compter sur le modèle pour s’en souvenir à partir de l’historique de conversation précédent. C’est une meilleure approche. Les préférences importantes devraient provenir de votre application. La mémoire de conversation devrait aider avec le contexte récent. Ne faites pas fouiller le modèle dans de vieux messages pour trouver quelque chose qui aurait dû être un paramètre utilisateur. C’est comme stocker le mot de passe de votre base de données dans un fil Slack et appeler ça de la gestion de configuration.
Messages système persistants
Un Agent() peut aussi utiliser un message système persistant. Par exemple :
agent.systemMessage(
"You are a helpful ColdFusion AI assistant. Be concise. Use CFScript examples."
);
response = agent.chat(
"Explain tokenWindowChatMemory.",
session.sessionId
);
writeOutput( encodeForHtml( response.message ) );
Un message système donne à l’assistant des instructions comportementales durables. Utilisez-le pour des instructions générales sur le rôle et le ton :
- vous êtes un assistant ColdFusion
- soyez concis
- évitez de deviner
- expliquez les compromis
- utilisez des exemples CFScript
- rappeler aux utilisateurs de valider la sortie du modèle
N’utilisez pas un message système comme un tiroir fourre-tout pour chaque fait que vous avez jamais appris au sujet de l’utilisateur. Les messages système devraient être stables, ciblés et pertinents.
Faites aussi attention au comportement documenté autour de la mémoire. Si vous comptez sur des messages système persistants, configurez CHATMEMORY correctement. Sinon, utilisez une structure de demande de clavardage pour les instructions système par appel.
La version courte :
- Message système : idéal pour un comportement persistant de l’assistant.
- Structure de demande de clavardage : idéale pour des instructions explicites par appel.
- Préférences de l’utilisateur : habituellement mieux stockées dans votre application et injectées volontairement.
- Mémoire de conversation : idéale pour le dialogue récent.
Quatre outils différents. Quatre tâches différentes. N’utilisez pas un tournevis comme cuillère simplement parce que les deux tiennent dans votre main.
Un petit formulaire de clavardage fonctionnel
Transformons cela en une page ColdFusion pratique. Cet exemple suppose :
application.aiApiKeyexiste- l’utilisateur a un
session.sessionId - nous utilisons la mémoire de fenêtre de messages en mémoire
- il s’agit d’une simple démo, pas d’une interface de clavardage de production peaufinée
if ( !structKeyExists( application, "memoryDemoAgent" ) ) {
lock scope = "application" type = "exclusive" timeout = 10 {
if ( !structKeyExists( application, "memoryDemoAgent" ) ) {
chatModel = ChatModel( {
provider : "openAI",
modelName : "gpt-5-nano",
apiKey : application.aiApiKey,
temperature : 0.3,
maxTokens : 700,
timeout : 30
} );
application.memoryDemoAgent = Agent( {
CHATMODEL : chatModel,
CHATMEMORY : {
TYPE : "messageWindowChatMemory",
MAXMESSAGES : 20,
PERUSER : true
}
} );
application.memoryDemoAgent.systemMessage(
"You are a helpful ColdFusion AI assistant. Use CFScript examples when code is helpful. Be concise."
);
}
}
}
userId = session.sessionId;
result = "";
if ( len( trim( form.message ) ) ) {
try {
response = application.memoryDemoAgent.chat(
trim( form.message ),
userId
);
result = response.message;
} catch ( any error ) {
writeLog(
file = "ai",
type = "error",
text = "AI memory demo failed: #error.message#"
);
result = "Sorry, I could not generate a response right now.";
}
}
Message
Send
Réponse
#encodeForHtml( result )#
Cela vous donne un assistant de base avec mémoire activée. Ensuite, essayez ceci :
My name is David and I prefer CFScript examples.Puis demandez :
What is my name, and what kind of examples do I prefer?L’assistant devrait être capable de répondre parce que l’historique de conversation est inclus par l’intermédiaire de la mémoire. Maintenant, actualisez. Posez quelques questions de plus. Essayez suffisamment de messages pour dépasser votre fenêtre. Redémarrez ColdFusion si vous utilisez un stockage en mémoire. Testez ce qui se passe.
C’est comme ça qu’on apprend où est la limite. Pas en supposant. En la piquant avec un bâton, comme tout développeur respectable depuis le début des temps.
À propos de ce verrouillage à double vérification
Dans l’exemple ci-dessus, vous avez peut-être remarqué ce modèle :
if ( !structKeyExists( application, "memoryDemoAgent" ) ) {
lock scope = "application" type = "exclusive" timeout = 10 {
if ( !structKeyExists( application, "memoryDemoAgent" ) ) {
// create it
}
}
}Il s’agit d’un modèle courant de verrouillage à double vérification. Si vous construisez une vraie application, vous pourriez initialiser vos services IA dans Application.cfc, un conteneur DI, ColdBox, ou toute autre structure déjà utilisée par votre application. Le but n’est pas de dire que cette initialisation précise au niveau de la page est parfaite. Le but est que la configuration de votre agent ne soit pas recréée au hasard à chaque requête, sauf si vous avez une raison de le faire. Créez le modèle et l’agent intentionnellement. Stockez-les intentionnellement. Gérez leur cycle de vie intentionnellement. « Au hasard jusqu’à ce que ça semble fonctionner » n’est pas une architecture. C’est un appel à l’aide avec des points-virgules.
Réinitialisation de la mémoire
Éventuellement, vous voudrez permettre aux utilisateurs de réinitialiser la conversation. Par exemple :
- recommencer
- effacer la discussion
- oublier cette conversation
- nouveau sujet
Selon votre implémentation et votre stratégie de stockage, la réinitialisation de la mémoire peut être gérée au moyen des opérations de cache disponibles, d’une nouvelle clé de conversation ou de votre propre logique applicative. L’approche conceptuelle la plus simple consiste à changer la clé de mémoire. Au lieu d’utiliser seulement :
userId = session.sessionId;Utilisez une clé propre à la conversation :
userId = session.sessionId & ":conversation-" & session.aiConversationId;Lorsque l’utilisateur clique sur « Nouvelle conversation », générez un nouveau session.aiConversationId. Par exemple :
if (
structKeyExists( form, "resetConversation" )
|| !structKeyExists( session, "aiConversationId" )
) {
session.aiConversationId = createUUID();
}
userId = session.sessionId & ":conversation-" & session.aiConversationId;
Chaque nouvelle conversation obtient maintenant un contexte de mémoire vierge sans qu’il soit nécessaire de retirer manuellement et de façon ciblée les anciens messages. C’est aussi utile si votre application prend en charge plusieurs conversations par utilisateur. Un utilisateur peut avoir :
- conversation de question au soutien
- conversation de rédaction de contenu
- conversation d’aide à l’inscription
- conversation « pourquoi ce code me déteste-t-il? »
Chacune peut avoir sa propre clé de mémoire. Parce que parfois, la réponse n’est pas « effacer la mémoire ». Parfois, la réponse est « arrêter de faire partager un bac à jouets à des conversations sans lien entre elles ».
Évitez de tout conserver pour toujours
La mémoire semble utile, donc l’instinct naturel du développeur est : « stockons tout pour toujours ». S’il vous plaît, ne commencez pas par là.
L’historique des conversations peut contenir des renseignements sensibles. Les utilisateurs collent des choses qu’ils ne devraient pas coller. Journaux, courriels, adresses, jetons d’accès, notes internes, données personnelles et, à l’occasion, un mot de passe, parce que l’humanité reste invaincue.
Avant de stocker durablement l’historique de discussion, décidez :
- ce que vous stockez
- où vous le stockez
- combien de temps vous le stockez
- qui peut y accéder
- comment les utilisateurs peuvent l’effacer
- s’il faut masquer les données sensibles
- s’il faut le chiffrer
- s’il doit être consigné dans les journaux du tout
- si des règles de conservation s’appliquent
Pour de nombreuses applications, une mémoire à courte durée de vie suffit. Pour d’autres, un historique persistant est précieux. L’idée n’est pas de dire « ne stockez jamais la mémoire ». L’idée est de dire « n’allez pas accidentellement bâtir une archive permanente des secrets des utilisateurs parce que la démo était bien faite ».
La mémoire ne rend pas le modèle véridique
La mémoire aide le modèle à conserver le contexte. Elle ne le rend pas correct. Si l’utilisateur dit : « La lune est faite d’index de base de données », puis demande plus tard « De quoi la lune est-elle faite? », la mémoire peut aider l’assistant à se souvenir de la déclaration précédente.
Cela ne rend pas la déclaration vraie. C’est important lorsque les utilisateurs affirment des faits que votre application devrait vérifier. Par exemple :
Je suis le propriétaire du compte.Ne laissez pas la mémoire transformer cela en autorisation. Si la propriété du compte compte, vérifiez la base de données.
isOwner = accountService.userIsAccountOwner(
userId = session.userId,
accountId = session.accountId
);Utilisez la mémoire pour assurer la continuité de la conversation. Utilisez votre application pour la vérité. Utilisez votre base de données pour l’état. Utilisez votre logique d’autorisation pour les permissions. Utilisez le modèle pour le langage et le raisonnement. Ne faites pas du robot le portier.
La mémoire ne remplace pas le RAG
La mémoire ne remplace pas non plus le RAG. La mémoire, c’est l’historique de la conversation. Le RAG, c’est la récupération à partir de documents ou de données externes. Si l’utilisateur demande : « Qu’ai-je demandé plus tôt? », c’est de la mémoire. Si l’utilisateur demande : « Que dit notre politique de remboursement au sujet des annulations après le début de la saison? », c’est probablement du RAG, en supposant que la réponse se trouve dans vos documents de politique. Vous pouvez combiner les deux plus tard.
Par exemple, la mémoire peut se rappeler que l’utilisateur pose une question sur l’inscription U12. Le RAG peut récupérer la politique officielle d’inscription. Le modèle peut alors répondre en utilisant à la fois la conversation récente et le texte de politique récupéré.
Mais n’entassez pas tout votre manuel de politique dans la mémoire de discussion en appelant cela du RAG. Ce n’est pas de la récupération. C’est de l’accumulation avec facturation au jeton.
La mémoire ne remplace pas les outils
La mémoire ne remplace pas non plus les outils. Si l’utilisateur dit : « Je me suis inscrit à l’atelier », puis demande plus tard : « Suis-je inscrit? », la mémoire peut se rappeler que l’utilisateur a dit s’être inscrit. Mais la bonne réponse devrait venir de votre application. Peut-être qu’il s’est inscrit. Peut-être que le paiement a échoué. Peut-être qu’il s’est inscrit au mauvais atelier. Peut-être qu’un administrateur l’a annulé. Peut-être que la base de données de production tient actuellement ensemble grâce à une tâche planifiée nommée fix_registration_again.cfm.
L’assistant ne devrait pas s’appuyer sur la mémoire pour des faits qui appartiennent à votre système d’enregistrement. C’est à cela que servent les outils. Nous couvrirons les outils CFC dans le prochain article.
Pour l’instant, retenez ceci :
- la mémoire se souvient de la conversation
- les outils récupèrent ou modifient les données de l’application
- le RAG récupère les connaissances des documents
- les garde-fous appliquent la sécurité et les politiques
Différentes couches. Différents rôles.
Liste de vérification pratique pour la conception de la mémoire
Lorsque vous ajoutez de la mémoire à une fonctionnalité d’IA ColdFusion, posez-vous ces questions.
À qui appartient la mémoire?
Est-ce par session anonyme? Par utilisateur authentifié? Par utilisateur et organisation? Par utilisateur et conversation? Pour une application multi-tenant, cela compte beaucoup. Une clé sûre peut inclure le locataire, le compte ou le groupe ainsi que l’identifiant de l’utilisateur.
memoryKey = "tenant-" & session.tenantId & ":user-" & session.userId;Ou, si vous prenez en charge des conversations séparées :
memoryKey = "tenant-" & session.tenantId
& ":user-" & session.userId
& ":conversation-" & session.aiConversationId;Laid? Un peu. Clair? Oui. Mieux qu’une soupe de mémoire interlocataires? Absolument.
Combien devrait-il s’en souvenir?
Commencez petit. Essayez :
MAXMESSAGES : 20Ou :
MAXTOKENS : 4000Puis testez. Si l’assistant oublie trop vite, augmentez prudemment. Si les requêtes deviennent lentes, coûteuses ou étranges, réduisez ou changez de stratégie.
Où la mémoire devrait-elle résider?
Utilisez un stockage en mémoire pour le développement local et les démos simples. Utilisez Redis ou un autre cache persistant configuré pour les déploiements en production groupés. Ne faites pas semblant qu’une application de production à deux nœuds, équilibrée en charge, est un seul JVM bien confortable, à moins d’aimer les bogues fantômes.
La mémoire contient-elle des données sensibles?
Supposez que oui jusqu’à preuve du contraire. Les utilisateurs collent tout. Tout. To. U. T.
Comment l’utilisateur la réinitialise-t-il?
Prévoyez une action « Nouvelle conversation » ou « Effacer la discussion ». Même si vous pensez que les utilisateurs n’en auront pas besoin, ils en auront besoin. Surtout après avoir collé la mauvaise chose et fixé l’écran comme s’ils venaient d’envoyer la paie à la lune.
Les préférences durables sont-elles stockées séparément?
Si une préférence doit survivre aux sessions, aux appareils et aux redémarrages, stockez-la dans votre base de données. Ne comptez pas sur la mémoire du clavardage pour les paramètres utilisateur durables.
L’assistant a-t-il le droit d’agir sur des affirmations mémorisées?
Probablement pas sans vérification. La mémoire n’est pas l’authentification. La mémoire n’est pas l’autorisation. La mémoire n’est pas la vérité. C’est juste du contexte.
Erreurs courantes
Passons en revue les erreurs les plus faciles à faire avec la mémoire de l’IA.
Oublier PERUSER
Voilà le principal. Si les utilisateurs doivent avoir des mémoires distinctes, définissez :
PERUSER : trueEt transmettez une vraie clé d’utilisateur à agent.chat().
N’omettez pas cela à la légère. Ne testez pas avec un seul utilisateur en supposant que tout ira bien. Tout fonctionne avec un seul utilisateur. C’est pourquoi tester avec un seul utilisateur est la façon dont les bogues se faufilent en production avec des lunettes de soleil.
Utiliser la même clé de mémoire pour tout le monde
C’est simplement oublier PERUSER avec des étapes supplémentaires. Si chaque appel utilise :
agent.chat( message, "default" );Alors chaque utilisateur partage la même clé de mémoire par utilisateur. Ce n’est pas une mémoire par utilisateur. C’est une discussion de groupe à laquelle personne n’a consenti.
Stocker les préférences uniquement en mémoire
Si la préférence de l’utilisateur compte au-delà de la conversation en cours, stockez-la comme donnée d’application. Les fenêtres de mémoire suppriment les anciens messages. Les serveurs redémarrent. Les entrées du cache expirent. Les utilisateurs changent de navigateur. Ne bâtissez pas des comportements importants sur « j’espère que le modèle s’en souvient depuis plus tôt ». L’espoir n’est pas une stratégie de persistance.
Conserver trop d’historique
Plus d’historique n’est pas toujours mieux. Cela peut augmenter l’utilisation des jetons, les coûts, la latence et la confusion. Gardez une quantité de mémoire adaptée à la tâche. L’assistant n’a pas besoin de se souvenir qu’il y a douze messages, l’utilisateur a dit « lol », à moins que vous ne facturiez à la nostalgie.
Traiter la mémoire comme une vérité
Si l’utilisateur dit qu’il est administrateur, vérifiez la base de données. Si l’utilisateur dit qu’il a déjà payé, vérifiez l’enregistrement de paiement. Si l’utilisateur dit que la politique de remboursement permet quelque chose, vérifiez la politique. Le modèle peut mémoriser des affirmations. Votre application valide les faits.
Tout consigner
La mémoire des conversations peut contenir des données sensibles. Faites attention à ce que vous consignez. Le débogage, c’est bien. Créer par accident une archive fantôme de conversations privées d’utilisateurs, c’est moins bien.
Une meilleure première fonctionnalité de mémoire
Une bonne première fonctionnalité de mémoire est simple et peu risquée. Par exemple :
- retenir le sujet de la conversation d’assistance en cours
- retenir que l’utilisateur a demandé des réponses concises dans cette session
- retenir les réponses de clarification récentes
- retenir le brouillon en cours dont on discute
- retenir que l’utilisateur pose une question sur un exemple de code précis
Évitez de faire de votre première fonctionnalité de mémoire quelque chose comme :
- retenir les instructions de paiement à jamais
- retenir les détails médicaux
- retenir les conseils juridiques
- retenir les mots de passe, clés ou jetons privés
- retenir les affirmations d’autorisation fournies par l’utilisateur
Commencez par la commodité conversationnelle. Ne commencez pas par construire un palais de mémoire rempli de problèmes de conformité.
La suite
À ce stade, notre assistant IA ColdFusion peut faire quelque chose de plus utile qu’un simple appel ChatModel(). Il peut se souvenir de la conversation récente. Il peut conserver une mémoire séparée par utilisateur. Il peut utiliser des fenêtres de messages ou des fenêtres de jetons. Il peut utiliser un stockage en mémoire pour les cas simples ou un stockage de cache persistant pour la production. Il peut recevoir des préférences durables de votre application et les utiliser comme partie de ses instructions.
C’est une étape majeure.
Mais il ne peut toujours rien faire de réel à l’intérieur de votre application. Si l’utilisateur demande :
What is my registration status?L’assistant peut se souvenir que l’utilisateur a posé une question sur l’inscription plus tôt. Mais il ne peut pas interroger votre base de données en toute sécurité à moins de lui donner un outil. C’est le prochain article. Nous ajouterons des outils CFC afin que l’IA puisse demander des données réelles de l’application au moyen de méthodes ColdFusion que vous contrôlez.
C’est là que les choses deviennent beaucoup plus puissantes. C’est aussi là que nous devons devenir beaucoup plus prudents. Parce que donner de la mémoire à l’assistant est une chose. Lui donner des mains en est une autre.
Réflexion finale
La mémoire donne l’impression qu’un assistant IA est plus intelligent parce qu’elle peut conserver le contexte d’un échange à l’autre. Mais la mémoire n’est pas magique. Ce n’est pas la vérité. Ce n’est pas une autorisation. Ce n’est pas un stockage permanent des préférences . Ce n’est pas du RAG. Ce n’est pas un remplacement des outils.
C’est de la gestion du contexte.
Bien utilisée, elle rend les fonctionnalités IA cohérentes et utiles. Mal utilisée, elle fait agir votre application comme un stagiaire étourdi qui lit parfois le journal intime de quelqu’un d’autre.
Alors utilisez Agent(). Configurez CHATMEMORY. Définissez PERUSER : true. Choisissez une fenêtre de mémoire sensée. Utilisez un stockage persistant quand la production l’exige. Enregistrez les préférences durables dans votre application.
Et souvenez-vous de la règle récurrente : le robot peut se souvenir de la conversation. ColdFusion, et surtout vous, gardez toujours le contrôle.