fix(local-llm): web_search local-only — Claude behaelt seine staerkeren Web-Tools

web_search war versehentlich in META_TOOLS -> Claude bekam es zusaetzlich zu
seinen nativen WebSearch/WebFetch/Bash (redundant/verwirrend). Jetzt als
WEB_SEARCH_TOOL nur im lokalen Tool-Set (_build_local_tools). Claude nutzt
weiter seine eigene Suche + Voll-Seiten-WebFetch (wichtig fuer Pentest/Research);
SearXNG ist fuer das lokale Tier, das sonst keinen Netzzugriff haette.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 12:53:03 +02:00
co-authored by Claude Opus 4.8
parent 3cd7350160
commit c3652d2f8e
+34 -28
View File
@@ -101,6 +101,33 @@ def _web_search(query: str, max_results: int = 5) -> str:
return "\n".join(lines)
# web_search ist bewusst LOCAL-ONLY (nicht in META_TOOLS): Claude hat seine
# eigenen, staerkeren Web-Tools (WebSearch + WebFetch/Voll-Seiten-lesen + Bash).
# SearXNG ist fuer das lokale Tier, das sonst gar keinen Netz-Zugriff haette.
# _dispatch_tool behandelt "web_search" trotzdem generisch (Name-Match).
WEB_SEARCH_TOOL = {
"type": "function",
"function": {
"name": "web_search",
"description": (
"Durchsuche das Web (via SearXNG) nach AKTUELLEN, nachschlagbaren "
"Infos: Wetter, News, Fakten, Oeffnungszeiten, Preise, Definitionen. "
"Nutze das, wenn die Antwort aktuelles Wissen braucht, das nicht im "
"Gedaechtnis steht. Praezise Suchanfrage (Suchmaschinen-Stil). "
"Ergebnis = Titel + Snippet + URL; fasse daraus knapp zusammen."
),
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Suchanfrage (praezise)"},
"max_results": {"type": "integer", "description": "Anzahl Treffer (Default 5, max 10)"},
},
"required": ["query"],
},
},
}
# Meta-Tool: ARIA kann selbst neue Skills bauen
META_TOOLS = [
{
@@ -846,29 +873,6 @@ META_TOOLS = [
},
},
},
{
"type": "function",
"function": {
"name": "web_search",
"description": (
"Durchsuche das Web (via SearXNG) nach AKTUELLEN, nachschlagbaren "
"Infos: Wetter, News, Fakten, Oeffnungszeiten, Preise, Definitionen "
"usw. Nutze das immer, wenn die Antwort aktuelles Wissen braucht, "
"das weder im Gedaechtnis noch in deinem Training steht (oder "
"veraltet sein koennte). Gib eine praezise Suchanfrage wie bei "
"Google. Ergebnis = Titel + Snippet + URL der Top-Treffer; fasse "
"daraus knapp die Antwort zusammen und nenne bei Bedarf die Quelle."
),
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Suchanfrage (praezise, Suchmaschinen-Stil)"},
"max_results": {"type": "integer", "description": "Anzahl Treffer (Default 5, max 10)"},
},
"required": ["query"],
},
},
},
# ── Projekte (Stefan-Konzept: Threads im Hauptchat verankert) ──
{
"type": "function",
@@ -1124,13 +1128,15 @@ class Agent:
_LOCAL_WINDOW_TURNS = 8 # nur die letzten N Turns ans lokale Modell (Speed)
_LOCAL_TOOL_ITERATIONS = 3 # max Tool-Runden lokal, sonst → Claude
# Kuratierte Tool-Auswahl fuers lokale Tier (B1b). Namen aus META_TOOLS +
# der Spotify-Skill. Bewusst klein (Speed + Sicherheit); alles andere → Claude.
_LOCAL_TOOL_NAMES = {"web_search", "memory_search", "trigger_timer"}
# Kuratierte Tool-Auswahl fuers lokale Tier (B1b): web_search (local-only,
# SearXNG) + memory_search/trigger_timer (aus META_TOOLS) + Spotify-Skill.
# Bewusst klein (Speed + Sicherheit); alles andere → Claude.
_LOCAL_TOOL_NAMES = {"memory_search", "trigger_timer"}
def _build_local_tools(self) -> list:
tools = [t for t in META_TOOLS
if t.get("function", {}).get("name") in self._LOCAL_TOOL_NAMES]
tools = [WEB_SEARCH_TOOL]
tools += [t for t in META_TOOLS
if t.get("function", {}).get("name") in self._LOCAL_TOOL_NAMES]
for s in skills_mod.list_skills(active_only=False):
if s.get("name") == "spotify" and s.get("active", True):
tools.append(_skill_to_tool(s))