homelab-brain/homelab-ai-bot/tools/rag.py
2026-03-26 12:30:10 +01:00

119 lines
4 KiB
Python

"""RAG Dokumentensuche - durchsucht die Hausmeister-Wissensbasis (RAGFlow)."""
import json
import urllib.request
import logging
log = logging.getLogger("tools.rag")
RAGFLOW_URL = "http://100.109.101.12:8080/api/v1"
RAGFLOW_TOKEN = "ragflow-test-token-2026"
DATASET_ID = "dc24edda27a311f19fe7fb811de6f016"
TOOLS = [
{
"type": "function",
"function": {
"name": "rag_search",
"description": (
"Durchsucht die private Dokumenten-Wissensbasis (>21.000 Dokumente: "
"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."
),
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Suchanfrage: Dokumentname, Thema oder Inhalt. Kurz und praezise, z.B. 'Familienbuch Opa Oma' oder 'Grundsteuer Erklaerung 2024'"
},
"top_k": {
"type": "integer",
"description": "Anzahl Ergebnisse (1-10)",
"default": 5
}
},
"required": ["query"]
},
},
},
]
SYSTEM_PROMPT_EXTRA = """RAG DOKUMENTENSUCHE:
Du hast Zugriff auf eine private Wissensbasis mit >21.000 Dokumenten (Vertraege, Versicherungen, Rente, Finanzamt, Familiendokumente, Anleitungen, Buecher, persoenliche Unterlagen).
Nutze rag_search wenn der User nach Dokumenten, Vertraegen, persoenlichen Unterlagen oder Informationen aus seinen Dateien fragt.
Die Suchanfrage sollte kurze Keywords sein, KEINE ganzen Saetze. Beispiele:
- "Familienbuch Opa Oma"
- "Grundsteuer Erklaerung"
- "Nürnberger Versicherung"
- "Allianz Beitraege"
Bei schlechten Ergebnissen: andere Keywords versuchen oder Dokumentnamen direkt suchen."""
def _api_call(path, method="GET", body=None):
url = f"{RAGFLOW_URL}{path}"
data = json.dumps(body).encode("utf-8") if body else None
req = urllib.request.Request(
url, data=data,
headers={
"Authorization": f"Bearer {RAGFLOW_TOKEN}",
"Content-Type": "application/json",
},
method=method,
)
with urllib.request.urlopen(req, timeout=30) as resp:
return json.loads(resp.read())
def handle_rag_search(query: str, top_k: int = 5, **kw):
if not query or not query.strip():
return "rag_search: query fehlt."
top_k = max(1, min(int(top_k or 5), 10))
try:
result = _api_call("/retrieval", method="POST", body={
"question": query,
"dataset_ids": [DATASET_ID],
"top_k": 2048,
"similarity_threshold": 0.1,
"vector_similarity_weight": 0.3,
})
chunks = result.get("data", {}).get("chunks", [])
if not chunks:
return f"Keine Ergebnisse fuer '{query}' in der Wissensbasis gefunden."
seen_docs = set()
lines = [f"**{len(chunks)} Treffer fuer '{query}'** (Top {top_k}):\n"]
count = 0
for c in chunks:
if count >= top_k:
break
doc_name = c.get("document_keyword", c.get("document_name", "?"))
sim = c.get("similarity", 0)
content = c.get("content", "")[:400].strip()
doc_key = doc_name
if doc_key in seen_docs:
continue
seen_docs.add(doc_key)
lines.append(f"---\n**{count+1}. {doc_name}** (Relevanz: {sim:.0%})")
if content:
lines.append(f"```\n{content}\n```")
count += 1
return "\n".join(lines)
except Exception as e:
log.error("RAG search error: %s", e)
return f"Fehler bei der Dokumentensuche: {e}"
HANDLERS = {
"rag_search": handle_rag_search,
}