mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-08 21:34:43 +02:00
* feat(stt): mémoire long-terme sémantique via Qdrant (5b) Serveur : longterm.py — collection Qdrant stt-memory (embeddings Qwen3 gpu-01, dim auto, Cosine), recall top-k injecté au prompt, remember des tours user. Tout dégrade proprement si Qdrant/embeddings injoignables (la mémoire court-terme tient). Env STT_MEMORY_LONGTERM, STT_QDRANT_URL, STT_EMBED_URL, STT_MEMORY_TOPK. Testé en process : dégradation OK (Qdrant down → mem=0, pas de crash, court-terme tient). Qdrant réparé le 17/06 (5c). Recherche sémantique réelle à valider sur cluster. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT * feat(stt): endpoint /v1/memory/health + upsert Qdrant synchrone - /v1/memory/health sonde activement embeddings + Qdrant + collection et expose les erreurs (recall/remember dégradent en silence → indébogables). Permet de diagnostiquer la mémoire long-terme sans kubectl exec. - remember() : upsert avec ?wait=true → le souvenir est immédiatement cherchable (sans wait, Qdrant met l'écriture en file → un recall cross-session immédiat pouvait le rater). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT * docs(stt): 5b mémoire long-terme validée en prod + backlog nomic-embed-text - Rappel cross-session confirmé (« Felix » retrouvé dans une nouvelle session), points_count vérifié via /v1/memory/health. - Note du fix upsert ?wait=true et de l'endpoint de diagnostic. - Roadmap : 5d (nomic-embed-text dim 768) en backlog qualité ; états haut/bas du doc mis à jour (déployé + validé sur cible). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT * 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 --------- Co-authored-by: Claude <noreply@anthropic.com>
203 lines
6.8 KiB
Markdown
203 lines
6.8 KiB
Markdown
# 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.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 — **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`).
|
||
|
||
```bash
|
||
# (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é) :
|
||
```bash
|
||
# 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
|
||
|
||
```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 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
|
||
|
||
```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 | 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 |
|