feat(stt-server): grounding RAG — le cerveau répond depuis la doc Funk (#27)

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>
This commit is contained in:
ALI YESILKAYA 2026-06-19 21:53:30 +02:00 committed by GitHub
parent 767a94b1d0
commit 1db84e9041
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 132 additions and 6 deletions

View file

@ -34,6 +34,7 @@ async def ask(
model: str | None = None,
history: list[dict] | None = None,
memories: list[str] | None = None,
knowledge: list[str] | None = None,
) -> str:
system = settings.system_prompt
if settings.disable_thinking:
@ -42,6 +43,14 @@ async def ask(
# → timeout (502). Le token de contrôle `/no_think` désactive le mode raisonnement.
# Inoffensif pour les modèles non-Qwen (simple texte ignoré).
system += "\n/no_think"
if knowledge:
# Contexte AUTORITAIRE : extraits de la doc Funk (RAG funk-docs). Le modèle doit
# répondre à partir de ça pour les questions sur le homelab (sinon il hallucine).
extraits = "\n\n".join(knowledge)
system += (
"\n\n=== Documentation Funk (réponds À PARTIR de ces extraits ; "
"si l'info n'y est pas, dis-le) ===\n" + extraits
)
if memories:
souvenirs = "\n".join(f"- {m}" for m in memories)
system += (