Costruire un chatbot con Google Gemini su una tua base di conoscenza

Tutorial passo passo, in italiano. Alla fine avrai un assistente che risponde solo con le informazioni dei tuoi documenti, cita le fonti e costa zero (o quasi).

Prova il chatbot di esempio →

1. L'idea: cos'è un RAG

Un modello linguistico non conosce i tuoi documenti. Con il RAG (Retrieval-Augmented Generation) a ogni domanda:

  1. Recuperi i 3-5 pezzi di documento più pertinenti (ricerca);
  2. li incolli nel prompt come "CONTESTO";
  3. chiedi a Gemini di rispondere solo da lì, citando le fonti.

Così non serve addestrare nulla: aggiornare la conoscenza = cambiare un file.

2. Vertex AI Agent Builder o Gemini API?

Vertex AI Agent Builder (Google Cloud)Gemini API + RAG fatto in casa (questo tutorial)
AccountProgetto Google Cloud con fatturazione attivaSolo account Google, chiave da AI Studio
CostoA consumo (ricerca + modello + indice); prova gratuita con creditiFree tier gratuito; a pagamento pochi centesimi
RicercaGestita da Google (Vertex AI Search, datastore)Tua: BM25 in 40 righe, o embedding
Quando sceglierloAziende, molti documenti (PDF, siti, Drive), SLA, dati in UEPrototipi, piccole KB, budget zero, pieno controllo

Il chatbot di esempio usa la seconda via: gratis e funzionante senza carta di credito. La sezione 8 spiega come passare ad Agent Builder.

3. Ottenere la chiave Gemini (gratis)

  1. Vai su aistudio.google.com/apikey e accedi con un account Google.
  2. Clicca Create API key (crea un progetto nuovo se richiesto). Non serve la fatturazione.
  3. Copia la chiave (inizia con AIza…) e mettila solo nel file .env del server:
GEMINI_API_KEY=AIza...la-tua-chiave
GEMINI_MODEL=gemini-2.5-flash
chmod 600 .env        # leggibile solo dal proprietario
echo .env >> .gitignore   # mai su git

4. Preparare la base di conoscenza

Una cartella kb/ con file Markdown. Ogni titolo (#, ##) diventa un "pezzo" (chunk) indicizzato.

kb/
  01-azienda.md      # chi siamo, orari, contatti
  02-spedizioni.md   # costi, tempi, resi
  03-prodotti.md     # catalogo
  04-faq.md          # domande frequenti
Regole d'oro. Un argomento per sezione, titoli parlanti, frasi complete con numeri espliciti ("gratuita sopra i 39 euro"), niente tabelle-immagine. Per i PDF: convertili prima in testo (pdftotext) e ricontrolla.

5. Il server (Python + FastAPI)

Tre pezzi: indice BM25, chiamata a Gemini, limiti anti-abuso. Il cuore:

# ricerca: punteggio BM25 per ogni chunk, prendo i migliori 4
ctx = idx.search(domanda)

SYSTEM = ("Sei l'assistente clienti di Caffè Aurora. Rispondi in italiano, "
          "SOLO con le informazioni nel CONTESTO. Se la risposta non c'è, dillo.")

body = {
  "systemInstruction": {"parts": [{"text": SYSTEM}]},
  "contents": [{"role": "user", "parts": [{"text":
      f"CONTESTO:\n{contesto}\n\nDOMANDA: {domanda}"}]}],
  "generationConfig": {"temperature": 0.2, "maxOutputTokens": 600}
}
url = f"https://generativelanguage.googleapis.com/v1beta/models/{MODEL}:generateContent"
r = httpx.post(url, json=body, headers={"x-goog-api-key": API_KEY})
risposta = r.json()["candidates"][0]["content"]["parts"][0]["text"]

Il file completo (~100 righe) è app/main.py nel progetto. Dettagli utili:

Volendo, ricerca semantica: al posto di BM25 calcola gli embedding di ogni chunk con il modello gemini-embedding-001 (endpoint :embedContent) e confronta con la domanda per similarità del coseno. Trova sinonimi ("consegna" ≈ "spedizione"), ma costa una chiamata in più a domanda.

6. La pagina della chat

Un HTML con un fetch('/api/chat') che manda domanda e ultimi 6 messaggi (per la memoria della conversazione) e mostra risposta e fonti. Usa sempre textContent, mai innerHTML, per non eseguire codice arrivato dal modello.

7. Pubblicare (Docker + Caddy)

# docker-compose.yml
services:
  gemini-agent:
    build: .
    restart: unless-stopped
    env_file: .env
    ports: ["127.0.0.1:8850:8000"]   # solo locale: Docker scavalca il firewall!
    volumes: ["./kb:/app/kb:ro"]
    mem_limit: 256m
# Caddyfile: HTTPS automatico
chatbot.tuodominio.it {
    reverse_proxy 127.0.0.1:8850
}
docker compose up -d --build
curl -s https://chatbot.tuodominio.it/api/health

Prima crea il record DNS A del sottodominio verso l'IP del server, poi ricarica Caddy (systemctl reload caddy).

8. Variante: Vertex AI Agent Builder

  1. Su console.cloud.google.com crea un progetto e attiva la fatturazione (metti subito un budget con avviso, es. 5 €).
  2. Cerca AI Applications (ex Agent Builder / Vertex AI Search) → Create app → tipo Search o Agent.
  3. Crea un data store: carica i documenti su Cloud Storage, o indica un sito o un Drive. Scegli la regione eu se i dati devono restare in Europa.
  4. Attendi l'indicizzazione, prova nella Preview, poi integra con il widget web o con l'API.
Pro: niente codice di ricerca, gestisce PDF e siti. Contro: serve la carta, i costi crescono con le query, più pezzi da configurare (IAM, regioni). Un'alternativa di mezzo è lo strumento File Search della Gemini API, che fa il RAG gestito con la stessa chiave di AI Studio: controlla prezzi e disponibilità nella documentazione.

9. Manutenzione e aggiornamento della base di conoscenza

10. Costi

VoceCosto
Gemini API free tier (Flash)0 € entro i limiti di richieste al minuto e al giorno
Gemini API a pagamento (Flash)pochi centesimi ogni migliaio di domande brevi
Server (VPS già esistente)0 € in più (container da ~60 MB di RAM)
Vertex AI Agent Buildera consumo, con crediti di prova; mettere sempre un budget

I limiti e i prezzi cambiano: verificali su ai.google.dev/gemini-api/docs/pricing. La demo ha un tetto di domande al giorno (DAILY_MAX) e al minuto per IP (RATE_PER_MIN): così non si esce dal gratuito.

Attenzione privacy: con il free tier Google può usare prompt e risposte per migliorare i suoi prodotti. Va bene con dati finti o pubblici; per dati aziendali o personali usa il piano a pagamento o Vertex AI.

11. Sicurezza

12. Errori comuni

SintomoCausa e rimedio
400 API key not validChiave copiata male, con spazi o virgolette nel .env.
404 model not foundNome modello sbagliato o ritirato: aggiorna GEMINI_MODEL.
429 RESOURCE_EXHAUSTEDSuperato il free tier: abbassa i limiti, aspetta, o attiva il piano a pagamento.
Risposte inventateIl contesto non contiene la risposta, o il prompt non dice "solo dal CONTESTO". Abbassa la temperatura.
"Non lo so" a domande ovvieLa ricerca non trova il pezzo: parole diverse tra domanda e documento. Aggiungi sinonimi al testo o passa agli embedding.
Risposta tagliatamaxOutputTokens troppo basso, o i modelli "thinking" consumano token: imposta thinkingBudget: 0.
Sito irraggiungibileManca il record DNS, o Caddy non ricaricato, o container fermo (docker ps).
Chiave nel repoRevocala subito; riscrivere la storia git non basta.

Demo con dati di fantasia ("Caffè Aurora"). Aggiornato a ottobre 2026.