Self-hosting
Caucus è progettato per girare per intero sulla tua macchina o nel tuo studio: database, vector store, reranker e, volendo, anche i modelli di linguaggio. Questa pagina porta da zero a uno stack funzionante. Tempo stimato: 10–15 minuti con il pacchetto corpus, qualche ora se ricostruisci il corpus da zero.
Prerequisiti
- Docker (con Docker Compose) per Postgres, Qdrant e Redis;
- uv (gestore Python) e Python 3.12;
- Node.js ≥ 20 e pnpm;
- una chiave OpenAI per la generazione delle risposte (default; backend alternativi: Ollama e modelli locali, vedi Backend LLM). Con il pacchetto corpus non servono chiamate di embedding: paghi solo la generazione, centesimi per centinaia di domande.
- Disco: ~8 GB liberi per il corpus completo (Postgres + Qdrant); 4 GB di RAM per i container sono sufficienti.
1. Clona e configura
git clone https://github.com/gral-digital/caucus && cd caucus cp .env.example .env # apri .env e imposta OPENAI_API_KEY=sk-...
Tutte le opzioni sono variabili d'ambiente documentate in .env.example: backend LLM ed embedding, device del reranker, rate limiting, autenticazione. I default vanno bene per un primo avvio locale.
2. Dipendenze e infrastruttura
make install # dipendenze Python (uv) + Node (pnpm) make up # Postgres :55432, Qdrant :6333, Redis make migrate # schema del database (Alembic)
3. Il corpus: importa il pacchetto (consigliato)
La via rapida è importare il pacchetto corpus pubblicato con le release: contiene le tabelle Postgres già popolate e gli embedding Qdrant già calcolati. Un solo comando, nessuna chiamata API, nessun costo:
make corpus-import SRC=https://github.com/gral-digital/caucus/releases/download/corpus-20260801
Lo script scarica i file (con ripresa automatica se la connessione cade), verifica i checksum SHA-256, controlla che lo schema del database sia alla revisione giusta e ripristina tabelle e collection. Le tabelle utente non vengono toccate. Dettagli su contenuto e licenze del pacchetto: Corpus.
L'alternativa è ricostruire tutto dalle fonti pubbliche (Normattiva, EUR-Lex, SentenzeWeb):
make seed-all # 50 fonti normative + 14 atti UE (~ centesimi di embedding) make harvest-cassazione # giurisprudenza, incrementale e resumabile (ore)
4. Avvia
make dev # API su :8000, web su :3000
Apri http://localhost:3000/app. Al primo avvio il reranker locale (bge-reranker-v2-m3) scarica i pesi e si scalda in qualche secondo; le richieste successive non pagano questo costo.
Backend LLM ed embedding
Il backend di default è OpenAI (gpt-4o per la generazione, gpt-4.1-mini per l'espansione query, text-embedding-3-small per gli embedding). Sono intercambiabili via env:
LLM_BACKEND=ollama: modelli locali via Ollama, per un deployment senza alcuna dipendenza cloud;EMBEDDING_BACKEND=local: embedding self-hosted (BGE-M3); nota che gli embedding del pacchetto corpus sono text-embedding-3-small: cambiando modello di embedding va rifatta l'indicizzazione vettoriale;RERANKER_BACKEND=local(default) conRERANKER_DEVICE=mps|cuda|cpu; in assenza delle dipendenze il sistema degrada a un reranker keyword e lo segnala nei log: le prestazioni misurate valgono solo con il cross-encoder attivo.
La qualità dichiarata nel benchmark è misurata sulla configurazione di riferimento: se cambi modelli, rimisura con make eval prima di fidarti dei numeri.
Autenticazione e multiutenza
In self-hosting l'app è aperta di default (nessuna registrazione: i dati non lasciano la tua macchina). Per esporre l'istanza a più utenti puoi attivare gli account con ACCOUNTS_ENABLED=true: registrazione e login con password (Argon2id), sessioni con token salvato solo come hash, documenti caricati legati all'utente. Per API machine-to-machine c'è il token statico API_AUTH_TOKEN (obbligatorio fuori da APP_ENV=local: il server non parte senza).
Deploy del frontend su Vercel
Il frontend è un'app Next.js standard e si deploya su Vercel così com'è; l'API (FastAPI + Postgres + Qdrant + reranker) gira invece su un server tuo (VPS, Fly.io, Railway…). Configurazione:
- Root Directory:
apps/web(il repo è un monorepo pnpm; Vercel rileva Next e pnpm da solo); - Variabile d'ambiente:
NEXT_PUBLIC_API_URL= URL pubblico della tua API (es.https://api.tuodominio.it). Le rewrite di Next proxano/api/v1/*verso quell'URL, quindi il browser parla solo col dominio del frontend; - lo streaming SSE attraversa il proxy senza buffering: la config Next disattiva già la compressione sulla rotta della chat. Se davanti all'API metti nginx, mantieni le esclusioni descritte sotto in Problemi comuni;
- CORS: passando dal proxy Next non serve aprire l'API ad altre origini; se invece esponi l'API direttamente, configura
CORS_ALLOW_ORIGINScon il dominio Vercel.
Problemi comuni
- Porte occupate: Postgres è mappato su :55432 proprio per non collidere con un Postgres locale; Qdrant usa :6333.
- «reranker_local_deps_missing_fallback_keyword» nei log: manca
sentence-transformersnel venv; rilanciamake install. Con il fallback keyword la qualità del retrieval cala sensibilmente. - Streaming che arriva «a blocchi»: se metti un reverse proxy davanti all'API, disattiva compressione e buffering su
/api/v1/chat(l'API imposta giàX-Accel-Buffering: noeCache-Control: no-transform). - Import corpus rifiutato: il pacchetto dichiara la revisione di schema per cui è stato prodotto: esegui
make migrate(o aggiorna il codice) e riprova.