PRD 5.14 rescris cu pivotul arhitectural: LLM doar etichetator OFFLINE, runtime = clasificator local fara API (fuzzy + embeddings), baza de cunostinte GOLD partajata cross-account (validarea unui service ajuta toate). Decizia 8 (corpus per-cont) SUPERSEDED. Tooling nou OpenRouter (free, familia NVIDIA Nemotron): or_common.py (client + corpus pe frecventa, cheie din .env) + or_modeltest.py (comparatie modele, acord ensemble vs Groq). Masurat: super-120b + nano-9b fiabile, 3/3 unanim pe 87% volum; ultra-550b aruncat. Corpus real (4 CSV service, coloana NR=frecventa) + etichete Groq bootstrap incluse ca date de masurare. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
14 KiB
PRD 5.14 — Mapare automata operatii service prin distilare LLM
Problema
La ingestie (canal API si import web), o prestatie poate veni cu cod_op_service
denumirein loc decod_prestatieRAR. Daca nu exista mapare, submission-ul intra inneeds_mappingsi asteapta confirmare umana. Service-urile reale au volume mari de denumiri particulare (masurat: 17.435 denumiri DISTINCTE in 4 CSV-uri de clienti reali —automotive13.170,sigma3.743,clever1.668,south875). Maparea manuala a acestora, prin editorulneeds_mapping, e prohibitiva: zeci de mii de operatii × confirmare umana.
Nomenclatorul RAR are doar 18 coduri foarte largi (REPARATIE, INTRETINERE,
REVIZIE PERIODICA, etc. — nomenclator_seed.py). Deci problema nu e potrivire de
sinonime, ci clasificare a mii de operatii granulare in 18 categorii abstracte
- detectare de „gunoi" (linii care nu sunt operatii:
ITP CT 12 ABC,DISCOUNT MATERIALE 5%,MANOPERA, nr. inmatriculare).
Viziune (pivot 2026-06-28)
LLM-ul NU ruleaza la runtime. Rol unic: etichetator offline care construieste un set de date (denumire -> cod). La runtime ruleaza un clasificator local mic, fara API (similaritate / fuzzy / embeddings), „distilat" din etichetele LLM + maparile validate de oameni. Trei straturi:
- Etichetare offline (LLM, periodic): acopera denumirile cu cele mai multe aparitii (frecventa) si grupeaza denumirile asemanatoare ca sa eticheteze ieftin.
- Clasificator runtime (fara AI): exact -> fuzzy/substring -> similaritate semantica (embeddings) peste baza de cunostinte. Zero cost per cerere, ruleaza pe LXC.
- Baza de cunostinte PARTAJATA: maparile validate de oameni din TOATE conturile de service contribuie la clasificare (strat „gold" comun), peste etichetele LLM („silver" bootstrap). Munca de validare a unui service ajuta toate service-urile.
Viitor (nu acum): un LLM generativ local pe LXC. Pasul curent foloseste un model de embedding (nu generativ): mic, CPU, milisecunde/text.
Premise
- Volumul de denumiri distincte e finit si se schimba lent. Odata etichetate, 90%+ din traficul viitor sunt repetari ale acelorasi denumiri (service-ul refoloseste propriul vocabular). Lege Zipf: top 100 denumiri = 43.6% volum, top 500 = 67.7%, top 1000 = 76.2% (din 155.195 operatii totale).
- RAR accepta NUMAI coduri din nomenclator. Un cod necunoscut -> HTTP 500
(
ORA-12899) + record PARTIAL FINALIZATA (terminal). Deci orice cod propus de un sistem automat TREBUIE validat fata de nomenclator inainte de enqueue (invariant existent inresolve_prestatii(..., valid_codes)). - Maparea gresita are cost asimetric: un cod gresit trimis = FINALIZATA
ireversibil la RAR. Deci pragul de auto-trimitere ramane conservator; incertul
ramane
needs_mappingcu om in bucla. Etichetele LLM NEVALIDATE = sugestie, nu auto-trimitere (vezi scara de incredere). - Hardware LLM local generativ e prea lent acum (masurat: Ollama LXC 104 generativ 180-320s/op). Embeddings locale insa sunt rapide pe CPU si suficiente pentru similaritate la runtime.
- Datele nu sunt sensibile (confirmat utilizator): denumirile de operatii pot merge la API-uri cloud pentru etichetare. PII incidental (nr. inmatriculare/VIN) se face scrub inainte de trimitere (F3).
Masuratori
Bootstrap (anterior, Groq)
- Groq
llama-3.3-70b: 28ms/op, acord 94% cu heuristica pe cazuri clare, detectare gunoi excelenta (NUL). Abandonat ca furnizor: cap zilnic free atins + cheie expusa.
OpenRouter free — NVIDIA Nemotron (masurat 2026-06-28)
Furnizor nou pentru etichetare: cheie utilizator, modele GRATUITE, date ne-sensibile.
-
Capcane de cont (rezolvate): modelele free dau initial
404 No allowed providersdin cauza unui allowlist de provideri pe cont (venice/together/fireworks/ atlas-cloud) —open-inference/google-ai-studio/nvidiaerau excluse. Fix: eliminat restrictia in Settings -> Preferences + activat toggle-ul de privacy „free endpoints may publish/train". WAF: User-AgentMozilla/5.0obligatoriu. -
Set fiabil = familia NVIDIA Nemotron. Restul modelelor sunt 429 (rate-limited upstream, partajat global: llama-3.3-70b, qwen3-next, gemma, hermes, dolphin) sau 404 (gpt-oss). Cap free tier ~50 cereri/zi fara credit.
-
Test ensemble pe top 120 dupa frecventa (46.4% din volum), 2026-06-28:
Model ms/op parse-fail acord vs Groq (overlap) nemotron-3-super-120b 1463 0 100% nemotron-nano-9b-v2 1248 0 100% nemotron-3-ultra-550b 6450 0 100% Acord ensemble ponderat pe volum: 3/3 unanim = 87% volum, 2/3 = 13%, dezacord total = 0%. Din unanim: 7 NUL (gunoi), 100 coduri reale.
-
Decizie model: pastram
super-120b+nano-9b; aruncamultra-550b(4-5x mai lent, zero castig de acuratete). Caveat: ensemble din aceeasi familie NVIDIA -> acordul supraestimeaza increderea fata de un ensemble cross-family. -
Dezacordurile (13%) sunt cazuri de granita taxonomica reala, nu zgomot:
REGLAT DIRECTIE/FARURI(OE-2 intretinere vs OE-4 reglare),MANOPERA TINICHIGERIE(NUL vs OE-1),DEZECHIPAT usa/bara(pas de demontare),INLOCUIT FILTRU AER(OE-1 vs OE-3). Astea trebuie sa cada inneeds_mapping.
Solutia
Stratul 1 — Etichetare offline (LLM, fara cod runtime)
Tool CLI (tools/mapare-llm/, stil tools/apikey). Etichetatorul OpenRouter
(or_common.py + or_label.py) clasifica denumirile in cele 18 coduri RAR + NUL:
- Prioritizare pe FRECVENTA (NR), nu alfabetic. Etichetam intai denumirile cu cele mai multe aparitii (acopera cel mai mult volum per apel).
- Grupare pe similaritate inainte de etichetare. Denumirile aproape identice
(
REGLAT DIRECTIE/REGLAT DIRECTIA/REGLARE DIRECTIE) se grupeaza; LLM eticheteaza doar reprezentantul grupului, codul se propaga la tot grupul. Maximizeaza acoperirea per apel LLM (critic pe cap free de ~50 cereri/zi). - Ensemble NVIDIA (
super-120b+nano-9b): acord -> incredere mai mare; dezacord -> ramane pentruneeds_mapping. Vot pe coduri, nu self-confidence. - Scrub PII (regex nr. inmatriculare/VIN) inainte de trimitere (F3, exista).
- Output: dataset etichetat cu
denumire, cod, sursa, confidence(provenienta).NULmarcat separat (ancore negative + supresie), NU se promoveaza la cod RAR.
Prompt cu reguli explicite (avarii grave DOAR la accident; vopsire = reparatie;
ulei+filtru = revizie; gunoi -> NUL). Batch mare (cap free tier), retry/backoff pe
429, respecta Retry-After.
Stratul 2 — Clasificator runtime (FARA AI, fara API)
Pentru o denumire din prezentare (canal API sau import), in app/mapping.py:
- Exact in baza de cunostinte (
operations_mapping+ strat partajat) -> cod direct. - Fuzzy/substring (
operation_text_rules,rapidfuzz) — exista deja. - Similaritate semantica (embeddings) — NOU: model multilingv mic (ex.
intfloat/multilingual-e5-smallsauparaphrase-multilingual-MiniLM), CPU. Vectorizam baza etichetata o data; la runtime vectorizam denumirea noua si luam cel mai apropiat vecin (sau top-k cu vot). Optional: clasificatorscikit-learn(regresie logistica / kNN) antrenat pe (embedding -> cod) pentru generalizare dincolo de vecinul exact. „Antrenarea pe datele de test" = acest pas, secunde, ruleaza oriunde. - Cod propus -> validat OBLIGATORIU
valid_codes(garda ORA-12899). Peste pragul de incredere -> conform scarii; altfelneeds_mapping.
Decizie de gazduire runtime: ramane deschisa pentru reviziile plan (in-proces in gateway vs microserviciu pe LXC/Flowise). Default propus: in-proces (cel mai simplu).
Stratul 3 — Baza de cunostinte PARTAJATA cross-account
Schimbare fata de versiunea anterioara (care izola corpusul per cont):
- Strat GOLD partajat: maparile validate de oameni (din
needs_mapping, in ORICE cont) intra intr-un store partajatdenumire_normalizata -> cod. Astfel validarea facuta de un service ridica increderea pentru toate. Cheia = denumire normalizata (scrub PII, lower, strip), nu textul brut. - Strat SILVER: etichetele LLM (bootstrap) — sugestii, NU auto-trimitere.
- Override per-cont: daca un cont mapeaza explicit o denumire la alt cod decat cel partajat (conflict legitim de vocabular), override-ul contului castiga pentru acel cont. Conflictele inter-cont se rezolva cu provenienta + (optional) majoritate.
Confirmarile umane curg organic prin folosirea normala a editorului needs_mapping
— FARA sesiune separata de adjudecare manuala (cerinta utilizator).
Scara de incredere (runtime, per operatie din prezentare)
| Treapta | Sursa | Actiune | Frictiune |
|---|---|---|---|
| Certa | exact in stratul GOLD (validat de om, orice cont) sau override cont | auto-trimite | zero |
| Inalta | embedding NN cu similaritate FOARTE inalta la o mapare GOLD + ensemble LLM unanim | auto-trimite (prag calibrat) | zero |
| Medie | LLM silver / similaritate medie | needs_mapping cu sugestie pre-completata -> 1 click |
minima |
| Joasa | similaritate slaba / coduri apropiate | needs_mapping manual |
normala |
| NUL | non-operatie (ITP, discount, nr. inmatriculare) | marcat „nu e operatie", suprimat | — |
Invariant F1 (pastrat): o eticheta pur-LLM NEVALIDATA nu auto-trimite singura; auto-send cere ori GOLD (validat de om), ori treapta „inalta" calibrata. Tensiunea centrala (utilizatorul se bazeaza pe LLM, dar FINALIZATA e ireversibil) = intrebarea cheie pentru reviziile plan: unde fix se aseaza bara treptei „inalta".
Integrare
- Stratul 1: tool CLI offline
tools/mapare-llm/(exista:or_common.py,or_modeltest.py; de adaugator_label.pycu grupare + propagare). - Stratul 2:
suggest_from_corpus+ similaritate embeddings inapp/mapping.py, apelata inpending_unmappedpentru sugestia din editor. Model embedding incarcat la pornire / serviciu, vectori pre-calculati pe baza. - Stratul 3: store partajat (tabela noua
shared_mappingssau coloana de scope peoperations_mapping), seed la confirmare umana; override per-cont. - Validare
valid_codespe tot lantul (exista).
Non-obiective
- Nu inlocuim confirmarea umana pentru cazuri incerte.
- Nu trimitem automat coduri sub prag / etichete LLM nevalidate.
- Nu adaugam dependenta cloud la RUNTIME (LLM doar offline pentru etichetare).
- Nu antrenam un LLM generativ local acum (viitor).
Riscuri
- Etichete LLM gresite tratate ca adevar daca scapa garda F1 (seed direct in GOLD).
- Ensemble aceeasi familie (NVIDIA) -> acord corelat-gresit; supraestimare incredere.
- Strat partajat cross-account: o denumire poate insemna lucruri diferite la service-uri diferite -> conflict; mitigat prin override per-cont + provenienta.
- Drift: denumiri noi neacoperite; embeddings ajuta dar nu elimina.
- Free tier OpenRouter flaky (429/404, cap 50/zi) -> etichetarea bulk e lenta; e offline, deci tolerabil, dar nu pe calea critica de productie.
- Model embedding ales: calitate pe limba romana de verificat empiric.
Decision Audit Trail
| # | Faza | Decizie | Clasificare | Principiu | Rationament | Respins |
|---|---|---|---|---|---|---|
| 1 | Eng | Seed-ul NU intra direct in stratul auto-send; etichetele LLM = strat SILVER (sugestii). Auto-send cere GOLD (validat de om) sau treapta inalta calibrata | TASTE (critic) | P1, P5 | resolve_prestatii->queued direct => seed auto = AUTO-TRIMITERE ghiciri la FINALIZATA ireversibil (Premisa 3) |
seed direct in auto-send |
| 2 | Eng | Seeder = INSERT OR IGNORE / refuza overwrite pe randuri validate de om |
MECHANICAL | P1 | re-rularea ar clobber-ui maparile umane cu ghiciri LLM | ON CONFLICT UPDATE |
| 3 | Eng | Scrub regex (nr. inmatriculare/VIN) inainte de trimitere la LLM | TASTE | P1 | gunoiul contine ITP CT 12 ABC = nr. inmatriculare = PII |
trimitere text brut |
| 4 | Eng | NUL = ancore negative in corpus + lista supresie | MECHANICAL | P1 | altfel gunoiul recurent reintra mereu in needs_mapping si fuzzy ii da cod gresit | exclude NUL |
| 5 | Eng | Coloana source/confidence (provenienta) pe baza de cunostinte |
MECHANICAL | P1 | audit + rollback batch model prost + safe re-seed | fara provenienta |
| 6 | Eng | Runtime = embeddings + clasificator mic (sklearn), NU LLM generativ | TASTE | P3, P5 | LLM generativ local prea lent (Premisa 4); embeddings CPU suficiente + rapide | LLM la runtime |
| 8 | Eng | SUPERSEDED: corpus partajat cross-account (strat GOLD comun), NU per-cont izolat; override per-cont pe conflict | TASTE | P1, P2 | cerinta utilizator: validarea unui service ajuta toate; muncă compusa. Conflictul de vocabular rezolvat prin override + provenienta | (vechi: corpus strict per-cont) |
| 9 | Eng | Furnizor etichetare = OpenRouter free, ensemble NVIDIA (super-120b + nano-9b); aruncat ultra-550b | MECHANICAL | P3 | masurat 2026-06-28: doar NVIDIA routeaza fiabil; ultra 4-5x lent fara castig | Groq (cap atins) / ultra |
| 10 | Eng | Etichetare prioritizata pe frecventa + grupare pe similaritate (eticheteaza reprezentant, propaga) | MECHANICAL | P2 | acopera mult mai mult volum per apel; critic pe cap free ~50/zi | etichetare alfabetica |
Istoric review (pre-pivot)
Versiunea anterioara a trecut prin /autoplan (mod SELECTIVE EXPANSION, subagent-only,
Codex indisponibil). Constatari portante atunci: F1 CRITIC (seed=auto-send),
F2/F3/F4 HIGH (idempotenta seed, scrub PII, ancore NUL), F5/F6/F7/F8 MEDIUM. Acele
decizii sunt incorporate in Decision Audit Trail de mai sus. Pivotul 2026-06-28
(LLM offline-only + runtime embeddings + strat partajat cross-account) NECESITA o
noua rulare de review (CEO / Eng / Design) — de aceea sectiunea GSTACK REVIEW REPORT
e goala momentan si se completeaza la urmatoarea rulare.
GSTACK REVIEW REPORT
(de completat la rularea reviziilor pe versiunea pivotata — plan-ceo / plan-eng / plan-design)