feat: web_search Tool via SearXNG ergaenzen
Issue #35 vervollstaendigt mit schneller Web-Suche (3-10s): - neues Tool web_search in tools/web_search.py - SearXNG Endpoint CT121 (intern + Tailscale Fallback) - strukturierte Treffer mit Snippets + Quellenlinks - Prompt-Hinweis fuer Routing: web_search vs deep_research
This commit is contained in:
parent
f54833c150
commit
6ef208c289
1 changed files with 99 additions and 0 deletions
99
homelab-ai-bot/tools/web_search.py
Normal file
99
homelab-ai-bot/tools/web_search.py
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
"""Web-Suche Tool via SearXNG (CT 121)."""
|
||||
|
||||
import requests
|
||||
|
||||
SEARXNG_URLS = [
|
||||
"http://10.10.10.121:8080",
|
||||
"http://100.74.196.29:8080",
|
||||
]
|
||||
|
||||
TOOLS = [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "web_search",
|
||||
"description": "Schnelle Web-Suche (3-10 Sekunden) ueber SearXNG. Nutze fuer aktuelle Fakten, Preise, News und einfache Web-Fragen.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "Suchanfrage, moeglichst konkret."
|
||||
},
|
||||
"max_results": {
|
||||
"type": "integer",
|
||||
"description": "Anzahl Ergebnisse (1-8)",
|
||||
"default": 5
|
||||
}
|
||||
},
|
||||
"required": ["query"]
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
SYSTEM_PROMPT_EXTRA = """WEB-SUCHE:
|
||||
Du hast das Tool web_search fuer schnelle Web-Recherche (3-10s).
|
||||
Nutze web_search bei aktuellen Fakten, Preisen, News, Vergleichen mit wenigen Quellen.
|
||||
Nutze deep_research nur bei komplexen Themen, die einen langen Report brauchen (2-5 Min).
|
||||
Wenn web_search genug ist: antworte mit kurzer Zusammenfassung + 2-5 Quellen."""
|
||||
|
||||
|
||||
def _search_once(base_url: str, query: str):
|
||||
r = requests.get(
|
||||
f"{base_url}/search",
|
||||
params={"q": query, "format": "json"},
|
||||
timeout=10,
|
||||
)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
|
||||
def handle_web_search(query: str, max_results: int = 5, **kw):
|
||||
if not query or not query.strip():
|
||||
return "web_search: query fehlt."
|
||||
|
||||
max_results = max(1, min(int(max_results or 5), 8))
|
||||
|
||||
last_err = None
|
||||
data = None
|
||||
used_url = None
|
||||
for base in SEARXNG_URLS:
|
||||
try:
|
||||
data = _search_once(base, query.strip())
|
||||
used_url = base
|
||||
break
|
||||
except Exception as e:
|
||||
last_err = e
|
||||
|
||||
if data is None:
|
||||
return f"web_search nicht erreichbar: {last_err}"
|
||||
|
||||
results = data.get("results", [])[:max_results]
|
||||
if not results:
|
||||
return f"Keine Treffer fuer: {query}"
|
||||
|
||||
lines = [
|
||||
f"Web-Suche: {query}",
|
||||
f"Quelle: {used_url}",
|
||||
"",
|
||||
]
|
||||
|
||||
for idx, item in enumerate(results, 1):
|
||||
title = (item.get("title") or "(ohne Titel)").strip()
|
||||
url = (item.get("url") or "").strip()
|
||||
snippet = (item.get("content") or "").strip().replace("\n", " ")
|
||||
if len(snippet) > 220:
|
||||
snippet = snippet[:220] + "..."
|
||||
|
||||
lines.append(f"{idx}. {title}")
|
||||
if snippet:
|
||||
lines.append(f" {snippet}")
|
||||
lines.append(f" {url}")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
HANDLERS = {
|
||||
"web_search": handle_web_search,
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue