feat(ingestion): supporto multi-documento in unica collection ChromaDB

Aggiunge la possibilità di unire più documenti in una singola collection
ChromaDB, con chunk_id prefissati per stem e metadato source per filtrare.

- ingest.py: --stems doc1 doc2 --collection nome (nuovo), --stem (invariato)
- rag.py / retrieve.py: --collection, source nei chunk, verbose mostra [source]

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-12 11:21:17 +02:00
parent b630316936
commit 606fad9e09
3 changed files with 137 additions and 73 deletions
+24 -15
View File
@@ -101,6 +101,7 @@ def retrieve(collection: chromadb.Collection, question: str) -> list[dict]:
):
chunks.append({
"text": text,
"source": meta.get("source", ""),
"sezione": meta.get("sezione", ""),
"titolo": meta.get("titolo", ""),
"distance": dist,
@@ -143,7 +144,8 @@ def answer(question: str, collection: chromadb.Collection, verbose: bool) -> Non
if c["titolo"]:
loc += f" > {c['titolo']}"
sim = 1 - c["distance"]
print(f" [{i}] {loc} (similarità: {sim:.3f})")
src = f"[{c['source']}] " if c.get("source") else ""
print(f" [{i}] {src}{loc} (similarità: {sim:.3f})")
print(f" {c['text'][:120].replace(chr(10), ' ')}...")
print("──────────────────────────────────────────────────────────────\n")
@@ -215,19 +217,23 @@ def main() -> int:
)
parser.add_argument(
"--stem",
required=True,
help=(
"Nome della collection ChromaDB da interrogare. "
"Le collection vengono create da: python ingestion/ingest.py --stem <nome>"
),
help="Collection di un singolo documento (retrocompatibile)",
)
parser.add_argument(
"--collection",
help="Collection multi-documento creata con: ingest.py --collection <nome> --stems ...",
)
args = parser.parse_args()
collection_name = args.collection or args.stem
if not collection_name:
parser.error("specifica --stem <nome> oppure --collection <nome>")
print("─── Pipeline RAG ────────────────────────────────────────────\n")
print(f" Documento : {args.stem}")
print(f" Modello : {LLM_MODEL}")
print(f" Top-K : {TOP_K}")
print(f" Thinking : {'off' if NO_THINK else 'on'}")
print(f" Collection : {collection_name}")
print(f" Modello : {LLM_MODEL}")
print(f" Top-K : {TOP_K}")
print(f" Thinking : {'off' if NO_THINK else 'on'}")
print()
if not CHROMA_DIR.exists():
@@ -236,13 +242,16 @@ def main() -> int:
client = chromadb.PersistentClient(path=str(CHROMA_DIR))
collections = [c.name for c in client.list_collections()]
if args.stem not in collections:
print(f"❌ Collection '{args.stem}' non trovata in chroma_db/")
print(f" → python ingestion/ingest.py --stem {args.stem}")
if collection_name not in collections:
print(f"❌ Collection '{collection_name}' non trovata in chroma_db/")
if args.stem:
print(f" → python ingestion/ingest.py --stem {collection_name}")
else:
print(f" → python ingestion/ingest.py --collection {collection_name} --stems doc1 doc2 ...")
return 1
collection = client.get_collection(args.stem)
print(f"✅ Collection '{args.stem}' caricata ({collection.count()} chunk)\n")
collection = client.get_collection(collection_name)
print(f"✅ Collection '{collection_name}' caricata ({collection.count()} chunk)\n")
run_loop(collection)
return 0