De ce te costa chatbotul AI 30k/luna si cum il reduci
Unde se duc banii intr-un chatbot AI si cum tai 40–70% din cost fara sa strici calitatea: tokeni, RAG, rutare, caching, auto-hosting si politici de productie.

30k/luna pe LLM nu e badge de onoare; e gaura in P&L. Costul explodeaza cand lasi tokenii, contextul si RAG-ul sa mearga fara frana, iar fiecare intrebare escaladeaza direct la un model premium.
Raspuns scurt: banii se duc in trei locuri — tokenii (input+output) catre un model scump, embeddarea si cautarea pentru RAG, si lipsa de control (caching, rutare, rate limit, politici). Taierile eficiente vin din dieta de tokeni, rutare pe modele mai mici cu escaladare, caching server-side, RAG igienic, batching, si — peste anumite praguri — self-hosting cu vLLM sau TGI.
Unde se duc banii la un chatbot AI
Nu toate costurile sunt evidente in prima luna. In a treia, devii expert in facturi. Cele mai comune surse:
- Tokeni LLM: context prea mare, raspunsuri lungi, chain-of-thought lasat liber, tool call-uri care primesc/returneaza JSON urias, sistem prompt umflat cu reguli redundante.
- RAG ingestion: embeddare pentru zeci de mii de documente, chunking gresit (prea multe bucati), re-indexari frecvente; query-uri cu top-k mare si reluare cand relevanta e slaba.
- Vector store: cluster dedicat de Milvus/Weaviate/Elastic vector cu RAM mare; sau Postgres cu
pgvectorsupradimensionat si fara index IVFFlat/HNSW corect setat. - Orchestrare: lanturi de tool-uri care dubleaza promptul, agenti care fac self-reflection multi-hop, function calling catre servicii externe cu tarife proprii.
- Moderare si guardrails: apeluri suplimentare per mesaj, adesea cu prompturi mari.
- Observabilitate: log-uri de prompt+raspuns stocate integral; sampling prea mic; ClickHouse/Datadog care creste liniar cu traficul.
- Egres si stocare: streaming SSE peste CDN, inregistrari audio pentru ASR/TTS, versiuni istorice de index RAG pastrate prea mult.
Daca nu masori tokenii, nici CFO-ul nu te mai masoara pe tine (gluma amarui de senior, dar adevarata).
O arhitectura de chatbot care nu rupe banca
Un flux simplu, dar disciplinat, scade semnificativ costul per conversatie:
- Client (web/mobile/Telegram Mini App) cu streaming SSE/WebSocket.
- API Gateway (Express/FastAPI) cu Auth, rate limit si metering.
- Feature flags si policies per plan (Free/Pro/Enterprise) — limite de tokeni si modele permise.
- Message store in Postgres (cu
jsonbpentru turn-by-turn), plus o tabela de agregate pentru rapoarte. - RAG: Postgres +
pgvectorsau Milvus pentru volum mare; chunking 512–1024 tokeni, deduplicare, TTL pe colectii temporare. - Cache Redis (sau Dragonfly) pentru:
- prompt+retrieval cache (fingerprint pe
user_intent + doc_ids + policy) - partial completion cache (primii N tokeni ai unui raspuns stabil)
- prompt+retrieval cache (fingerprint pe
- Orchestrator: router mic (classifier) pe model rapid; escaladeaza doar cand scorul de incredere e sub prag.
- LLM providers: mix — model mid-tier implicit, premium doar pentru intrebari grele; fallback la self-host (vLLM) pentru clase bine-intonate.
- Observabilitate: OpenTelemetry + ClickHouse/Parquet S3 cu sampling adaptiv.
Flux textual (simplificat)
- User -> API: mesaj.
- API -> Policy: verifica planul, bugetul de tokeni si restrictiile.
- RAG -> top-k din vector store (dinamizat de intent; nu mereu k=10!).
- Prompt builder -> comprima sistem prompt + sumarizeaza istoricul.
- Cache lookup -> raspuns identic recent? returneaza instant.
- Router -> alege modelul:
fast(implicit),premium(escaladare),local(clase specifice). - LLM -> stream raspuns; log only headers + 1–2 preview chunks (nu totul pentru fiecare user).
- Store -> salveaza conversatia in mod comprimat (rezumat + difuri, nu tot istoricul textual la nesfarsit).
Snippet de middleware pentru dieta de tokeni si cache
import { createHash } from 'crypto';
import { encode as tokenize } from 'gpt-tokenizer';
import Redis from 'ioredis';
import fetch from 'node-fetch';
const redis = new Redis(process.env.REDIS_URL!);
function clampTokens(text: string, max: number) {
const tokens = tokenize(text);
if (tokens.length <= max) return text;
// tai la granita de propozitie, aproximativ
const truncated = tokens.slice(0, max - 20);
return truncated.join('') + ' ...';
}
function fp(input: any) {
return createHash('sha256').update(JSON.stringify(input)).digest('hex');
}
async function llmCall(model: string, prompt: string, maxOut: number) {
return fetch(process.env.LLM_ENDPOINT!, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ model, prompt, max_tokens: maxOut, stream: true })
});
}
export async function chatbotHandler(req, res) {
const { userId, plan } = req.auth;
const { message, context, docs } = req.body;
const SYSTEM = 'Asistent concis. Raspunde cu pași clari.';
const maxUser = plan === 'pro' ? 1200 : 600;
const maxHist = plan === 'pro' ? 1600 : 800;
const maxOut = plan === 'pro' ? 800 : 400;
const history = clampTokens(context || '', maxHist);
const userMsg = clampTokens(message || '', maxUser);
const prompt = `${SYSTEM}\nContext:\n${history}\nDocs:\n${(docs||[]).join('\n')}\nIntrebare:${userMsg}`;
const key = `qa:${fp({ userMsg, docs: (docs||[]).slice(0,5), policy: plan })}`;
const cached = await redis.get(key);
if (cached) {
res.writeHead(200, { 'Content-Type': 'text/event-stream' });
res.write(`data: ${cached}\n\n`);
return res.end();
}
// Router simplu: model rapid default; premium doar pentru intrebari lungi sau daca esueaza
const baseModel = process.env.MODEL_FAST!; // ex: gpt-4o-mini / llama-3.1-70b-instruct
const premium = process.env.MODEL_PREMIUM!; // ex: gpt-5 / claude-opus
const usePremium = tokenize(userMsg).length > 500 || (docs||[]).length > 8;
const model = usePremium ? premium : baseModel;
const resp = await llmCall(model, prompt, maxOut);
res.writeHead(200, { 'Content-Type': 'text/event-stream' });
let firstChunk = '';
for await (const chunk of resp.body as any) {
const text = chunk.toString();
if (firstChunk.length < 500) firstChunk += text;
res.write(`data: ${text}\n\n`);
}
// cache doar un snapshot scurt; evita cache la infinit pe raspunsuri lungi
await redis.setex(key, 60 * 15, firstChunk);
res.end();
}
Observatii:
- Token budget fix per plan reduce variatia costurilor.
- Cache pe fingerprint de intent si doc-ids da hit rate bun pe intrebari FAQ.
- Router-ul simplu taiat pe lungime/numar de documente elimina 30–60% din apeluri premium intr-o aplicatie tipica de suport intern.
Trade-off-uri cheie care dicteaza costul
Alegerea modelului, a vector store-ului si a strategiei de livrare influenteaza direct costul si latenta. Mai jos, o comparatie pragmatica:
| Optiune | Cost relativ | Latenta | Complexitate operare | Cand o alegi |
|---|---|---|---|---|
| API model premium (hosted) | mare | mica-medie | foarte mica | cand calitatea pe intrebari complexe e critica si volumul este mic-mediu |
| API model mid-tier (hosted) | mediu | mic | foarte mica | cand marea majoritate a intrebarilor sunt factuale/templated |
| Self-host vLLM pe GPU | mic-medie la volum | mic-medie | mare | cand ai trafic stabil si clase de task-uri bine definite |
| RAG cu Postgres+pgvector | mic | mic | mic | cand setul de documente < ~5–10M embeddings |
| RAG cu Milvus/Weaviate | mediu | mic | mediu-mare | cand ai vectori multi-milion si cerinte de HA/replicare |
| Cache server-side Redis | foarte mic | foarte mic | mic | cand ai intrebari repetabile/FAQ |
Pentru alegerea modelului pe productie, vezi si analiza noastra despre modele pentru SaaS in productie.
Tactici concrete de reducere a costului (fara sa strici UX-ul)
1) Dieta de tokeni
- Trunchiaza istoricul conversatiei cu rezumate iterative. Pastreaza entitatile/obiectivele, nu tot dialogul literal.
- Comprima sistem prompt-ul: scoate reguli redundante, muta ghidajul in exemple scurte (
few-shot) doar cand chiar ajuta. - Controleaza tool calling-ul: trimite catre model doar schema necesara (ex:
zod/OpenAPI partial), nu toata documentatia. - Taie output-urile prolixe: seteaza
max_tokenssi cere raspunsuri in pasi concreti.
2) Rutare pe modele + escaladare
- Classifier ieftin (ex: un model mic sau chiar reguli) decide clasa de intent.
- Model rapid pentru majoritatea; daca scorul de incredere < prag, escaladeaza la premium.
- Pentru intrebari strict pe documentatia ta, foloseste un model local bine instruit (ex: Llama 3.1 70B instruct pe vLLM) — calitatea e suficienta.
3) Caching disciplinat
- Cache pe intrebari identice sau echivalente semantic (hash pe
stemmed query+ ids docuri). TTL 15–60 minute. - Partial completion cache: salveaza primii 300–500 tokeni ai raspunsurilor populare; utilizatorul percepe viteza, diferenta restului e minora.
- Cache pe rezultate RAG (doc ids + scoruri). Multe intrebari ating acelasi top-k.
4) RAG igienic
- Chunking 512–1024 tokeni, cu overlap redus (10–15%).
- Deduplicare si normalizare (hash pe continut curatat de layout). Eviti embeddings duplicate.
- Top-k dinamic: pornesc cu k=4; cresc la 6–8 doar daca scorul scade sub prag.
- Hybrid search (BM25 + vector) pentru a micsora k si a creste precizia de la primul pas.
- Batch embeddings si rate-limit ingestia; nu reedita intreg corpul de continut pentru mici schimbari.
5) Observabilitate orientata pe cost
- Logheaza doar metadate + mostre (sampling adaptiv in functie de plan/eroare). Nu salva fiecare prompt integral.
- Computeaza cost per feature si per ruta de model; eticheteaza evenimentele cu
model,tokens_in/out,rag_k,cache_hit. - Alarme pe
tokens_outliersilooping tools.
6) Guardrails eficiente
- Moderare pe classifier local pentru pre-filtrare; trimite catre API-ul scump doar cazurile neclare.
- Reguli explicite anti-injectie in RAG: filtrare instructiuni de sistem din surse; markup
data-originin prompt pentru a delimita citatele.
7) Cand sa mergi pe self-host
- Cand rata de utilizare e previzibila si >60–70% din traficul tau se incadreaza intr-o sarcina repetabila.
- Foloseste vLLM (GPU sharing si paginare de atentie) si quantizare (ex: FP8/INT4 acolo unde calitatea ramane acceptabila).
- Mentine fallback catre un API hosted pentru varfuri sau intrebari atipice.
Exemplu de modelare a costului: cum ajungi la 30k/luna si cum il tai la ~12–18k
Nu sunt cifre universale; folosim un exemplu didactic pentru a vedea ordine de marime. Adapteaza X/Y/Z la tarifele tale actuale.
Ipoteze:
- 100k conversatii/luna, 2 mesaje utilizator per conversatie, 1 raspuns model per mesaj.
- Medie per mesaj: 800 tokeni input (istoric+RAG+prompt), 400 tokeni output.
- 60% din mesaje sunt „simple”, 40% „grele”.
- Preturi ipotetice: model premium la
Y$ / 1M tokeni output siX$ / 1M tokeni input; model mid-tier la ~30% din asta; self-host ~Z $ / 1M echivalent (amortizat GPU+energie).
Calcul (exemplu):
- Tokeni/luna: 100k conv * 2 mesaje * (0.8k in + 0.4k out) = 240M tokeni.
- Fara rutare: totul pe premium. Cost ≈ 240M * (ponderi input/output si X/Y). Daca X=10 si Y=30 (ipoteza), ordinul de marime sare spre zeci de mii.
- Cu rutare + dieta + cache:
- 60% pe mid-tier (0.3X/0.3Y), 25% pe premium, 15% pe self-host (Z << X/Y la volum stabil).
- Tokeni scad 25–35% datorita trunchierii si RAG k dinamic (ex: 240M -> ~165M–180M).
Adaugi:
- Embeddings: ingest initial + lunar incremental (batch, dedup). Cu chunking corect, ordinea de marime tinde sa fie mult sub costul de generare, mai ales dupa luna 1.
- Vector store: Postgres cu
pgvectorpe un cluster moderat, vs un serviciu vector dedicat cu cost fix mai mare; alegi in functie de volum. - Observabilitate: sampling + agregate; tai 70–90% din volum fata de log complet.
Concluzie: este realizabil, in scenariul ipotetic de mai sus, sa treci de la ~30k la ~12–18k/luna fara sa degradezi semnificativ calitatea raspunsurilor. Cheia este disciplina pe tokens, rutare si RAG.
Ce se strica in productie
- Explozia istoricului: multe UI trimit tot transcriptul la fiecare mesaj. Solutie: sumar incremental si ferestre glisante pe intentii.
- Tool loops: modelul cheama aceeasi functie de mai multe ori cautand „confirmari”. Pune bugete pe tool-uri si heuristici de oprire.
- RAG drift: indexuri invechite, scoruri inconsistente dupa schimbari de normalizare; lipsa reindexarii selective. Fa migration scripts si versionare pe colectii.
- Permisiuni multi-tenant: scapari de documente intre clienti cand
tenant_idnu e in toate join-urile. Daca construiesti SaaS, vezi si ghidul nostru despre multi-tenant pe Postgres/Prisma. - Outages si rate limits la provider: lipsa de backoff si idempotenta duce la duplicate si cost dublu. Pastreaza
request_idla nivel de business, nu doar transport. - Streaming care curge la canal deschis dupa ce userul a plecat: nu inchizi SSE corect, platesti egress si compute.
- Prompt injection din surse RAG: instructiuni in documente care „hijack” comportamentul. Normalizeaza si marcheaza citatele, nu oferi control asupra sistem prompt-ului.
- Log-uri scurse: salvarea continutului sensibil integral in observabilitate. Foloseste redaction si hashing pe PII.
Cost si ROI: cum decizi ce tai si cand investesti
- Unit economics: calculeaza cost per conversatie rezolvata. Compara cu costul suportului uman. Daca botul rezolva 50% din tichete la jumatate de cost, esti pe directia buna.
- Metrici vitale:
cost/msg,cost/conv,cache_hit%,premium_escalation%,tokens_in/out per class,deflection_rate(tichete evitate),CSAT/RTT. - Plan de maturizare:
- Luna 1–2: hosted API, RAG simplu cu Postgres, cache, token diet. Tinta: stabilitate si p95 sub 2–3s.
- Luna 3–4: router + sampling in observabilitate, guardrails pe classifier local, k dinamic.
- Peste 5–6: self-host pe clase repetabile, optimizari de embeddings, fine-tuning pe instructii locale (cand datele si volumele justifica).
- Cand sa NU optimizezi prematur: daca ai <5k conversatii/luna, focus pe calitatea raspunsului si colectarea de semnale; KPI-ul tau e fit-ul, nu inca centii per raspuns.
Schema de cost tipica pe componente (exemplu orientativ)
- LLM completari: 55–70% din total.
- Embeddings + RAG queries: 10–20%.
- Vector store si stocare: 5–10%.
- Observabilitate + log-ingest: 5–10%.
- Diverse (moderare, egress, retries): 5–10%.
Nu urmari 0 absolut; urmareste platoul in care cost/rezolvare e stabil si CSAT ramane constant.
Mini ghid de selectie a stack-ului
- Frontend: streaming SSE by default; WebSocket doar cand chiar ai bidirectionalitate. Render progresiv.
- Backend: Node/Express sau FastAPI, important e sa expui flux SSE fara proxy care taie conexiunea.
- Cache: Redis/Dragonfly cu eviction LRU si TTL scurt pentru Q/A populare.
- RAG: Postgres 15+ cu
pgvectorpentru <10M embeddings; Milvus/Weaviate pentru volum mare si HA. - Inference: mix hosted + vLLM. Pastreaza adaptor comun (unified interface) si toggles per plan.
- Observabilitate: OpenTelemetry -> ClickHouse/Parquet cu sampling; dashboards pe
cost by route.
Exemple de politici si praguri utile
max_tokens_inper plan (Free/Pro/Ent) simax_tokens_outper mesaj.max_tool_callsper conversatie simax_chain_depthpentru agenti.rag_k_initial=4,rag_k_max=8,min_score=0.2cu fallback BM25.premium_escalation%tinta < 20% pentru planurile standard.cache_hit%tinta > 35% pe intrebari non-personalizate.
FAQ
Q: De ce RAG-ul meu e scump chiar daca nu am mult trafic? A: Probabil ingerezi si re-embedd-uiesti prea des sau chunking-ul e prea granulat. Deduplica pe hash, fa batch-uri saptamanale si foloseste top-k dinamic.
Q: Are sens sa fac fine-tuning ca sa reduc costul? A: Poate. Daca ai clase repetitive de intrebari si date curate, un model mai mic fine-tuned iti scade costul si latenta. Nu incepe cu asta; pune intai rutare si dieta de tokeni.
Q: Postgres + pgvector sau un vector DB dedicat? A: Pentru <10M embeddings si cerinte simple, Postgres e suficient si ieftin. Dedicat cand ai volum mare, HA si nevoi de scalare orizontala/observabilitate.
Q: Cati tokeni sa pastrez in istoric? A: Cat sa mentii coerenta pe task; tipic 400–1200 tokeni, restul in rezumat. Mentine entitati si obiective, nu toata conversatia literal.
Q: Merita self-host pe GPU? A: Daca ai trafic stabil si mixul de intrebari e predictibil, da — mai ales cu vLLM si quantizare. Pastreaza fallback hosted pentru varfuri si intrebari atipice.
Q: Cum evit prompt injection prin RAG? A: Normalizeaza sursele, marcheaza citatele, filtreaza instructiunile de sistem din documente si trateaza outputul modelului ca sugestie, nu comanda, inainte de tool calls sensibile.
Concluzii cheie
- Costul mare vine din tokeni necontrolati, RAG neigienic si lipsa de rutare/caching, nu din „magia” modelului in sine.
- Dieta de tokeni + router pe model + cache server-side reduc costul fara sa degradeze calitatea perceputa.
- RAG trebuie tratat ca un sistem de cautare: chunking corect, dedup, top-k dinamic si hybrid search.
- Observabilitatea cu sampling si metri pe ruta/model e obligatorie pentru a evita surprize la factura.
- Self-host cu vLLM devine rentabil peste un anumit volum stabil; pastreaza totusi fallback hosted.
- Politici explicite (tokeni, tool calls, escaladare) mentin bugetul previzibil si UX-ul consistent.
Daca construiesti un chatbot AI pentru produsul tau sau pentru operatiuni interne si vrei sa cobori costul fara sa pierzi calitatea, scrie-ne — incepem cu un audit tehnic si un plan de masuri concrete. Contacteaza MTBYTE: /contact
URMATORUL PAS
Ti-a placut abordarea?
Aplicam aceleasi principii in proiectele clientilor: AI, automatizari, produse care nu se sting dupa lansare.