WP15 #9
|
|
@ -1,6 +1,6 @@
|
||||||
"""
|
"""
|
||||||
app/routers/chat.py — RAG Endpunkt (WP-06 Hybrid Router + WP-07 Interview Mode)
|
app/routers/chat.py — RAG Endpunkt (WP-06 Hybrid Router + WP-07 Interview Mode)
|
||||||
Version: 2.4.0 (Interview Support)
|
Version: 2.4.1 (Fix: Type-based Intent Detection)
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
- Hybrid Intent Router (Keyword + LLM)
|
- Hybrid Intent Router (Keyword + LLM)
|
||||||
|
|
@ -8,14 +8,16 @@ Features:
|
||||||
- Interview Loop (Schema-driven Data Collection)
|
- Interview Loop (Schema-driven Data Collection)
|
||||||
- Context Enrichment (Payload/Source Fallback)
|
- Context Enrichment (Payload/Source Fallback)
|
||||||
- Data Flywheel (Feedback Logging Integration)
|
- Data Flywheel (Feedback Logging Integration)
|
||||||
|
- NEU: Lädt detection_keywords aus types.yaml für präzise Erkennung.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from fastapi import APIRouter, HTTPException, Depends
|
from fastapi import APIRouter, HTTPException, Depends
|
||||||
from typing import List, Dict, Any
|
from typing import List, Dict, Any, Optional
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
import logging
|
import logging
|
||||||
import yaml
|
import yaml
|
||||||
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from app.config import get_settings
|
from app.config import get_settings
|
||||||
|
|
@ -30,6 +32,7 @@ logger = logging.getLogger(__name__)
|
||||||
# --- Helper: Config Loader ---
|
# --- Helper: Config Loader ---
|
||||||
|
|
||||||
_DECISION_CONFIG_CACHE = None
|
_DECISION_CONFIG_CACHE = None
|
||||||
|
_TYPES_CONFIG_CACHE = None
|
||||||
|
|
||||||
def _load_decision_config() -> Dict[str, Any]:
|
def _load_decision_config() -> Dict[str, Any]:
|
||||||
settings = get_settings()
|
settings = get_settings()
|
||||||
|
|
@ -51,15 +54,32 @@ def _load_decision_config() -> Dict[str, Any]:
|
||||||
logger.error(f"Failed to load decision config: {e}")
|
logger.error(f"Failed to load decision config: {e}")
|
||||||
return default_config
|
return default_config
|
||||||
|
|
||||||
|
def _load_types_config() -> Dict[str, Any]:
|
||||||
|
"""Lädt die types.yaml für Keyword-Erkennung."""
|
||||||
|
path = os.getenv("MINDNET_TYPES_FILE", "config/types.yaml")
|
||||||
|
try:
|
||||||
|
with open(path, "r", encoding="utf-8") as f:
|
||||||
|
return yaml.safe_load(f) or {}
|
||||||
|
except Exception:
|
||||||
|
return {}
|
||||||
|
|
||||||
def get_full_config() -> Dict[str, Any]:
|
def get_full_config() -> Dict[str, Any]:
|
||||||
global _DECISION_CONFIG_CACHE
|
global _DECISION_CONFIG_CACHE
|
||||||
if _DECISION_CONFIG_CACHE is None:
|
if _DECISION_CONFIG_CACHE is None:
|
||||||
_DECISION_CONFIG_CACHE = _load_decision_config()
|
_DECISION_CONFIG_CACHE = _load_decision_config()
|
||||||
return _DECISION_CONFIG_CACHE
|
return _DECISION_CONFIG_CACHE
|
||||||
|
|
||||||
|
def get_types_config() -> Dict[str, Any]:
|
||||||
|
global _TYPES_CONFIG_CACHE
|
||||||
|
if _TYPES_CONFIG_CACHE is None:
|
||||||
|
_TYPES_CONFIG_CACHE = _load_types_config()
|
||||||
|
return _TYPES_CONFIG_CACHE
|
||||||
|
|
||||||
def get_decision_strategy(intent: str) -> Dict[str, Any]:
|
def get_decision_strategy(intent: str) -> Dict[str, Any]:
|
||||||
config = get_full_config()
|
config = get_full_config()
|
||||||
strategies = config.get("strategies", {})
|
strategies = config.get("strategies", {})
|
||||||
|
# Fallback: Wenn Intent INTERVIEW ist, aber nicht konfiguriert, nehme FACT
|
||||||
|
# (Aber INTERVIEW sollte in decision_engine.yaml stehen!)
|
||||||
return strategies.get(intent, strategies.get("FACT", {}))
|
return strategies.get(intent, strategies.get("FACT", {}))
|
||||||
|
|
||||||
# --- Helper: Target Type Detection (WP-07) ---
|
# --- Helper: Target Type Detection (WP-07) ---
|
||||||
|
|
@ -67,39 +87,39 @@ def get_decision_strategy(intent: str) -> Dict[str, Any]:
|
||||||
def _detect_target_type(message: str, configured_schemas: Dict[str, Any]) -> str:
|
def _detect_target_type(message: str, configured_schemas: Dict[str, Any]) -> str:
|
||||||
"""
|
"""
|
||||||
Versucht zu erraten, welchen Notiz-Typ der User erstellen will.
|
Versucht zu erraten, welchen Notiz-Typ der User erstellen will.
|
||||||
Nutzt Keywords und Mappings.
|
Nutzt Keywords aus types.yaml UND Mappings.
|
||||||
"""
|
"""
|
||||||
message_lower = message.lower()
|
message_lower = message.lower()
|
||||||
|
|
||||||
# 1. Direkter Match mit Schema-Keys (z.B. "projekt", "entscheidung")
|
# 1. Check types.yaml detection_keywords (Priority!)
|
||||||
# Ignoriere 'default' hier
|
types_cfg = get_types_config()
|
||||||
|
types_def = types_cfg.get("types", {})
|
||||||
|
|
||||||
|
for type_name, type_data in types_def.items():
|
||||||
|
keywords = type_data.get("detection_keywords", [])
|
||||||
|
for kw in keywords:
|
||||||
|
if kw.lower() in message_lower:
|
||||||
|
return type_name
|
||||||
|
|
||||||
|
# 2. Direkter Match mit Schema-Keys
|
||||||
for type_key in configured_schemas.keys():
|
for type_key in configured_schemas.keys():
|
||||||
if type_key == "default":
|
if type_key == "default": continue
|
||||||
continue
|
|
||||||
if type_key in message_lower:
|
if type_key in message_lower:
|
||||||
return type_key
|
return type_key
|
||||||
|
|
||||||
# 2. Synonym-Mapping (Deutsch -> Schema Key)
|
# 3. Synonym-Mapping (Legacy Fallback)
|
||||||
# Dies verbessert die UX, falls User deutsche Begriffe nutzen
|
|
||||||
synonyms = {
|
synonyms = {
|
||||||
"projekt": "project",
|
"projekt": "project", "vorhaben": "project",
|
||||||
"vorhaben": "project",
|
"entscheidung": "decision", "beschluss": "decision",
|
||||||
"entscheidung": "decision",
|
|
||||||
"beschluss": "decision",
|
|
||||||
"ziel": "goal",
|
"ziel": "goal",
|
||||||
"erfahrung": "experience",
|
"erfahrung": "experience", "lektion": "experience",
|
||||||
"lektion": "experience",
|
|
||||||
"wert": "value",
|
"wert": "value",
|
||||||
"prinzip": "principle",
|
"prinzip": "principle",
|
||||||
"grundsatz": "principle",
|
"notiz": "default", "idee": "default"
|
||||||
"notiz": "default",
|
|
||||||
"idee": "default"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for term, schema_key in synonyms.items():
|
for term, schema_key in synonyms.items():
|
||||||
if term in message_lower:
|
if term in message_lower:
|
||||||
# Prüfen, ob der gemappte Key auch konfiguriert ist
|
|
||||||
if schema_key in configured_schemas:
|
|
||||||
return schema_key
|
return schema_key
|
||||||
|
|
||||||
return "default"
|
return "default"
|
||||||
|
|
@ -126,7 +146,6 @@ def _build_enriched_context(hits: List[QueryHit]) -> str:
|
||||||
)
|
)
|
||||||
title = hit.note_id or "Unbekannt"
|
title = hit.note_id or "Unbekannt"
|
||||||
|
|
||||||
# [FIX] Robustes Auslesen des Typs (Payload > Source > Unknown)
|
|
||||||
payload = hit.payload or {}
|
payload = hit.payload or {}
|
||||||
note_type = payload.get("type") or source.get("type", "unknown")
|
note_type = payload.get("type") or source.get("type", "unknown")
|
||||||
note_type = str(note_type).upper()
|
note_type = str(note_type).upper()
|
||||||
|
|
@ -142,52 +161,58 @@ def _build_enriched_context(hits: List[QueryHit]) -> str:
|
||||||
|
|
||||||
async def _classify_intent(query: str, llm: LLMService) -> tuple[str, str]:
|
async def _classify_intent(query: str, llm: LLMService) -> tuple[str, str]:
|
||||||
"""
|
"""
|
||||||
Hybrid Router v3:
|
Hybrid Router v4:
|
||||||
Gibt Tuple zurück: (Intent, Source)
|
1. Decision Keywords (Strategie)
|
||||||
|
2. Type Keywords (Interview Trigger)
|
||||||
|
3. LLM (Fallback)
|
||||||
"""
|
"""
|
||||||
config = get_full_config()
|
config = get_full_config()
|
||||||
strategies = config.get("strategies", {})
|
strategies = config.get("strategies", {})
|
||||||
settings = config.get("settings", {})
|
settings = config.get("settings", {})
|
||||||
|
|
||||||
query_lower = query.lower()
|
query_lower = query.lower()
|
||||||
best_intent = None
|
|
||||||
max_match_length = 0
|
|
||||||
|
|
||||||
# 1. FAST PATH: Keywords
|
# 1. FAST PATH A: Strategie Keywords (z.B. "Soll ich...")
|
||||||
for intent_name, strategy in strategies.items():
|
for intent_name, strategy in strategies.items():
|
||||||
if intent_name == "FACT": continue
|
if intent_name == "FACT": continue
|
||||||
keywords = strategy.get("trigger_keywords", [])
|
keywords = strategy.get("trigger_keywords", [])
|
||||||
for k in keywords:
|
for k in keywords:
|
||||||
if k.lower() in query_lower:
|
if k.lower() in query_lower:
|
||||||
if len(k) > max_match_length:
|
return intent_name, "Keyword (Strategy)"
|
||||||
max_match_length = len(k)
|
|
||||||
best_intent = intent_name
|
|
||||||
|
|
||||||
if best_intent:
|
# 2. FAST PATH B: Type Keywords (z.B. "Projekt", "passiert") -> INTERVIEW
|
||||||
return best_intent, "Keyword (Fast Path)"
|
# Wir prüfen, ob ein Typ erkannt wird. Wenn ja -> Interview.
|
||||||
|
# Wir laden Schemas nicht hier, sondern nutzen types.yaml global
|
||||||
|
types_cfg = get_types_config()
|
||||||
|
types_def = types_cfg.get("types", {})
|
||||||
|
|
||||||
# 2. SLOW PATH: LLM Router
|
for type_name, type_data in types_def.items():
|
||||||
|
keywords = type_data.get("detection_keywords", [])
|
||||||
|
for kw in keywords:
|
||||||
|
if kw.lower() in query_lower:
|
||||||
|
return "INTERVIEW", f"Keyword (Type: {type_name})"
|
||||||
|
|
||||||
|
# 3. SLOW PATH: LLM Router
|
||||||
if settings.get("llm_fallback_enabled", False):
|
if settings.get("llm_fallback_enabled", False):
|
||||||
router_prompt_template = settings.get("llm_router_prompt", "")
|
router_prompt_template = settings.get("llm_router_prompt", "")
|
||||||
if router_prompt_template:
|
if router_prompt_template:
|
||||||
prompt = router_prompt_template.replace("{query}", query)
|
prompt = router_prompt_template.replace("{query}", query)
|
||||||
logger.info("Keywords failed. Asking LLM for Intent...")
|
logger.info("Keywords failed. Asking LLM for Intent...")
|
||||||
|
|
||||||
|
try:
|
||||||
raw_response = await llm.generate_raw_response(prompt)
|
raw_response = await llm.generate_raw_response(prompt)
|
||||||
|
|
||||||
# Parsing logic
|
|
||||||
llm_output_upper = raw_response.upper()
|
llm_output_upper = raw_response.upper()
|
||||||
found_intents = []
|
|
||||||
|
# Zuerst INTERVIEW prüfen (LLMs erkennen oft "Create" Intention)
|
||||||
|
if "INTERVIEW" in llm_output_upper or "CREATE" in llm_output_upper:
|
||||||
|
return "INTERVIEW", "LLM Router"
|
||||||
|
|
||||||
for strat_key in strategies.keys():
|
for strat_key in strategies.keys():
|
||||||
if strat_key in llm_output_upper:
|
if strat_key in llm_output_upper:
|
||||||
found_intents.append(strat_key)
|
return strat_key, "LLM Router"
|
||||||
|
|
||||||
if len(found_intents) == 1:
|
except Exception as e:
|
||||||
return found_intents[0], "LLM Router (Slow Path)"
|
logger.error(f"Router LLM failed: {e}")
|
||||||
elif len(found_intents) > 1:
|
|
||||||
return found_intents[0], f"LLM Ambiguous {found_intents}"
|
|
||||||
else:
|
|
||||||
return "FACT", "LLM Fallback (No Match)"
|
|
||||||
|
|
||||||
return "FACT", "Default (No Match)"
|
return "FACT", "Default (No Match)"
|
||||||
|
|
||||||
|
|
@ -202,7 +227,7 @@ async def chat_endpoint(
|
||||||
logger.info(f"Chat request [{query_id}]: {request.message[:50]}...")
|
logger.info(f"Chat request [{query_id}]: {request.message[:50]}...")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 1. Intent Detection (mit Source)
|
# 1. Intent Detection
|
||||||
intent, intent_source = await _classify_intent(request.message, llm)
|
intent, intent_source = await _classify_intent(request.message, llm)
|
||||||
logger.info(f"[{query_id}] Final Intent: {intent} via {intent_source}")
|
logger.info(f"[{query_id}] Final Intent: {intent} via {intent_source}")
|
||||||
|
|
||||||
|
|
@ -210,57 +235,55 @@ async def chat_endpoint(
|
||||||
strategy = get_decision_strategy(intent)
|
strategy = get_decision_strategy(intent)
|
||||||
prompt_key = strategy.get("prompt_template", "rag_template")
|
prompt_key = strategy.get("prompt_template", "rag_template")
|
||||||
|
|
||||||
# --- SPLIT LOGIC: INTERVIEW vs. RAG ---
|
|
||||||
|
|
||||||
sources_hits = []
|
sources_hits = []
|
||||||
final_prompt = ""
|
final_prompt = ""
|
||||||
|
|
||||||
if intent == "INTERVIEW":
|
if intent == "INTERVIEW":
|
||||||
# --- WP-07: INTERVIEW MODE ---
|
# --- INTERVIEW MODE ---
|
||||||
# Kein Retrieval. Wir nutzen den Dialog-Kontext.
|
# Wir müssen jetzt herausfinden, WELCHES Schema wir nutzen.
|
||||||
|
# Dazu schauen wir wieder in die types.yaml (via _detect_target_type)
|
||||||
|
|
||||||
# 1. Schema Loading (Late Binding)
|
# Schemas aus decision_engine.yaml laden (falls dort overrides sind)
|
||||||
schemas = strategy.get("schemas", {})
|
# oder generisch aus types.yaml bauen (besser!)
|
||||||
target_type = _detect_target_type(request.message, schemas)
|
|
||||||
active_schema = schemas.get(target_type, schemas.get("default"))
|
|
||||||
|
|
||||||
logger.info(f"[{query_id}] Starting Interview for Type: {target_type}")
|
# Strategie: Wir nutzen _detect_target_type, das jetzt types.yaml kennt.
|
||||||
|
target_type = _detect_target_type(request.message, strategy.get("schemas", {}))
|
||||||
|
|
||||||
# Robustes Schema-Parsing (Dict vs List)
|
# Schema laden (aus types.yaml bevorzugt)
|
||||||
if isinstance(active_schema, dict):
|
types_cfg = get_types_config()
|
||||||
fields_list = active_schema.get("fields", [])
|
type_def = types_cfg.get("types", {}).get(target_type, {})
|
||||||
hint_str = active_schema.get("hint", "")
|
|
||||||
|
# Hole Schema-Felder aus types.yaml (schema: [...])
|
||||||
|
fields_list = type_def.get("schema", [])
|
||||||
|
|
||||||
|
# Fallback auf decision_engine.yaml, falls in types.yaml nichts steht
|
||||||
|
if not fields_list:
|
||||||
|
configured_schemas = strategy.get("schemas", {})
|
||||||
|
fallback_schema = configured_schemas.get(target_type, configured_schemas.get("default"))
|
||||||
|
if isinstance(fallback_schema, dict):
|
||||||
|
fields_list = fallback_schema.get("fields", [])
|
||||||
else:
|
else:
|
||||||
fields_list = active_schema # Fallback falls nur Liste definiert
|
fields_list = fallback_schema or []
|
||||||
hint_str = ""
|
|
||||||
|
logger.info(f"[{query_id}] Interview Type: {target_type}. Fields: {len(fields_list)}")
|
||||||
|
|
||||||
fields_str = "\n- " + "\n- ".join(fields_list)
|
fields_str = "\n- " + "\n- ".join(fields_list)
|
||||||
|
|
||||||
# 2. Context Logic
|
# Prompt Assembly
|
||||||
# Hinweis: In einer Stateless-API ist {context_str} idealerweise die History.
|
|
||||||
# Da ChatRequest (noch) kein History-Feld hat, nutzen wir einen Placeholder
|
|
||||||
# oder verlassen uns darauf, dass der Client die History im Prompt mitschickt
|
|
||||||
# (Streamlit Pattern: Appends history to prompt).
|
|
||||||
# Wir labeln es hier explizit.
|
|
||||||
context_str = "Bisheriger Verlauf (falls vorhanden): Siehe oben/unten."
|
|
||||||
|
|
||||||
# 3. Prompt Assembly
|
|
||||||
template = llm.prompts.get(prompt_key, "")
|
template = llm.prompts.get(prompt_key, "")
|
||||||
final_prompt = template.replace("{context_str}", context_str) \
|
final_prompt = template.replace("{context_str}", "Dialogverlauf...") \
|
||||||
.replace("{query}", request.message) \
|
.replace("{query}", request.message) \
|
||||||
.replace("{target_type}", target_type) \
|
.replace("{target_type}", target_type) \
|
||||||
.replace("{schema_fields}", fields_str) \
|
.replace("{schema_fields}", fields_str) \
|
||||||
.replace("{schema_hint}", hint_str)
|
.replace("{schema_hint}", "")
|
||||||
|
|
||||||
# Keine Hits im Interview
|
|
||||||
sources_hits = []
|
sources_hits = []
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# --- WP-06: STANDARD RAG MODE ---
|
# --- RAG MODE ---
|
||||||
inject_types = strategy.get("inject_types", [])
|
inject_types = strategy.get("inject_types", [])
|
||||||
prepend_instr = strategy.get("prepend_instruction", "")
|
prepend_instr = strategy.get("prepend_instruction", "")
|
||||||
|
|
||||||
# 2. Primary Retrieval
|
|
||||||
query_req = QueryRequest(
|
query_req = QueryRequest(
|
||||||
query=request.message,
|
query=request.message,
|
||||||
mode="hybrid",
|
mode="hybrid",
|
||||||
|
|
@ -270,9 +293,7 @@ async def chat_endpoint(
|
||||||
retrieve_result = await retriever.search(query_req)
|
retrieve_result = await retriever.search(query_req)
|
||||||
hits = retrieve_result.results
|
hits = retrieve_result.results
|
||||||
|
|
||||||
# 3. Strategic Retrieval (WP-06 Kernfeature)
|
|
||||||
if inject_types:
|
if inject_types:
|
||||||
logger.info(f"[{query_id}] Executing Strategic Retrieval for types: {inject_types}...")
|
|
||||||
strategy_req = QueryRequest(
|
strategy_req = QueryRequest(
|
||||||
query=request.message,
|
query=request.message,
|
||||||
mode="hybrid",
|
mode="hybrid",
|
||||||
|
|
@ -281,19 +302,16 @@ async def chat_endpoint(
|
||||||
explain=False
|
explain=False
|
||||||
)
|
)
|
||||||
strategy_result = await retriever.search(strategy_req)
|
strategy_result = await retriever.search(strategy_req)
|
||||||
|
|
||||||
existing_ids = {h.node_id for h in hits}
|
existing_ids = {h.node_id for h in hits}
|
||||||
for strat_hit in strategy_result.results:
|
for strat_hit in strategy_result.results:
|
||||||
if strat_hit.node_id not in existing_ids:
|
if strat_hit.node_id not in existing_ids:
|
||||||
hits.append(strat_hit)
|
hits.append(strat_hit)
|
||||||
|
|
||||||
# 4. Context Building
|
|
||||||
if not hits:
|
if not hits:
|
||||||
context_str = "Keine relevanten Notizen gefunden."
|
context_str = "Keine relevanten Notizen gefunden."
|
||||||
else:
|
else:
|
||||||
context_str = _build_enriched_context(hits)
|
context_str = _build_enriched_context(hits)
|
||||||
|
|
||||||
# 5. Generation Setup
|
|
||||||
template = llm.prompts.get(prompt_key, "{context_str}\n\n{query}")
|
template = llm.prompts.get(prompt_key, "{context_str}\n\n{query}")
|
||||||
|
|
||||||
if prepend_instr:
|
if prepend_instr:
|
||||||
|
|
@ -302,35 +320,25 @@ async def chat_endpoint(
|
||||||
final_prompt = template.replace("{context_str}", context_str).replace("{query}", request.message)
|
final_prompt = template.replace("{context_str}", context_str).replace("{query}", request.message)
|
||||||
sources_hits = hits
|
sources_hits = hits
|
||||||
|
|
||||||
# --- COMMON GENERATION ---
|
# --- GENERATION ---
|
||||||
|
|
||||||
system_prompt = llm.prompts.get("system_prompt", "")
|
system_prompt = llm.prompts.get("system_prompt", "")
|
||||||
|
|
||||||
logger.info(f"[{query_id}] Sending to LLM (Intent: {intent}, Template: {prompt_key})...")
|
# Hier nutzen wir das erhöhte Timeout aus dem LLMService Update
|
||||||
|
|
||||||
# System-Prompt separat übergeben
|
|
||||||
answer_text = await llm.generate_raw_response(prompt=final_prompt, system=system_prompt)
|
answer_text = await llm.generate_raw_response(prompt=final_prompt, system=system_prompt)
|
||||||
|
|
||||||
duration_ms = int((time.time() - start_time) * 1000)
|
duration_ms = int((time.time() - start_time) * 1000)
|
||||||
|
|
||||||
# 6. Logging (Fire & Forget)
|
# Logging
|
||||||
try:
|
try:
|
||||||
log_search(
|
log_search(
|
||||||
query_id=query_id,
|
query_id=query_id,
|
||||||
query_text=request.message,
|
query_text=request.message,
|
||||||
results=sources_hits,
|
results=sources_hits,
|
||||||
mode="interview" if intent == "INTERVIEW" else "chat_rag",
|
mode="interview" if intent == "INTERVIEW" else "chat_rag",
|
||||||
metadata={
|
metadata={"intent": intent, "source": intent_source}
|
||||||
"intent": intent,
|
|
||||||
"intent_source": intent_source,
|
|
||||||
"generated_answer": answer_text,
|
|
||||||
"model": llm.settings.LLM_MODEL
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except: pass
|
||||||
logger.error(f"Logging failed: {e}")
|
|
||||||
|
|
||||||
# 7. Response
|
|
||||||
return ChatResponse(
|
return ChatResponse(
|
||||||
query_id=query_id,
|
query_id=query_id,
|
||||||
answer=answer_text,
|
answer=answer_text,
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,31 @@
|
||||||
# config/decision_engine.yaml
|
# config/decision_engine.yaml
|
||||||
# Steuerung der Decision Engine (WP-06 + WP-07)
|
# Steuerung der Decision Engine (Intent Recognition)
|
||||||
# Hybrid-Modus: Keywords (Fast) + LLM Router (Smart Fallback)
|
# Version: 2.4.0 (Clean Architecture: Generic Intents only)
|
||||||
version: 1.3
|
|
||||||
|
version: 1.4
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
llm_fallback_enabled: true
|
llm_fallback_enabled: true
|
||||||
|
|
||||||
# Few-Shot Prompting für bessere SLM-Performance
|
# Few-Shot Prompting für den LLM-Router (Slow Path)
|
||||||
# Erweitert um INTERVIEW Beispiele
|
|
||||||
llm_router_prompt: |
|
llm_router_prompt: |
|
||||||
Du bist ein Klassifikator. Analysiere die Nachricht und wähle die passende Strategie.
|
Du bist ein Klassifikator. Analysiere die Nachricht und wähle die passende Strategie.
|
||||||
Antworte NUR mit dem Namen der Strategie.
|
Antworte NUR mit dem Namen der Strategie.
|
||||||
|
|
||||||
STRATEGIEN:
|
STRATEGIEN:
|
||||||
- INTERVIEW: User will Wissen strukturieren, Notizen anlegen, Projekte starten ("Neu", "Festhalten").
|
- INTERVIEW: User will Wissen erfassen, Notizen anlegen oder Dinge festhalten.
|
||||||
- DECISION: Rat, Strategie, Vor/Nachteile, "Soll ich".
|
- DECISION: Rat, Strategie, Vor/Nachteile, "Soll ich".
|
||||||
- EMPATHY: Gefühle, Frust, Freude, Probleme, "Alles ist sinnlos", "Ich bin traurig".
|
- EMPATHY: Gefühle, Frust, Freude, Probleme.
|
||||||
- CODING: Code, Syntax, Programmierung, Python.
|
- CODING: Code, Syntax, Programmierung.
|
||||||
- FACT: Wissen, Fakten, Definitionen.
|
- FACT: Wissen, Fakten, Definitionen.
|
||||||
|
|
||||||
BEISPIELE:
|
BEISPIELE:
|
||||||
User: "Wie funktioniert Qdrant?" -> FACT
|
User: "Wie funktioniert Qdrant?" -> FACT
|
||||||
User: "Soll ich Qdrant nutzen?" -> DECISION
|
User: "Soll ich Qdrant nutzen?" -> DECISION
|
||||||
User: "Ich möchte ein neues Projekt anlegen" -> INTERVIEW
|
User: "Ich möchte etwas notieren" -> INTERVIEW
|
||||||
User: "Lass uns eine Entscheidung festhalten" -> INTERVIEW
|
User: "Lass uns das festhalten" -> INTERVIEW
|
||||||
User: "Schreibe ein Python Script" -> CODING
|
User: "Schreibe ein Python Script" -> CODING
|
||||||
User: "Alles ist grau und sinnlos" -> EMPATHY
|
User: "Alles ist grau und sinnlos" -> EMPATHY
|
||||||
User: "Mir geht es heute gut" -> EMPATHY
|
|
||||||
|
|
||||||
NACHRICHT: "{query}"
|
NACHRICHT: "{query}"
|
||||||
|
|
||||||
|
|
@ -51,11 +50,9 @@ strategies:
|
||||||
- "empfehlung"
|
- "empfehlung"
|
||||||
- "strategie"
|
- "strategie"
|
||||||
- "entscheidung"
|
- "entscheidung"
|
||||||
- "wert"
|
|
||||||
- "prinzip"
|
|
||||||
- "vor- und nachteile"
|
|
||||||
- "abwägung"
|
- "abwägung"
|
||||||
inject_types: ["value", "principle", "goal"]
|
- "vergleich"
|
||||||
|
inject_types: ["value", "principle", "goal", "risk"]
|
||||||
prompt_template: "decision_template"
|
prompt_template: "decision_template"
|
||||||
prepend_instruction: |
|
prepend_instruction: |
|
||||||
!!! ENTSCHEIDUNGS-MODUS !!!
|
!!! ENTSCHEIDUNGS-MODUS !!!
|
||||||
|
|
@ -72,6 +69,7 @@ strategies:
|
||||||
- "angst"
|
- "angst"
|
||||||
- "nervt"
|
- "nervt"
|
||||||
- "überfordert"
|
- "überfordert"
|
||||||
|
- "müde"
|
||||||
inject_types: ["experience", "belief", "profile"]
|
inject_types: ["experience", "belief", "profile"]
|
||||||
prompt_template: "empathy_template"
|
prompt_template: "empathy_template"
|
||||||
prepend_instruction: null
|
prepend_instruction: null
|
||||||
|
|
@ -88,56 +86,37 @@ strategies:
|
||||||
- "syntax"
|
- "syntax"
|
||||||
- "json"
|
- "json"
|
||||||
- "yaml"
|
- "yaml"
|
||||||
|
- "bash"
|
||||||
inject_types: ["snippet", "reference", "source"]
|
inject_types: ["snippet", "reference", "source"]
|
||||||
prompt_template: "technical_template"
|
prompt_template: "technical_template"
|
||||||
prepend_instruction: null
|
prepend_instruction: null
|
||||||
|
|
||||||
# 5. Interview / Datenerfassung (WP-07)
|
# 5. Interview / Datenerfassung
|
||||||
|
# HINWEIS: Spezifische Typen (Projekt, Ziel etc.) werden automatisch
|
||||||
|
# über die types.yaml erkannt. Hier stehen nur generische Trigger.
|
||||||
INTERVIEW:
|
INTERVIEW:
|
||||||
description: "Der User möchte strukturiertes Wissen erfassen (Projekt, Notiz, Idee)."
|
description: "Der User möchte Wissen erfassen."
|
||||||
trigger_keywords:
|
trigger_keywords:
|
||||||
- "neue notiz"
|
- "neue notiz"
|
||||||
- "neues projekt"
|
- "etwas notieren"
|
||||||
- "neue entscheidung"
|
|
||||||
- "neues ziel"
|
|
||||||
- "festhalten"
|
- "festhalten"
|
||||||
- "entwurf erstellen"
|
- "erstellen"
|
||||||
- "interview"
|
|
||||||
- "dokumentieren"
|
- "dokumentieren"
|
||||||
|
- "anlegen"
|
||||||
|
- "interview"
|
||||||
- "erfassen"
|
- "erfassen"
|
||||||
- "idee speichern"
|
- "idee speichern"
|
||||||
inject_types: [] # Keine RAG-Suche, reiner Kontext-Dialog
|
- "draft"
|
||||||
|
inject_types: []
|
||||||
prompt_template: "interview_template"
|
prompt_template: "interview_template"
|
||||||
prepend_instruction: null
|
prepend_instruction: null
|
||||||
|
|
||||||
# LATE BINDING SCHEMAS:
|
# Schemas: Hier nur der Fallback.
|
||||||
# Definition der Pflichtfelder pro Typ (korrespondiert mit types.yaml)
|
# Spezifische Schemas (Project, Experience) kommen jetzt aus types.yaml!
|
||||||
# Wenn ein Typ hier fehlt, wird 'default' genutzt.
|
|
||||||
schemas:
|
schemas:
|
||||||
default:
|
default:
|
||||||
fields: ["Titel", "Thema/Inhalt", "Tags"]
|
fields:
|
||||||
|
- "Titel"
|
||||||
|
- "Thema/Inhalt"
|
||||||
|
- "Tags"
|
||||||
hint: "Halte es einfach und übersichtlich."
|
hint: "Halte es einfach und übersichtlich."
|
||||||
|
|
||||||
project:
|
|
||||||
fields: ["Titel", "Zielsetzung (Goal)", "Status (draft/active)", "Wichtige Stakeholder", "Nächste Schritte"]
|
|
||||||
hint: "Achte darauf, Abhängigkeiten zu anderen Projekten mit [[rel:depends_on]] zu erfragen."
|
|
||||||
|
|
||||||
decision:
|
|
||||||
fields: ["Titel", "Kontext (Warum entscheiden wir?)", "Getroffene Entscheidung", "Betrachtete Alternativen", "Status (proposed/final)"]
|
|
||||||
hint: "Wichtig: Frage explizit nach den Gründen gegen die Alternativen."
|
|
||||||
|
|
||||||
goal:
|
|
||||||
fields: ["Titel", "Zeitrahmen (Deadline)", "Messkriterien (KPIs)", "Verbundene Werte"]
|
|
||||||
hint: "Ziele sollten SMART formuliert sein."
|
|
||||||
|
|
||||||
experience:
|
|
||||||
fields: ["Titel", "Situation (Kontext)", "Erkenntnis (Learning)", "Emotionale Keywords (für Empathie-Suche)"]
|
|
||||||
hint: "Fokussiere dich auf die persönliche Lektion."
|
|
||||||
|
|
||||||
value:
|
|
||||||
fields: ["Titel (Name des Werts)", "Definition (Was bedeutet das für uns?)", "Anti-Beispiel (Was ist es nicht?)"]
|
|
||||||
hint: "Werte dienen als Entscheidungsgrundlage."
|
|
||||||
|
|
||||||
principle:
|
|
||||||
fields: ["Titel", "Handlungsanweisung", "Begründung"]
|
|
||||||
hint: "Prinzipien sind härter als Werte."
|
|
||||||
|
|
@ -99,44 +99,37 @@ technical_template: |
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
interview_template: |
|
interview_template: |
|
||||||
TASK:
|
TASK:
|
||||||
Erstelle einen Markdown-Entwurf für eine Notiz vom Typ '{target_type}'.
|
Du bist ein professioneller Ghostwriter. Verwandle den "USER INPUT" in eine strukturierte Notiz vom Typ '{target_type}'.
|
||||||
|
|
||||||
SCHEMA (Inhaltliche Pflichtfelder für den Body):
|
STRUKTUR (Nutze EXAKT diese Überschriften):
|
||||||
{schema_fields}
|
{schema_fields}
|
||||||
|
|
||||||
USER INPUT:
|
USER INPUT:
|
||||||
"{query}"
|
"{query}"
|
||||||
|
|
||||||
ANWEISUNG:
|
ANWEISUNG ZUM INHALT:
|
||||||
1. Extrahiere Informationen aus dem Input.
|
1. Analysiere den Input genau.
|
||||||
2. Generiere validen Markdown.
|
2. Schreibe die Inhalte unter die passenden Überschriften aus der STRUKTUR-Liste oben.
|
||||||
|
3. STIL: Schreibe flüssig, professionell und in der Ich-Perspektive. Korrigiere Grammatikfehler, aber behalte den persönlichen Ton bei.
|
||||||
|
4. Wenn Informationen für einen Abschnitt fehlen, schreibe nur: "[TODO: Ergänzen]". Erfinde nichts dazu.
|
||||||
|
|
||||||
OUTPUT REGELN (STRIKT BEACHTEN):
|
OUTPUT FORMAT (YAML + MARKDOWN):
|
||||||
A. FRONTMATTER (YAML):
|
|
||||||
- 'type': Muss '{target_type}' sein (oder 'experience', 'project' etc.). NIEMALS 'draft'.
|
|
||||||
- 'status': Muss IMMER 'draft' sein.
|
|
||||||
- 'tags': Eine JSON-Liste von Strings OHNE Hashtags. Beispiel: ['Recycling', 'Konflikt']. NICHT: [#Recycling].
|
|
||||||
- Keine Sätze im YAML, nur Daten.
|
|
||||||
|
|
||||||
B. BODY (Markdown):
|
|
||||||
- Nutze für jedes Schema-Feld eine Markdown-Überschrift (## Feldname).
|
|
||||||
- Schreibe den Inhalt DARUNTER.
|
|
||||||
|
|
||||||
HINWEIS ZUM TYP:
|
|
||||||
{schema_hint}
|
|
||||||
|
|
||||||
OUTPUT FORMAT BEISPIEL:
|
|
||||||
```markdown
|
|
||||||
---
|
---
|
||||||
type: {target_type}
|
type: {target_type}
|
||||||
status: draft
|
status: draft
|
||||||
title: ...
|
title: (Erstelle einen treffenden, kurzen Titel für den Inhalt)
|
||||||
tags: ["Tag1", "Tag2"]
|
tags: [Tag1, Tag2]
|
||||||
---
|
---
|
||||||
# Titel der Notiz
|
|
||||||
|
|
||||||
## Erstes Schema Feld
|
# (Wiederhole den Titel hier)
|
||||||
Der Inhalt hier...
|
|
||||||
|
## (Erster Begriff aus STRUKTUR)
|
||||||
|
(Text...)
|
||||||
|
|
||||||
|
## (Zweiter Begriff aus STRUKTUR)
|
||||||
|
(Text...)
|
||||||
|
|
||||||
|
(usw.)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
version: 1.6 # Balance zwischen Speed, Kontext und Smartness
|
version: 2.4.0 # Optimized for Async Intelligence & Hybrid Router
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# 1. CHUNKING PROFILES
|
# 1. CHUNKING PROFILES
|
||||||
|
|
@ -6,42 +6,40 @@ version: 1.6 # Balance zwischen Speed, Kontext und Smartness
|
||||||
|
|
||||||
chunking_profiles:
|
chunking_profiles:
|
||||||
|
|
||||||
# A. SHORT & FAST (Für atomare Schnipsel)
|
# A. SHORT & FAST
|
||||||
# Einsatz: Glossar, Tasks, Risiken
|
# Für Glossar, Tasks, Risiken. Kleine Schnipsel.
|
||||||
# Vorteil: Präzise Treffer für kurze Infos.
|
|
||||||
sliding_short:
|
sliding_short:
|
||||||
strategy: sliding_window
|
strategy: sliding_window
|
||||||
enable_smart_edge_allocation: false # AUS (Speed)
|
enable_smart_edge_allocation: false
|
||||||
target: 200
|
target: 200
|
||||||
max: 350
|
max: 350
|
||||||
overlap: [30, 50]
|
overlap: [30, 50]
|
||||||
|
|
||||||
# B. STANDARD & FAST (Der neue "Mittelweg")
|
# B. STANDARD & FAST
|
||||||
# Einsatz: Quellen, Journal, Daily Logs
|
# Der "Traktor": Robust für Quellen, Journal, Daily Logs.
|
||||||
# Vorteil: Viel Kontext für RAG, aber rasendschneller Import ohne LLM.
|
|
||||||
sliding_standard:
|
sliding_standard:
|
||||||
strategy: sliding_window
|
strategy: sliding_window
|
||||||
enable_smart_edge_allocation: false # AUS (Speed)
|
enable_smart_edge_allocation: false
|
||||||
target: 450 # Größerer Kontext!
|
target: 450
|
||||||
max: 650
|
max: 650
|
||||||
overlap: [50, 100]
|
overlap: [50, 100]
|
||||||
|
|
||||||
# C. SMART FLOW (Premium Chunking)
|
# C. SMART FLOW (Performance-Safe Mode)
|
||||||
# Einsatz: Konzepte, Projekte, Erfahrungen
|
# Für Konzepte, Projekte, Erfahrungen.
|
||||||
# Vorteil: LLM prüft Inhalt und verlinkt präzise. Kostet Zeit.
|
# HINWEIS: 'enable_smart_edge_allocation' ist vorerst FALSE, um Ollama
|
||||||
|
# bei der Generierung nicht zu überlasten. Später wieder aktivieren.
|
||||||
sliding_smart_edges:
|
sliding_smart_edges:
|
||||||
strategy: sliding_window
|
strategy: sliding_window
|
||||||
enable_smart_edge_allocation: true # AN (Intelligenz)
|
enable_smart_edge_allocation: false
|
||||||
target: 400
|
target: 400
|
||||||
max: 600
|
max: 600
|
||||||
overlap: [50, 80]
|
overlap: [50, 80]
|
||||||
|
|
||||||
# D. SMART STRUCTURE
|
# D. SMART STRUCTURE
|
||||||
# Einsatz: Profile, Werte, Prinzipien
|
# Für Profile, Werte, Prinzipien. Trennt hart an Überschriften (H2).
|
||||||
# Vorteil: Respektiert die Markdown-Struktur (H2).
|
|
||||||
structured_smart_edges:
|
structured_smart_edges:
|
||||||
strategy: by_heading
|
strategy: by_heading
|
||||||
enable_smart_edge_allocation: true # AN (Intelligenz)
|
enable_smart_edge_allocation: false
|
||||||
split_level: 2
|
split_level: 2
|
||||||
max: 600
|
max: 600
|
||||||
target: 400
|
target: 400
|
||||||
|
|
@ -52,7 +50,7 @@ chunking_profiles:
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
defaults:
|
defaults:
|
||||||
retriever_weight: 1.0
|
retriever_weight: 1.0
|
||||||
chunking_profile: sliding_standard # Fallback auf Standard (sicher & performant)
|
chunking_profile: sliding_standard
|
||||||
edge_defaults: []
|
edge_defaults: []
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|
@ -61,53 +59,110 @@ defaults:
|
||||||
|
|
||||||
types:
|
types:
|
||||||
|
|
||||||
# --- MASSENDATEN (Speed + Kontext) ---
|
# --- KERNTYPEN (Hoch priorisiert & Smart) ---
|
||||||
|
|
||||||
source:
|
experience:
|
||||||
chunking_profile: sliding_standard # JETZT: Mehr Kontext (450 Token), trotzdem schnell
|
chunking_profile: sliding_smart_edges
|
||||||
retriever_weight: 0.50
|
retriever_weight: 0.90
|
||||||
edge_defaults: []
|
edge_defaults: ["derived_from", "references"]
|
||||||
|
# Hybrid Classifier: Wenn diese Worte fallen, ist es eine Experience
|
||||||
|
detection_keywords:
|
||||||
|
- "passiert"
|
||||||
|
- "erlebt"
|
||||||
|
- "gefühl"
|
||||||
|
- "situation"
|
||||||
|
- "stolz"
|
||||||
|
- "geärgert"
|
||||||
|
- "reaktion"
|
||||||
|
- "moment"
|
||||||
|
- "konflikt"
|
||||||
|
# Ghostwriter Schema: Sprechende Anweisungen für besseren Textfluss
|
||||||
schema:
|
schema:
|
||||||
- "Metadaten (Autor, URL, Datum)"
|
- "Situation (Was ist passiert?)"
|
||||||
- "Zusammenfassung"
|
- "Meine Reaktion (Was habe ich getan?)"
|
||||||
- "Originaltext / Ausschnitte"
|
- "Ergebnis & Auswirkung"
|
||||||
|
- "Reflexion & Learning (Was lerne ich daraus?)"
|
||||||
|
|
||||||
journal:
|
project:
|
||||||
chunking_profile: sliding_standard # JETZT: Mehr Kontext für Tagebucheinträge
|
chunking_profile: sliding_smart_edges
|
||||||
retriever_weight: 0.80
|
retriever_weight: 0.97
|
||||||
edge_defaults: ["references", "related_to"]
|
edge_defaults: ["references", "depends_on"]
|
||||||
|
detection_keywords:
|
||||||
|
- "projekt"
|
||||||
|
- "vorhaben"
|
||||||
|
- "ziel ist"
|
||||||
|
- "meilenstein"
|
||||||
|
- "planen"
|
||||||
|
- "starten"
|
||||||
|
- "mission"
|
||||||
schema:
|
schema:
|
||||||
- "Tages-Log"
|
- "Mission & Zielsetzung"
|
||||||
- "Erkenntnisse"
|
- "Aktueller Status & Blockaden"
|
||||||
- "Entscheidungen"
|
- "Nächste konkrete Schritte"
|
||||||
|
- "Stakeholder & Ressourcen"
|
||||||
|
|
||||||
# --- ATOMARE DATEN (Speed + Präzision) ---
|
decision:
|
||||||
|
chunking_profile: structured_smart_edges
|
||||||
|
retriever_weight: 1.00 # MAX: Entscheidungen sind Gesetz
|
||||||
|
edge_defaults: ["caused_by", "references"]
|
||||||
|
detection_keywords:
|
||||||
|
- "entschieden"
|
||||||
|
- "wahl"
|
||||||
|
- "optionen"
|
||||||
|
- "alternativen"
|
||||||
|
- "beschluss"
|
||||||
|
- "adr"
|
||||||
|
schema:
|
||||||
|
- "Kontext & Problemstellung"
|
||||||
|
- "Betrachtete Optionen (Alternativen)"
|
||||||
|
- "Die Entscheidung"
|
||||||
|
- "Begründung (Warum diese Wahl?)"
|
||||||
|
|
||||||
task:
|
# --- PERSÖNLICHKEIT & IDENTITÄT ---
|
||||||
chunking_profile: sliding_short # Kurz halten
|
|
||||||
retriever_weight: 0.80
|
|
||||||
edge_defaults: ["depends_on", "part_of"]
|
|
||||||
schema: ["Aufgabe", "Kontext", "DoD"]
|
|
||||||
|
|
||||||
glossary:
|
value:
|
||||||
chunking_profile: sliding_short # Kurz halten
|
chunking_profile: structured_smart_edges
|
||||||
retriever_weight: 0.40
|
retriever_weight: 1.00
|
||||||
edge_defaults: ["related_to"]
|
edge_defaults: ["related_to"]
|
||||||
schema: ["Begriff", "Definition"]
|
detection_keywords: ["wert", "wichtig ist", "moral", "ethik"]
|
||||||
|
schema: ["Definition", "Warum mir das wichtig ist", "Leitsätze für den Alltag"]
|
||||||
|
|
||||||
risk:
|
principle:
|
||||||
chunking_profile: sliding_short
|
chunking_profile: structured_smart_edges
|
||||||
retriever_weight: 0.85
|
retriever_weight: 0.95
|
||||||
edge_defaults: ["related_to", "blocks"]
|
edge_defaults: ["derived_from", "references"]
|
||||||
schema: ["Beschreibung", "Mitigation"]
|
detection_keywords: ["prinzip", "regel", "grundsatz", "leitlinie"]
|
||||||
|
schema: ["Das Prinzip", "Anwendung & Beispiele"]
|
||||||
|
|
||||||
belief:
|
belief:
|
||||||
chunking_profile: sliding_short
|
chunking_profile: sliding_short
|
||||||
retriever_weight: 0.90
|
retriever_weight: 0.90
|
||||||
edge_defaults: ["related_to"]
|
edge_defaults: ["related_to"]
|
||||||
schema: ["Glaubenssatz", "Reflexion"]
|
detection_keywords: ["glaube", "überzeugung", "denke dass", "meinung"]
|
||||||
|
schema: ["Der Glaubenssatz", "Ursprung & Reflexion"]
|
||||||
|
|
||||||
# --- KERN-WISSEN (Smart Edges / LLM Active) ---
|
profile:
|
||||||
|
chunking_profile: structured_smart_edges
|
||||||
|
retriever_weight: 0.70
|
||||||
|
edge_defaults: ["references", "related_to"]
|
||||||
|
schema: ["Rolle / Identität", "Fakten & Daten", "Historie"]
|
||||||
|
|
||||||
|
# --- STRATEGIE & RISIKO ---
|
||||||
|
|
||||||
|
goal:
|
||||||
|
chunking_profile: sliding_smart_edges
|
||||||
|
retriever_weight: 0.95
|
||||||
|
edge_defaults: ["depends_on", "related_to"]
|
||||||
|
schema: ["Zielzustand", "Zeitrahmen & KPIs", "Motivation"]
|
||||||
|
|
||||||
|
risk:
|
||||||
|
chunking_profile: sliding_short
|
||||||
|
retriever_weight: 0.85
|
||||||
|
edge_defaults: ["related_to", "blocks"]
|
||||||
|
detection_keywords: ["risiko", "gefahr", "bedrohung", "problem", "angst"]
|
||||||
|
schema: ["Beschreibung des Risikos", "Mögliche Auswirkungen", "Gegenmaßnahmen"]
|
||||||
|
|
||||||
|
# --- BASIS & WISSEN ---
|
||||||
|
|
||||||
concept:
|
concept:
|
||||||
chunking_profile: sliding_smart_edges
|
chunking_profile: sliding_smart_edges
|
||||||
|
|
@ -115,46 +170,32 @@ types:
|
||||||
edge_defaults: ["references", "related_to"]
|
edge_defaults: ["references", "related_to"]
|
||||||
schema:
|
schema:
|
||||||
- "Definition"
|
- "Definition"
|
||||||
- "Kontext"
|
- "Kontext & Hintergrund"
|
||||||
- "Verwandte Konzepte"
|
- "Verwandte Konzepte"
|
||||||
|
|
||||||
project:
|
task:
|
||||||
chunking_profile: sliding_smart_edges
|
chunking_profile: sliding_short
|
||||||
retriever_weight: 0.97
|
retriever_weight: 0.80
|
||||||
edge_defaults: ["references", "depends_on"]
|
edge_defaults: ["depends_on", "part_of"]
|
||||||
schema:
|
schema: ["Aufgabe", "Kontext", "Definition of Done"]
|
||||||
- "Mission"
|
|
||||||
- "Status"
|
|
||||||
- "Next Actions"
|
|
||||||
|
|
||||||
experience:
|
journal:
|
||||||
chunking_profile: sliding_smart_edges
|
chunking_profile: sliding_standard
|
||||||
retriever_weight: 0.90
|
retriever_weight: 0.80
|
||||||
edge_defaults: ["derived_from", "references"]
|
|
||||||
schema: ["Situation", "Aktion", "Ergebnis", "Learning"]
|
|
||||||
|
|
||||||
# --- STRUKTUR-DATEN (Smart Structure / LLM Active) ---
|
|
||||||
|
|
||||||
profile:
|
|
||||||
chunking_profile: structured_smart_edges
|
|
||||||
retriever_weight: 0.70
|
|
||||||
edge_defaults: ["references", "related_to"]
|
edge_defaults: ["references", "related_to"]
|
||||||
schema: ["Rolle", "Fakten", "Historie"]
|
schema: ["Log-Eintrag", "Gedanken & Erkenntnisse"]
|
||||||
|
|
||||||
value:
|
source:
|
||||||
chunking_profile: structured_smart_edges
|
chunking_profile: sliding_standard
|
||||||
retriever_weight: 1.00
|
retriever_weight: 0.50
|
||||||
|
edge_defaults: []
|
||||||
|
schema:
|
||||||
|
- "Metadaten (Autor, URL, Datum)"
|
||||||
|
- "Kernaussage / Zusammenfassung"
|
||||||
|
- "Zitate & Notizen"
|
||||||
|
|
||||||
|
glossary:
|
||||||
|
chunking_profile: sliding_short
|
||||||
|
retriever_weight: 0.40
|
||||||
edge_defaults: ["related_to"]
|
edge_defaults: ["related_to"]
|
||||||
schema: ["Definition", "Motivation", "Leitsätze"]
|
schema: ["Begriff", "Definition"]
|
||||||
|
|
||||||
principle:
|
|
||||||
chunking_profile: structured_smart_edges
|
|
||||||
retriever_weight: 0.95
|
|
||||||
edge_defaults: ["derived_from", "references"]
|
|
||||||
schema: ["Prinzip", "Anwendung"]
|
|
||||||
|
|
||||||
decision:
|
|
||||||
chunking_profile: structured_smart_edges
|
|
||||||
retriever_weight: 1.00
|
|
||||||
edge_defaults: ["caused_by", "references"]
|
|
||||||
schema: ["Problem", "Optionen", "Entscheidung", "Warum"]
|
|
||||||
Loading…
Reference in New Issue
Block a user