This commit is contained in:
team3
2026-06-29 01:46:34 +02:00
parent bf7ebe045b
commit 753b95b689
2 changed files with 34 additions and 1 deletions

View File

@@ -23,7 +23,7 @@ from pathlib import Path
import database as db
import embedding
from agents import kill_process, cancel_scope, clear_scope, run_agent
from config import KONSENS_GRACE, RECHERCHE_GRACE, KONSENS_MAX_RUNDEN, DEFAULT_PROVIDER, CRAWL_KEEP_PATTERNS, CRAWL_NOISE_PATTERNS, CRAWL_MIN_CHARS, QUELLE_RELEVANZ_CHUNK, QUELLE_RELEVANZ_SNIPPET, EMBEDDING_AKTIV
from config import KONSENS_GRACE, RECHERCHE_GRACE, KONSENS_MAX_RUNDEN, DEFAULT_PROVIDER, CRAWL_KEEP_PATTERNS, CRAWL_NOISE_PATTERNS, CRAWL_MIN_CHARS, QUELLE_RELEVANZ_CHUNK, QUELLE_RELEVANZ_SNIPPET, EMBEDDING_AKTIV, EMBEDDING_SUB_DUP
from fsutil import atomic_write_text, atomic_write_json
from jsonio import read_json_file as _json_datei
from paths import arbeit_dir, bausteine_path, frage_muster_path, project_dir, subbausteine_path, quelle_path, quelle_crawl_dir, safe_ordner
@@ -845,12 +845,41 @@ async def _subbausteine_block(ctx: GenContext, set_p, files: dict, entries: dict
if sn and sn not in have:
await db.upsert_subbaustein(topic, norm_by_num[num], sn, titel, s)
await db.set_subbaustein_felder(topic, norm_by_num[num], sn, status="konsens")
await _dedup_subbausteine(topic, roh) # Near-Dup-Filter je Baustein (deterministisch, kein LLM)
if not roh:
_bausteine_errors[topic] = "Keine Subbausteine ermittelt"
return None
return roh
async def _dedup_subbausteine(topic: str, roh: dict[str, list[str]]) -> None:
"""Deterministischer Near-Duplicate-Filter pro Baustein: Subbausteine mit Cosine ≥
EMBEDDING_SUB_DUP sind dieselbe Aussage (im engen Baustein-Kontext zuverlässig — kein LLM
nötig). Behält je Dublett-Gruppe den informativsten (längsten); Rest → DB verworfen + aus `roh`.
Modell fehlt → still überspringen (wie der übrige Embedding-Fallback)."""
if not EMBEDDING_AKTIV or not await asyncio.to_thread(embedding.verfuegbar):
return
for titel, subs in list(roh.items()):
if len(subs) < 2:
continue
sims = await asyncio.to_thread(embedding.embed_sims, subs)
if sims is None:
return
behalten: list[int] = []
verworfen: list[int] = []
for i in sorted(range(len(subs)), key=lambda x: (-len(subs[x]), x)): # informativster zuerst
if any(float(sims[i][j]) >= EMBEDDING_SUB_DUP for j in behalten):
verworfen.append(i)
else:
behalten.append(i)
if not verworfen:
continue
bnorm = _norm_titel(titel)
for i in verworfen:
await db.set_subbaustein_felder(topic, bnorm, _norm_titel(subs[i]), status="verworfen")
roh[titel] = [subs[i] for i in sorted(behalten)] # Original-Reihenfolge der Behaltenen
async def _stufen_block(ctx: GenContext, set_p, files: dict, roh: dict, instructions: str) -> dict | None:
"""Block C: drei Phasen mit Barriere — Finden (einstufen), Wählen (Vote), Klären.
Lokale IDs 1..n pro Paket, hinterher auf globale gid gemappt.

View File

@@ -37,6 +37,10 @@ EMBEDDING_MODELL = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
# LLM-Listen kurz und stabil (belegt: Embedding-Block + LLM-Judge ≈ 95 % Precision).
EMBEDDING_BLOCK_FLOOR = 0.5 # Mindest-Cosine, damit zwei Kandidaten in EINEN Block dürfen
EMBEDDING_BLOCK_CAP = 25 # max. Titel je Block (LLM-Liste kurz/stabil halten)
# Subbaustein-Dedup: rein deterministisch (kein LLM). Subbausteine sind kurze Aussagen IM SELBEN
# Baustein-Kontext — ab dieser Cosine sind zwei dieselbe Aussage (an aak geprüft: ≥0,88 ausnahmslos
# echte Dubletten). Konservativ 0,90, damit verschiedene Aspekte (∈NP ≠ NP-schwer) getrennt bleiben.
EMBEDDING_SUB_DUP = 0.90
# Deckel für gleichzeitige CLI-Agenten-Prozesse (über alle Generierungen hinweg).
# Eigene Spur für interaktive Aufrufe (Chat, Elemente), damit sie nicht hinter