02-ce-que-je-construis/bundles/tlr-rag.md

tlr-rag — bundle cœur RAG L0

tlr-rag est la fondation retrieval de l'écosystème Telaria. Il transforme des documents Markdown en une base interrogeable par similarité sémantique, sans aucune dépendance à un LLM — la génération est du ressort des surfaces (L2 : chat, veille).

Champ Valeur
Package Composer telaria/rag-bundle
Namespace Telaria\Rag\
Pilote telaria-app (même release flow)
Version en prod v0.1.3 — 200 docs / 2 528 chunks indexés

Spec fonctionnelle complète : specs/ia-coeur.md Tuto pas-à-pas : ../tutos/ia/rag-bout-en-bout.md Déploiement VPS : ../vps/09-ia-embeddings.md


Pipeline

Indexation (batch, hors-ligne)
  *.md ──▶ IngestionService ──▶ ChunkerInterface ──▶ EmbeddingClient HTTP ──▶ VectorStore
            (walk + filtre          (size=512 tok        POST /embed              (sqlite-vec
             .aiignore)              overlap=64)         passages → float[768])    upsert)

Requête (à la demande)
  question ──▶ EmbeddingClient HTTP ──▶ VectorStore.search ──▶ Hit[] (chunk + score + source)
               POST /embed query                kNN cosinus

Réindexation incrémentale : content_hash par chunk — seuls les chunks modifiés sont ré-embeddés.

Zéro clé IA en L0 — le cœur ne génère rien. L'embedding est délégué au microservice Python tlr-embeddings.


Schéma SQLite (index vectoriel)

Fichier : var/rag/index.sqlite (artefact dérivé, non sauvegardé — régénérable via app:rag:ingest).

Table Colonnes clés Rôle
document id, path, title, content_hash, indexed_at métadonnées par document
chunk id, document_id, section, anchor, position, content, token_count, content_hash fragment de texte indexé
chunk_vector table virtuelle sqlite-vec — chunk_id ↔ embedding float[768] recherche kNN cosinus
ingest_run id, source_root, started_at, finished_at, docs, chunks, status traçabilité des indexations

Extension requise : vec0.so chargée par PHP via Pdo\Sqlite::loadExtension(RAG_SQLITE_VEC_PATH).


Microservice d'embeddings (contrat HTTP)

Le microservice Python tlr-embeddings (FastAPI, port 8001, modèle intfloat/multilingual-e5-base, dim 768).

GET  /health
→ { "status": "ok", "model": "intfloat/multilingual-e5-base", "dim": 768 }

POST /embed
→ requête : { "type": "query" | "passage", "texts": ["..."] }
→ réponse : { "model": "...", "dim": 768, "vectors": [[0.012, ...], ...] }

→ 422 si type hors {query, passage} ou texts vide (erreur d'entrée, pas de fallback silencieux)

Convention e5 : les préfixes query: / passage: sont gérés côté service selon le type — le bundle PHP envoie le texte brut.


Interfaces Symfony (bundle)

Signatures figées en v0.1.x :

ChunkerInterface::chunk(Document $document): Chunk[]

EmbeddingClientInterface::embed(string $type, string[] $texts): float[][]
EmbeddingClientInterface::health(): array{status, model, dim}

VectorStoreInterface::initialize(): void
VectorStoreInterface::upsertDocument(Document $doc, Chunk[] $chunks, float[][] $vectors): void
VectorStoreInterface::documentHash(string $path): ?string
VectorStoreInterface::search(float[] $vector, int $k): Hit[]
VectorStoreInterface::stats(): array{documents, chunks, last_indexed_at}

RetrievalService::retrieve(string $query, ?int $k = null): Hit[]
IngestionService::ingest(?string $sourceRoot = null, bool $incremental = true): IngestReport

Modèles : Chunk{documentPath, documentTitle, section, anchor, position, content, tokenCount, contentHash} · Hit{chunk, score} avec score = 1 - distance_cosinus (∈ ~[0,1]).


Configuration (config/packages/telaria_rag.yaml)

Variable d'env Mappe vers Défaut
RAG_EMBEDDING_URL embedding.service_url http://127.0.0.1:8001
RAG_DB_PATH store.database_path %kernel.project_dir%/var/rag/index.sqlite
RAG_SQLITE_VEC_PATH store.extension_path vec0

Paramètres YAML (dans telaria_rag.*) :

Clé Défaut Notes
source_root %kernel.project_dir%/docs racine des .md à indexer
chunk.size 512 tokens par chunk
chunk.overlap 64 chevauchement
embedding.model intfloat/multilingual-e5-base
embedding.dimension 768
embedding.batch_size 32 chunks par appel /embed
retrieval.k 5 top-k par défaut
excluded_paths ["SCRATCH.md", "inputs/legacy/"] jamais indexés

Commandes CLI

# Indexation complète (supprime l'index existant)
php bin/console app:rag:ingest --full

# Indexation incrémentale (ne ré-embedde que ce qui a changé)
php bin/console app:rag:ingest
# ou
php bin/console app:rag:reindex

# Tester une requête
php bin/console app:rag:search "sécurité VPS" --k=5

# État de l'index + santé du microservice
php bin/console app:rag:stats

UI de diagnostic : /admin/rag (ROLE_ADMIN) — statistiques, dernier ingest, formulaire de test.


Dépannage

RAG vide — 0 document, 0 chunk

# 1. Microservice actif ?
systemctl is-active telaria-embeddings
curl http://127.0.0.1:8001/health

# 2. Extension sqlite-vec chargée ?
php -r "new PDO('sqlite::memory:'); echo 'ok';"
php bin/console app:rag:stats  # signale si extension absente

# 3. Relancer l'indexation complète
php bin/console app:rag:ingest --full

Microservice Python crashé après upgrade Python

Le venv Python (/var/www/telaria-embeddings/venv) est lié à la version de Python. Après un upgrade OS :

# Supprimer et reconstruire le venv
rm -rf /var/www/telaria-embeddings/venv
cd /var/www/telaria-embeddings
python3 -m venv venv
./venv/bin/pip install -r requirements.txt
sudo systemctl restart telaria-embeddings

Index corrompu (fichiers WAL non fermés)

Si index.sqlite-wal ou index.sqlite-shm existent et que PHP échoue à lire l'index :

# Réinitialiser proprement (artefact dérivé, pas de perte de donnée)
rm -f var/rag/index.sqlite var/rag/index.sqlite-wal var/rag/index.sqlite-shm
php bin/console app:rag:ingest --full

Score trop faible — mauvais résultats

  • Vérifier le seuil score_threshold dans chat_config (BO /admin) — recommandé ≥ 0.6 pour multilingual-e5-base.
  • Vérifier les préfixes e5 : requêtes → type=query, passages → type=passage. Une inversion donne de mauvais scores.
  • Chunk size : si les chunks sont trop courts (< 100 tokens), le contexte sémantique est insuffisant.

Voir aussi

Assistant documentaire

Posez une question sur la documentation. Les réponses citent leurs sources — un clic ouvre le document à gauche.

Loading…
Loading the web debug toolbar…
Attempt #