mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-11 14:14:42 +02:00
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:
parent
767a94b1d0
commit
1db84e9041
7 changed files with 132 additions and 6 deletions
|
|
@ -19,6 +19,7 @@ from stt_server import __version__
|
|||
from stt_server import brain
|
||||
from stt_server.brain import ask as brain_ask
|
||||
from stt_server.config import settings
|
||||
from stt_server.knowledge import Knowledge
|
||||
from stt_server.longterm import LongTermMemory
|
||||
from stt_server.memory import SessionStore
|
||||
|
||||
|
|
@ -34,6 +35,7 @@ if not log.handlers:
|
|||
|
||||
sessions = SessionStore()
|
||||
longterm = LongTermMemory() if settings.memory_longterm else None
|
||||
knowledge = Knowledge() if settings.docs_rag else None
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
|
|
@ -43,6 +45,8 @@ async def lifespan(app: FastAPI):
|
|||
await brain.aclose()
|
||||
if longterm:
|
||||
await longterm.aclose()
|
||||
if knowledge:
|
||||
await knowledge.aclose()
|
||||
|
||||
|
||||
app = FastAPI(title="STT-server", version=__version__, lifespan=lifespan)
|
||||
|
|
@ -97,11 +101,13 @@ async def v1_ask(req: AskRequest, background: BackgroundTasks) -> AskReply:
|
|||
)
|
||||
t0 = time.perf_counter()
|
||||
history = sessions.history(req.session_id) if req.session_id else None
|
||||
# recall : timeout serré, dégrade vite ; renvoie aussi le vecteur (réutilisé par store)
|
||||
# recall : timeout serré, dégrade vite ; renvoie aussi le vecteur (réutilisé ci-dessous)
|
||||
memories, qvec = await longterm.recall(text) if longterm else ([], None)
|
||||
# RAG doc : on réutilise qvec (même embedder nomic) → ancre la réponse dans funk-docs
|
||||
docs = await knowledge.search(text, qvec) if knowledge else []
|
||||
t_recall = time.perf_counter()
|
||||
try:
|
||||
reply = await brain_ask(text, model, history, memories)
|
||||
reply = await brain_ask(text, model, history, memories, docs)
|
||||
except httpx.HTTPError as e:
|
||||
raise HTTPException(status_code=502, detail=f"upstream LiteLLM : {e}") from e
|
||||
t_gen = time.perf_counter()
|
||||
|
|
@ -112,12 +118,13 @@ async def v1_ask(req: AskRequest, background: BackgroundTasks) -> AskReply:
|
|||
if longterm:
|
||||
background.add_task(longterm.store, req.session_id or "anon", text, qvec)
|
||||
log.info(
|
||||
"ask model=%s recall=%.0fms gen=%.0fms total=%.0fms mem=%d",
|
||||
"ask model=%s recall=%.0fms gen=%.0fms total=%.0fms mem=%d docs=%d",
|
||||
model,
|
||||
(t_recall - t0) * 1000,
|
||||
(t_gen - t_recall) * 1000,
|
||||
(t_gen - t0) * 1000,
|
||||
len(memories),
|
||||
len(docs),
|
||||
)
|
||||
return AskReply(reply=reply, model=model)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue