feat(conscience): recall hybride complément gaté — pgvector + sidecar granite #20

Merged
kevin merged 1 commit from feat/recall-hybride-pgvector into main 2026-07-16 11:06:47 +00:00
Owner

Recall hybride « complément gaté » — ton design, mesuré puis câblé

Le SQL réformé garde la main ; le vectoriel ne complète (fusion RRF) que quand le match lexical est faible (< recall.hybrid_gate_terms termes, défaut 3, seuil validé sur holdout anti-surajustement). Jamais de fusion brute (mesurée : −8 pts sur les tours réels).

Le vrai code, validé bout-en-bout par le harnais

SQL seul hybride (vrai code)
synthétique · base 34 % 54 %
tours réels · base 52 % 52 % (jamais en dessous)
holdout · base 36 % 48 %
synthétique · ×10 propre 21 % 33 %
tours réels · ×10 propre 24 % 32 %
holdout · ×10 propre 32 % 44 %

Pendant la validation, le harnais a attrapé un écart réel : je fusionnais le top-15 SQL au lieu du top-5 mesuré → 48 % au lieu de 56 % sur les tours réels (régression vs SQL seul !). Corrigé, géométrie mesurée respectée, commentaire gravé dans le code.

Infra minimale

  • Store = pgvector sur le Postgres de l'app (nouveau provider = sous-classe de SupabaseVectorStore, URL dérivée de DATABASE_URL — zéro nouveau service, zéro credential en config ; l'extension est déjà dans l'image prod). C'était l'intuition de Kevin (msg #3142) bien avant ce chantier.
  • Embeddings = sidecar TEI granite-107m-multilingual (gagnant du harnais FR→FR), OpenAI-compatible, overlay séparé deploy/compose.embeddings.yml (~400 Mo RAM ; 3,3 Go dispo vérifiés sur le VPS). Le docker-compose de prod n'est pas touché (gotcha gravé).
  • Backfill idempotent scripts/conscience_vector_backfill.py : réindexe les vector_point_id NULL sans passer par memory_upsert (qui fausserait updated_at donc la récence).

Sûreté

Fail-open intégral : vecteur absent / pas prêt / en erreur → SQL seul = comportement 5.128.0 à l'identique. La feature est dormante tant que vector_provider n'est pas configuré → on peut merger et déployer le code, puis activer l'infra séparément.

CI : service Postgres → pgvector/pgvector:pg16 (même image que la prod). 8 tests hybride + 3 pgvector + caractérisation révisée (memories = SQL-first assumé). Plugin conscience 4.36.0.

🤖 Generated with Claude Code

## Recall hybride « complément gaté » — ton design, mesuré puis câblé Le SQL réformé **garde la main** ; le vectoriel ne **complète** (fusion RRF) que quand le match lexical est faible (< `recall.hybrid_gate_terms` termes, défaut 3, seuil validé sur holdout anti-surajustement). Jamais de fusion brute (mesurée : −8 pts sur les tours réels). ### Le vrai code, validé bout-en-bout par le harnais | | SQL seul | **hybride (vrai code)** | |---|---|---| | synthétique · base | 34 % | **54 %** | | tours réels · base | 52 % | 52 % *(jamais en dessous)* | | holdout · base | 36 % | **48 %** | | synthétique · ×10 propre | 21 % | **33 %** | | tours réels · ×10 propre | 24 % | **32 %** | | holdout · ×10 propre | 32 % | **44 %** | Pendant la validation, le harnais a attrapé un écart réel : je fusionnais le top-15 SQL au lieu du top-5 mesuré → 48 % au lieu de 56 % sur les tours réels (régression vs SQL seul !). Corrigé, géométrie mesurée respectée, commentaire gravé dans le code. ### Infra minimale - **Store = `pgvector` sur le Postgres de l'app** (nouveau provider = sous-classe de SupabaseVectorStore, URL dérivée de `DATABASE_URL` — zéro nouveau service, zéro credential en config ; l'extension est déjà dans l'image prod). C'était l'intuition de Kevin (msg #3142) bien avant ce chantier. - **Embeddings = sidecar TEI** `granite-107m-multilingual` (gagnant du harnais FR→FR), OpenAI-compatible, **overlay séparé** `deploy/compose.embeddings.yml` (~400 Mo RAM ; 3,3 Go dispo vérifiés sur le VPS). Le docker-compose de prod n'est pas touché (gotcha gravé). - **Backfill idempotent** `scripts/conscience_vector_backfill.py` : réindexe les `vector_point_id` NULL sans passer par memory_upsert (qui fausserait `updated_at` donc la récence). ### Sûreté **Fail-open intégral** : vecteur absent / pas prêt / en erreur → SQL seul = comportement 5.128.0 à l'identique. La feature est **dormante** tant que `vector_provider` n'est pas configuré → on peut merger et déployer le code, puis activer l'infra séparément. CI : service Postgres → `pgvector/pgvector:pg16` (même image que la prod). 8 tests hybride + 3 pgvector + caractérisation révisée (memories = SQL-first assumé). Plugin conscience 4.36.0. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(conscience): recall hybride « complément gaté » — pgvector + sidecar granite, le dense ne complète que si le lexical est faible
All checks were successful
CI / Backend — pytest (pull_request) Successful in 1m45s
CI / i18n — usage → locales (pull_request) Successful in 31s
3e485477c3
Design de Kevin, mesuré AVANT d être codé (harnais recall, 3 golds x
2 échelles, seuil validé sur holdout anti-surajustement), puis le code
réel re-validé bout-en-bout par le harnais :

                    SQL seul → HYBRIDE (vrai code)
  synthétique base    34 %   →  54 %
  tours réels base    52 %   →  52 %   (jamais en dessous)
  holdout     base    36 %   →  48 %
  synthétique x10     21 %   →  33 %
  tours réels x10     24 %   →  32 %
  holdout     x10     32 %   →  44 %

Mécanique (ports/memory.py, hors gel) : le SQL réformé GARDE LA MAIN
(il bat le dense pur sur la distribution réelle ; le dense s effondre à
20 % sur le holdout x10 seul) ; le vectoriel ne complète (fusion RRF,
égalité → SQL) que si le meilleur match lexical < recall.hybrid_gate_terms
(3, configurable). Géométrie mesurée : fusion du TOP-K SQL avec le
top-15 dense — un pool SQL élargi éjecte le bon hit (vérifié −8 pts).
Fail-open intégral : vecteur absent/KO → SQL seul (= comportement
actuel ; la feature est DORMANTE sans configuration).

Infra sans nouveau service de store : provider "pgvector" =
SupabaseVectorStore pointé sur le Postgres DE L APP via DATABASE_URL
(l extension y est déjà — prod pgvector/pg16 ; intuition Kevin msg 3142).
Embeddings = sidecar TEI granite-107m (gagnant du harnais FR→FR),
OpenAI-compatible, overlay séparé deploy/compose.embeddings.yml
(~400 Mo RAM, 3,3 Go dispo vérifiés). Backfill idempotent
scripts/conscience_vector_backfill.py (réindexe les vector_point_id
NULL sans toucher updated_at). CI : service Postgres → pgvector/pg16.

8 tests hybride + 3 pgvector + caractérisation révisée (comportement
memories = SQL-first assumé). Plugin conscience 4.36.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
kevin merged commit a5052eed80 into main 2026-07-16 11:06:47 +00:00
kevin deleted branch feat/recall-hybride-pgvector 2026-07-16 11:06:47 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kevin/Gungnir!20
No description provided.