Implement WP-24c v4.2.0: Introduce configurable header names and levels for LLM validation and Note-Scope zones in the chunking system. Update chunking models, parser, and processor to support exclusion of edge zones during chunking. Enhance documentation and configuration files to reflect new environment variables for improved flexibility in Markdown processing.
This commit is contained in:
parent
39fd15b565
commit
003a270548
|
|
@ -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)
|
||||||
|
def get_note_scope_zone_headers() -> List[str]:
|
||||||
|
"""
|
||||||
|
Lädt die konfigurierten Header-Namen für Note-Scope Zonen.
|
||||||
|
Fallback auf Defaults, falls nicht konfiguriert.
|
||||||
|
"""
|
||||||
|
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",
|
"Smart Edges",
|
||||||
"Relationen",
|
"Relationen",
|
||||||
"Global Links",
|
"Global Links",
|
||||||
"Note-Level Relations",
|
"Note-Level Relations",
|
||||||
"Globale Verbindungen"
|
"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:
|
||||||
|
|
|
||||||
|
|
@ -46,3 +46,18 @@ 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