Funk-lab/admin/ia/rag.md
ALI YESILKAYA af98b47018
docs(cluster): aligne la doc sur l'état réel + re-ingest RAG + fix ubatch embed (#44)
* fix(rag): ubatch=2048 pour llama-embed + retry rag-ingest + nettoie defaults rag

L'instance llama-embed (:1238) tournait avec l'ubatch llama.cpp par défaut (512).
En mode --embeddings + pooling, toute l'entrée doit tenir dans un seul ubatch →
tout chunk > 512 tokens échouait en HTTP 500 « input too large to process.
increase the physical batch size ». ~46 chunks du RAG (CHUNK_MAX=2000 chars ≈
700 tokens) n'étaient pas indexés.

- llama_server : ajoute llama_embed_ubatch_size (2048 = ctx) + flags
  --batch-size/--ubatch-size dans le template llama-embed.service.
- rag-ingest : retry (5×, backoff) sur erreurs transitoires 5xx/réseau de l'embed.
- rag/defaults : aligne embed_url/embed_model sur nomic :1238 (étaient des vars
  mortes pointant encore qwen3-8b :1234 — trompeuses).

Résultat : ré-ingestion 436/436 chunks, 0 erreur.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(cluster): aligne la doc sur l'état réel (relevé 2026-06-21) + snapshot

Passe de vérification terrain (SSH s01/g01 + kubectl) pour corriger les écarts
doc↔réalité, et ajout d'un document de référence vérifié.

- admin/ops/etat-cluster.md (nouveau) : snapshot daté — machines, services+ports
  par hôte, workloads k8s, namespaces, IngressRoute, bases PG, modèles LiteLLM,
  RAG/Qdrant, + procédure pour régénérer le relevé.
- OS AlmaLinux 9.7 → 9.8 (s01/g01) ; précise k8s v1.33.1 (CLAUDE/README/install/talos).
- RAG funk-docs : retire le warning périmé « supprimée 2026-06-17 / à re-ingérer » →
  reconstruite (436 chunks, nomic-embed-text :1238 dim 768, CPU). Maj rag.md,
  incidents.md, stt.md.
- Namespace sacrifice (hors-repo, hors ArgoCD) + bases PG grafana/sacrifice +
  services ai via IngressRoute + registry in-cluster (CLAUDE.md, k9s.md).
- Services de résilience (llm-heartbeat, llama-watchdog/embed) et instances CPU
  manuelles :1236/:1237 (souvent éteintes) documentés.
- Journal progress/2026-06-21.md : section relevé + RAG.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 23:29:05 +02:00

188 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.900.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) |