SPB Git forge

spb/immbot-ai

Public
1commits 1branches 0releases
1.5 MBsize
maindefault branch
20 days agolast push
TypeScript 98.3% CSS 0.9% Shell 0.7%
5.3 KB · 84 lines markdown
Rendered Raw Blame History
1# Architecture RAG — Immbot AI23## Vue d'ensemble45Corpus : les fichiers **sources LaTeX** des deux cours (diapositives beamer, plans de cours,6ateliers, aide-mémoires, glossaire) — soit ~1 700 diapositives et ~40 documents. L'ingestion7travaille sur la source (pas le PDF) : structure exacte, numéros de diapositives fiables,8équations intactes.910```11Fichiers cours ──> Scanner ──> Parseur LaTeX ──> Chunker structurel ──> Fragments+métadonnées12                                                                          │13                                              SQLite : chunks + FTS5 + embeddings (blob 384d)14                                                                          │15Question ──> embedding local ──> [FTS5 BM25 ∥ cosinus] ──> fusion RRF ──> filtres/boost ──>16   expansion voisins ──> contexte numéroté [S1..Sn] ──> LLM ──> validation citations ──> réponse citée17```1819## Espaces de connaissances (isolation)2021`official-imm1003` · `official-imm1033` · `student-temporary-upload` (fichiers joints à une22conversation, portée = cette conversation) · `student-persistent-files` (bibliothèque personnelle) ·23`instructor-private` (examens, blueprints, analyses — jamais servis aux étudiants) ·24`general-knowledge` (aucun fragment : étiquette pour les réponses hors RAG).25Croisement inter-cours désactivé par défaut, activable par l'admin, toujours signalé dans la réponse.2627## Fragmentation structurelle2829| Source | Unité de fragment | Métadonnées clés |30|---|---|---|31| Diapositives beamer | 1 frame = 1 fragment (titre + contenu + boîtes sémantiques aplaties) ; fusion des frames de suite (1/2, 2/2) au même titre | cours, séance, n° de diapositive, titre, section courante, type de boîte (définition/important/exemple/formule) |32| Plans de cours / articles LaTeX | section/sous-section, redécoupée par paragraphes si > ~1 800 caractères, avec chevauchement d'une phrase | cours, document, section, titre |33| Ateliers (énoncés/solutions) | par exercice/question (`\section`, `enumerate` de premier niveau) | cours, atelier, type (énoncé/solution) |34| Glossaire | par entrée (terme FR/EN + définition) | terme, cours |35| Markdown/TXT | par titre `#`/`##` | document, titre |36| Téléversements étudiants (PDF/DOCX/XLSX/CSV/images) | extraction texte par page/feuille ; images passées telles quelles aux modèles vision | conversation, page/feuille |3738Le texte LaTeX est **détexifié** pour l'indexation (macros sémantiques UQO converties en préfixes39« Définition : », « Important : » ; équations conservées en notation `$...$` pour l'affichage)40tout en conservant la version affichable. Contexte minimal garanti : chaque fragment inclut41cours + document + section pour rester compréhensible isolément.4243## Embeddings4445`Xenova/multilingual-e5-small` (384 d) exécuté localement via `@huggingface/transformers`46(préfixes `query:` / `passage:` conformes à E5). Choix motivé : OpenRouter n'expose pas47d'embeddings ; le modèle est multilingue (corpus français), léger (~120 Mo), et le corpus tient48en mémoire (2-3k × 384 floats ≈ 4 Mo) → cosinus exact en < 10 ms, pas d'index ANN nécessaire.4950## Recherche hybride51521. Analyse de la requête : cours actif (jamais deviné : choisi dans l'interface), détection de53   séance/diapositive citée explicitement, type de question (définition/calcul/comparaison).542. Candidats : FTS5 `bm25()` (top 30, unicode61 + remove_diacritics) ∥ cosinus vectoriel (top 30).553. **Fusion RRF** (k=60) + boosts : correspondance exacte de terme du glossaire, fragments de type56   « définition » pour les questions de définition, tableaux pour les questions de données.574. Dédoublonnage par document/diapositive, **expansion aux diapositives voisines** (±1) quand le58   fragment gagnant est une suite (1/2 → 2/2).595. Budget de contexte : top 8-12 fragments équilibrés entre documents, plafonné en jetons.606. Contexte transmis : `[S1] (IMM1003 — Séance 4 — Diapositive 18 — « Titre ») texte…`.6162## Citations : contrat strict6364- Le modèle ne peut citer que les balises `[Sx]` du contexte fourni (politique dans65  `prompts/citation-policy.md`).66- Post-traitement serveur : chaque `[Sx]` est résolu vers son fragment ; toute balise inconnue est67  retirée et comptée (`invalid_citation_rate` journalisé). Le client reçoit la liste résolue68  (document, séance, diapositive, extrait exact, contexte voisin) → panneau source cliquable.69- Mode « Cours uniquement » sans contexte pertinent (scores sous seuil) → réponse de refus honnête70  standardisée, sans appel « créatif ».7172## Ingestion incrémentale7374Somme de contrôle SHA-256 par fichier ; réingestion seulement si modifiée ; suppression des75fragments orphelins ; exécutions journalisées dans `ingestion_runs` (fichiers, fragments, erreurs,76durée) ; rapport lisible dans `docs/ingestion-report.md` et l'admin.7778## Évaluation7980`evaluation/imm1003-test-set.json` et `imm1033-test-set.json` : questions dorées avec documents81attendus. Script `scripts/verify.sh` → `evaluation/rag-evaluation.md` : rappel@k des sources,82taux de citations valides, taux de refus corrects (questions hors corpus), isolation inter-cours83(les questions IMM1033 ne doivent pas remonter de fragments IMM1003 quand le croisement est off).84