Funk-lab/admin/ia/rag.md
Claude 4da1589a6f
feat(stt): embeddings dédiés nomic-embed-text sur gpu-01 (:1238) + migration auto
Remplace Qwen3 (chat réutilisé, dim 4096, peu discriminant) par un modèle
d'embedding spécialisé nomic-embed-text (dim 768) pour la mémoire long-terme.

Ansible (rôle llama_server) :
- nouvelle instance optionnelle `llama-embed` (llama_embed_enabled) servant un
  modèle d'embedding dédié sur :1238, GPU ; télécharge le GGUF si absent.
- activée sur gpu-01 (host_vars) : nomic-embed-text-v1.5 f16.

STT-server :
- STT_EMBED_URL → :1238, STT_EMBED_MODEL → nomic-embed-text (deployment + config).
- _ensure_collection détecte le changement de dimension (4096→768) et recrée
  automatiquement la collection stt-memory (anciens vecteurs incomparables) —
  pas de drop manuel.

Docs : llama_server README, rag.md, stt.md (5d ), CLAUDE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
2026-06-17 18:56:14 +00:00

6.8 KiB
Raw Blame History

RAG — Documentation Funk

⚠️ HS depuis 2026-06-05 — Qdrant en crash-loop (segment funk-docs corrompu). Procédure de réparation dans 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: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/ (NVMe) Copie locale du dossier admin/
Collection Qdrant funk-docs 339 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.900.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 — déjà fait pour STT (instance nomic-embed-text sur :1238, dim 768) : le rôle llama_server gère désormais une instance dédiée embeddings sur gpu-01 (GPU), activée par llama_embed_enabled (voir ansible/roles/llama_server/README.md). STT pointe dessus (STT_EMBED_URL=http://192.168.10.20:1238/v1/embeddings).

# (re)déployer l'instance embeddings sur gpu-01
ansible-playbook -i inventory.yml playbooks/gpu-01.yml --tags llama_server

Pour basculer le RAG sur cette même instance (quand il sera réparé) :

# Modifier ansible/roles/rag/defaults/main.yml :
#   embed_url: "http://192.168.10.20:1238/v1/embeddings"
#   embed_model: "nomic-embed-text"
# Puis re-indexer (la dimension passe à 768 → collection recréée) : 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

# 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é)

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

# 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 339 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

# 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 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 NVMe — survivent aux redémarrages
Score minimum MIN_SCORE = 0.60 dans rag-query — tous les résultats sont au-dessus avec ce modèle