Progetti
LangChainPythonFastAPIpgvectorOpenAIDocker

Pipeline RAG + Agenti LLM per automazione documenti aziendali

Il problema di partenza: un'azienda con centinaia di documenti interni (policy, manuali, contratti, report) e zero capacità di interrogarli in modo strutturato. La ricerca per parola chiave non funziona su testi lunghi e non cattura il significato. Il sistema doveva rispondere a domande in linguaggio naturale, citare le fonti e non inventarsi nulla.

Architettura

Il sistema è diviso in tre blocchi distinti: ingestion, retrieval e inference.

Ingestion pipeline

I documenti entrano nel sistema attraverso una pipeline di preprocessing che gestisce PDF, DOCX e testo plain. Ogni documento viene:

  1. Estratto e pulito (rimozione header/footer, normalizzazione encoding)
  2. Suddiviso in chunk con overlap configurabile (512 token, overlap 64)
  3. Embeddato con text-embedding-ada-002 di OpenAI
  4. Salvato in PostgreSQL con estensione pgvector

Il chunking con overlap è critico: senza di esso, una risposta che attraversa il confine tra due chunk viene tagliata e il contesto si perde.

Ingestion pipeline: da documento grezzo a vettori indicizzati in pgvector

Retrieval con reranking

La query dell'utente viene embeddatat e confrontata con i vettori in pgvector tramite cosine similarity. I top-20 risultati vengono poi passati a un reranker cross-encoder (BGE-reranker-base) che riduce il set a 5 chunk con il punteggio di rilevanza più alto.

Il reranking risolve un problema reale: i modelli di embedding bi-encoder sono veloci ma imprecisi sul ranking. Il cross-encoder è lento ma sa effettivamente confrontare query e chunk insieme. Usarli in sequenza bilancia velocità e qualità.

Agenti LLM

Sopra il retrieval è stato costruito un layer di agenti con LangChain. L'agente principale ha accesso a tre tool:

  • document_search: interroga pgvector con la query riformulata
  • calculator: per domande che richiedono calcoli su dati estratti
  • date_context: inietta la data corrente per domande temporali

L'agente decide autonomamente quale tool usare, in quale ordine, e quando ha abbastanza contesto per rispondere. Il prompt di sistema vincola il modello a citare le fonti e a rispondere "non so" quando il contesto non è sufficiente.

Flusso agente: da query a risposta con tool use e citazione fonti

API e deployment

L'interfaccia è una REST API FastAPI con:

  • Endpoint /query (POST): riceve la domanda, restituisce risposta + fonti + latenza
  • Endpoint /ingest (POST): accetta file, avvia la pipeline asincrona
  • Autenticazione Bearer token
  • Rate limiting per tenant
  • Logging strutturato su ogni chiamata (latenza, token usati, chunk recuperati)

Il tutto containerizzato con Docker Compose: un container FastAPI, uno PostgreSQL+pgvector, uno per il worker asincrono (Celery + Redis).

Risultati

  • Latenza media per query: 1.8s (embedding + retrieval + inference)
  • Accuracy su un test set di 50 domande interne: 87% di risposte corrette con fonte citata
  • Hallucination rate: <5% (misurato manualmente su campione)
  • Zero risposte inventate su domande fuori dominio — il sistema risponde correttamente "non trovato"