fix(maria): pragul de acoperire la 0,80 si temperatura 0 — doua raspunsuri inventate

Grupul "Maria Test", 2026-09-01, ambele mesaje au primit raspunsuri inventate:

- "am si eu o factura pe luna august cu eroare in spv la trimitere AUTO SULE"
  (cosinus 0,768) — mesajul nu spune CE eroare e; Maria a explicat cum se reface
  o factura stearsa si a trimis omul sa verifice drepturile pe CIF in SPV.
- captura cu `<Error errorMessage="CUI cumparator incorect"/>` (0,778) — eroarea
  nu exista in niciun document; Maria a inventat o procedura cu "ID de descarcare",
  Borderou eFactura si retrimitere manuala.

Cauza: `RANK_STRONG_COSINE=0,70` inseamna "cosinusul singur e destul", dar toate
chunk-urile eFactura seamana intre ele — la 0,7x cosinusul nu mai distinge "e in
documente" de "e despre eFactura". Aceeasi greseala ca la codurile Oracle
(ORA-06550 vs ORA-12541, b7d75f0), doar ca fara cod pe care sa te sprijini.

- RANK_STRONG_COSINE 0,70 -> 0,80: peste atat trec doar potrivirile aproape
  textuale, restul cad pe dovada lexicala (termenii rari ai intrebarii chiar in
  chunk-uri). Ambele mesaje escaladeaza acum la suport.
- LLM_TEMPERATURE=0 la apelul modelului. Fara el llama.cpp foloseste 0,8 —
  creativitate exact acolo unde vrem doar ce scrie in context.
- Cele doua cazuri reale sunt adaugate in ops/calibrate-rank.py: 25/25.

Teste: 99 pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4uzvgm7AyJch5WH8QHRhY
This commit is contained in:
Claude Agent
2026-09-01 18:24:37 +00:00
parent 5e60394c20
commit 45b36591c9
6 changed files with 41 additions and 4 deletions

View File

@@ -39,6 +39,7 @@ DEFAULTS: dict[str, str] = {
"EMBED_MODEL": "nomic-embed-text",
"TOP_K": "3",
"MAX_TOKENS": "250",
"LLM_TEMPERATURE": "0",
"POLL_INTERVAL_S": "2",
"TEST_MODE_SELF_CHAT_ONLY": "true",
# Grupuri in care Maria are voie sa raspunda (JID-uri separate prin virgula).
@@ -56,7 +57,7 @@ DEFAULTS: dict[str, str] = {
"OCR_TIMEOUT_S": "60",
# Ordonarea chunk-urilor si pragul de la care se considera ca raspunsul chiar
# e in documente (vezi rag/rank.py pentru masuratoarea din spatele valorilor).
"RANK_STRONG_COSINE": "0.70",
"RANK_STRONG_COSINE": "0.80",
"RANK_WEAK_COSINE": "0.58",
"RANK_RECALL_N": "12",
"RANK_MIN_RARE_RATIO": "0.5",

View File

@@ -175,6 +175,11 @@ def ask_llm(chunks: list[str], question: str, istoric: list[dict] | None = None)
json={
"messages": mesaje,
"max_tokens": config.get_int("MAX_TOKENS", 250),
# Fara asta llama.cpp raspunde cu temperatura lui implicita (0,8).
# Aici nu vrem creativitate: raspunsul trebuie sa fie ce scrie in
# context, la fel de fiecare data. Vezi raspunsurile inventate din
# 2026-09-01 (grup „Maria Test").
"temperature": float(config.get("LLM_TEMPERATURE", "0")),
},
timeout=60,
)

View File

@@ -39,8 +39,17 @@ RRF_K = 60 # constanta standard din Reciprocal Rank Fusion
def strong_cosine() -> float:
"""Peste atat, singur cosinusul e de ajuns (RANK_STRONG_COSINE)."""
return float(config.get("RANK_STRONG_COSINE", "0.70"))
"""Peste atat, singur cosinusul e de ajuns (RANK_STRONG_COSINE).
Era 0,70 si a fost prea jos: pe 2026-09-01, „am o factura cu eroare in SPV"
(0,768) si o captura cu `errorMessage="CUI cumparator incorect"` (0,778) au
trecut drept acoperite, desi prima nu spune ce eroare e, iar a doua nu exista
in documente. Toate chunk-urile eFactura seamana intre ele: 0,7x nu distinge
„e in documente" de „e despre eFactura". La 0,80 trec doar potrivirile
aproape textuale, restul cad pe dovada lexicala (termenii rari din intrebare
chiar in chunk-uri). Verificat cu ops/calibrate-rank.py: 25/25.
"""
return float(config.get("RANK_STRONG_COSINE", "0.80"))
def weak_cosine() -> float: