Files
breakpilot-compliance/docs-src/development/rag_reingest_spec.md
T
Benjamin Admin 017c9b3c12 feat(advisor): Legal-RAG Zitier-Metadaten — ai-sdk + Advisor/Drafting lesen article_label
ai-sdk (legal_rag_client/scroll/types) liest die gepinnten Spec-Felder
article_label/regulation_code/article/paragraph/sub/citation_style/is_recital
mit Fallback auf alt-ingestierte Chunks (regulation_id, section); neuer getBool-Helfer.
Advisor + Drafting-Engine bilden die Quellenzeile primaer aus article_label
("BDSG § 38 Abs. 1"), sonst aus den strukturierten Feldern. 17 Tests gruen, tsc sauber.
Vertrag: docs-src/development/rag_reingest_spec.md (§2/§7). Deploy an den Re-Ingest
gekoppelt — neue Felder sind bis dahin leer (graceful Fallback).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-20 14:34:15 +02:00

9.1 KiB

RAG Re-Ingest-Spezifikation — Zitierfähige Chunks (Cross-Session-Vertrag)

Status: v1 — Vertrag zwischen core-Session (Ingestion/Pipeline) und compliance-Session (Consumer: ai-sdk/Advisor). Datum: 2026-06-19 Ziel: Chunks neu ingestieren mit sauberem Text + vollständigen Legal-Metadaten, damit Controls/Findings zitierfähig werden ("BDSG § 38 Abs. 1", "Art. 13 Abs. 1 lit. c DSGVO") — ohne die teuren Pass 0a/0b/Dedup.

Controls hängen an control_uuid, nicht an Chunks (canonical_controls hat keine chunk_id/chunk_hash-Spalte; ebenso atom_classification, control_classification, doc_check_controls). Ein Chunk-Re-Ingest bricht keine Control. Das einzige stale-werdende Artefakt ist das Idempotenz-Ledger compliance.canonical_processed_chunks (Key sha256(text)+collection+document_version) — relevant nur für zukünftige Generierung.

Pass 0a/0b/Dedup entfallen. Stattdessen werden Controls per Textabgleich an die neuen Chunks re-gelinkt (Zitat-Anreicherung). Reichweite:

  • 7 % der 315.914 Controls haben source_original_text (Re-Link-Anker) → direkter Abgleich.
  • ~93 % Atome erben das Zitat über parent_control_uuid.
  • self-written brauchen kein Chunk-Zitat (eigene Bibliothek).
  • unmatched Reste → billiges per-Control-LLM-Zitat (Tier-3), keine Regenerierung.

1. Ingestion-Anforderungen (Frage 2)

  1. chunk_strategy="legal" EXPLIZIT setzen. (Korrektur zur Historie: recursive aliased inzwischen auf chunk_text_legal, embedding-service/main.py:1079/1093, live-verifiziert — Upload mit recursive lieferte section:"§ 38", paragraph:"(1)", paragraph_num:1. Trotzdem legal explizit, nicht aufs Alias verlassen.)
  2. Deterministische Chunk-ID (heute random) = sha1(regulation_code|article|paragraph|chunk_index|document_version) → stabiler Re-Link + Alt/Neu-Koexistenz.
  3. chunk_hash IN die Payload schreiben (heute nur im PG-Ledger) = sha256(normalisierter chunk_text).
  4. Echte document_version (heute hardcoded "1.0") → Re-Chunk kollidiert sonst im Ledger.
  5. Upload-before-delete je Collection (alte Chunks erst nach Verify löschen).

2. PAYLOAD-FELD-VERTRAG (verbindlich — Consumer liest GENAU diese Namen)

Die ai-sdk/Advisor liest die consumer-facing Felder. Ingestion füllt alle.

Feld Typ Consumer Beschreibung / Beispiel
article_label string JA (Anzeige) Fertig formatiert, direkt druckbar. "BDSG § 38 Abs. 1" · "Art. 13 Abs. 1 lit. c DSGVO". Ingestion formatiert (kennt §- vs Art.-Stil).
regulation_code string JA Kurzcode, UPPERCASE: BDSG,DSGVO,TTDSG,DDG,CRA,NIS2
citation_style enum JA paragraph (§-Gesetze) | article (EU-Verordnungen) — steuert §/Art.-Rendering, falls Consumer selbst formatiert
article string JA bare Nummer: "38" bzw. "13" (egal ob § oder Art.)
paragraph string JA bare Absatz: "1" (nicht "(1)")
sub string|null JA feinste Granularität: "lit. c" · "Satz 2" · "Nr. 3"
is_recital bool JA Erwägungsgrund vs operativer Artikel
regulation_name string optional Volltext: "Bundesdatenschutzgesetz"
page int|null optional Seite (PDF-Quellen)
chunk_text string JA sauberer Text (keine Soft-Hyphens/OCR-Reste)
section_header string optional Kontext-Überschrift, separat (nicht inline im chunk_text)
chunk_id string deterministisch (s. §1.2)
chunk_hash string sha256(normalisierter Text)
document_id, document_version, chunk_index Identität/Versionierung
doc_type, use_case[], source_type, license, bundesland, year Scope Routing/Scope (source_type: gesetz/leitlinie/urteil)

Verbindlich: article_label ist der bevorzugte Anzeige-Pfad (Ingestion ownt die Zitat-Formatierung, weil sie die Regulierung kennt). Die strukturierten Teile (regulation_code/article/paragraph/sub) sind zusätzlich für Filtern/Gruppieren da.

3. Normalisierung alt → neu (core-seitiger Transform)

Der legal-Chunker emittiert heute uneinheitlich; Ingestion normalisiert:

heute (raw payload) → neu
section = "§ 38" / "Artikel 13" citation_style (§→paragraph, Art/Artikel→article) + article="38"/"13"
section_title section_header
paragraph="(1)" / paragraph_num=1 paragraph="1"
(lit./Satz/Nr. aus _PARAGRAPH_RE) sub (best-effort)
regulation_id/regulation_short (extra_metadata) regulation_code (UPPERCASE)
article_label (formatiert aus regulation_code+style+article+paragraph+sub)

article_label-Formatierung:

  • paragraph-Stil: "{regulation_code} § {article} Abs. {paragraph}" (+ " {sub}")
  • article-Stil: "Art. {article} Abs. {paragraph} {sub} {regulation_code}"

Erweiterung von control-pipeline/services/citation_backfill.py (heute 3-Tier, Tier-1 = sha256(source_original_text) → Chunk-Hash-Index): Tier-1 bricht beim Re-Chunk (neuer Text → neuer Hash) → Fuzzy/Embedding-Alignment ergänzen (source_original_text ↔ neue Chunk-Texte, Substring + Cosine). Präzedenz: PDF-QA-Matcher (~52 % Trefferquote). Füllt canonical_controls.source_citation = {regulation_code, article, paragraph, sub, page, source_type, license, url}. Atome erben über parent_control_uuid. doc_check_controls re-derivieren danach automatisch zitierfähig (derive_doc_check_controls.py liest source_citation->>'article'/'source').

Beim künftigen Generieren IMMER source_original_text setzen (warum heute nur 7 % re-linkbar sind).

5. Pipeline-Reihenfolge

  1. Re-Ingest je Collection: strategy="legal", deterministische IDs, neue document_version, normalisierte Payload + chunk_hash.
  2. Verify: Zähler alt/neu + Stichprobe article/paragraph/article_label befüllt.
  3. Re-Link (citation_backfill erweitert) → source_citation; Atome erben.
  4. Reste → Tier-3-LLM-Zitat.
  5. Alte Chunks löschen.
  6. (optional, nur für künftige Generierung) Ledger canonical_processed_chunks neu aufbauen.

6. Arbeitsteilung + Akzeptanz

core-Session: Ingest-Spec umsetzen, citation_backfill Hash→Fuzzy→Embedding, Payload-Normalisierung (§3), deterministische IDs/chunk_hash/document_version, AGG-Lücke.

compliance-Session (Consumer): ai-sdk legal_rag_client.go + Advisor/Drafting auf die §2-Feldnamen ummappen (kein Deploy vor Pin — jetzt gepinnt), Prod-Qdrant-Verify, 6-Fragen-Re-Test (sind §38 BDSG / AGG / CRA Art. 14 grounded zitiert?).

Akzeptanzkriterium: Advisor rendert für eine Beispielfrage eine echte Fundstelle aus article_label (z. B. "BDSG § 38 Abs. 1"), nicht nur "Quelle: BDSG".

7. Consumer-Detailabschnitt (compliance-Session — implementiert 2026-06-19)

Status: Code steht + getestet (17 Tests grün, tsc sauber). Deploy gekoppelt an den Re-Ingest (liest bis dahin leere Felder → graceful, Advisor zeigt wie heute "Quelle: BDSG").

Response-Feld (JSON) gelesen aus Payload Fallback (alt-Korpus)
article_label article_label — (leer → Consumer baut selbst)
regulation_code regulation_code regulation_id
article article section ("§ 38")
paragraph paragraph
sub sub
citation_style citation_style
is_recital is_recital (bool)
text chunk_text
regulation_name regulation_name_de
regulation_short regulation_short
category,pages,source_url,score category,pages,source,(score)

/sdk/v1/rag/search liefert diese Felder snake_case. Neuer Bool-Helfer getBool ergänzt.

7.2 Advisor + Drafting: Fundstellen-Format

Beide Konsumenten (admin-compliance/lib/sdk/agents/advisor-rag.ts, .../drafting-engine/rag-query.ts) bilden die Quellenzeile so:

source = article_label?.trim()                                   // bevorzugt: druckbar aus Ingestion
       || [regulation_short|regulation_name|regulation_code, article, paragraph, sub]
            .filter(Boolean).join(' ')                            // Fallback: strukturiert zusammensetzen
       || 'Unbekannt'
Ausgabe je Treffer:  [Quelle N: {source}]\n{text}

→ Der Advisor druckt article_label direkt (kein §-vs-Art-Ableiten); citation_style nur nötig, falls wir später selbst formatieren. Erfüllt das Akzeptanzkriterium (§6): "BDSG § 38 Abs. 1" statt nur "Quelle: BDSG".

7.3 Deploy-Kopplung

Code ist additiv/safe (neue Felder leer bis Re-Ingest). Kein Solo-Deploy — geht mit dem Re-Ingest-Go-Live live, danach 6-Fragen-Re-Test auf prod (§38/AGG/CRA Art. 14 grounded zitiert?).

8. Offen (core)

  • AGG-Lücke: Quelle (§ 15 Abs. 4 — Bewerberdaten-Frist) zu spezifizieren + ingestieren.
  • Soft-Hyphen/OCR-Normalisierung des chunk_text — Regelsatz definieren.