L'architettura moderna predefinita per chatbot su base di conoscenza
La ricerca tradizionale nella knowledge base restituisce link; l'utente li legge. Il RAG trasforma questo processo in una risposta conversazionale immediata con citazioni. Se fatto bene, gli utenti ricevono risposte in 2 secondi invece di cercare in 5 documenti. Se fatto male, il chatbot allucina e il CTO vieta il progetto per un anno. Questa pagina spiega la differenza.
Lo stack minimo praticabile per la produzione
- Vector store: pgvector se usi già Postgres, Pinecone o Qdrant per una soluzione gestita
- Embeddings: text-embedding-3-large, chiamato direttamente su OpenAI — Kunavo non fornisce embeddings e, in ogni caso, la chiamata agli embeddings è separata da quella di generazione
- Retrieval: ibrido (vettoriale + BM25 con reciprocal rank fusion)
- Generazione: Claude Sonnet 5 con cache_control nel prompt di sistema
- UI: risposte in streaming, visualizzazione delle citazioni, fallback «Non lo so»
from openai import OpenAI
client = OpenAI(api_key="sk-kn-...", base_url="https://api.kunavo.com/v1")
def chat(question: str, history: list[dict]) -> dict:
chunks = hybrid_retrieve(question, k=5) # vector + BM25
context = "\n\n---\n\n".join(
f"[doc:{c['id']}] {c['text']}" for c in chunks
)
resp = client.chat.completions.create(
model="claude-sonnet-5",
messages=[
{"role": "system", "content": [{
"type": "text",
"text": (
"Answer only from Context. Cite [doc:N] for each claim. "
"If Context doesn't answer, say 'I don't have that.' "
"Be concise, no throat-clearing."
),
"cache_control": {"type": "ephemeral"},
}]},
*history,
{"role": "user", "content": f"# Context\n{context}\n\n# Q\n{question}"},
],
max_tokens=600,
)
answer = resp.choices[0].message.content
cited_ids = parse_citations(answer) # extract [doc:N] references
return {"answer": answer, "sources": [c for c in chunks if c["id"] in cited_ids]}Costo su scala di produzione
- Indicizzazione iniziale: circa $0,25 per 5.000 documenti da 500 token ciascuno
- 1.000 query/giorno: circa $210/mese con caching
- 10.000 query/giorno: circa $2.100/mese
- Se usi Haiku 4.5 invece di Sonnet: circa 4 volte più economico, circa 85% della qualità delle risposte
Analisi architetturale completa nella guida all'implementazione RAG. Note sull'ottimizzazione specifica per lingua nel deep dive sul RAG giapponese e nella guida al RAG spagnolo.
I tre schemi che prevengono davvero le allucinazioni
- Cita ogni affermazione: tag
[doc:42]nell'output del modello. Se l'id citato non è nel set recuperato, il modello ha allucinato — blocca e registra - Rifiuto esplicito nel prompt di sistema: «Se il Contesto non risponde, dì “Non ne ho informazioni.”» Senza questa istruzione, il modello completa usando la conoscenza generale
- Limite di output di 600 token: le risposte brevi sono di solito più accurate. È negli output più lunghi che si insinuano invenzioni aggiuntive
Cosa distribuire nella settimana 1 e nella settimana 4
| Settimana | Traguardo |
|---|---|
| 1 | 100 documenti, un'unica strategia di chunking, ricerca vettoriale di base, set di valutazione da 10 domande, recall@5 di circa il 70% |
| 2 | Corpus completo, retrieval ibrido, set di valutazione da 100 domande, citazioni obbligatorie, beta interna |
| 3 | Ottimizza il chunking sulla base delle domande fallite, distribuisci agli utenti interni, misura il CSAT |
| 4 | Monitoraggio e dashboard dei costi, limite di spesa giornaliero, beta pubblica o lancio in produzione |
Inizia da /app/signup
Una ricarica da $10 copre l'indicizzazione iniziale di circa 100.000 documenti e 1.500 query di test — più che sufficiente per un prototipo funzionale, e il saldo non scade mai. Poi leggi la guida RAG completa per gli schemi di produzione.
FAQ
Quanto costa una query in un chatbot RAG?
Circa $0,007 per query con Claude Sonnet 4.6 e prompt caching attivo, oppure circa $0,001 con Claude Haiku 4.5, che offre all’incirca l’85% della qualità a un settimo del costo.
Come posso impedire a un chatbot RAG di generare allucinazioni?
Tre accorgimenti risolvono la maggior parte del problema: richiedi al modello di citare un ID [doc:N] per ogni affermazione, inserisci un’istruzione esplicita di rifiuto nel prompt di sistema e limita la risposta con max_tokens=600. Quindi, prima di mostrarla, verifica che ogni ID citato sia presente nel set recuperato.
Quale dimensione dovrebbero avere i segmenti di un indice RAG?
Da 1.000 a 1.500 caratteri per segmento, con una sovrapposizione di 100-200 caratteri; suddividi con RecursiveCharacterTextSplitter e crea embeddings con text-embedding-3-large.
La ricerca vettoriale da sola è sufficiente per il recupero RAG?
No. Il recupero ibrido combina la similarità vettoriale con la ricerca per parole chiave BM25, unisce i risultati con reciprocal rank fusion e seleziona i 5 segmenti migliori.