rag: bessere Treffer + Anti-Halluzination
- top_k min=5, default=8 (LLM kann nicht mehr top_k=3 setzen) - docnm_kwd boost 1.5→3.0 (Ordner/Dateinamen staerker gewichten) - Ordnerpfad als Kategorie-Info in Ausgabe - Content-Snippet 400→600 Zeichen - SYSTEM_PROMPT_EXTRA: LLM darf keine Details erfinden - es_size erhoehen fuer breitere Suche Ref: Issue #51
This commit is contained in:
parent
0e1c7a6ebb
commit
a43c0b913b
3 changed files with 33 additions and 11 deletions
Binary file not shown.
Binary file not shown.
|
|
@ -20,6 +20,8 @@ KB_ID = "dc24edda27a311f19fe7fb811de6f016"
|
|||
OLLAMA_EMBED_URL = "http://100.84.255.83:11434/api/embeddings"
|
||||
EMBED_MODEL = "nomic-embed-text"
|
||||
|
||||
MIN_TOP_K = 5
|
||||
|
||||
TOOLS = [
|
||||
{
|
||||
"type": "function",
|
||||
|
|
@ -30,7 +32,9 @@ TOOLS = [
|
|||
"Vertraege, Versicherungen, Rente, Finanzamt, Familiendokumente, "
|
||||
"Anleitungen, Buecher, persoenliche Unterlagen). "
|
||||
"Nutze dieses Tool wenn der User nach einem bestimmten Dokument, "
|
||||
"Vertrag, Brief oder persoenlicher Information fragt."
|
||||
"Vertrag, Brief oder persoenlicher Information fragt. "
|
||||
"Bei breiten Fragen ('welche Versicherungen', 'alle Vertraege') "
|
||||
"immer top_k=10 verwenden."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
|
|
@ -44,8 +48,8 @@ TOOLS = [
|
|||
},
|
||||
"top_k": {
|
||||
"type": "integer",
|
||||
"description": "Anzahl Ergebnisse (1-10)",
|
||||
"default": 5,
|
||||
"description": "Anzahl Ergebnisse (5-10, Standard 8)",
|
||||
"default": 8,
|
||||
},
|
||||
},
|
||||
"required": ["query"],
|
||||
|
|
@ -62,7 +66,12 @@ Die Suchanfrage sollte kurze Keywords sein, KEINE ganzen Saetze. Beispiele:
|
|||
- "Grundsteuer Erklaerung"
|
||||
- "Nuernberger Versicherung"
|
||||
- "Allianz Beitraege"
|
||||
Bei schlechten Ergebnissen: andere Keywords versuchen oder Dokumentnamen direkt suchen."""
|
||||
Bei schlechten Ergebnissen: andere Keywords versuchen oder Dokumentnamen direkt suchen.
|
||||
WICHTIG:
|
||||
- Bei breiten Kategorie-Fragen ("welche Versicherungen", "alle Vertraege"): top_k=10
|
||||
- Liste NUR die Dokumente auf die rag_search zurueckliefert. ERFINDE KEINE Details die nicht im Ergebnis stehen.
|
||||
- Der Ordnerpfad im Dokumentnamen (vor dem Dateinamen, getrennt durch __) zeigt die Kategorie.
|
||||
- Wenn das Ergebnis Dokumente zeigt, liste sie auf — auch wenn du den Inhalt nicht vollstaendig kennst."""
|
||||
|
||||
|
||||
def _basic_auth_header() -> str:
|
||||
|
|
@ -104,6 +113,14 @@ def _ocr_note(text: str) -> str:
|
|||
return ""
|
||||
|
||||
|
||||
def _folder_from_docname(name: str) -> str:
|
||||
"""Extrahiert den Ordnerpfad aus docnm_kwd (__ = Trenner)."""
|
||||
parts = name.rsplit("__", 1)
|
||||
if len(parts) == 2:
|
||||
return parts[0].replace("__", " > ").replace("_", " ")
|
||||
return ""
|
||||
|
||||
|
||||
def _es_hybrid_search(query: str, es_size: int) -> dict:
|
||||
qvec = _ollama_embed(query)
|
||||
if not qvec:
|
||||
|
|
@ -125,7 +142,7 @@ def _es_hybrid_search(query: str, es_size: int) -> dict:
|
|||
"should": [
|
||||
{"match": {"content_de": {"query": query, "boost": 2.0}}},
|
||||
{"match": {"content_ltks": {"query": query.lower(), "boost": 0.4}}},
|
||||
{"match": {"docnm_kwd": {"query": query, "boost": 1.5}}},
|
||||
{"match": {"docnm_kwd": {"query": query, "boost": 3.0}}},
|
||||
],
|
||||
"minimum_should_match": 0,
|
||||
}
|
||||
|
|
@ -153,12 +170,12 @@ def _es_hybrid_search(query: str, es_size: int) -> dict:
|
|||
return {"_error": str(e)}
|
||||
|
||||
|
||||
def handle_rag_search(query: str, top_k: int = 5, **kw):
|
||||
def handle_rag_search(query: str, top_k: int = 8, **kw):
|
||||
if not query or not query.strip():
|
||||
return "rag_search: query fehlt."
|
||||
|
||||
top_k = max(1, min(int(top_k or 5), 10))
|
||||
es_size = min(100, max(top_k * 12, 35))
|
||||
top_k = max(MIN_TOP_K, min(int(top_k or 8), 10))
|
||||
es_size = min(120, max(top_k * 12, 50))
|
||||
|
||||
data = _es_hybrid_search(query.strip(), es_size)
|
||||
if "_error" in data:
|
||||
|
|
@ -170,7 +187,7 @@ def handle_rag_search(query: str, top_k: int = 5, **kw):
|
|||
|
||||
seen_docs: set[str] = set()
|
||||
lines: list[str] = []
|
||||
lines.append(f"**{len(hits)} Roh-Treffer fuer '{query}'** (Top {top_k} Dokumente):\n")
|
||||
lines.append(f"**{len(hits)} Treffer fuer '{query}'** (Top {top_k} Dokumente):\n")
|
||||
|
||||
count = 0
|
||||
for h in hits:
|
||||
|
|
@ -185,10 +202,15 @@ def handle_rag_search(query: str, top_k: int = 5, **kw):
|
|||
|
||||
score = h.get("_score") or 0.0
|
||||
raw = src.get("content_with_weight") or src.get("content_de") or ""
|
||||
content = raw[:400].strip()
|
||||
content = raw[:600].strip()
|
||||
ocr = _ocr_note(raw)
|
||||
folder = _folder_from_docname(doc_name)
|
||||
filename = doc_name.rsplit("__", 1)[-1] if "__" in doc_name else doc_name
|
||||
folder_line = f" Ordner: {folder}" if folder else ""
|
||||
|
||||
lines.append(f"---\n**{count + 1}. {doc_name}** (Score: {score:.3f}){ocr}")
|
||||
lines.append(f"---\n**{count + 1}. {filename}** (Score: {score:.1f}){ocr}")
|
||||
if folder_line:
|
||||
lines.append(folder_line)
|
||||
if content:
|
||||
lines.append(f"```\n{content}\n```")
|
||||
count += 1
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue