Asa n'est plus bloqué sur le seul contexte « doc cluster grounding-strict ». Le client
choisit un contexte par requête ; le serveur change le system prompt ET injecte les
données live du domaine, puis renvoie le contexte assemblé pour le visualiseur du HUD.
- contexts.py : profils funk / ghostfolio / grafana / alerting / cluster (system prompt
+ sources) + assemble() (prompt final + structure de visualisation).
- sources.py : fetchers live best-effort (Ghostfolio auth+details, Alertmanager alerts
hors Watchdog, Prometheus cluster/metrics), env-config, dégradation propre.
- brain.py : ask() reçoit le system prompt déjà assemblé (assemblage remonté).
- app.py : /v1/ask accepte `context`, renvoie context_id + le contexte assemblé ;
nouveau GET /v1/contexts ; RAG doc conditionné au profil.
- config.py : URLs sources + STT_GHOSTFOLIO_TOKEN + STT_DEFAULT_CONTEXT.
- deployment : env in-cluster (Prometheus/Alertmanager monitoring, Ghostfolio ai),
jeton via secret optionnel stt-server-secrets/ghostfolio-token.
- bump 0.3.1 → 0.4.0.
Validé en local : assemblage (blocs+RAG+mémoire), parsing des sources (mock),
endpoints /v1/contexts et /v1/ask (LLM mocké) — context_id, visualiseur, fallback
contexte inconnu → funk.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sur un sujet absent de la doc Funk, le 8B comblait le vide en devinant
(« j'ai un switch ? » → tantôt « Oui » tantôt « Non », fausse assurance).
Le grounding marche (docs=6) mais la doc n'a rien à ancrer.
- config.py : system_prompt durci — si la doc ne mentionne PAS explicitement
l'élément, répondre « la doc Funk ne le précise pas », ne jamais affirmer
oui/non par déduction ni inventer de détail (modèle, marque, nombre, nom).
- admin/infra/reseau.md : section « Topologie physique — switch cluster »
(switch présent, modèle à confirmer) → comble le gap doc qui causait
l'hallucination sur le matériel réseau.
- bump 0.3.0 → 0.3.1
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sans contexte, le modèle (qwen3-8b) hallucinait sur le homelab (« stockage
décentralisé », « worker nodes »…) car il ignore tout du cluster réel. Le
cerveau interroge désormais la collection funk-docs (la doc admin/ indexée) et
injecte les passages pertinents au prompt → il répond à partir de la vraie doc.
Coût ~nul : funk-docs et stt-memory partagent le même embedder nomic (:1238,
768 dim) → le vecteur de requête calculé pour le recall mémoire est réutilisé
pour la recherche doc (une embed, deux recherches). Dégrade en silence si
Qdrant/embed down (réponse sans doc plutôt qu'échec).
Module knowledge.py (STT_DOCS_RAG, TOPK=6, MIN_SCORE=0.45). Log /v1/ask
expose docs=<n>. Serveur 0.2.1 → 0.3.0.
Validé : « c'est quoi le nom des nœuds ? » → avant « worker/master nodes »
(inventé) ; après « Kubernetes ; nœuds storage-01, compute-01, compute-02 »
(tiré de la doc).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Suite au déploiement 0.2.0, deux points observés en pilotant l'app en direct :
- Le log de timing (`ask … recall/gen/total`) n'émettait pas : uvicorn ne
configure que ses propres loggers → on attache un handler INFO sur `stt_server`.
- La chaîne LiteLLM→llama-server (ROCm gfx1031) se fige par à-coups (~1-2 min,
502 pour tous les appels, cf. incidents-llm-gpu.md). Résilience côté STT :
brain tente 2× (fermeture du client httpx entre les essais → connexion neuve si
le pool est vicié) et le timeout passe à 30s PAR tentative (≤ ~2× au pire).
Un blip transitoire devient une requête récupérée au lieu d'un 502.
bump serveur 0.2.0 → 0.2.1
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Cause de la latence 30-45s : l'endpoint d'embeddings (gpu-01:1238) peut se
geler ; recall ET remember l'attendaient ~20s chacun (timeout → dégradation
silencieuse), s'ajoutant à la réponse. Refactor :
- store (ex-remember) en BackgroundTasks → APRÈS la réponse, hors latence perçue ;
suppression de `?wait=true` (pas d'attente du flush Qdrant)
- recall renvoie aussi le vecteur de la requête → store le réutilise (1 embed/tour
au lieu de 2, le 2ᵉ portait sur le même texte)
- timeout recall serré (4s, STT_MEMORY_RECALL_TIMEOUT) : un embed lent/mort dégrade
vite (souvenirs vides) au lieu de bloquer ; store tolère 20s en arrière-plan
- clients httpx persistants (pooling/keep-alive) côté brain + longterm, fermés via
lifespan (plus de handshake TCP par appel)
- log de timing par requête (recall/gen/total/mem) pour diagnostiquer
- bump serveur 0.1.0 → 0.2.0
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>