docs: mise à jour documentation — NVMe, Qwen3, gaps IaC

- CLAUDE.md : /srv/data NVMe (plus RAID5), structure k8s/ expliquée,
  namespace ai ajouté, Hermes data code/données séparés
- README.md : roadmap complète (n8n/Open WebUI/monitoring opérationnels),
  Talos v1.13, vault vars complètes, rôles Ansible manquants, RAID5→NVMe
- admin/ia/rag.md : 284→339 chunks, RAID5→NVMe
- admin/ia/hermes.md : RAID5→NVMe (incidents 2026-05-13 et 2026-05-29)
- admin/ia/litellm.md : qwen2.5→qwen3-8b, gap IaC CPU models documenté
- admin/ia/llama_server.md : gap IaC instances CPU documenté
- admin/index_knowledge.py : 5 chunks RAG mis à jour (Qwen2.5→Qwen3,
  RAID5→NVMe, vault vars + rôles complets)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
alkatrazz 2026-05-30 22:58:24 +02:00
parent 7f6fee94c2
commit 529bb66ebd
7 changed files with 101 additions and 33 deletions

View file

@ -5,7 +5,7 @@ Hermes Agent tourne en deux services systemd sur **storage-01** :
- `hermes-dashboard` — interface web (port 9119)
Il passe par **LiteLLM** (`:4000`) pour toute inférence — Qwen local ou Claude API.
Les données persistantes sont sur le RAID5 : `/srv/data/hermes`.
Les données persistantes sont dans `/srv/data/hermes` (NVMe bind-mount depuis 2026-05-29, plus RAID5).
---
@ -330,7 +330,7 @@ ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags litellm
## Arborescence
Depuis l'incident 2026-05-13, le code est sur le SSD OS et les données sur le RAID5.
Depuis l'incident 2026-05-13, le code est sur le SSD OS. Depuis l'incident 2026-05-29, les données sont sur NVMe (`/home/data` bind-monté sur `/srv/data`), plus sur le RAID5.
```
/opt/hermes/ → home utilisateur hermes (SSD OS)
@ -340,7 +340,7 @@ Depuis l'incident 2026-05-13, le code est sur le SSD OS et les données sur le R
├── hermes_cli/ → source CLI
└── web/ → source frontend dashboard
/srv/data/hermes/ → HERMES_HOME (RAID5) — données persistantes
/srv/data/hermes/ → HERMES_HOME (NVMe bind-mount) — données persistantes
├── config.yaml → configuration profil par défaut (géré Ansible)
├── .env → LM_BASE_URL, LM_API_KEY (géré Ansible)
├── memories/ → mémoire persistante profil par défaut
@ -413,7 +413,7 @@ Fermer le TUI et en ouvrir un nouveau après chaque modification.
| Sujet | Détail |
|---|---|
| Code vs données | Code + venv : `/opt/hermes/.hermes/hermes-agent/` (SSD OS) — Profils/données : `/srv/data/hermes/` (RAID5) |
| Code vs données | Code + venv : `/opt/hermes/.hermes/hermes-agent/` (SSD OS) — Profils/données : `/srv/data/hermes/` (NVMe) |
| `HERMES_HOME` | Toujours préfixer les commandes hermes avec `HERMES_HOME=/srv/data/hermes` |
| `LM_API_KEY` | Doit valoir `lm-studio` exactement |
| `context_length` | Hermes exige 64k minimum — override via `model.context_length: 65536` dans config.yaml |

View file

@ -56,7 +56,7 @@ Script déployé sur storage-01 :
```bash
sudo hermes-switch status # voir le modèle actuel de hermes-default
sudo hermes-switch qwen # Qwen2.5-14B local (gratuit, ~35 tok/s)
sudo hermes-switch qwen # Qwen3-8B local GPU (gratuit, ~60 tok/s)
sudo hermes-switch claude # Claude Sonnet 4.6 (payant, ~1-2$ par session debug)
```
@ -84,7 +84,7 @@ curl http://127.0.0.1:4000/v1/models \
curl http://127.0.0.1:4000/v1/chat/completions \
-H "Authorization: Bearer lm-studio" \
-H "Content-Type: application/json" \
-d '{"model": "qwen2.5-14b-instruct", "messages": [{"role": "user", "content": "Dis bonjour"}], "max_tokens": 30}'
-d '{"model": "qwen3-8b", "messages": [{"role": "user", "content": "Dis bonjour"}], "max_tokens": 30}'
# Test inférence Claude
curl http://127.0.0.1:4000/v1/chat/completions \
@ -106,6 +106,22 @@ elle vient du vault Ansible (`vault_anthropic_api_key`). Jamais en clair dans co
---
## ⚠️ Gap IaC — modèles CPU absents du template Ansible
`ansible/roles/litellm/templates/config.yaml.j2` n'inclut que 4 modèles :
`hermes-default`, `qwen3-8b`, `claude-sonnet-4-6`, `claude-opus-4-7`.
Les entrées `qwen3-1.7b-system` (:1236) et `qwen3-1.7b-monitor` (:1237) ont été ajoutées
**manuellement** dans `/etc/litellm/config.yaml` sur storage-01.
Un `make apply-storage` sur un hôte vierge ne déploierait PAS les routes CPU nécessaires
à `ask-agent system` et `ask-agent monitor`.
**Axe d'amélioration** : ajouter les 2 entrées CPU dans `config.yaml.j2` avec des variables
dans `defaults/main.yml` (`litellm_cpu_system_url`, `litellm_cpu_monitor_url`).
---
## Ajouter un modèle
1. Modifier `roles/litellm/templates/config.yaml.j2` :

View file

@ -177,6 +177,17 @@ sudo systemctl restart llama-server
---
## ⚠️ Gap IaC — instances CPU non couvertes par Ansible
Le rôle `ansible/roles/llama_server/` ne déploie que l'instance **GPU** (`llama-server.service` sur :1234).
Les instances CPU (`llama-server-system` :1236 et `llama-server-monitor` :1237) ont été créées **manuellement** et ne sont pas encore dans le code Ansible.
Conséquence : un `make apply-gpu` complet sur un hôte vierge ne déploierait PAS les instances CPU.
**Axe d'amélioration** : étendre le rôle `llama_server` pour déployer les 3 instances via une boucle (`with_items` ou `loop` Ansible), avec des variables dédiées dans `host_vars/gpu-01/vars.yml`.
---
## Points d'attention
| Sujet | Détail |
@ -189,3 +200,4 @@ sudo systemctl restart llama-server
| Gemma 4 interdit | Crash ROCm sur prompts >800 tokens |
| Modèles sur NFS | `/mnt/models` monté depuis storage-01 (NFS) — si NFS down, les 3 services échouent au démarrage |
| 3 services indépendants | Chaque instance a son propre service systemd — redémarrer l'un n'affecte pas les autres |
| Instances CPU hors Ansible | llama-server-system et llama-server-monitor créés manuellement — voir section Gap IaC ci-dessus |

View file

@ -34,8 +34,8 @@ Hermes formule sa réponse en citant les sources
| `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) |
| Docs indexées | `/srv/data/rag/docs/` (NVMe) | Copie locale du dossier `admin/` |
| Collection Qdrant | `funk-docs` | 339 chunks — dimension 4096 (Cosine) |
---
@ -132,7 +132,7 @@ rsync -av --delete admin/ storage-01:/srv/data/rag/docs/
ssh storage-01 "rag-ingest /srv/data/rag/docs/"
```
L'ingestion prend ~5-10 minutes pour 284 chunks (embeddings via GPU).
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).
---
@ -175,7 +175,7 @@ ansible/roles/rag/
hermes-skills/funk/rag-docs/
└── SKILL.md # Source versionnée du skill (copié dans files/)
/srv/data/rag/ (RAID5 storage-01)
/srv/data/rag/ (NVMe storage-01 — bind-mount /home/data)
├── docs/ # Copie de admin/ — source des chunks
└── (Qdrant stocke dans /srv/data/qdrant/)
```
@ -190,5 +190,5 @@ hermes-skills/funk/rag-docs/
| 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 |
| 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 |

View file

@ -32,12 +32,12 @@ KNOWLEDGE = [
{
"category": "litellm",
"tags": ["litellm", "proxy", "modèle", "switch"],
"text": "LiteLLM tourne sur storage-01 port 4000. master_key doit valoir exactement lm-studio. Hermes utilise l'alias hermes-default. Pour switcher: sudo hermes-switch qwen (Qwen2.5-7B local gratuit) ou sudo hermes-switch claude (Claude Sonnet 4.6 ~1-2$ par session). Le script modifie /etc/litellm/config.yaml et redémarre le service.",
"text": "LiteLLM tourne sur storage-01 port 4000. master_key doit valoir exactement lm-studio. Hermes utilise l'alias hermes-default. Pour switcher: sudo hermes-switch qwen (Qwen3-8B local gratuit) ou sudo hermes-switch claude (Claude Sonnet 4.6 ~1-2$ par session). Le script modifie /etc/litellm/config.yaml et redémarre le service.",
},
{
"category": "litellm",
"tags": ["litellm", "config", "modèles", "anthropic"],
"text": "LiteLLM config /etc/litellm/config.yaml expose: hermes-default (alias switchable), qwen2.5-7b-instruct (gpu-01:1234), claude-sonnet-4-6 (API Anthropic), claude-opus-4-7 (API Anthropic). ANTHROPIC_API_KEY dans l'environnement systemd via vault Ansible.",
"text": "LiteLLM config /etc/litellm/config.yaml expose: hermes-default (alias switchable), qwen3-8b (gpu-01:1234 GPU), qwen3-1.7b-system (gpu-01:1236 CPU), qwen3-1.7b-monitor (gpu-01:1237 CPU), claude-sonnet-4-6 (API Anthropic), claude-opus-4-7 (API Anthropic). ANTHROPIC_API_KEY dans l'environnement systemd via vault Ansible.",
},
{
"category": "hermes",
@ -52,7 +52,7 @@ KNOWLEDGE = [
{
"category": "hermes",
"tags": ["hermes", "cli", "path", "git"],
"text": "Toujours lancer hermes -z depuis /srv/data/hermes pour éviter l'erreur PermissionError sur .git. Hermes remonte l'arborescence à la recherche d'un .git et échoue s'il tombe sur /home/ansible/.git sans permission. HERMES_HOME=/srv/data/hermes, données sur RAID5.",
"text": "Toujours lancer hermes -z depuis /srv/data/hermes pour éviter l'erreur PermissionError sur .git. Hermes remonte l'arborescence à la recherche d'un .git et échoue s'il tombe sur /home/ansible/.git sans permission. HERMES_HOME=/srv/data/hermes, données sur NVMe (bind-mount /home/data depuis 2026-05-29).",
},
{
"category": "hermes",
@ -72,17 +72,17 @@ KNOWLEDGE = [
{
"category": "gpu",
"tags": ["llama-server", "embeddings", "pooling", "vecteurs"],
"text": "llama-server doit être démarré avec --embeddings --pooling mean pour exposer /v1/embeddings compatible OpenAI. Sans --pooling mean: erreur 'Pooling type none is not OAI compatible'. Qwen2.5-7B produit des vecteurs de dimension 3584. Endpoint: http://192.168.10.20:1234/v1/embeddings.",
"text": "llama-server doit être démarré avec --embeddings --pooling mean pour exposer /v1/embeddings compatible OpenAI. Sans --pooling mean: erreur 'Pooling type none is not OAI compatible'. Qwen3-8B produit des vecteurs de dimension 3584. Endpoint: http://192.168.10.20:1234/v1/embeddings.",
},
{
"category": "gpu",
"tags": ["modèles", "qwen", "gemma", "performance"],
"text": "Modèle actif gpu-01: Qwen2.5-14B-Instruct-Q4_K_M (~35 tok/s génération, ~200 tok/s prefill, ROCm natif). Contexte limité à 16384 tokens (VRAM: 8GB modèle + 3GB KV cache = 11GB sur 12GB). Alias API: qwen2.5-14b-instruct. Ne pas utiliser Gemma 4: crash ROCm >800 tokens. Dimension embeddings: 5120.",
"text": "Modèle actif gpu-01: Qwen3-8B Q4_K_M (~60 tok/s génération, ~300 tok/s prefill, ROCm 7.x natif). Contexte 32768 tokens (VRAM: ~5GB modèle + ~4GB KV cache = ~9GB sur 12GB). Alias API: qwen3-8b. Instances CPU: qwen3-1.7b-system sur :1236 et qwen3-1.7b-monitor sur :1237 (~21 tok/s CPU). Ne pas utiliser Gemma 4: crash ROCm >800 tokens. Dimension embeddings: 3584.",
},
{
"category": "postgresql",
"tags": ["postgresql", "pgdg", "PGDATA", "RAID5"],
"text": "PostgreSQL 16 installé depuis repo officiel pgdg sur storage-01. PGDATA sur RAID5: /srv/data/postgres. Override systemd dans /etc/systemd/system/postgresql-16.service.d/pgdata.conf. Auth: peer en local, scram-sha-256 pour connexions réseau. Bases: hermes et litellm avec utilisateurs dédiés.",
"text": "PostgreSQL 16 installé depuis repo officiel pgdg sur storage-01. PGDATA sur NVMe: /srv/data/postgres (bind-mount /home/data depuis 2026-05-29). Override systemd dans /etc/systemd/system/postgresql-16.service.d/pgdata.conf. Auth: peer en local, scram-sha-256 pour connexions réseau. Bases: hermes, litellm, n8n, openwebui avec utilisateurs dédiés.",
},
{
"category": "qdrant",
@ -97,7 +97,7 @@ KNOWLEDGE = [
{
"category": "ansible",
"tags": ["ansible", "vault", "secrets", "variables"],
"text": "Secrets Ansible dans group_vars/all/vault.yml: vault_anthropic_api_key, vault_pg_hermes_password, vault_pg_litellm_password. Rôles idempotents: common, gateway, dnsmasq, nfs_server, postgresql, qdrant, minio, litellm, hermes_agent, llama_server, rocm. Playbooks: storage-01.yml et gpu-01.yml.",
"text": "Secrets Ansible dans group_vars/all/vault.yml: vault_anthropic_api_key, vault_pg_hermes_password, vault_pg_litellm_password, vault_pg_n8n_password, vault_pg_openwebui_password, vault_postfix_relay_password. Rôles idempotents: common, gateway, dnsmasq, nfs_server, postgresql, qdrant, minio, litellm, hermes_agent, rag, alertmanager_webhook, postfix_relay, node_exporter, llama_server, rocm. Playbooks: storage-01.yml et gpu-01.yml.",
},
{
"category": "ansible",