De quoi on parlait la dernière fois ?
Jusqu'au 19 mai, l'assistant retenait tout, sauf la conversation en cours. Un écran qui s'éteint, un réseau qui saute, un passage par une autre application, et le fil des dernières minutes disparaissait : « oui » ne voulait plus rien dire, et « de quoi on parlait la dernière fois ? » recevait « je ne retrouve pas de conversation récente ». Les souvenirs étaient intacts. Cette journée a réparé la mémoire courte : une seule conversation par personne qui survit aux coupures, les échanges passés lus tels quels et datés, et un contexte qui ne se vide plus quand une de ses sources tousse.
Deux mémoires, et une seule qui tenait
Quand on parle de mémoire à propos de cette application, on pense à la mémoire neuronale : les fiches, les liens entre elles, ce qui est retenu pour des mois. C'est la mémoire longue, et au 19 mai elle marchait bien. Une semaine plus tôt, la recherche avait même appris à suivre les liens entre les souvenirs plutôt que de se fier à la seule ressemblance des mots.
Mais il existe une seconde mémoire, dont personne ne parle parce qu'entre humains elle va de soi. C'est celle des dix dernières minutes. Quand on dit « oui » à quelqu'un, il sait à quelle question. Quand on dit « et lui aussi », il sait de qui il s'agit. Cette mémoire-là n'est pas rangée dans une fiche : elle vit dans le fil de la conversation, du côté du serveur, sous la forme des derniers échanges relus par le modèle à chaque tour.
Et cette mémoire courte se perdait. Pas au bout d'une heure : au bout de quelques secondes, dès que la liaison entre le téléphone et le serveur se rompait, pour n'importe quelle raison. Le résultat était étrange à vivre. L'assistant se souvenait du prénom du dentiste et de la date de renouvellement d'un passeport, mais pas de la phrase qu'il venait de prononcer. Il donnait l'impression d'une personne à la mémoire encyclopédique et à l'attention défaillante, et cette impression était pire que si la mémoire longue avait été vide, parce qu'elle contredisait ce qu'on venait d'entendre.
Début d'après-midi : un chef d'orchestre par connexion
Le téléphone et le serveur se parlent par une liaison permanente, ouverte au lancement de l'application. Côté serveur, un chef d'orchestre reçoit ce que dit l'utilisateur, fait tourner le modèle, exécute ses outils et renvoie la réponse. C'est lui qui tient l'historique de la conversation.
Le défaut tenait dans une ligne : ce chef d'orchestre était construit pour chaque liaison. Une liaison, un chef d'orchestre, un historique à lui. Tant que la liaison vit, tout va bien. Mais une liaison meurt bien plus souvent qu'on ne l'imagine. L'écran s'éteint dans la poche : le système coupe la liaison pour économiser la batterie. On sort de chez soi : le wifi lâche, le réseau mobile prend le relais, et la liaison est refaite. On répond à un message dans une autre application et on revient : liaison refaite. À chaque fois, l'application se reconnecte toute seule, en silence, sans rien montrer. Et à chaque fois, le serveur fabriquait un nouveau chef d'orchestre, avec un historique vide, comme si une personne inconnue venait d'entrer.
Le modèle recevait alors la mémoire longue, et rien d'autre. Un « oui » lancé après un écran éteint devenait « oui à quoi ? ». Une demande formulée en deux temps, la première moitié avant la coupure et la seconde après, n'avait plus de première moitié. Et le même matin, l'assistant venait d'apprendre qu'on pouvait lui dire qui parle quand le téléphone est prêté à quelqu'un d'autre, sans que le propriétaire change ; cette déclaration vivait dans le même historique, et elle s'évaporait avec lui, au risque de ranger sous le mauvais nom ce que la personne de passage venait de dire.
La correction a pris la forme d'un déplacement. Il n'y a plus qu'un seul chef d'orchestre pour tout le serveur, et c'est lui qui garde toutes les conversations en cours, une par personne. Tout ce qui dépendait de la liaison, l'écran vers lequel envoyer une fiche à afficher, la façon de programmer un rappel pour ce téléphone précis, lui est remis au moment de chaque tour au lieu d'être scellé dans sa construction. Ainsi, quand une liaison se refait, elle retrouve la conversation qu'elle avait quittée : même historique, même locuteur déclaré, même fil. La règle est simple à énoncer : une reconnexion dans la demi-heure qui suit le dernier échange reprend la même conversation ; au-delà, on en ouvre une nouvelle.
Ce déplacement en imposait un second. Jusque-là, la fermeture de la liaison servait de signal de fin : c'est à ce moment que la conversation était résumée et archivée dans la mémoire longue. Si la conversation doit survivre à la fermeture, ce signal ne vaut plus rien. Le serveur passe donc en revue, toutes les cinq minutes, les conversations dont le propriétaire est silencieux depuis plus d'une demi-heure, les archive et les retire de sa mémoire vive. Rien ne s'accumule, et une conversation abandonnée en cours de route finit quand même dans la base, au lieu de se perdre au prochain redémarrage.
Fin d'après-midi : « je ne retrouve pas de conversation récente »
Le fil ne se rompait plus. Restait une question, posée le jour même à la voix, qui recevait une mauvaise réponse : « de quoi on parlait la dernière fois ? ».
Le matériel existait pourtant. Quand une conversation s'archive, un résumé en est écrit dans la mémoire longue, comme un souvenir parmi d'autres. Le problème était dans ce « parmi d'autres ». Avant chaque tour, le serveur assemble pour le modèle un aperçu de ce que sait la mémoire : les souvenirs de travail, ce qui a été mentionné ces derniers jours, un échantillon du reste. Les résumés de conversations passées s'y glissaient dans la liste des faits, sans étiquette. Le modèle voyait « week-end en Sicile, Claire, dates à confirmer » entre le code du portail et l'anniversaire de Paul, et n'avait aucun moyen de savoir que cette ligne racontait la conversation d'il y a douze minutes plutôt qu'un projet noté un jour. À la question « de quoi on parlait », il cherchait une conversation, n'en reconnaissait aucune, et répondait qu'il n'en retrouvait pas de récente. La réponse était sous ses yeux, déguisée en fait.
La première correction a donné à ces résumés leur propre section, en tête de l'aperçu, avec ce qui les distingue d'un fait : une date relative, « il y a 12 min », et la longueur de l'échange, « 4 tours ». Et une consigne, dans la même section : quand l'utilisateur demande de quoi on parlait, s'il se souvient, ou dit qu'il a oublié ce qu'on disait, s'appuyer d'abord sur ces résumés, avant toute recherche dans les fiches. Les mêmes résumés ont été retirés des autres listes, pour ne pas apparaître deux fois sous deux étiquettes.
Trois minutes plus tard : lire la conversation elle-même
La section a tenu trois minutes avant d'être refaite, parce qu'elle reposait sur un compromis qui n'avait pas lieu d'être.
Le résumé écrit à l'archivage a été pensé pour la recherche par ressemblance de sens : court, dense, calculé pour être retrouvé plus tard à partir d'un indice. C'est un index, pas un compte rendu. Or les conversations elles-mêmes sont conservées, avec chaque tour, dans une table de la base de données. Pour répondre à « de quoi on parlait », l'index est un détour : la matière est à côté, entière.
L'aperçu lit donc désormais cette table directement. Il présente les dernières conversations, de la plus récente à la plus ancienne, chacune avec son résumé, son âge et son nombre de tours. Et pour la plus récente, il déballe les derniers échanges tels qu'ils ont eu lieu, « Toi : est-ce que tu peux me faire une liste pour le week-end », « Moi : voilà, j'ai noté tout ça », les extraits raccourcis s'ils sont longs. Le modèle n'a plus à deviner de quoi parlait la session précédente : il l'a sous les yeux, mot pour mot, et il peut répondre avec son contenu plutôt qu'avec une paraphrase.
Il y a une leçon de méthode dans ces trois minutes. Quand la donnée existe sous sa forme brute, il vaut mieux la montrer que montrer ce qu'on en a dérivé. Le résumé garde son rôle, celui d'être retrouvé par ressemblance dans des semaines ; pour la question d'aujourd'hui, la transcription est la bonne réponse.
Début de soirée : une source qui tombe ne vide plus tout
Le dernier défaut de la journée ne se voyait qu'une fois de temps en temps, et c'est ce qui le rendait difficile à attraper.
L'aperçu de mémoire remis au modèle est assemblé à partir de plusieurs sources : les conversations récentes, les souvenirs de travail, ce qui a été mentionné ces derniers jours, l'échantillon du reste, et les règles personnelles. Elles sont interrogées en parallèle, pour ne pas additionner leurs temps d'attente. Mais elles l'étaient avec une règle du tout ou rien : si une seule des requêtes échouait, un délai côté base de données, un refus passager, l'ensemble était abandonné et le modèle recevait un aperçu vide. Il répondait alors, en toute bonne foi, qu'il ne se souvenait pas. Il n'avait littéralement rien.
La règle est devenue « tout ce qui répond est gardé ». Chaque source est attendue séparément ; celle qui échoue est notée dans les journaux et remplacée par une liste vide, les autres passent. Un contexte amputé d'une source vaut mieux qu'un contexte absent, et de loin : le modèle qui a les conversations récentes mais pas l'échantillon du reste répond presque comme d'habitude, celui qui n'a rien répond comme un inconnu.
Deux mesures ont accompagné ce changement. La première concerne le modèle lui-même : il arrivait que le service distant renvoie une réponse vide sur le premier appel d'un tour, une surcharge maquillée en succès. L'utilisateur entendait alors la phrase de secours, celle qui annonce un souci technique, prévue une semaine plus tôt pour les vraies pannes. Ce premier appel est désormais retenté une fois, après une courte pause, avant de renoncer. Une fois seulement, et seulement le premier : au milieu d'une chaîne d'outils, rejouer un appel reviendrait à exécuter deux fois ce qui a déjà été fait, créer deux fiches, programmer deux rappels.
La seconde mesure est une trace. À chaque tour, le serveur écrit dans ses journaux ce qu'il a réellement remis au modèle : combien de conversations récentes, combien de souvenirs de chaque étage, combien de règles, et la taille de l'ensemble. Avant, quand quelqu'un rapportait « il a oublié », il n'y avait aucun moyen de savoir si le modèle avait mal lu une mémoire pleine ou lu correctement une mémoire vide. Ce sont deux défauts sans rapport, qui produisent le même symptôme, et on ne corrige pas ce qu'on ne peut pas distinguer.
Ce que la journée aura appris
Trois défauts qui n'avaient rien en commun ont produit, pendant des semaines, une seule et même plainte : « il ne se souvient pas de ce qu'on vient de dire ». Un historique attaché à une liaison fragile. Des comptes rendus de conversation déguisés en faits. Une mémoire qui se vidait entièrement pour une source en retard. Aucun de ces défauts ne touchait aux souvenirs eux-mêmes ; tous touchaient à la façon de les remettre au modèle au bon moment.
C'est ce qui rend la mémoire courte si particulière. Un trou dans la mémoire longue passe souvent inaperçu : on ne remarque pas ce qu'on ne demande pas. Un trou dans la mémoire courte se voit à la seconde, parce qu'il contredit ce qu'on vient de vivre. Une personne qui oublie un rendez-vous d'il y a trois mois est distraite ; une personne qui oublie la phrase précédente n'écoutait pas. L'assistant donnait la seconde impression alors qu'il avait le premier défaut, et encore, pas vraiment.
Depuis le 19 mai, une conversation reprise après un écran éteint, un trajet ou un détour par une autre application est la même conversation. « De quoi on parlait la dernière fois ? » reçoit la réponse, avec les mots de la dernière fois. Et quand quelque chose manque, on peut savoir pourquoi. La mémoire longue fait qu'on peut revenir dans des mois ; la mémoire courte fait qu'on peut revenir dans une minute. Il fallait les deux pour que parler à l'application ressemble à parler à quelqu'un.
