# RAG — Documentation Funk 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:1234/v1/embeddings │ 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/` (RAID5) | Copie locale du dossier `admin/` | | Collection Qdrant | `funk-docs` | 284 chunks — dimension 4096 (Cosine) | --- ## Modèle d'embedding utilisé **Qwen3-8B** via llama-server GPU (port 1234), avec les flags `--embeddings --pooling mean`. C'est le modèle de chat principal, réutilisé pour les embeddings. ### Limitation connue Qwen3-8B est un modèle génératif, **pas un modèle d'embedding dédié**. Ses représentations vectorielles ont peu de discrimination sémantique : les scores de similarité cosinus sont uniformément hauts (0.90–0.95) quelle que soit la pertinence du résultat. Conséquence : les résultats retournés ne sont pas triés par pertinence réelle — le fichier avec le plus de tokens (ex : `incidents.md`) remonte souvent en premier. ### Quand améliorer Pour une recherche sémantique précise, utiliser un modèle d'embedding dédié : | Modèle | Taille | Dimension | Notes | |---|---|---|---| | `nomic-embed-text-v1.5` | ~274 MB | 768 | Rapide, bon équilibre qualité/taille | | `bge-m3` | ~1.2 GB | 1024 | Multilingue (français natif) — meilleur choix pour ce repo | Déploiement si besoin : ```bash # Sur gpu-01 — télécharger le modèle ssh gpu-01 "lms get nomic-ai/nomic-embed-text-v1.5-GGUF" # Ajouter une instance llama-server sur port 1238 (CPU, embedding only) # Modifier ansible/roles/rag/defaults/main.yml : # embed_url: "http://192.168.10.20:1238/v1/embeddings" # embed_model: "nomic-embed-text-v1.5" # Puis re-indexer : rag-ingest /srv/data/rag/docs/ ``` --- ## 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 ~5-10 minutes pour 284 chunks (embeddings via GPU). 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/ (RAID5 storage-01) ├── docs/ # Copie de admin/ — source des chunks └── (Qdrant stocke dans /srv/data/qdrant/) ``` --- ## Points d'attention | Sujet | Détail | |---|---| | Qualité embeddings | Qwen3-8B = modèle chat réutilisé — scores peu discriminants. Fonctionnel mais pas optimal. | | Modèle dédié | `nomic-embed-text` ou `bge-m3` diviseraient les faux positifs par ~3 | | Contention GPU | `rag-ingest` sollicite le GPU (port 1234) pendant ~5-10 min — éviter pendant une session d'inférence active | | Re-indexation | Obligatoire après modification de `admin/` — pas de sync automatique | | Qdrant persistance | Données dans `/srv/data/qdrant/` sur RAID5 — survivent aux redémarrages | | Score minimum | `MIN_SCORE = 0.60` dans `rag-query` — tous les résultats sont au-dessus avec ce modèle |