feat(rag): adatta pipeline allo schema chunks AST-based + ottimizza system prompt

config.py:
- EMBED_MODEL: qwen3-embedding:0.6b → bge-m3 (multilingua, migliore su testi accademici)
- SYSTEM_PROMPT: lingua esplicita, anti-allucinazione rafforzata, citazione strutturata
  con percorso sezione, passaggi numerati per spiegazioni, fallback al plurale

ingestion/ingest.py:
- embed su content_for_embedding (prefisso header contestuale)
- store content_original in ChromaDB (testo pulito per retrieval)
- metadata aggiornati: header_path, chunk_index, content_type, flags, start/end_line

rag.py, retrieve.py:
- sostituisce sezione/titolo (schema vecchio) con header_path (schema AST)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 09:10:35 +02:00
parent 89d77d35d6
commit 2939d2f8ca
4 changed files with 40 additions and 34 deletions
+8 -13
View File
@@ -85,7 +85,7 @@ def call_ollama(prompt: str, system: str = "") -> str:
def retrieve(collection: chromadb.Collection, question: str) -> list[dict]:
"""
Genera l'embedding della domanda e recupera i TOP_K chunk più simili.
Ritorna lista di dict con chiavi: text, sezione, titolo, distance.
Ritorna lista di dict con chiavi: text, source, header_path, distance.
"""
vector = embed(question)
results = collection.query(
@@ -100,11 +100,10 @@ def retrieve(collection: chromadb.Collection, question: str) -> list[dict]:
results["distances"][0],
):
chunks.append({
"text": text,
"source": meta.get("source", ""),
"sezione": meta.get("sezione", ""),
"titolo": meta.get("titolo", ""),
"distance": dist,
"text": text,
"source": meta.get("source", ""),
"header_path": meta.get("header_path", ""),
"distance": dist,
})
return chunks
@@ -116,10 +115,8 @@ def build_prompt(question: str, chunks: list[dict]) -> str:
context_parts = []
for i, c in enumerate(chunks, start=1):
header = f"[Contesto {i}"
if c["sezione"]:
header += f"{c['sezione']}"
if c["titolo"]:
header += f" > {c['titolo']}"
if c["header_path"]:
header += f"{c['header_path']}"
header += "]"
context_parts.append(f"{header}\n{c['text']}")
@@ -140,11 +137,9 @@ def answer(question: str, collection: chromadb.Collection, verbose: bool) -> Non
if verbose:
print("\n── Chunk recuperati ──────────────────────────────────────────")
for i, c in enumerate(chunks, start=1):
loc = c["sezione"]
if c["titolo"]:
loc += f" > {c['titolo']}"
sim = 1 - c["distance"]
src = f"[{c['source']}] " if c.get("source") else ""
loc = c["header_path"] or ""
print(f" [{i}] {src}{loc} (similarità: {sim:.3f})")
print(f" {c['text'][:120].replace(chr(10), ' ')}...")
print("──────────────────────────────────────────────────────────────\n")