WP24c - Agentic Edge Validation & Chunk-Aware Multigraph-System (v4.5.8) #22
|
|
@ -13,6 +13,7 @@ class RawBlock:
|
||||||
level: Optional[int]
|
level: Optional[int]
|
||||||
section_path: str
|
section_path: str
|
||||||
section_title: Optional[str]
|
section_title: Optional[str]
|
||||||
|
exclude_from_chunking: bool = False # WP-24c v4.2.0: Flag für Edge-Zonen, die nicht gechunkt werden sollen
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Chunk:
|
class Chunk:
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@ FILE: app/core/chunking/chunking_parser.py
|
||||||
DESCRIPTION: Zerlegt Markdown in logische Einheiten (RawBlocks).
|
DESCRIPTION: Zerlegt Markdown in logische Einheiten (RawBlocks).
|
||||||
Hält alle Überschriftenebenen (H1-H6) im Stream.
|
Hält alle Überschriftenebenen (H1-H6) im Stream.
|
||||||
Stellt die Funktion parse_edges_robust zur Verfügung.
|
Stellt die Funktion parse_edges_robust zur Verfügung.
|
||||||
|
WP-24c v4.2.0: Identifiziert Edge-Zonen und markiert sie für Chunking-Ausschluss.
|
||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
|
import os
|
||||||
from typing import List, Tuple, Set
|
from typing import List, Tuple, Set
|
||||||
from .chunking_models import RawBlock
|
from .chunking_models import RawBlock
|
||||||
from .chunking_utils import extract_frontmatter_from_text
|
from .chunking_utils import extract_frontmatter_from_text
|
||||||
|
|
@ -20,7 +22,10 @@ def split_sentences(text: str) -> list[str]:
|
||||||
return [p.strip() for p in _SENT_SPLIT.split(text) if p.strip()]
|
return [p.strip() for p in _SENT_SPLIT.split(text) if p.strip()]
|
||||||
|
|
||||||
def parse_blocks(md_text: str) -> Tuple[List[RawBlock], str]:
|
def parse_blocks(md_text: str) -> Tuple[List[RawBlock], str]:
|
||||||
"""Zerlegt Text in logische Einheiten (RawBlocks), inklusive H1-H6."""
|
"""
|
||||||
|
Zerlegt Text in logische Einheiten (RawBlocks), inklusive H1-H6.
|
||||||
|
WP-24c v4.2.0: Identifiziert Edge-Zonen (LLM-Validierung & Note-Scope) und markiert sie für Chunking-Ausschluss.
|
||||||
|
"""
|
||||||
blocks = []
|
blocks = []
|
||||||
h1_title = "Dokument"
|
h1_title = "Dokument"
|
||||||
section_path = "/"
|
section_path = "/"
|
||||||
|
|
@ -29,6 +34,31 @@ def parse_blocks(md_text: str) -> Tuple[List[RawBlock], str]:
|
||||||
# Frontmatter entfernen
|
# Frontmatter entfernen
|
||||||
fm, text_without_fm = extract_frontmatter_from_text(md_text)
|
fm, text_without_fm = extract_frontmatter_from_text(md_text)
|
||||||
|
|
||||||
|
# WP-24c v4.2.0: Konfigurierbare Header-Namen und -Ebenen
|
||||||
|
llm_validation_headers = os.getenv(
|
||||||
|
"MINDNET_LLM_VALIDATION_HEADERS",
|
||||||
|
"Unzugeordnete Kanten,Edge Pool,Candidates"
|
||||||
|
)
|
||||||
|
llm_validation_header_list = [h.strip() for h in llm_validation_headers.split(",") if h.strip()]
|
||||||
|
if not llm_validation_header_list:
|
||||||
|
llm_validation_header_list = ["Unzugeordnete Kanten", "Edge Pool", "Candidates"]
|
||||||
|
|
||||||
|
note_scope_headers = os.getenv(
|
||||||
|
"MINDNET_NOTE_SCOPE_ZONE_HEADERS",
|
||||||
|
"Smart Edges,Relationen,Global Links,Note-Level Relations,Globale Verbindungen"
|
||||||
|
)
|
||||||
|
note_scope_header_list = [h.strip() for h in note_scope_headers.split(",") if h.strip()]
|
||||||
|
if not note_scope_header_list:
|
||||||
|
note_scope_header_list = ["Smart Edges", "Relationen", "Global Links", "Note-Level Relations", "Globale Verbindungen"]
|
||||||
|
|
||||||
|
# Header-Ebenen konfigurierbar (Default: LLM=3, Note-Scope=2)
|
||||||
|
llm_validation_level = int(os.getenv("MINDNET_LLM_VALIDATION_HEADER_LEVEL", "3"))
|
||||||
|
note_scope_level = int(os.getenv("MINDNET_NOTE_SCOPE_HEADER_LEVEL", "2"))
|
||||||
|
|
||||||
|
# Status-Tracking für Edge-Zonen
|
||||||
|
in_exclusion_zone = False
|
||||||
|
exclusion_zone_type = None # "llm_validation" oder "note_scope"
|
||||||
|
|
||||||
# H1 für Note-Titel extrahieren (Metadaten-Zweck)
|
# H1 für Note-Titel extrahieren (Metadaten-Zweck)
|
||||||
h1_match = re.search(r'^#\s+(.*)', text_without_fm, re.MULTILINE)
|
h1_match = re.search(r'^#\s+(.*)', text_without_fm, re.MULTILINE)
|
||||||
if h1_match:
|
if h1_match:
|
||||||
|
|
@ -47,20 +77,47 @@ def parse_blocks(md_text: str) -> Tuple[List[RawBlock], str]:
|
||||||
if buffer:
|
if buffer:
|
||||||
content = "\n".join(buffer).strip()
|
content = "\n".join(buffer).strip()
|
||||||
if content:
|
if content:
|
||||||
blocks.append(RawBlock("paragraph", content, None, section_path, current_section_title))
|
blocks.append(RawBlock(
|
||||||
|
"paragraph", content, None, section_path, current_section_title,
|
||||||
|
exclude_from_chunking=in_exclusion_zone
|
||||||
|
))
|
||||||
buffer = []
|
buffer = []
|
||||||
|
|
||||||
level = len(heading_match.group(1))
|
level = len(heading_match.group(1))
|
||||||
title = heading_match.group(2).strip()
|
title = heading_match.group(2).strip()
|
||||||
|
|
||||||
|
# WP-24c v4.2.0: Prüfe, ob dieser Header eine Edge-Zone startet
|
||||||
|
is_llm_validation_zone = (
|
||||||
|
level == llm_validation_level and
|
||||||
|
any(title.lower() == h.lower() for h in llm_validation_header_list)
|
||||||
|
)
|
||||||
|
is_note_scope_zone = (
|
||||||
|
level == note_scope_level and
|
||||||
|
any(title.lower() == h.lower() for h in note_scope_header_list)
|
||||||
|
)
|
||||||
|
|
||||||
|
if is_llm_validation_zone:
|
||||||
|
in_exclusion_zone = True
|
||||||
|
exclusion_zone_type = "llm_validation"
|
||||||
|
elif is_note_scope_zone:
|
||||||
|
in_exclusion_zone = True
|
||||||
|
exclusion_zone_type = "note_scope"
|
||||||
|
elif in_exclusion_zone:
|
||||||
|
# Neuer Header gefunden, der keine Edge-Zone ist -> Zone beendet
|
||||||
|
in_exclusion_zone = False
|
||||||
|
exclusion_zone_type = None
|
||||||
|
|
||||||
# Pfad- und Titel-Update für die Metadaten der folgenden Blöcke
|
# Pfad- und Titel-Update für die Metadaten der folgenden Blöcke
|
||||||
if level == 1:
|
if level == 1:
|
||||||
current_section_title = title; section_path = "/"
|
current_section_title = title; section_path = "/"
|
||||||
elif level == 2:
|
elif level == 2:
|
||||||
current_section_title = title; section_path = f"/{current_section_title}"
|
current_section_title = title; section_path = f"/{current_section_title}"
|
||||||
|
|
||||||
# Die Überschrift selbst als regulären Block hinzufügen
|
# Die Überschrift selbst als regulären Block hinzufügen (auch markiert, wenn in Zone)
|
||||||
blocks.append(RawBlock("heading", stripped, level, section_path, current_section_title))
|
blocks.append(RawBlock(
|
||||||
|
"heading", stripped, level, section_path, current_section_title,
|
||||||
|
exclude_from_chunking=in_exclusion_zone
|
||||||
|
))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Trenner (---) oder Leerzeilen beenden Blöcke, außer innerhalb von Callouts
|
# Trenner (---) oder Leerzeilen beenden Blöcke, außer innerhalb von Callouts
|
||||||
|
|
@ -68,17 +125,26 @@ def parse_blocks(md_text: str) -> Tuple[List[RawBlock], str]:
|
||||||
if buffer:
|
if buffer:
|
||||||
content = "\n".join(buffer).strip()
|
content = "\n".join(buffer).strip()
|
||||||
if content:
|
if content:
|
||||||
blocks.append(RawBlock("paragraph", content, None, section_path, current_section_title))
|
blocks.append(RawBlock(
|
||||||
|
"paragraph", content, None, section_path, current_section_title,
|
||||||
|
exclude_from_chunking=in_exclusion_zone
|
||||||
|
))
|
||||||
buffer = []
|
buffer = []
|
||||||
if stripped == "---":
|
if stripped == "---":
|
||||||
blocks.append(RawBlock("separator", "---", None, section_path, current_section_title))
|
blocks.append(RawBlock(
|
||||||
|
"separator", "---", None, section_path, current_section_title,
|
||||||
|
exclude_from_chunking=in_exclusion_zone
|
||||||
|
))
|
||||||
else:
|
else:
|
||||||
buffer.append(line)
|
buffer.append(line)
|
||||||
|
|
||||||
if buffer:
|
if buffer:
|
||||||
content = "\n".join(buffer).strip()
|
content = "\n".join(buffer).strip()
|
||||||
if content:
|
if content:
|
||||||
blocks.append(RawBlock("paragraph", content, None, section_path, current_section_title))
|
blocks.append(RawBlock(
|
||||||
|
"paragraph", content, None, section_path, current_section_title,
|
||||||
|
exclude_from_chunking=in_exclusion_zone
|
||||||
|
))
|
||||||
|
|
||||||
return blocks, h1_title
|
return blocks, h1_title
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,11 @@ DESCRIPTION: Der zentrale Orchestrator für das Chunking-System.
|
||||||
- Integriert physikalische Kanten-Injektion (Propagierung).
|
- Integriert physikalische Kanten-Injektion (Propagierung).
|
||||||
- Stellt H1-Kontext-Fenster sicher.
|
- Stellt H1-Kontext-Fenster sicher.
|
||||||
- Baut den Candidate-Pool für die WP-15b Ingestion auf.
|
- Baut den Candidate-Pool für die WP-15b Ingestion auf.
|
||||||
|
WP-24c v4.2.0: Konfigurierbare Header-Namen für LLM-Validierung.
|
||||||
"""
|
"""
|
||||||
import asyncio
|
import asyncio
|
||||||
import re
|
import re
|
||||||
|
import os
|
||||||
import logging
|
import logging
|
||||||
from typing import List, Dict, Optional
|
from typing import List, Dict, Optional
|
||||||
from .chunking_models import Chunk
|
from .chunking_models import Chunk
|
||||||
|
|
@ -31,6 +33,10 @@ async def assemble_chunks(note_id: str, md_text: str, note_type: str, config: Op
|
||||||
fm, body_text = extract_frontmatter_from_text(md_text)
|
fm, body_text = extract_frontmatter_from_text(md_text)
|
||||||
blocks, doc_title = parse_blocks(md_text)
|
blocks, doc_title = parse_blocks(md_text)
|
||||||
|
|
||||||
|
# WP-24c v4.2.0: Filtere Blöcke aus Edge-Zonen (LLM-Validierung & Note-Scope)
|
||||||
|
# Diese Bereiche sollen nicht als Chunks angelegt werden, sondern nur die Kanten extrahiert werden
|
||||||
|
blocks_for_chunking = [b for b in blocks if not getattr(b, 'exclude_from_chunking', False)]
|
||||||
|
|
||||||
# Vorbereitung des H1-Präfix für die Embedding-Fenster (Breadcrumbs)
|
# Vorbereitung des H1-Präfix für die Embedding-Fenster (Breadcrumbs)
|
||||||
h1_prefix = f"# {doc_title}" if doc_title else ""
|
h1_prefix = f"# {doc_title}" if doc_title else ""
|
||||||
|
|
||||||
|
|
@ -38,11 +44,11 @@ async def assemble_chunks(note_id: str, md_text: str, note_type: str, config: Op
|
||||||
# Alle Strategien nutzen nun einheitlich context_prefix für die Window-Bildung.
|
# Alle Strategien nutzen nun einheitlich context_prefix für die Window-Bildung.
|
||||||
if config.get("strategy") == "by_heading":
|
if config.get("strategy") == "by_heading":
|
||||||
chunks = await asyncio.to_thread(
|
chunks = await asyncio.to_thread(
|
||||||
strategy_by_heading, blocks, config, note_id, context_prefix=h1_prefix
|
strategy_by_heading, blocks_for_chunking, config, note_id, context_prefix=h1_prefix
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
chunks = await asyncio.to_thread(
|
chunks = await asyncio.to_thread(
|
||||||
strategy_sliding_window, blocks, config, note_id, context_prefix=h1_prefix
|
strategy_sliding_window, blocks_for_chunking, config, note_id, context_prefix=h1_prefix
|
||||||
)
|
)
|
||||||
|
|
||||||
if not chunks:
|
if not chunks:
|
||||||
|
|
@ -63,14 +69,29 @@ async def assemble_chunks(note_id: str, md_text: str, note_type: str, config: Op
|
||||||
k, t = parts
|
k, t = parts
|
||||||
ch.candidate_pool.append({"kind": k, "to": t, "provenance": "explicit"})
|
ch.candidate_pool.append({"kind": k, "to": t, "provenance": "explicit"})
|
||||||
|
|
||||||
# 5. Global Pool (Unzugeordnete Kanten aus dem Dokument-Ende)
|
# 5. Global Pool (Unzugeordnete Kanten - kann mitten im Dokument oder am Ende stehen)
|
||||||
# Sucht nach dem Edge-Pool Block im Original-Markdown.
|
# WP-24c v4.2.0: Konfigurierbare Header-Namen und -Ebene via .env
|
||||||
pool_match = re.search(
|
# Sucht nach ALLEN Edge-Pool Blöcken im Original-Markdown (nicht nur am Ende).
|
||||||
r'###?\s*(?:Unzugeordnete Kanten|Edge Pool|Candidates)\s*\n(.*?)(?:\n#|$)',
|
llm_validation_headers = os.getenv(
|
||||||
body_text,
|
"MINDNET_LLM_VALIDATION_HEADERS",
|
||||||
re.DOTALL | re.IGNORECASE
|
"Unzugeordnete Kanten,Edge Pool,Candidates"
|
||||||
)
|
)
|
||||||
if pool_match:
|
header_list = [h.strip() for h in llm_validation_headers.split(",") if h.strip()]
|
||||||
|
# Fallback auf Defaults, falls leer
|
||||||
|
if not header_list:
|
||||||
|
header_list = ["Unzugeordnete Kanten", "Edge Pool", "Candidates"]
|
||||||
|
|
||||||
|
# Header-Ebene konfigurierbar (Default: 3 für ###)
|
||||||
|
llm_validation_level = int(os.getenv("MINDNET_LLM_VALIDATION_HEADER_LEVEL", "3"))
|
||||||
|
header_level_pattern = "#" * llm_validation_level
|
||||||
|
|
||||||
|
# Regex-Pattern mit konfigurierbaren Headern und Ebene
|
||||||
|
# WP-24c v4.2.0: finditer statt search, um ALLE Zonen zu finden (auch mitten im Dokument)
|
||||||
|
# Zone endet bei einem neuen Header (jeder Ebene) oder am Dokument-Ende
|
||||||
|
header_pattern = "|".join(re.escape(h) for h in header_list)
|
||||||
|
zone_pattern = rf'^{re.escape(header_level_pattern)}\s*(?:{header_pattern})\s*\n(.*?)(?=\n#|$)'
|
||||||
|
|
||||||
|
for pool_match in re.finditer(zone_pattern, body_text, re.DOTALL | re.IGNORECASE | re.MULTILINE):
|
||||||
global_edges = parse_edges_robust(pool_match.group(1))
|
global_edges = parse_edges_robust(pool_match.group(1))
|
||||||
for e_str in global_edges:
|
for e_str in global_edges:
|
||||||
parts = e_str.split(':', 1)
|
parts = e_str.split(':', 1)
|
||||||
|
|
|
||||||
|
|
@ -23,19 +23,34 @@ from .graph_extractors import (
|
||||||
)
|
)
|
||||||
|
|
||||||
# WP-24c v4.2.0: Header-basierte Identifikation von Note-Scope Zonen
|
# WP-24c v4.2.0: Header-basierte Identifikation von Note-Scope Zonen
|
||||||
NOTE_SCOPE_ZONE_HEADERS = [
|
# Konfigurierbar via MINDNET_NOTE_SCOPE_ZONE_HEADERS (komma-separiert)
|
||||||
"Smart Edges",
|
def get_note_scope_zone_headers() -> List[str]:
|
||||||
"Relationen",
|
"""
|
||||||
"Global Links",
|
Lädt die konfigurierten Header-Namen für Note-Scope Zonen.
|
||||||
"Note-Level Relations",
|
Fallback auf Defaults, falls nicht konfiguriert.
|
||||||
"Globale Verbindungen"
|
"""
|
||||||
]
|
import os
|
||||||
|
headers_env = os.getenv(
|
||||||
|
"MINDNET_NOTE_SCOPE_ZONE_HEADERS",
|
||||||
|
"Smart Edges,Relationen,Global Links,Note-Level Relations,Globale Verbindungen"
|
||||||
|
)
|
||||||
|
header_list = [h.strip() for h in headers_env.split(",") if h.strip()]
|
||||||
|
# Fallback auf Defaults, falls leer
|
||||||
|
if not header_list:
|
||||||
|
header_list = [
|
||||||
|
"Smart Edges",
|
||||||
|
"Relationen",
|
||||||
|
"Global Links",
|
||||||
|
"Note-Level Relations",
|
||||||
|
"Globale Verbindungen"
|
||||||
|
]
|
||||||
|
return header_list
|
||||||
|
|
||||||
def extract_note_scope_zones(markdown_body: str) -> List[Tuple[str, str]]:
|
def extract_note_scope_zones(markdown_body: str) -> List[Tuple[str, str]]:
|
||||||
"""
|
"""
|
||||||
WP-24c v4.2.0: Extrahiert Note-Scope Zonen aus Markdown.
|
WP-24c v4.2.0: Extrahiert Note-Scope Zonen aus Markdown.
|
||||||
|
|
||||||
Identifiziert Sektionen mit spezifischen Headern (z.B. "## Smart Edges")
|
Identifiziert Sektionen mit spezifischen Headern (konfigurierbar via .env)
|
||||||
und extrahiert alle darin enthaltenen Links.
|
und extrahiert alle darin enthaltenen Links.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -46,8 +61,14 @@ def extract_note_scope_zones(markdown_body: str) -> List[Tuple[str, str]]:
|
||||||
|
|
||||||
edges: List[Tuple[str, str]] = []
|
edges: List[Tuple[str, str]] = []
|
||||||
|
|
||||||
# Regex für Header-Erkennung (## oder ###)
|
# WP-24c v4.2.0: Konfigurierbare Header-Ebene
|
||||||
header_pattern = r'^#{2,3}\s+(.+?)$'
|
import os
|
||||||
|
import re
|
||||||
|
note_scope_level = int(os.getenv("MINDNET_NOTE_SCOPE_HEADER_LEVEL", "2"))
|
||||||
|
header_level_pattern = "#" * note_scope_level
|
||||||
|
|
||||||
|
# Regex für Header-Erkennung (konfigurierbare Ebene)
|
||||||
|
header_pattern = rf'^{re.escape(header_level_pattern)}\s+(.+?)$'
|
||||||
|
|
||||||
lines = markdown_body.split('\n')
|
lines = markdown_body.split('\n')
|
||||||
in_zone = False
|
in_zone = False
|
||||||
|
|
@ -60,9 +81,11 @@ def extract_note_scope_zones(markdown_body: str) -> List[Tuple[str, str]]:
|
||||||
header_text = header_match.group(1).strip()
|
header_text = header_match.group(1).strip()
|
||||||
|
|
||||||
# Prüfe, ob dieser Header eine Note-Scope Zone ist
|
# Prüfe, ob dieser Header eine Note-Scope Zone ist
|
||||||
|
# WP-24c v4.2.0: Dynamisches Laden der konfigurierten Header
|
||||||
|
zone_headers = get_note_scope_zone_headers()
|
||||||
is_zone_header = any(
|
is_zone_header = any(
|
||||||
header_text.lower() == zone_header.lower()
|
header_text.lower() == zone_header.lower()
|
||||||
for zone_header in NOTE_SCOPE_ZONE_HEADERS
|
for zone_header in zone_headers
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_zone_header:
|
if is_zone_header:
|
||||||
|
|
|
||||||
|
|
@ -45,4 +45,19 @@ MINDNET_VAULT_ROOT=./vault_prod
|
||||||
MINDNET_VOCAB_PATH=/mindnet/vault/mindnet/_system/dictionary/edge_vocabulary.md
|
MINDNET_VOCAB_PATH=/mindnet/vault/mindnet/_system/dictionary/edge_vocabulary.md
|
||||||
|
|
||||||
# Change Detection für effiziente Re-Imports
|
# Change Detection für effiziente Re-Imports
|
||||||
MINDNET_CHANGE_DETECTION_MODE=full
|
MINDNET_CHANGE_DETECTION_MODE=full
|
||||||
|
|
||||||
|
# --- WP-24c v4.2.0: Konfigurierbare Markdown-Header für Edge-Zonen ---
|
||||||
|
# Komma-separierte Liste von Headern für LLM-Validierung
|
||||||
|
# Format: Header1,Header2,Header3
|
||||||
|
MINDNET_LLM_VALIDATION_HEADERS=Unzugeordnete Kanten,Edge Pool,Candidates
|
||||||
|
|
||||||
|
# Header-Ebene für LLM-Validierung (1-6, Default: 3 für ###)
|
||||||
|
MINDNET_LLM_VALIDATION_HEADER_LEVEL=3
|
||||||
|
|
||||||
|
# Komma-separierte Liste von Headern für Note-Scope Zonen
|
||||||
|
# Format: Header1,Header2,Header3
|
||||||
|
MINDNET_NOTE_SCOPE_ZONE_HEADERS=Smart Edges,Relationen,Global Links,Note-Level Relations,Globale Verbindungen
|
||||||
|
|
||||||
|
# Header-Ebene für Note-Scope Zonen (1-6, Default: 2 für ##)
|
||||||
|
MINDNET_NOTE_SCOPE_HEADER_LEVEL=2
|
||||||
|
|
@ -50,6 +50,11 @@ Diese Variablen steuern die Infrastruktur, Pfade und globale Timeouts. Seit der
|
||||||
| `MINDNET_LL_BACKGROUND_LIMIT`| `2` | **Traffic Control:** Max. parallele Hintergrund-Tasks (Semaphore). |
|
| `MINDNET_LL_BACKGROUND_LIMIT`| `2` | **Traffic Control:** Max. parallele Hintergrund-Tasks (Semaphore). |
|
||||||
| `MINDNET_CHANGE_DETECTION_MODE` | `full` | `full` (Text + Meta) oder `body` (nur Text). |
|
| `MINDNET_CHANGE_DETECTION_MODE` | `full` | `full` (Text + Meta) oder `body` (nur Text). |
|
||||||
| `MINDNET_DEFAULT_RETRIEVER_WEIGHT` | `1.0` | **Neu (WP-22):** Systemweiter Standard für das Retriever-Gewicht einer Notiz. |
|
| `MINDNET_DEFAULT_RETRIEVER_WEIGHT` | `1.0` | **Neu (WP-22):** Systemweiter Standard für das Retriever-Gewicht einer Notiz. |
|
||||||
|
| `MINDNET_LLM_VALIDATION_HEADERS` | `Unzugeordnete Kanten,Edge Pool,Candidates` | **Neu (v4.2.0):** Komma-separierte Header-Namen für LLM-Validierung. |
|
||||||
|
| `MINDNET_LLM_VALIDATION_HEADER_LEVEL` | `3` | **Neu (v4.2.0):** Header-Ebene für LLM-Validierung (1-6, Default: 3 für ###). |
|
||||||
|
| `MINDNET_NOTE_SCOPE_ZONE_HEADERS` | `Smart Edges,Relationen,Global Links,Note-Level Relations,Globale Verbindungen` | **Neu (v4.2.0):** Komma-separierte Header-Namen für Note-Scope Zonen. |
|
||||||
|
| `MINDNET_NOTE_SCOPE_HEADER_LEVEL` | `2` | **Neu (v4.2.0):** Header-Ebene für Note-Scope Zonen (1-6, Default: 2 für ##). |
|
||||||
|
| `MINDNET_IGNORE_FOLDERS` | *(leer)* | **Neu (v4.1.0):** Komma-separierte Liste von Ordnernamen, die beim Import ignoriert werden. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
242
docs/03_Technical_References/KONFIGURATION_EDGE_ZONEN.md
Normal file
242
docs/03_Technical_References/KONFIGURATION_EDGE_ZONEN.md
Normal file
|
|
@ -0,0 +1,242 @@
|
||||||
|
# Konfiguration von Edge-Zonen Headern (v4.2.0)
|
||||||
|
|
||||||
|
**Version:** v4.2.0
|
||||||
|
**Status:** Aktiv
|
||||||
|
|
||||||
|
## Übersicht
|
||||||
|
|
||||||
|
Das Mindnet-System unterstützt zwei Arten von speziellen Markdown-Sektionen für Kanten:
|
||||||
|
|
||||||
|
1. **LLM-Validierung Zonen** - Links, die vom LLM validiert werden
|
||||||
|
2. **Note-Scope Zonen** - Links, die der gesamten Note zugeordnet werden
|
||||||
|
|
||||||
|
Die Header-Namen für beide Zonen-Typen sind über Umgebungsvariablen konfigurierbar.
|
||||||
|
|
||||||
|
## Konfiguration via .env
|
||||||
|
|
||||||
|
### LLM-Validierung Header
|
||||||
|
|
||||||
|
**Umgebungsvariablen:**
|
||||||
|
- `MINDNET_LLM_VALIDATION_HEADERS` - Komma-separierte Liste von Header-Namen
|
||||||
|
- `MINDNET_LLM_VALIDATION_HEADER_LEVEL` - Header-Ebene (1-6, Default: 3 für `###`)
|
||||||
|
|
||||||
|
**Format:** Komma-separierte Liste von Header-Namen
|
||||||
|
|
||||||
|
**Default:**
|
||||||
|
```
|
||||||
|
MINDNET_LLM_VALIDATION_HEADERS=Unzugeordnete Kanten,Edge Pool,Candidates
|
||||||
|
MINDNET_LLM_VALIDATION_HEADER_LEVEL=3
|
||||||
|
```
|
||||||
|
|
||||||
|
**Beispiel:**
|
||||||
|
```env
|
||||||
|
MINDNET_LLM_VALIDATION_HEADERS=Unzugeordnete Kanten,Edge Pool,Candidates,Zu prüfende Links
|
||||||
|
MINDNET_LLM_VALIDATION_HEADER_LEVEL=3
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verwendung in Markdown:**
|
||||||
|
```markdown
|
||||||
|
### Unzugeordnete Kanten
|
||||||
|
|
||||||
|
related_to:Ziel-Notiz
|
||||||
|
depends_on:Andere Notiz
|
||||||
|
```
|
||||||
|
|
||||||
|
**Wichtig:** Diese Bereiche werden **nicht als Chunks angelegt**, sondern nur die Kanten extrahiert.
|
||||||
|
|
||||||
|
### Note-Scope Zone Header
|
||||||
|
|
||||||
|
**Umgebungsvariablen:**
|
||||||
|
- `MINDNET_NOTE_SCOPE_ZONE_HEADERS` - Komma-separierte Liste von Header-Namen
|
||||||
|
- `MINDNET_NOTE_SCOPE_HEADER_LEVEL` - Header-Ebene (1-6, Default: 2 für `##`)
|
||||||
|
|
||||||
|
**Format:** Komma-separierte Liste von Header-Namen
|
||||||
|
|
||||||
|
**Default:**
|
||||||
|
```
|
||||||
|
MINDNET_NOTE_SCOPE_ZONE_HEADERS=Smart Edges,Relationen,Global Links,Note-Level Relations,Globale Verbindungen
|
||||||
|
MINDNET_NOTE_SCOPE_HEADER_LEVEL=2
|
||||||
|
```
|
||||||
|
|
||||||
|
**Beispiel:**
|
||||||
|
```env
|
||||||
|
MINDNET_NOTE_SCOPE_ZONE_HEADERS=Smart Edges,Relationen,Globale Verbindungen,Note-Level Links
|
||||||
|
MINDNET_NOTE_SCOPE_HEADER_LEVEL=2
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verwendung in Markdown:**
|
||||||
|
```markdown
|
||||||
|
## Smart Edges
|
||||||
|
|
||||||
|
[[rel:depends_on|Globale Notiz]]
|
||||||
|
[[rel:part_of|System-Übersicht]]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Wichtig:** Diese Bereiche werden **nicht als Chunks angelegt**, sondern nur die Kanten extrahiert.
|
||||||
|
|
||||||
|
## Konfiguration in prod.env
|
||||||
|
|
||||||
|
Fügen Sie die folgenden Zeilen zu Ihrer `.env` oder `config/prod.env` hinzu:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# --- WP-24c v4.2.0: Konfigurierbare Markdown-Header für Edge-Zonen ---
|
||||||
|
# Komma-separierte Liste von Headern für LLM-Validierung
|
||||||
|
MINDNET_LLM_VALIDATION_HEADERS=Unzugeordnete Kanten,Edge Pool,Candidates
|
||||||
|
|
||||||
|
# Header-Ebene für LLM-Validierung (1-6, Default: 3 für ###)
|
||||||
|
MINDNET_LLM_VALIDATION_HEADER_LEVEL=3
|
||||||
|
|
||||||
|
# Komma-separierte Liste von Headern für Note-Scope Zonen
|
||||||
|
MINDNET_NOTE_SCOPE_ZONE_HEADERS=Smart Edges,Relationen,Global Links,Note-Level Relations,Globale Verbindungen
|
||||||
|
|
||||||
|
# Header-Ebene für Note-Scope Zonen (1-6, Default: 2 für ##)
|
||||||
|
MINDNET_NOTE_SCOPE_HEADER_LEVEL=2
|
||||||
|
```
|
||||||
|
|
||||||
|
**Wichtig:** Beide Zonen-Typen werden **nicht als Chunks angelegt**. Nur die Kanten werden extrahiert, der Text selbst wird vom Chunking ausgeschlossen.
|
||||||
|
|
||||||
|
## Unterschiede
|
||||||
|
|
||||||
|
### LLM-Validierung Zonen
|
||||||
|
|
||||||
|
- **Header-Ebene:** Konfigurierbar via `MINDNET_LLM_VALIDATION_HEADER_LEVEL` (Default: 3 = `###`)
|
||||||
|
- **Zweck:** Links werden vom LLM validiert
|
||||||
|
- **Provenance:** `global_pool`
|
||||||
|
- **Scope:** `chunk` (wird Chunks zugeordnet)
|
||||||
|
- **Aktivierung:** Nur wenn `enable_smart_edge_allocation: true`
|
||||||
|
- **Chunking:** ❌ **Diese Bereiche werden NICHT als Chunks angelegt** - nur Kanten werden extrahiert
|
||||||
|
|
||||||
|
**Beispiel:**
|
||||||
|
```markdown
|
||||||
|
### Unzugeordnete Kanten
|
||||||
|
|
||||||
|
related_to:Mögliche Verbindung
|
||||||
|
depends_on:Unsichere Notiz
|
||||||
|
```
|
||||||
|
|
||||||
|
### Note-Scope Zonen
|
||||||
|
|
||||||
|
- **Header-Ebene:** Konfigurierbar via `MINDNET_NOTE_SCOPE_HEADER_LEVEL` (Default: 2 = `##`)
|
||||||
|
- **Zweck:** Links werden der gesamten Note zugeordnet
|
||||||
|
- **Provenance:** `explicit:note_zone`
|
||||||
|
- **Scope:** `note` (Note-weite Verbindung)
|
||||||
|
- **Aktivierung:** Immer aktiv
|
||||||
|
- **Chunking:** ❌ **Diese Bereiche werden NICHT als Chunks angelegt** - nur Kanten werden extrahiert
|
||||||
|
|
||||||
|
**Beispiel:**
|
||||||
|
```markdown
|
||||||
|
## Smart Edges
|
||||||
|
|
||||||
|
[[rel:depends_on|Globale Notiz]]
|
||||||
|
[[rel:part_of|System-Übersicht]]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### ✅ Empfohlen
|
||||||
|
|
||||||
|
1. **Konsistente Header-Namen:**
|
||||||
|
- Nutzen Sie aussagekräftige Namen
|
||||||
|
- Dokumentieren Sie die verwendeten Header in Ihrem Team
|
||||||
|
|
||||||
|
2. **Minimale Konfiguration:**
|
||||||
|
- Nutzen Sie die Defaults, wenn möglich
|
||||||
|
- Nur bei Bedarf anpassen
|
||||||
|
|
||||||
|
3. **Dokumentation:**
|
||||||
|
- Dokumentieren Sie benutzerdefinierte Header in Ihrer Projekt-Dokumentation
|
||||||
|
|
||||||
|
### ❌ Vermeiden
|
||||||
|
|
||||||
|
1. **Zu viele Header:**
|
||||||
|
- Zu viele Optionen können verwirrend sein
|
||||||
|
- Beschränken Sie sich auf 3-5 Header pro Typ
|
||||||
|
|
||||||
|
2. **Ähnliche Namen:**
|
||||||
|
- Vermeiden Sie Header, die sich zu ähnlich sind
|
||||||
|
- Klare Unterscheidung zwischen LLM-Validierung und Note-Scope
|
||||||
|
|
||||||
|
## Technische Details
|
||||||
|
|
||||||
|
### Code-Referenzen
|
||||||
|
|
||||||
|
- **LLM-Validierung:** `app/core/chunking/chunking_processor.py` (Zeile 66-72)
|
||||||
|
- **Note-Scope Zonen:** `app/core/graph/graph_derive_edges.py` → `get_note_scope_zone_headers()`
|
||||||
|
|
||||||
|
### Fallback-Verhalten
|
||||||
|
|
||||||
|
- Wenn die Umgebungsvariable nicht gesetzt ist, werden die Defaults verwendet
|
||||||
|
- Wenn die Variable leer ist, werden ebenfalls die Defaults verwendet
|
||||||
|
- Header-Namen werden case-insensitive verglichen
|
||||||
|
|
||||||
|
### Regex-Escape
|
||||||
|
|
||||||
|
- Header-Namen werden automatisch für Regex escaped
|
||||||
|
- Sonderzeichen in Header-Namen sind sicher
|
||||||
|
|
||||||
|
## Beispiel-Konfiguration
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Eigene Header-Namen für LLM-Validierung (H3)
|
||||||
|
MINDNET_LLM_VALIDATION_HEADERS=Zu prüfende Links,Kandidaten,Edge Pool
|
||||||
|
MINDNET_LLM_VALIDATION_HEADER_LEVEL=3
|
||||||
|
|
||||||
|
# Eigene Header-Namen für Note-Scope Zonen (H2)
|
||||||
|
MINDNET_NOTE_SCOPE_ZONE_HEADERS=Globale Relationen,Note-Verbindungen,Smart Links
|
||||||
|
MINDNET_NOTE_SCOPE_HEADER_LEVEL=2
|
||||||
|
```
|
||||||
|
|
||||||
|
**Alternative:** Beide auf H2 setzen:
|
||||||
|
```env
|
||||||
|
MINDNET_LLM_VALIDATION_HEADER_LEVEL=2
|
||||||
|
MINDNET_NOTE_SCOPE_HEADER_LEVEL=2
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verwendung:**
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
type: decision
|
||||||
|
title: Meine Notiz
|
||||||
|
---
|
||||||
|
|
||||||
|
# Inhalt
|
||||||
|
|
||||||
|
## Globale Relationen
|
||||||
|
|
||||||
|
[[rel:depends_on|System-Architektur]]
|
||||||
|
|
||||||
|
### Zu prüfende Links
|
||||||
|
|
||||||
|
related_to:Mögliche Verbindung
|
||||||
|
```
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
**Q: Kann ich beide Zonen-Typen in einer Notiz verwenden?**
|
||||||
|
A: Ja, beide können gleichzeitig verwendet werden.
|
||||||
|
|
||||||
|
**Q: Was passiert, wenn ein Header in beiden Listen steht?**
|
||||||
|
A: Die Note-Scope Zone hat Vorrang (wird als Note-Scope behandelt).
|
||||||
|
|
||||||
|
**Q: Können Header-Namen Leerzeichen enthalten?**
|
||||||
|
A: Ja, Leerzeichen werden beibehalten.
|
||||||
|
|
||||||
|
**Q: Werden Header-Namen case-sensitive verglichen?**
|
||||||
|
A: Nein, der Vergleich ist case-insensitive.
|
||||||
|
|
||||||
|
**Q: Kann ich Header-Namen mit Sonderzeichen verwenden?**
|
||||||
|
A: Ja, Sonderzeichen werden automatisch für Regex escaped.
|
||||||
|
|
||||||
|
## Zusammenfassung
|
||||||
|
|
||||||
|
- ✅ **LLM-Validierung:**
|
||||||
|
- `MINDNET_LLM_VALIDATION_HEADERS` (Header-Namen, komma-separiert)
|
||||||
|
- `MINDNET_LLM_VALIDATION_HEADER_LEVEL` (Header-Ebene 1-6, Default: 3)
|
||||||
|
- ❌ **Nicht als Chunks angelegt** - nur Kanten werden extrahiert
|
||||||
|
- ✅ **Note-Scope Zonen:**
|
||||||
|
- `MINDNET_NOTE_SCOPE_ZONE_HEADERS` (Header-Namen, komma-separiert)
|
||||||
|
- `MINDNET_NOTE_SCOPE_HEADER_LEVEL` (Header-Ebene 1-6, Default: 2)
|
||||||
|
- ❌ **Nicht als Chunks angelegt** - nur Kanten werden extrahiert
|
||||||
|
- ✅ **Format:** Komma-separierte Liste für Header-Namen
|
||||||
|
- ✅ **Fallback:** Defaults werden verwendet, falls nicht konfiguriert
|
||||||
|
- ✅ **Case-insensitive:** Header-Namen werden case-insensitive verglichen
|
||||||
Loading…
Reference in New Issue
Block a user