# RAG — Documentation Funk > ✅ **Opérationnel** (relevé 2026-06-21) — `funk-docs` reconstruite après l'incident Qdrant du > 2026-06-17 : **436 chunks**, statut 🟢 green, embeddings **nomic-embed-text** (`:1238`, dim 768). > `rag-query` fonctionne. Détails de l'incident : `admin/incidents.md` (entrée 2026-06-05). Le RAG (Retrieval-Augmented Generation) permet à Hermes de répondre en s'appuyant sur la documentation du repo (`admin/`) plutôt que sur sa seule mémoire de modèle. --- ## Architecture ``` Hermes (funk-ai) │ terminal: rag-query "comment relancer dnsmasq ?" ▼ /usr/local/bin/rag-query (storage-01) │ 1. Embed la question → POST http://192.168.10.20:1238/v1/embeddings (nomic-embed-text) │ 2. Recherche vectorielle → POST http://127.0.0.1:6333/collections/funk-docs/points/search ▼ Qdrant (storage-01:6333) │ Retourne les N chunks les plus proches sémantiquement ▼ rag-query affiche les extraits + fichier source + score │ ▼ Hermes formule sa réponse en citant les sources ``` --- ## Composants déployés | Composant | Emplacement | Rôle | |---|---|---| | Qdrant | storage-01:6333/6334 | Base vectorielle — stocke les embeddings | | `rag-ingest` | `/usr/local/bin/rag-ingest` | Indexe les docs dans Qdrant | | `rag-query` | `/usr/local/bin/rag-query` | Interroge Qdrant depuis la ligne de commande | | Skill `rag-docs` | Profil `funk-ai` Hermes | Enseigne à Hermes comment utiliser `rag-query` | | Docs indexées | `/srv/data/rag/docs/` (NVMe) | Copie locale du dossier `admin/` | | Collection Qdrant | `funk-docs` | **436 chunks**, 🟢 green, **dim 768 Cosine** (nomic-embed-text) | --- ## Modèle d'embedding utilisé **nomic-embed-text** via l'instance dédiée llama-server `llama-embed` sur gpu-01 (`:1238`, **CPU**, dim 768). C'est un **vrai modèle d'embedding** — les scripts déployés `rag-ingest` et `rag-query` le hardcodent (`EMBED_URL=http://192.168.10.20:1238/v1/embeddings`, `EMBED_MODEL=nomic-embed-text`). > Historique : le RAG utilisait au départ **Qwen3-8B** (modèle de chat, `:1234`, dim 4096) réutilisé > pour les embeddings → scores cosinus saturés (0.90–0.95), peu discriminants. La migration vers > nomic (dim 768) étale les scores → tri par pertinence réel. La collection a été recréée à dim 768. > ⚠️ **Drift IaC** : `ansible/roles/rag/defaults/main.yml` a longtemps gardé `embed_url: :1234` / > `embed_model: qwen3-8b` — variables **mortes** (le handler lance `rag-ingest` sans passer d'env → > le défaut hardcodé nomic du script gagne). Aligné sur nomic dans le même lot que ce relevé. L'instance `llama-embed` est gérée par le rôle `llama_server` (`llama_embed_enabled`, voir son README). ```bash # (re)déployer l'instance embeddings sur gpu-01 ansible-playbook -i inventory.yml playbooks/gpu-01.yml --tags llama_server ``` ### Alternative envisagée | Modèle | Taille | Dimension | Notes | |---|---|---|---| | `nomic-embed-text` | ~274 MB | 768 | **En service** — rapide, bon équilibre qualité/taille | | `bge-m3` | ~1.2 GB | 1024 | Multilingue (français natif) — option si la qualité FR doit monter | --- ## Utilisation ### Via Hermes (funk-ai) Le skill `rag-docs` est chargé dans le profil `funk-ai`. Hermes l'utilise automatiquement pour les questions sur le cluster : ``` # Dans le TUI Hermes : "Comment je relance dnsmasq ?" → Hermes appelle rag-query en interne et cite les sources ``` ### En ligne de commande ```bash # Depuis storage-01 rag-query "ma question" rag-query "ma question" --top 3 # limiter les résultats (défaut: 5) # Exemples rag-query "comment relancer llama-server gpu" rag-query "nftables firewall port cluster" rag-query "hermes profils configuration" rag-query "alertmanager webhook pipeline" rag-query "monitoring grafana dashboard" ``` --- ## Mise à jour de l'index L'index doit être re-généré après chaque modification de la doc `admin/`. ### Via Ansible (recommandé) ```bash cd ansible/ ../.venv/bin/ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags rag ``` Ansible synchronise `admin/` vers `/srv/data/rag/docs/` puis relance automatiquement `rag-ingest` (handler Ansible). ### Manuellement ```bash # Synchroniser les docs (depuis le poste perso) rsync -av --delete admin/ storage-01:/srv/data/rag/docs/ # Ré-indexer (depuis storage-01) ssh storage-01 "rag-ingest /srv/data/rag/docs/" ``` L'ingestion prend quelques minutes pour ~436 chunks (embeddings via l'instance nomic `:1238`, CPU). Elle est idempotente — re-lancer ne crée pas de doublons (IDs stables basés sur MD5 du fichier+section). --- ## Administration Qdrant ```bash # Collections existantes curl -s http://storage-01:6333/collections | python3 -m json.tool # Stats de la collection funk-docs curl -s http://storage-01:6333/collections/funk-docs | python3 -m json.tool # Nombre de points indexés curl -s http://storage-01:6333/collections/funk-docs \ | python3 -c "import sys,json; print(json.load(sys.stdin)['result']['points_count'])" # Vider et re-créer la collection (si re-indexation propre nécessaire) curl -s -X DELETE http://storage-01:6333/collections/funk-docs rag-ingest /srv/data/rag/docs/ # Statut du service ssh storage-01 "systemctl status qdrant --no-pager" ``` --- ## Structure des fichiers ``` ansible/roles/rag/ ├── defaults/main.yml # URLs Qdrant/embed, collection, répertoires ├── tasks/main.yml # Déploiement scripts + docs + skill Hermes ├── handlers/main.yml # Handler : Run rag-ingest + Restart hermes-agent └── files/ ├── rag-ingest # Script Python d'ingestion ├── rag-query # Script Python de requête └── rag-docs/SKILL.md # Skill Hermes hermes-skills/funk/rag-docs/ └── SKILL.md # Source versionnée du skill (copié dans files/) /srv/data/rag/ (NVMe storage-01 — bind-mount /home/data) ├── docs/ # Copie de admin/ — source des chunks └── (Qdrant stocke dans /srv/data/qdrant/) ``` --- ## Points d'attention | Sujet | Détail | |---|---| | Qualité embeddings | `nomic-embed-text` (modèle dédié) — scores cosinus discriminants, tri par pertinence réel | | Embeddings CPU | `llama-embed` (:1238) tourne en **CPU** (découplé du slot chat GPU) — `rag-ingest` ne contend pas le GPU. ubatch=2048 requis (sinon 500 sur chunks > 512 tokens) | | Re-indexation | Obligatoire après modification de `admin/` — pas de sync automatique | | Qdrant persistance | Données dans `/srv/data/qdrant/` sur NVMe — survivent aux redémarrages | | Score minimum | `MIN_SCORE` dans `rag-query` ajusté pour nomic (scores plus étalés que qwen3-8b) |