IA â microservice embeddings, RAG, workers Messenger
Ce document couvre la couche IA de Telaria : l'indexation vectorielle (RAG L0) et les workers asynchrones. Pour le serveur MCP (L1) :
10-mcp.md.
1. Architecture IA â vue d'ensemble
Documents Markdown (telaria-doc)
â
âŒ
app:rag:ingest (CLI Symfony)
â chunks + appels embeddings
âŒ
tlr-embeddings (Python / FastAPI) â port 8001
â vecteurs float32 (768 dimensions)
âŒ
sqlite-vec (extension SQLite)
â index kNN persistĂ© dans var/rag/index.sqlite
âŒ
app:rag:search ou interface Chat
â requĂȘte â k voisins les plus proches
âŒ
Génération Claude (L2, clé API Anthropic)
Deux composants sont externes Ă l'application Symfony :
tlr-embeddings: microservice Python qui convertit du texte en vecteurssqlite-vec: extension SQLite (.sonatif) qui effectue la recherche kNN
2. tlr-embeddings â microservice Python
RĂŽle
Expose une API HTTP simple :
POST /embedâ convertit une liste de textes en vecteurs float32 (768 dim)GET /healthâ statut du service
ModĂšle utilisĂ© : multilingual-e5-base (Hugging Face) â supporte le français et l'anglais.
Installation
# RĂ©pertoire d'installation sudo mkdir -p /opt/tlr-embeddings sudo chown ubuntu:ubuntu /opt/tlr-embeddings git clone git@github.com:<owner>/tlr-embeddings.git /opt/tlr-embeddings cd /opt/tlr-embeddings # Environnement virtuel Python python3 -m venv .venv .venv/bin/pip install -r requirements.txt # requirements.txt pine torch en version CPU-only (pas de GPU requis) # â ïž Premier pip install : tĂ©lĂ©charge ~1,1 Go (modĂšle Hugging Face)
Le
requirements.lockdoit ĂȘtre gĂ©nĂ©rĂ© sur le serveur Linux (pas sur Windows/macOS) â les wheelstorchsont spĂ©cifiques Ă l'OS et Ă l'architecture.
Service systemd â /etc/systemd/system/tlr-embeddings.service
[Unit] Description=Telaria Embeddings Service After=network.target [Service] User=ubuntu WorkingDirectory=/opt/tlr-embeddings ExecStart=/opt/tlr-embeddings/.venv/bin/python app.py # Hugging Face stocke le modĂšle en dehors de /tmp (persistant entre reboots) Environment=HF_HOME=/var/lib/tlr-embeddings/hf # Premier dĂ©marrage : tĂ©lĂ©charge le modĂšle (~1,1 Go) â 10 min timeout TimeoutStartSec=600 # Durcissement ProtectSystem=strict ReadWritePaths=/var/lib/tlr-embeddings NoNewPrivileges=yes PrivateTmp=yes Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target
sudo mkdir -p /var/lib/tlr-embeddings/hf sudo chown ubuntu:ubuntu /var/lib/tlr-embeddings sudo systemctl daemon-reload sudo systemctl enable --now tlr-embeddings # Vérifier (attendre le chargement du modÚle) curl http://127.0.0.1:8001/health # {"status":"ok","model":"multilingual-e5-base","dim":768}
Empreinte mémoire
- Premier démarrage : ~1,1 Go téléchargés, mis en cache dans
HF_HOME - Runtime : ~440 Mo RAM une fois le modÚle chargé
- Démarrages suivants : modÚle chargé depuis le cache local (~30 secondes)
Contrat d'interface /embed
POST http://127.0.0.1:8001/embed Content-Type: application/json { "type": "query", "texts": ["Comment déployer Telaria sur un VPS ?"] }
type peut ĂȘtre "query" (recherche) ou "passage" (indexation). Tout autre valeur â HTTP 422.
3. sqlite-vec â recherche kNN dans SQLite
Pourquoi SQLite et non pgvector ou Pinecone ?
Sur un VPS sans PostgreSQL, SQLite suffit pour le volume de telaria-doc (~2400 chunks). ZĂ©ro infrastructure supplĂ©mentaire, zĂ©ro coĂ»t, rĂ©sultats cohĂ©rents avec cosinus > 0.8 sur des requĂȘtes en français.
Installation de l'extension
sqlite-vec est une extension SQLite native (.so) qui n'est pas incluse par défaut.
# Télécharger la release loadable (x86-64 Linux) # Voir https://github.com/asg017/sqlite-vec/releases wget https://github.com/asg017/sqlite-vec/releases/download/v0.1.x/\ sqlite-vec-0.1.x-loadable-linux-x86_64.tar.gz tar xzf sqlite-vec-0.1.x-loadable-linux-x86_64.tar.gz sudo mkdir -p /usr/local/lib/sqlite-vec sudo mv vec0.so /usr/local/lib/sqlite-vec/ sudo chmod 755 /usr/local/lib/sqlite-vec/vec0.so
Configurer le chemin dans .env.local :
RAG_SQLITE_VEC_PATH=/usr/local/lib/sqlite-vec/vec0.so
Chargement par PHP 8.5
Le bundle tlr-rag charge l'extension via :
$pdo = new \PDO('sqlite:' . $dbPath); $pdo->loadExtension($vecPath); // \Pdo\Sqlite::loadExtension() en PHP 8.5
â ïž Si
open_basedirest activĂ© dans PHP-FPM, le chemin devec0.sodoit y ĂȘtre inclus. Sur Telaria,open_basedirest dĂ©sactivĂ© en prod pour Ă©viter cette contrainte.
4. Index RAG â ingestion des documents
Structure de l'index
var/rag/ âââ index.sqlite â base SQLite principale (chunks + mĂ©tadonnĂ©es) âââ index.sqlite-wal â Write-Ahead Log (SQLite en Ă©criture) âââ index.sqlite-shm â Shared Memory
Les fichiers
-walet-shmsont créés dynamiquement par SQLite lors des Ă©critures. Le rĂ©pertoire doit ĂȘtre accessible en Ă©criture parwww-data(lecture/requĂȘtes web) et par l'utilisateur qui lance l'ingest.
Droits â setgid pour hĂ©ritage de groupe
sudo chgrp -R www-data /var/www/telaria/var/rag sudo chmod -R g+rwX /var/www/telaria/var/rag sudo chmod g+s /var/www/telaria/var/rag # setgid : tout nouveau fichier créé dans ce répertoire hérite du groupe www-data
Configuration du bundle RAG
# config/packages/telaria_rag.yaml telaria_rag: source_root: '%kernel.project_dir%/docs' # clone de telaria-doc # Chemins exclus de l'indexation (toujours) excluded_paths: - 'SCRATCH.md' - 'inputs/legacy/' # contenu brouillon, jamais dans le corpus RAG embedding: service_url: '%env(RAG_EMBEDDING_URL)%' # http://127.0.0.1:8001 model: 'intfloat/multilingual-e5-base' dimension: 768 batch_size: 32 chunk: size: 512 # tokens cible par chunk overlap: 64 # chevauchement pour ne pas couper le sens retrieval: k: 5 # top-k résultats par défaut store: database_path: '%env(resolve:RAG_DB_PATH)%' extension_path: '%env(RAG_SQLITE_VEC_PATH)%'
.aiignoreĂ la racine du corpus remplit le mĂȘme rĂŽle que.gitignorepour l'indexation : tout fichier listĂ© est exclu de l'ingest, mĂȘme s'il est Markdown.inputs/legacy/y figure par dĂ©faut â contenu de rĂ©fĂ©rence technique non destinĂ© au RAG.
Lancer l'ingestion
# PremiĂšre ingestion (indexation complĂšte) sudo -u www-data php bin/console app:rag:ingest --full # Ingestion incrĂ©mentale (nouveaux documents uniquement â compare les content_hash) sudo -u www-data php bin/console app:rag:ingest # RĂ©-indexation incrĂ©mentale explicite sudo -u www-data php bin/console app:rag:reindex # Statistiques aprĂšs ingestion php bin/console app:rag:stats # Attendu : ~180 documents / ~2400 chunks # Test de recherche php bin/console app:rag:search "comment dĂ©ployer Telaria ?" --k=5 # Attendu : top-5 chunks pertinents avec score cosinus > 0.8
Corpus source
Le bundle tlr-rag lit les fichiers Markdown depuis rag.source_root (configuré dans config/packages/telaria_rag.yaml). Par défaut : %kernel.project_dir%/docs/ (un clone de telaria-doc).
# Cloner telaria-doc comme source du corpus git clone git@github-telaria-doc:<owner>/telaria-doc.git /var/www/telaria/docs
Schéma SQLite de l'index
document : id, path, title, content_hash, indexed_at chunk : id, document_id, section, anchor, position, content, token_count, content_hash chunk_vector : table virtuelle sqlite-vec (chunk_id â vecteur float32[768]) ingest_run : id, source_root, started_at, finished_at, docs, chunks, status
chunk_vector est la table virtuelle créée par sqlite-vec. Elle stocke les vecteurs et permet la recherche kNN (SELECT ... FROM chunk_vector WHERE knn_search(...)).
UI de diagnostic /admin/rag
L'interface d'administration expose le travail "invisible" du RAG :
- AccĂšs :
https://telaria.dev/admin/rag(requiertROLE_ADMIN) - Statistiques en temps réel : nb documents, chunks, date derniÚre indexation, santé du microservice
- Formulaire de requĂȘte de test â affichage des chunks rĂ©cupĂ©rĂ©s avec score de similaritĂ© et lien vers la source
- Dégrade proprement si
sqlite-vecou le microservice sont absents (banniĂšre d'avertissement, pas d'erreur 500)
C'est l'artefact "vitrine" du RAG â dĂ©montrer au recruteur ou client que le retrieval fonctionne, avec les scores et les sources.
5. Workers Symfony Messenger â tĂąches asynchrones
Les tùches longues (ingestion RAG, veille agentique) sont traitées de maniÚre asynchrone via Symfony Messenger. Les workers consomment la file de messages en arriÚre-plan.
Configuration Messenger
# config/packages/messenger.yaml framework: messenger: transports: async: dsn: '%env(MESSENGER_TRANSPORT_DSN)%' # doctrine://default?queue_name=default (BDD comme transport) routing: 'App\Message\IngestDocuments': async 'Tlr\Codexia\Message\ProcessVeille': async
Service systemd worker â /etc/systemd/system/telaria-worker.service
[Unit] Description=Telaria Symfony Messenger Worker After=network.target mysql.service [Service] User=www-data WorkingDirectory=/var/www/telaria ExecStart=php /var/www/telaria/bin/console messenger:consume async --time-limit=3600 Restart=always RestartSec=30 ; Recharger aprÚs un déploiement (le code a changé) KillSignal=SIGTERM [Install] WantedBy=multi-user.target
sudo systemctl daemon-reload sudo systemctl enable --now telaria-worker sudo systemctl status telaria-worker
Redémarrer les workers aprÚs un déploiement
AprÚs un git pull, les workers tournent avec l'ancien code. Il faut les redémarrer :
sudo systemctl restart telaria-worker
Le Symfony Messenger supporte le
--time-limit: le worker s'arrĂȘte proprement aprĂšs 1h et systemd le relance. Ăvite les fuites mĂ©moire sur les workers longue durĂ©e.
Ătape suivante : 10-mcp.md