📘 Tender-RAG-Lab — Hybrid RAG (Classic + Graph RAG) per Gare di Appalto
Sistema avanzato di Retrieval-Augmented Generation (RAG) progettato per supportare l’intero ciclo di vita delle gare di appalto:
- Scouting
- Bid / No-Bid
- Analisi documentale
- Drafting dell’offerta
- Compliance checking
- Q&A avanzata
- Reportistica
Il progetto combina:
- Classic RAG → chunking intelligente, vector search su Milvus, reranking, multi-step retrieval.
- Graph RAG → Knowledge Graph su Neo4j specifico per il dominio appalti (Tender / Lot / Requirement / Deadline / …).
Obiettivo: costruire un sistema robusto, scalabile, production-grade, estendibile nel tempo e valutabile con metriche chiare.
🚦 Roadmap per Fasi
Phase 0 — Domain Understanding & Data Modeling
Obiettivo: capire cosa stai risolvendo (use case), come sono fatti i documenti, e come modellare dati + grafo in modo minimo ma utile.
0.1 Catalogo documentale
Tipi di documento supportati:
bando
disciplinare
capitolato_tecnico
capitolato_amministrativo
qna_ufficiali (chiarimenti)
addenda / rettifiche
allegato_tecnico
allegato_amministrativo
offerta_passata
template_interno
Per ogni tipo: mappare struttura tipica (capitoli/articoli), sezione requisiti, criteri di aggiudicazione, scadenze, penali, ecc.
0.2 Use case prioritari (v1)
Use case che guidano tutte le scelte:
-
UC1 – Requisiti obbligatori per lotto
- “Trova tutti i requisiti obbligatori per il Lotto 2 e dimmi se li soddisfiamo.”
-
UC2 – Compliance checklist
- “Genera una checklist di compliance per questa gara, per il Lotto X.”
-
UC3 – Confronto tra capitolati
- “Riassumi differenze chiave tra il capitolato corrente e quello della gara X-2023.”
-
UC4 – Scadenze & vincoli temporali
- “Elenca tutte le scadenze (Q&A, sopralluogo, presentazione offerta, ecc.).”
-
UC5 – Gare simili
- “Mostrami gare simili a questa dove abbiamo già partecipato.”
0.3 Data Model v0 (documenti + chunk)
Database (SQL / document DB, da adattare al tuo stack).
Tabella: tender_documents
TABLE tender_documents (
id UUID PRIMARY KEY,
source_system TEXT, -- es. "ANAC", "client_portal"
client_id TEXT, -- per multi-tenant in futuro
tender_code TEXT, -- CIG / codice interno
document_type TEXT, -- "bando", "disciplinare", ...
lot_id TEXT NULL, -- se riferito a un lotto specifico
title TEXT,
language TEXT,
publication_date DATE NULL,
url TEXT NULL,
file_path TEXT,
metadata JSONB, -- ente, cpv, categoria, ecc.
created_at TIMESTAMP,
updated_at TIMESTAMP
);
Tabella: chunks
TABLE chunks (
id UUID PRIMARY KEY,
document_id UUID REFERENCES tender_documents(id),
chunk_index INT,
content TEXT,
section_path TEXT, -- es. "Capitolato > Art. 3 > Requisiti tecnici"
page_start INT NULL,
page_end INT NULL,
embedding_id TEXT, -- id verso Milvus oppure campo logico
metadata JSONB, -- lot_id, clause_type, etc.
created_at TIMESTAMP
);
Campi metadata tipici per i chunk:
tender_code
document_type
lot_id
clause_type (es. requisito_tecnico, requisito_economico, scadenza, penale, …)
heading_raw (titolo articolo/paragrafo)
0.4 Knowledge Graph v0 (Neo4j)
Modello minimo ma già utile.
Node types
-
Tender
tender_code, title, publication_date, cpv_code, base_amount, …
-
Lot
lot_id, name, cpv_code, base_amount
-
Requirement
id, type (tecnico/economico/amministrativo), description, mandatory (bool)
-
Deadline
id, type (Q&A, sopralluogo, offerta,…), date, notes
-
Penalty
id, description, amount, type
-
Criterion
id, type (tecnico/economico), weight, description
-
DocumentSection
id, document_id, chunk_id, section_path, page_start, page_end
-
Organization
name, role (ente_appaltante, concorrente, RTI member,…)
Relationships
(Tender)-[:HAS_LOT]->(Lot)
(Lot)-[:HAS_REQUIREMENT]->(Requirement)
(Tender)-[:HAS_DEADLINE]->(Deadline)
(Tender)-[:HAS_CRITERION]->(Criterion)
(Requirement)-[:REFERENCED_IN]->(DocumentSection)
(Deadline)-[:REFERENCED_IN]->(DocumentSection)
(Penalty)-[:REFERENCED_IN]->(DocumentSection)
(Tender)-[:ISSUED_BY]->(Organization)
Phase 1 — Classic RAG Baseline (Milvus + Reranker)
Obiettivo: Classic RAG forte, stabile, con metriche base, prima di introdurre il grafo.
1.1 Ingestion & Preprocessing
Path: src/ingestion/
Componenti:
pdf_parser.py — estrazione testo da PDF (pdfplumber / pymupdf)
word_parser.py — estrazione testo da .docx
ingestion_pipeline.py