diff --git a/app/core/retrieval/decision_engine.py b/app/core/retrieval/decision_engine.py index d6bc373..f8f355a 100644 --- a/app/core/retrieval/decision_engine.py +++ b/app/core/retrieval/decision_engine.py @@ -3,11 +3,12 @@ FILE: app/core/retrieval/decision_engine.py DESCRIPTION: Der Agentic Orchestrator für WP-25. Realisiert Multi-Stream Retrieval, Intent-basiertes Routing und parallele Wissens-Synthese. -VERSION: 1.0.1 +VERSION: 1.0.2 STATUS: Active FIX: -- Behebung eines potenziellen KeyError bei fehlender 'FACT_WHAT' Strategie (Fallback-Resilienz). -- Einführung einer mehrstufigen Sicherheitskaskade für die Strategiewahl. +- WP-25 ROBUSTNESS: Pre-Initialization aller Stream-Variablen zur Vermeidung von KeyErrors. +- Behebung von Template-Mismatches bei unvollständigen Strategie-Definitionen. +- Erhalt der Sicherheitskaskade für die Strategiewahl. """ import asyncio import logging @@ -167,12 +168,20 @@ class DecisionEngine: template = self.llm_service.get_prompt(template_key, provider=provider) system_prompt = self.llm_service.get_prompt("system_prompt", provider=provider) - template_vars = {**stream_results, "query": query} + # WP-25 ROBUSTNESS FIX: + # Wir stellen sicher, dass alle Variablen, die im Template vorkommen könnten, + # zumindest mit einem leeren String initialisiert sind. + all_possible_streams = ["values_stream", "facts_stream", "biography_stream", "risk_stream", "tech_stream"] + template_vars = {s: "" for s in all_possible_streams} + + # Überschreiben mit tatsächlichen Ergebnissen + template_vars.update(stream_results) + template_vars["query"] = query + prepend = strategy.get("prepend_instruction", "") try: # Sicherheitscheck: Sind alle benötigten Platzhalter im Template vorhanden? - # Im Fehlerfall Fallback auf eine einfache Zusammenführung final_prompt = template.format(**template_vars) if prepend: final_prompt = f"{prepend}\n\n{final_prompt}" @@ -197,7 +206,7 @@ class DecisionEngine: except KeyError as e: logger.error(f"Template Variable mismatch in '{template_key}': Missing {e}") # Fallback: Einfaches Aneinanderreihen der gefundenen Stream-Inhalte - fallback_context = "\n\n".join(stream_results.values()) + fallback_context = "\n\n".join([v for v in stream_results.values() if v]) return await self.llm_service.generate_raw_response( f"Beantworte: {query}\n\nKontext:\n{fallback_context}", system=system_prompt, diff --git a/config/decision_engine.yaml b/config/decision_engine.yaml index 4cc61a1..98abd48 100644 --- a/config/decision_engine.yaml +++ b/config/decision_engine.yaml @@ -1,67 +1,53 @@ # config/decision_engine.yaml -# VERSION: 3.1.2 (WP-25: Multi-Stream Agentic RAG) +# VERSION: 3.1.3 (WP-25: Multi-Stream Sync Fix) # STATUS: Active -# DoD: Strikte Trennung von Logik und Instruktion. Prompt in prompts.yaml verschoben. +# DoD: Harmonisierung der Streams mit prompts.yaml zur Vermeidung von KeyErrors. version: 3.1 settings: llm_fallback_enabled: true router_provider: "auto" - # Der Prompt-Key für den Router in prompts.yaml router_prompt_key: "intent_router_v1" -# --- EBENE 1: STREAM-LIBRARY (Bausteine) --- +# --- EBENE 1: STREAM-LIBRARY --- streams_library: values_stream: name: "Identität & Ethik" query_template: "Welche meiner Werte und Prinzipien betreffen: {query}" filter_types: ["value", "principle", "belief"] top_k: 5 - edge_boosts: - guides: 3.0 - enforced_by: 2.5 - based_on: 2.0 + edge_boosts: {guides: 3.0, enforced_by: 2.5, based_on: 2.0} facts_stream: name: "Operative Realität" query_template: "Status, Ressourcen und Fakten zu: {query}" filter_types: ["project", "decision", "resource", "task", "milestone"] top_k: 5 - edge_boosts: - part_of: 2.0 - depends_on: 1.5 - implemented_in: 1.5 + edge_boosts: {part_of: 2.0, depends_on: 1.5, implemented_in: 1.5} biography_stream: name: "Persönliche Erfahrung" query_template: "Welche Erlebnisse habe ich im Kontext von {query} gemacht?" filter_types: ["experience", "journal"] top_k: 3 - edge_boosts: - related_to: 1.5 - experienced_in: 2.0 + edge_boosts: {related_to: 1.5, experienced_in: 2.0} risk_stream: name: "Risiko-Radar" query_template: "Gefahren, Hindernisse oder Risiken bei: {query}" filter_types: ["risk", "obstacle"] top_k: 3 - edge_boosts: - blocks: 2.5 - impacts: 2.0 - risk_of: 2.5 + edge_boosts: {blocks: 2.5, impacts: 2.0, risk_of: 2.5} tech_stream: name: "Technische Referenz" query_template: "Technische Dokumentation und Code-Beispiele für: {query}" filter_types: ["snippet", "reference", "source"] top_k: 5 - edge_boosts: - uses: 2.5 - implemented_in: 3.0 + edge_boosts: {uses: 2.5, implemented_in: 3.0} -# --- EBENE 2: STRATEGIEN (Orchestrierung) --- +# --- EBENE 2: STRATEGIEN --- strategies: FACT_WHEN: description: "Abfrage von Zeitpunkten und Historie." @@ -69,6 +55,7 @@ strategies: use_streams: - "facts_stream" - "biography_stream" + - "tech_stream" # Hinzugefügt für Kompatibilität mit fact_synthesis_v1 prompt_template: "fact_synthesis_v1" FACT_WHAT: @@ -76,11 +63,12 @@ strategies: preferred_provider: "openrouter" use_streams: - "facts_stream" + - "biography_stream" # Hinzugefügt für Kompatibilität mit fact_synthesis_v1 - "tech_stream" prompt_template: "fact_synthesis_v1" DECISION: - description: "Der User sucht Rat, Strategie oder Abwägung." + description: "Rat, Strategie oder Abwägung." preferred_provider: "gemini" use_streams: - "values_stream" @@ -95,7 +83,7 @@ strategies: use_streams: - "biography_stream" - "values_stream" - prompt_template: "empathy_template" + prompt_template: "empathy_template" # Erwartet nur {context_str} oder spezifische Felder CODING: description: "Technische Anfragen und Programmierung."