Chapitres

DOC-05 / Référence technique · Chapitre 08

Mémoire & apprentissage

Trois mémoires (réflexe, doctrine, intuition), un recall sémantique, et une boucle qui transforme chaque erreur en garde-fou.

Cette page décrit comment le harness agentique se souvient (mémoire à trois niveaux), comment il retrouve l'information pertinente (recall RAG vectoriel), et comment il capitalise ses erreurs et ses succès en règles réutilisables (la boucle cicatrices → apprentissage → leçons).

La mémoire à trois niveaux

Le système distingue trois mémoires, de granularité et de discipline d'écriture croissantes.

NiveauSupportRôle
1 — réflexefichiers memory/*.mdChargés dans chaque session. Règles dures, feedbacks, références. Strict, grep-able, une ligne par entrée dans l'index.
2 — doctrineZettelkasten Obsidian (le Vault brain)Le « pourquoi » : décisions, doctrine, concepts. Exploratoire, relié note à note par des liens internes.
3 — sémantiquetable vectorielle ps_ac_embedding (pgvector, index HNSW cosine, 1024 dimensions)Index sémantique de tout ce qui précède + des tables métier. C'est le moteur du recall RAG.

Niveau 1 — réflexe

Quelques centaines de fichiers Markdown (feedback_*, user_*, project_*, reference_*), indexés par un fichier maître. Ils sont injectés dans le contexte de chaque session : c'est la mémoire « réflexe », chargée sans recall explicite. Elle est réservée aux vraies doctrines impactantes — chaque entrée d'index tient sur une seule ligne.

Niveau 2 — doctrine (Zettelkasten)

Le Vault brain regroupe plusieurs sous-dossiers : permanent (consolidé), inbox (dépôt brouillon), moc, daily, fleeting. Les notes sont reliées par wikilinks, avec un frontmatter YAML type / status.

Règle de promotion : inbox/ est la zone de dépôt où l'intelligence écrit librement ; permanent/ n'est jamais modifié sans ordre explicite du Fondateur. Aucun auto-merge inbox → permanent ni inbox → memory : la consolidation reste un geste humain.

Niveau 3 — sémantique (pgvector)

Une seule table vectorielle porte l'index sémantique, avec un index HNSW en distance cosine et une contrainte d'unicité sur le couple (source_type, source_id). Les vecteurs sont de dimension 1024, produits par le fournisseur d'embeddings canonique.

Indexation

Deux automates alimentent les niveaux 2 et 3. Ne pas les confondre : l'un remplit une table relationnelle (recherche structurée / UI du hub), l'autre remplit la table vectorielle (recall sémantique).

  • Indexeur du Zettelkastensy_brain_note. Parcourt les sous-dossiers du Vault, parse le frontmatter et extrait les wikilinks. Sync incrémental par comparaison de date de modification : UPSERT sur le chemin, suppression des lignes orphelines dont le fichier n'existe plus. Cron toutes les 15 minutes, idempotent.
  • Synchroniseur d'embeddingsps_ac_embedding. Embed les sources puis UPSERT. Déduplication par hash SHA-256 du contenu (skip si le couple source a déjà le même hash). Chunking MVP « 1 fichier = 1 chunk », troncature à 16 000 caractères. Embed par lots de 50 entrées.

Les sources indexées et leur source_type :

source_typeOrigine
cicatrice / victoiretable des cicatrices (échecs vs succès, selon kind)
memoryfichiers memory/*.md (hors index maître)
brain-<sous-dossier>notes du Vault brain
doctrine / chantier / agent / drill / conduitetables métier actives
iterationtriplets ReAct (raison / action / observation)

Réindexation immédiate : une cicatrice gravée pendant une boucle ReAct est ré-embeddée à la volée par une fonction dédiée, sans attendre le sync nocturne — elle devient recherchable au RAG dans la foulée.

Le recall RAG

Une requête texte est transformée en vecteur, puis comparée par distance cosine aux embeddings stockés. Le flux :

requête texte ──embed──> vecteur
   │
   ▼
SELECT source_type, source_id, content_chunk, metadata,
       1 - (embedding <=> vec) AS similarity
FROM ps_ac_embedding
[WHERE source_type = ANY(scope)]      -- filtre de portée optionnel
ORDER BY embedding <=> vec            -- distance cosine HNSW
LIMIT fetch_k
   │
   ▼
re-rank importance × récence ──> top-K final ──> bump du compteur de recall
  • Portées exposées à l'utilisateur : iterations, cicatrices, victoires, memory, brain, doctrine, chantiers, agents, drill, conduite, all.
  • Re-rank importance × récence : pour les cicatrices uniquement, on sur-récupère puis on pondère par similarité × (1 + importance/10) × exp(-âge_jours/365). Une cicatrice neuve et importante est boostée ; une vieille cicatrice mineure s'efface.
  • Bump anti-oubli : chaque cicatrice servie voit son compteur de recall incrémenté et sa date de dernier rappel mise à jour. Le cron d'archivage ne purge que ce qui n'a jamais été rappelé.
  • Interprétation des scores : au-delà de 0,75 très pertinent ; entre 0,65 et 0,75 pertinent ; en dessous, à valider manuellement.

La boucle d'apprentissage

C'est le cœur de la capitalisation. Une erreur (ou un succès reproductible) devient une donnée, puis une suggestion concrète, puis — après validation humaine — une règle chargée dans toutes les sessions futures.

ReAct / chantier
      │ erreur résolue (ou succès reproductible)
      ▼
table des cicatrices  (kind = failure | victory ; le « check » = la leçon)
      │ réindexation immédiate en pgvector
      │ scoring d'importance ; flag learnable
      ▼
moteur d'apprentissage  (LLM : cicatrice learnable → suggestion)
      │ INSERT suggestion (status = pending)
      ▼
hub : feed / apply / patch   (VALIDATION HUMAINE)
      │ status → applied | refused | modified
      ▼
journal d'audit  +  application réelle dans la destination
      ▼
boucle fermée : la règle est dans memory/ ou un CLAUDE.md → réflexe de la session suivante

La table des cicatrices

Source unique des leçons. Le champ kind sépare échecs et succès dans la même table. Le champ check_added porte la leçon : pour un échec, ce qu'on a ajouté pour ne pas recommencer ; pour une victoire, le pattern à reproduire. L'importance, scorée par un LLM, pondère le recall. Le booléen learnable est la porte d'entrée du moteur d'apprentissage.

Le moteur d'apprentissage

Pipeline : il récupère les cicatrices learnable qui n'ont pas encore de suggestion, triées par importance ; il purge les données personnelles avant tout appel LLM (et re-filtre la sortie, défense en profondeur) ; le LLM renvoie un JSON {destination, texte, diff avant, diff après} ; une suggestion est insérée avec le statut pending.

Les six destinations possibles d'une suggestion :

DestinationSens
claude_mdrègle à ajouter ou modifier dans un fichier de directives CLAUDE.md
settings_jsonconfig hooks / permissions / variables dans la configuration du harness
memorynote persistante de niveau 1 (réflexe)
brain_inboxnouvelle note Zettelkasten (concept / doctrine)
skillcréer ou améliorer une compétence invocable
chantier_outilnouveau chantier ou automate
Aucune auto-application : le moteur ne fait que proposer. La validation passe par le hub (feed, apply, patch), et chaque application validée laisse une trace dans un journal d'audit.

Leçons post-chantier

Un agent dédié, Montessori, drafte une leçon à la clôture d'un chantier. Il charge un bundle d'audit (méta, travaux, tâches, dernières itérations ReAct, cicatrices liées, logs de runs tronqués), le passe à un LLM avec un prompt figé en cinq sections : delta de tokens estimés vs réels, top 3 des erreurs récurrentes, top 3 des patterns à standardiser, une doctrine candidate, un outil à créer. Un garde-fou ROI refuse les chantiers trop petits. La sortie atterrit en brouillon dans brain/inbox/ ; la promotion vers le consolidé reste un geste humain.

Des patterns aux compétences

Un second pipeline transforme les patterns récurrents observés dans les boucles ReAct en propositions de skills. Un détecteur hebdomadaire passe un lot d'itérations terminées à un LLM qui repère les patterns présents sur au moins trois tâches et méritant une compétence. Chaque proposition non-doublon est insérée avec le statut pending ; un moniteur horaire alerte le Fondateur si la file d'attente dépasse un seuil. Une proposition validée dans le hub est promue en compétence native, dès lors invocable.

Le rêve nocturne

Un automate de consolidation tourne la nuit : il détecte les cicatrices répétées trois fois ou plus pour en drafter une promotion, et compacte les transcripts. Son garde-fou est strict — jamais d'auto-merge vers le consolidé ou vers le réflexe, et un mode simulation par défaut. La même discipline gouverne l'hygiène mensuelle de la mémoire de niveau 1 : détection des liens morts, archivage des fichiers obsolètes, déduplication par hash, le tout sous verrou anti-chevauchement et avec un rapport horodaté à chaque passage.

La façade IA

Tout appel IA du système passe par une façade unique, qui expose deux fonctions canoniques : embed (texte → vecteur) et complete (mission → texte ou JSON).

  • Routing par fichier : en mode auto, la façade lit un fichier YAML de routing qui associe chaque usage à un fournisseur et un modèle. Changer de fournisseur, c'est changer un mot dans ce YAML — pas de redéploiement, le run suivant relit la config. Fail-soft : YAML absent ou invalide → on retombe sur les valeurs par défaut.
  • Embed : le fournisseur souverain européen est canonique ; d'autres fournisseurs restent branchables.
  • Complete : l'invocation Claude passe par le mécanisme d'invocation d'agent du système (jamais en ligne de commande brute) ; les fournisseurs HTTP appliquent jusqu'à deux retries sur les erreurs transitoires (429 / 5xx), avec backoff, un 4xx restant permanent.
Anti-leak (règle P0) : aucune clé d'API n'apparaît jamais dans le code ou la documentation. Les identifiants des fournisseurs et de la base sont lus depuis l'environnement, par nom de variable, dans des fichiers de secrets non versionnés.

Une seule source de vérité

Au-dessus des trois niveaux de mémoire règne une règle unique : la base de données est la seule source de vérité. Le Markdown ne sert qu'aux runbooks et aux doctrines ; tout référentiel qui change vit en base. C'est la discipline qui empêche la connaissance de se contredire à mesure qu'elle grandit — et qui fait du collectif un organisme qui se renforce au lieu de répéter ses fautes.