Funk-lab/progress/2026-05-11.md
alkatrazz 24c0bf9e12 docs: progression 2026-05-14 + désignore progress/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 22:28:10 +02:00

22 KiB
Raw Blame History

2026-05-11 — Hermes opérationnel sur Qwen3.5-9B

Résumé

Hermes Agent pleinement fonctionnel sur storage-01 avec le modèle Qwen3.5-9B sur gpu-01. Chemin parcouru : 6 blocages techniques résolus dans la même session.


Blocages rencontrés et résolus

1. auxiliary.compression.context_length manquant dans config.yaml

Symptôme : Failed to initialize agent: Auxiliary compression model google/gemma-4-e4b has a context window of 4,096 tokens, which is below the minimum 64,000 required.

Cause : Hermes a deux vérifications de contexte distinctes — le modèle principal (model.context_length) et le modèle de compression auxiliaire (auxiliary.compression.context_length). Seule la première était surchargée.

Fix : Ajout dans roles/hermes_agent/templates/config.yaml.j2 :

auxiliary:
  compression:
    context_length: {{ hermes_context_length }}

2. Crash GPU Vulkan sur Gemma 4 E4B avec long prompt (>800 tokens)

Symptôme : The model has crashed without additional information. (Exit code: null) dès le premier appel Hermes (system prompt ~15 000 tokens). Modèle rechargé avec n_ctx=4096 par défaut, puis erreur de contexte en cascade.

Cause : Bug dans le backend Vulkan de llama.cpp avec l'architecture Gemma 4. Gemma 4 utilise une attention interleaved global/local avec sliding window de 512 tokens. Quand le prompt dépasse 800 tokens (juste au-delà du sliding window), les layers d'attention globale crashent dans l'implémentation Vulkan. Confirmé par test binaire : OK à 500 tokens, crash à ~900 tokens.

Note : Le crash n'est pas lié à la VRAM — Gemma 4 utilise GQA aggressif, le KV cache réel à 65536 tokens est ~2 GB seulement (7 global layers × 65536 × 4096 bytes). La VRAM ne serait pas le facteur limitant.

Fix : Passage sur Qwen3.5-9B qui utilise une attention GQA standard, sans problème Vulkan connu. Fichiers modifiés :

  • host_vars/gpu-01/vars.yml : lm_studio_default_model: "qwen/qwen3.5-9b"
  • roles/hermes_agent/defaults/main.yml : hermes_model: "qwen/qwen3.5-9b"

3. dnsmasq crash au boot (interface USB ethernet non disponible)

Symptôme : Après reboot de storage-01, gpu-01 ne peut plus télécharger de paquets (yum makecache bloque). DNS timeout vers 192.168.10.1.

Cause : dnsmasq démarre avec After=network.target mais l'interface USB ethernet enp6s0f3u2c2 prend plus de temps à apparaître. dnsmasq log : dnsmasq: unknown interface enp6s0f3u2c2 → crash.

Fix :

  • Immédiat : systemctl reset-failed dnsmasq && systemctl start dnsmasq
  • Permanent : override systemd dans roles/dnsmasq/tasks/main.yml qui crée /etc/systemd/system/dnsmasq.service.d/wait-for-network.conf :
    [Unit]
    After=network-online.target
    Wants=network-online.target
    

4. LM_API_KEY=qwen/qwen3.5-9b dans le .env de Hermes

Symptôme : Failed to initialize agent: Failed to initialize OpenAI client: bad marshal data (invalid reference) — erreur trompeuse, masque le vrai problème.

Cause : La commande hermes model avait écrit le nom du modèle à la place de la clé API dans /srv/data/hermes/.env. La clé API pour LM Studio doit être une chaîne arbitraire (lm-studio), pas le nom du modèle.

Fix : sed -i 's/^LM_API_KEY=.*/LM_API_KEY=lm-studio/' /srv/data/hermes/.env


5. Fichiers .pyc pydantic corrompus sur le RAID5

Symptôme : Failed to initialize OpenAI client: bad marshal data (invalid reference) persistait même après fix du .env.

Cause : Le reboot du RAID5 a laissé des fichiers .pyc Python partiellement écrits dans le venv de Hermes. Spécifiquement pydantic/fields et ses dépendances. Python essaie de charger le bytecode compilé → ValueError: bad marshal data (invalid reference).

Traceback exact :

File ".../openai/_models.py", line 39, in <module>
    from pydantic.fields import FieldInfo
  File "<frozen importlib._bootstrap_external>", line 729, in _compile_bytecode
ValueError: bad marshal data (invalid reference)

Fix :

find /srv/data/hermes/hermes-agent/venv/lib/python3.11/site-packages \
  -name '*.pyc' -delete

Python recompile les .pyc au prochain import depuis les .py sources (intacts).

Leçon : Données applicatives sur RAID5 = écriture partielle possible sur reboot non-propre. Les fichiers .pyc ne sont pas critiques (régénérables) mais peuvent bloquer l'application entièrement.


Changements ansible

Fichier Changement
roles/common/tasks/main.yml Ajout tâche Upgrade all packages (tag update)
roles/common/handlers/main.yml Ajout handler Reboot if kernel updated
roles/lm_studio/tasks/main.yml Ajout socat dans les dépendances dnf
roles/lm_studio/files/run-llmster.sh Ajout lms unload --all avant le chargement du modèle
roles/hermes_agent/templates/config.yaml.j2 Ajout auxiliary.compression.context_length
roles/hermes_agent/defaults/main.yml Modèle passé à qwen/qwen3.5-9b
roles/dnsmasq/tasks/main.yml Ajout override systemd wait-for-network.conf
roles/dnsmasq/handlers/main.yml Ajout handler Reload systemd
host_vars/gpu-01/vars.yml lm_studio_default_model: "qwen/qwen3.5-9b"

État final

  • Hermes Agent opérationnel sur storage-01 (hermes chat fonctionne)
  • Modèle Qwen3.5-9B chargé sur gpu-01 avec contexte 65 536 tokens via Vulkan
  • Proxy socat actif : 192.168.10.20:1234127.0.0.1:1234 (contourne le rebind llmster post-Vulkan)
  • DNS résolu après reboot grâce à l'override network-online.target
  • Mises à jour système effectuées sur storage-01 et gpu-01

Prochaines étapes (après session matin)

  • Configurer Claude (API Anthropic) comme second modèle dans Hermes
  • Route statique Freebox : 192.168.10.0/24192.168.1.200
  • Premier commit GitHub (repo privé)
  • Stubs rôles : postgresql, qdrant, minio

2026-05-11 — Session après-midi : llama-server ROCm (remplacement LM Studio)

Résumé

Remplacement complet de LM Studio pour l'inférence par llama-server compilé from source avec ROCm 7.x. Gain de performance ×5 (15 → 70 tok/s génération). Résolution du bug de contexte --parallel 4 qui limitait chaque slot à 8192 tokens.


Blocages rencontrés et résolus

6. Hermes — temps de réponse de 2 minutes

Symptôme : Hermes met ~2 minutes pour répondre, même sur des requêtes courtes.

Investigation :

  • nvtop : GPU à 90% pendant les 2 minutes → le GPU est utilisé, pas d'idle
  • journalctl -u lm-studio : backend = Vulkan (pas ROCm)
  • Comparaison : Vulkan ~100 tok/s prefill / ~15 tok/s génération ; Hermes system prompt ≈ 15 000 tokens → ~2 min juste pour le prefill (15 000 ÷ 100 ≈ 150s)

Tentative 1 — activer le backend ROCm de LM Studio :

  • lms runtime get lmstudio-community/gguf-parser --release latest : backends dans .lmstudio/extensions/backends/ (Node.js addons + libs partagées)
  • Backend ROCm compilé pour ROCm 6.x : libhipblas.so.2, librocblas.so.4, libamdhip64.so.6 — ROCm 7.2.3 installé expose .so.3, .so.5, .so.7
  • Tentative patchelf pour corriger les SONAME : fixe les DT_NEEDED entries mais incompatibilité ABI profonde (structs, signatures de fonctions changées entre ROCm 6 et 7 — SONAME seul n'est pas suffisant)
  • Résultat : crash GPU au warmup (Exit code: null = SIGSEGV) pour tous les modèles

Fix final — llama.cpp compilé from source avec ROCm 7.x (option B) :


7. Build llama.cpp from source (ROCm 7.x)

Packages requis (non installés initialement) :

sudo dnf install -y hipblas-devel rocblas-devel hip-devel hipcc cmake gcc-c++ git patchelf

Problème cmake — HIP compiler :

  • cmake -DCMAKE_HIP_COMPILER=hipcc → rejeté (pas dans PATH, cmake ne trouve pas)
  • Fix : utiliser le chemin absolu {{ rocm_path }}/llvm/bin/clang++

Commande de build finale :

cd /opt/llama.cpp
cmake -B build \
  -DGGML_HIP=ON \
  -DAMDGPU_TARGETS=gfx1030 \
  -DCMAKE_BUILD_TYPE=Release \
  -DROCM_PATH=/opt/rocm \
  -DCMAKE_PREFIX_PATH=/opt/rocm \
  -DCMAKE_HIP_COMPILER=/opt/rocm/llvm/bin/clang++
cmake --build build --target llama-server -j$(nproc)

Note gfx1031 → gfx1030 : RX 6700XT = gfx1031 (non officiel). Target cmake = gfx1030 (compatible) + HSA_OVERRIDE_GFX_VERSION=10.3.0 dans le service systemd.

Autre problème : après systemctl stop lm-studio, le processus llmster survivait (double-fork) et tenait le port 1234. Fix : sudo kill $(pgrep llmster) && sudo kill $(pgrep socat)


8. Tentative Qwen3.5-9B sur llama-server — crash ROCm

Symptôme : llama-server crash au warmup avec Qwen3.5-9B (ggml_cuda_op_mul_mat assertion failure).

Cause : Qwen3.5-9B utilise l'architecture Gated Delta Net (hybride SSM + attention) — non supportée par le backend ROCm de llama.cpp. Confirmé : crash identique avec plusieurs versions GGUF de ce modèle.

Fix : Passage sur Qwen2.5-7B-Instruct (transformer standard, GQA classique, aucun problème ROCm). Modèle déjà présent sur le NFS.


9. Bug --parallel 4 — contexte insuffisant pour Hermes

Symptôme : Hermes renvoie HTTP 400 context window exceeded même avec --ctx-size 32768. System prompt Hermes = 14 579 tokens.

Cause : --parallel N divise le ctx-size total en N slots égaux. Avec --parallel 4 --ctx-size 32768 → chaque slot = 8192 tokens. 14 579 > 8192 → dépassement dès le premier appel Hermes.

Fix :

sudo sed -i 's/--parallel 4/--parallel 1/' /etc/systemd/system/llama-server.service
sudo systemctl daemon-reload && sudo systemctl restart llama-server

Corrigé aussi dans roles/llama_server/defaults/main.yml : llama_parallel: 1.


Performances finales (RX 6700XT, ROCm 7.x natif)

Backend Prefill Génération TTFT Hermes (15k tokens)
LM Studio Vulkan ~100 tok/s ~15 tok/s ~150s
llama-server ROCm 7.x ~400 tok/s ~70 tok/s ~35s

Gain ×4 prefill, ×4.5 génération — gain ×4 sur le TTFT Hermes.


Changements ansible

Fichier Changement
roles/llama_server/tasks/main.yml Création — build ROCm, service systemd, firewall, désactive lm-studio
roles/llama_server/defaults/main.yml Création — llama_parallel: 1 (critique : 4 → context bug)
roles/llama_server/templates/llama-server.service.j2 Création — template service systemd
roles/rocm/defaults/main.yml Ajout rocm_build_packages (hipblas-devel, rocblas-devel, hip-devel, hipcc)
roles/hermes_agent/defaults/main.yml Modèle → qwen2.5-7b-instruct
playbooks/gpu-01.yml Remplacement rôle lm_studiollama_server
host_vars/gpu-01/vars.yml Suppression vars lm_studio, ajout llama_model_path + llama_model_alias
group_vars/gpu_hosts/vars.yml Suppression vars lm_studio (port, host, context)
admin/llama_server.md Création — doc ops complète
admin/lm_studio.md Refonte — gestion modèles uniquement, service désactivé
admin/hermes.md Mise à jour — modèle, config.yaml, endpoint llama-server
admin/systeme.md Table services gpu-01 : lm-studio → llama-server
admin/incidents.md Création — incident storage-01 XFS + résolution
admin/README.md Ajout entrées llama_server.md et incidents.md

État final

  • llama-server opérationnel sur gpu-01 (192.168.10.20:1234) — API OpenAI-compatible
  • Modèle : Qwen2.5-7B-Instruct Q4_K_S — 32768 tokens ctx, 1 slot (requis pour Hermes)
  • Hermes : fonctionne correctement, réponse en ~35s (vs 2 min avant)
  • LM Studio : désactivé pour l'inférence, reste installé pour lms get / lms ls

Prochaines étapes (après session matin, avant session LiteLLM)

  • Configurer Claude (API Anthropic) comme second modèle dans Hermes fait
  • Route statique Freebox : 192.168.10.0/24192.168.1.200
  • Premier commit GitHub (repo privé)
  • Stubs rôles : postgresql, qdrant, minio

2026-05-11 — Session soir : LiteLLM proxy + intégration Claude API

Résumé

Déploiement de LiteLLM comme proxy unifié sur storage-01. Hermes passe désormais par LiteLLM pour toute inférence — Qwen local par défaut, Claude API switchable sans toucher à la configuration de Hermes.


Blocages rencontrés et résolus

10. Hermes ne résout pas le provider LiteLLM

Symptôme : hermes -z échoue avec AuthError: No inference provider configured même avec LM_BASE_URL=http://127.0.0.1:4000/v1 dans le .env.

Investigation :

  • hermes doctor avec LM_API_KEY=lm-studio → "✓ API key or custom endpoint configured"
  • hermes doctor avec LM_API_KEY=funk-litellm → pas reconnu

Cause 1 : LM_API_KEY doit valoir lm-studio exactement — c'est la valeur magic qui active le provider "LM Studio" (OpenAI-compatible custom endpoint) dans Hermes. Toute autre valeur n'est pas reconnue.

Cause 2 : config.yaml manquait model.provider: lmstudio et model.base_url. Sans ces champs, Hermes ne sait pas quel provider utiliser même si .env est correct.

Format config.yaml correct :

model:
  provider: lmstudio
  base_url: "http://127.0.0.1:4000/v1"
  default: "hermes-default"
  context_length: 65536

Fix :

  • LM_API_KEY=lm-studio dans .env (géré par lineinfile Ansible)
  • litellm_master_key: lm-studio pour que LiteLLM accepte les requêtes Hermes
  • Ajout de provider et base_url dans le template config.yaml.j2

11. PermissionError hermes -z depuis le mauvais répertoire

Symptôme : PermissionError: [Errno 13] Permission denied: '/home/ansible/.git'

Cause : hermes -z remonte l'arborescence pour trouver un .git. Lancé depuis /home/ansible, l'utilisateur hermes n'a pas accès.

Fix : Toujours lancer depuis /srv/data/hermes :

cd /srv/data/hermes && hermes -z "question"

12. 404 sur /api/v1/models à l'init Hermes

Symptôme : Logs LiteLLM montrent des GET /api/v1/models HTTP/1.1" 404.

Cause : Hermes appelle /api/v1/models lors de l'initialisation — LiteLLM n'expose que /v1/models. Ce 404 n'est pas bloquant, les requêtes POST /v1/chat/completions fonctionnent normalement.

Fix : Aucun — comportement Hermes attendu, sans impact fonctionnel.


Architecture finale LiteLLM

Hermes (hermes-default)
        │  LM_API_KEY=lm-studio
        │  LM_BASE_URL=http://127.0.0.1:4000/v1
        ▼
   LiteLLM (:4000)  master_key=lm-studio
        │
        ├── hermes-default → qwen2.5-7b-instruct → llama-server gpu-01  (défaut)
        ├── hermes-default → claude-sonnet-4-6   → api.anthropic.com    (switch)
        └── [autres modèles accessibles par nom direct]

Switch sans toucher Hermes : modifier uniquement le bloc hermes-default dans /etc/litellm/config.yaml + sudo systemctl restart litellm.

Proof : Qwen répond "Je suis Claude" (hallucination sur l'identité — comportement normal des 7B). La GPU qui chauffe sur gpu-01 est la vraie source de vérité.


Changements ansible

Fichier Changement
roles/litellm/ Création complète du rôle (defaults, tasks, handlers, templates)
roles/litellm/templates/config.yaml.j2 Alias hermes-default + 3 modèles
roles/litellm/defaults/main.yml master_key: lm-studio, host: 127.0.0.1
roles/hermes_agent/defaults/main.yml hermes_lm_base_url: 127.0.0.1:4000, api_key: lm-studio
roles/hermes_agent/templates/config.yaml.j2 Ajout provider: lmstudio, base_url, model.default
roles/hermes_agent/templates/hermes-agent.service.j2 LM_BASE_URL/LM_API_KEY (pas HERMES_LLM_*), gateway run
roles/hermes_agent/tasks/main.yml Tâches lineinfile pour .env (LM_BASE_URL, LM_API_KEY)
playbooks/storage-01.yml Rôle litellm ajouté avant hermes_agent
group_vars/all/vault.yml vault_anthropic_api_key (clé Anthropic chiffrée)
admin/hermes.md Refonte complète — architecture LiteLLM, config correcte, switch
admin/litellm.md Correction master_key, procédure switch, points d'attention

État final

  • LiteLLM opérationnel sur storage-01 (:4000), 4 modèles enregistrés
  • Hermes utilise Qwen local via LiteLLM — ~70 tok/s, gratuit
  • Claude Sonnet/Opus disponibles via switch LiteLLM uniquement (clé API Anthropic en vault)
  • Vault Ansible : vault_anthropic_api_key chiffré dans group_vars/all/vault.yml

Prochaines étapes

  • Route statique Freebox : 192.168.10.0/24192.168.1.200
  • Premier commit GitHub (repo privé)
  • Mémoire Hermes sur cluster : Qdrant (vectoriel) + PostgreSQL sur storage-01, embeddings via Qwen, retrieval via Claude API pour les tâches complexes
  • Stubs rôles : postgresql, qdrant, minio

2026-05-11 — Session nuit : Qdrant + PostgreSQL + embeddings + upgrade 14B

Résumé

Déploiement de la stack mémoire vectorielle complète pour Hermes : PostgreSQL 16 et Qdrant v1.13.4 sur storage-01 (RAID5). Activation des embeddings sur llama-server. Installation du skill qdrant-vector-search dans Hermes. Indexation de 17 chunks de connaissance dans Qdrant. Upgrade modèle Qwen2.5-7B → 14B.


Blocages rencontrés et résolus

13. Embeddings llama-server — erreur 400 pooling

Symptôme : curl /v1/embeddings400 Pooling type 'none' is not OAI compatible

Cause : Sur les LLM causaux (Qwen2.5), le pooling par défaut de llama-server est none (pas de agrégation des token embeddings). Le format OAI attend un vecteur unique.

Fix : Ajout du flag --pooling mean dans le template service llama-server. Variables Ansible : llama_embeddings: true + llama_pooling: "mean".


14. qdrant-client non installé dans le venv Hermes

Symptôme : ModuleNotFoundError: No module named 'qdrant_client' lors des tests Python.

Cause : Le skill qdrant-vector-search fournit la documentation API à Hermes mais n'installe pas automatiquement qdrant-client dans tous les environnements.

Fix : Installation manuelle + ajout dans le rôle Ansible :

/srv/data/hermes/hermes-agent/venv/bin/pip install "qdrant-client>=1.12.0"

Tâche ansible.builtin.pip ajoutée dans roles/hermes_agent/tasks/main.yml.


15. Hermes utilise execute_code (mauvais env Python) au lieu du terminal

Symptôme : Hermes échoue en boucle quand on lui demande d'utiliser qdrant-client. Il utilise l'outil 🐍 execute_code qui tourne dans son propre env Python sans qdrant-client.

Cause : Qwen 7B ne sait pas distinguer quand utiliser execute_code vs terminal. Sur les tâches avec imports externes, il faut forcer l'approche "écrire un script + terminal".

Workaround : Écrire le script dans /tmp/script.py puis exécuter via terminal avec le chemin complet /srv/data/hermes/hermes-agent/venv/bin/python /tmp/script.py.

Fix structurel : PATH du venv ajouté dans le service systemd hermes-agent et dans ~/.bashrc de l'utilisateur hermes.


16. Segfault llama-server avec Qwen2.5-14B à 32k contexte

Symptôme : code=dumped, signal=SEGV au démarrage du service après upgrade 14B.

Cause : VRAM insuffisante. Qwen2.5-14B Q4_K_M ≈ 8 GB + KV cache 32k ≈ 6 GB = ~14 GB → dépasse les 12 GB de la RX 6700XT.

Fix : Réduction du contexte à 16384 tokens dans host_vars/gpu-01/vars.yml :

llama_ctx_size: 16384

Budget VRAM résultant : ~8 GB (modèle) + ~3 GB (KV cache) = ~11 GB


17. qdrant-client API : client.search() supprimé en v1.14+

Découverte : qdrant-client v1.18 (installé dans le venv) vs serveur Qdrant v1.13.4. La méthode client.search() a été supprimée en v1.14 — utiliser client.query_points().

Note : Warning de compatibilité de version (majeure OK, mineure diff > 1) affiché au démarrage du client mais sans impact fonctionnel sur les opérations de base.


Réalisations

Qdrant opérationnel

  • Collection hermes_memory créée : dim=5120 (14B), distance=COSINE
  • 17 chunks de connaissance indexés (architecture, Hermes, LiteLLM, ROCm, PostgreSQL, Ansible)
  • Recherche sémantique validée : score 0.82-0.85 sur requêtes pertinentes
  • Script d'indexation : admin/index_knowledge.py

Skill Hermes

  • mlops/qdrant (qdrant-vector-search) installé et actif
  • qdrant-client v1.18 dans le venv Hermes
  • PATH venv dans service systemd et bashrc

Script hermes-switch

  • /usr/local/bin/hermes-switch [qwen|claude|status]
  • Switch LiteLLM + restart automatique
  • Déployé via roles/litellm/files/hermes-switch

Upgrade modèle

  • Qwen2.5-7B → Qwen2.5-14B Q4_K_M
  • Contexte : 32768 → 16384 (contrainte VRAM)
  • Alias API : qwen2.5-14b-instruct

Changements ansible

Fichier Changement
roles/llama_server/defaults/main.yml Ajout llama_embeddings: true, llama_pooling: mean
roles/llama_server/templates/llama-server.service.j2 Flags --embeddings --pooling mean conditionnels
roles/hermes_agent/tasks/main.yml pip install qdrant-client, PATH venv dans bashrc
roles/hermes_agent/templates/hermes-agent.service.j2 Environment=PATH avec venv en premier
roles/litellm/files/hermes-switch Création script switch modèle
roles/litellm/tasks/main.yml Déploiement hermes-switch
roles/litellm/templates/config.yaml.j2 Alias qwen2.5-14b-instruct (remplace 7b)
host_vars/gpu-01/vars.yml Modèle 14B, llama_ctx_size: 16384
admin/index_knowledge.py Script indexation Qdrant (17 chunks)
admin/llama_server.md Modèle 14B, embeddings, contrainte VRAM documentés
admin/litellm.md hermes-switch documenté, alias mis à jour
admin/hermes.md Section skill Qdrant ajoutée

État final

  • PostgreSQL 16 : opérationnel sur storage-01 (RAID5 /srv/data/postgres)
  • Qdrant v1.13.4 : opérationnel sur storage-01 (RAID5 /srv/data/qdrant)
  • llama-server : Qwen2.5-14B, 16384 ctx, embeddings activés
  • Hermes : skill qdrant actif, 17 chunks indexés dans hermes_memory
  • hermes-switch : déployé et fonctionnel

Prochaines étapes

  • Route statique Freebox : 192.168.10.0/24192.168.1.200
  • Premier commit GitHub (repo privé)
  • Tester Hermes 14B sur les tâches agent complexes (Qdrant queries)
  • Mettre à jour la dimension des vecteurs dans index_knowledge.py (5120 pour 14B vs 3584 pour 7B)
  • MinIO : rôle à déployer