From 9cc16bb2205be62a7ab877f0eb224d39f1165232 Mon Sep 17 00:00:00 2001 From: Lars Date: Tue, 9 Dec 2025 13:14:24 +0100 Subject: [PATCH] fehlerkorrektzur Hybrid chat --- app/config.py | 14 +++---- app/services/llm_service.py | 79 ++++++------------------------------- 2 files changed, 16 insertions(+), 77 deletions(-) diff --git a/app/config.py b/app/config.py index dbffba1..862e4f9 100644 --- a/app/config.py +++ b/app/config.py @@ -1,12 +1,7 @@ """ -app/config.py — zentrale Konfiguration (ENV → Settings) - -Version: - 0.4.0 (WP-06: Added Decision Engine Config) -Stand: - 2025-12-08 +app/config.py — zentrale Konfiguration +Version: 0.4.0 (WP-06 Complete) """ - from __future__ import annotations import os from functools import lru_cache @@ -27,8 +22,9 @@ class Settings: OLLAMA_URL: str = os.getenv("MINDNET_OLLAMA_URL", "http://127.0.0.1:11434") LLM_MODEL: str = os.getenv("MINDNET_LLM_MODEL", "phi3:mini") PROMPTS_PATH: str = os.getenv("MINDNET_PROMPTS_PATH", "config/prompts.yaml") - - # WP-06 Decision Engine + + # NEU für WP-06 + LLM_TIMEOUT: float = float(os.getenv("MINDNET_LLM_TIMEOUT", "120.0")) DECISION_CONFIG_PATH: str = os.getenv("MINDNET_DECISION_CONFIG", "config/decision_engine.yaml") # API diff --git a/app/services/llm_service.py b/app/services/llm_service.py index 215bd8a..09c591f 100644 --- a/app/services/llm_service.py +++ b/app/services/llm_service.py @@ -1,8 +1,6 @@ """ app/services/llm_service.py — LLM Client (Ollama) - -Version: - 0.2.0 (WP-06 Hybrid Router Support) +Version: 0.2.0 (WP-06 Hybrid Router Support) """ import httpx @@ -26,12 +24,9 @@ class LLMService: ) def _load_prompts(self) -> dict: - """Lädt Prompts aus der konfigurierten YAML-Datei.""" path = Path(self.settings.PROMPTS_PATH) if not path.exists(): - logger.warning(f"Prompt config not found at {path}, using defaults.") return {} - try: with open(path, "r", encoding="utf-8") as f: return yaml.safe_load(f) @@ -41,16 +36,16 @@ class LLMService: async def generate_raw_response(self, prompt: str) -> str: """ - Führt einen direkten LLM Call ohne RAG-Template aus. - Ideal für Classification/Routing. + NEU: Führt einen direkten LLM Call ohne RAG-Template aus. + Wird vom Router für die Antwortgenerierung genutzt. """ payload = { "model": self.settings.LLM_MODEL, "prompt": prompt, "stream": False, "options": { - "temperature": 0.0, # Deterministisch für Routing! - "num_ctx": 512 # Kleines Fenster reicht für Classification + "temperature": 0.0, + "num_ctx": 512 } } @@ -58,76 +53,24 @@ class LLMService: response = await self.client.post("/api/generate", json=payload) if response.status_code != 200: logger.error(f"Ollama Error ({response.status_code}): {response.text}") - return "FACT" # Fallback bei Fehler + return "Fehler bei der Generierung." data = response.json() return data.get("response", "").strip() except Exception as e: logger.error(f"LLM Raw Gen Error: {e}") - return "FACT" + return "Interner LLM Fehler." async def generate_rag_response(self, query: str, context_str: str) -> str: - """ - Generiert eine Antwort basierend auf Query und Kontext (RAG). - """ - # Template hier ist nur Fallback, falls im Router nichts übergeben wird. - # Im Normalfall formatiert der Router den context_str bereits vor oder übergibt das Template. - # Hier nutzen wir simple substitution, da der Prompt meist schon vom Router aufbereitet ist - # oder wir nutzen das Standard-Template aus der YAML. - - # HINWEIS: In der neuen Architektur (chat.py) wird das Template bereits VOR diesem Aufruf - # geladen und formatiert, und als 'prompt' übergeben? - # Nein, chat.py ruft generate_rag_response(query, context_str) auf. - # Wir müssen sicherstellen, dass wir das *richtige* Template nutzen. - # Da generate_rag_response aktuell KEINEN 'template_key' Parameter hat, - # gehen wir davon aus, dass 'context_str' bereits Instruktionen enthält ODER - # dass chat.py den Prompt komplett baut. - - # Um die API sauber zu halten: chat.py übergibt jetzt den FERTIGEN Prompt als context_str? - # Nein, chat.py baut den Prompt mit replace(). - # Wir ändern diese Methode leicht ab, um flexibler zu sein: - # Wir erwarten, dass der Aufrufer (chat.py) die volle Kontrolle hat. - - # Damit es 100% zusammenpasst mit dem chat.py unten: - # chat.py baut den finalen Prompt selbst zusammen! - # Wir nutzen daher generate_raw_response eigentlich auch für RAG, - # ODER wir passen generate_rag_response an, dass es "dumm" ist. - - # Legacy Support für generate_rag_response: - # Wir bauen den Prompt zusammen, falls noch nicht geschehen. - # ABER: chat.py in meiner Version unten macht das Template-Handling. - # Daher ist der sauberste Weg: chat.py ruft generate_raw_response auf für die Antwort! - - # FIX für Kompatibilität: Wir leiten rag_response intern auf raw um, - # bauen aber vorher den Prompt, falls context_str übergeben wird. - - # Da wir chat.py kontrollieren (siehe unten), ändern wir chat.py so, - # dass es generate_raw_response nutzt! Das ist viel sauberer. - # Diese Methode bleibt für Backward Compatibility. - + """Legacy Support / Fallback""" system_prompt = self.prompts.get("system_prompt", "") rag_template = self.prompts.get("rag_template", "{context_str}\n\n{query}") final_prompt = rag_template.format(context_str=context_str, query=query) - payload = { - "model": self.settings.LLM_MODEL, - "system": system_prompt, - "prompt": final_prompt, - "stream": False, - "options": { - "temperature": 0.7, - "num_ctx": 2048 - } - } - - try: - response = await self.client.post("/api/generate", json=payload) - if response.status_code != 200: - return f"Error: {response.text}" - return response.json().get("response", "") - except Exception as e: - return f"Error: {str(e)}" + # Wir nutzen intern nun auch raw_response, um Code zu sparen + full_prompt = f"{system_prompt}\n\n{final_prompt}" + return await self.generate_raw_response(full_prompt) async def close(self): await self.client.aclose() \ No newline at end of file