wiki/compliance/Neutralisierung.md
2026-03-29 21:55:05 +02:00

13 KiB
Raw Blame History

Neutralisierung

Stand: 2026-03-29


1. Grundidee

Neutralisierung passiert dort, wo Content entsteht oder ins System einfliesst — nicht als nachgelagerter Filter vor dem Modell-Call. Wenn Content einmal neutralisiert ist (z. B. im RAG), bleibt er neutralisiert. Kein doppeltes Verarbeiten.


2. Wer fordert Neutralisierung?

Drei Quellen, von breit nach spezifisch:

Quelle Flag im Code Bedeutung
Feature-Instanz DataNeutraliserConfig.enabled (hat featureInstanceId + mandateId) Alle Daten in dieser Feature-Instanz werden neutralisiert. Betrifft jeden Content-Einstieg innerhalb dieser Instanz.
Chat-Workflow / Session ServiceCenterContext.requireNeutralization (gesetzt z. B. vom AI-Workspace oder Automation) Dieser Workflow/Turn: jeder Content, der hier verarbeitet wird, wird neutralisiert.
Dokument oder Quelle FileItem.neutralize, DataSource.neutralize, FeatureDataSource.neutralize Dieses konkrete Objekt: Content daraus wird neutralisiert, egal ob die Feature-Instanz oder der Workflow es sonst fordern würden.

Auswertung: Irgendeine Quelle sagt True → neutralisieren. Keine Quelle kann eine andere aufheben. Es gibt kein False-Override, das ein True von woanders aushebelt.


3. Wo passiert die Neutralisierung?

Am Punkt der Content-Einspeisung — dort wo Rohdaten zu verarbeitbarem Content werden:

Content-Einstieg Was passiert Wer prüft das Flag
Datei-Indexierung (RAG) Text-Chunks werden über processText neutralisiert, bevor sie ins Embedding gehen. Medien: nur internes Modell oder nicht indexieren. Ergebnis: RAG enthält nur neutralisierten Content. mainServiceKnowledge.indexFile liest FileItem.neutralize
Content-Extraktion (Dokumente für KI-Verarbeitung) Extrahierter Text/Tabellen werden neutralisiert. PDF, DOCX, XLSX, PPTX über processFile (Extract → neutralisieren → zurückschreiben). Caller kennt die Quelle und deren Flag
User-Prompt (Chat-Eingabe) Prompt-Text wird durch processText neutralisiert, wenn Feature-Instanz oder Workflow es fordern. mainServiceAi prüft Context-Flag / Config
DataSource-Download Flag wird auf erstellte FileItems vererbt → bei Extraktion/Indexierung greift das File-Flag automatisch. mainServiceAgent._resolveDataSource / _downloadFromDataSource
FeatureDataSource-Abfrage Wenn eine FeatureDataSource.neutralize=True hat → Content aus diesem Sub-Agent-Call wird neutralisiert. mainServiceAgent._queryFeatureInstance setzt requireNeutralization=True
Workflow-Aktion neutralizeData Expliziter Neutralisierungs-Schritt auf bereits extrahierten ContentParts. Workflow-Config + NeutralizationConfig.enabled

Was NICHT nochmal neutralisiert werden muss:

  • RAG-Chunks, die bereits neutralisiert indexiert sind — die sind schon sauber.
  • Web-Suchergebnisse — enthalten keine Mandantendaten, brauchen keine Neutralisierung.

Flag-Änderung: Ändert sich FileItem.neutralize (Toggle) → Index löschen → Re-Indexierung triggern → neuer Index ist im richtigen Zustand.


4. Engine: NeutralizationService

Eine Engine, drei Einstiege, aufgerufen an den Content-Einstiegspunkten aus Abschnitt 3.

API Eingabe Status
processText(text) Rohtext (Prompt, Message, Text-ContentPart, Text-Chunk) Ist
processFile(fileId) Datei aus DB — wird nach MIME geroutet Ist
processBinaryBytes / Async Bytes + Dateiname + MIME Ist
processImage(imageBytes, fileName) Bild-Datei oder Bild-ContentPart (image/png, image/jpeg, …) Soll — fehlt heute

Ist-Zustand Bilder: _processBinaryFile überspringt Parts mit typeGroup == 'image' (unverändert durchgereicht). Eigenständige Bild-Dateien (image/* MIME) werden in _isBinaryMimeType als Skip behandelt. Es gibt keinen Bild-Neutralisierungs-Pfad.

Soll: processImage als eigener Einstieg. Ruft internes Vision-Modell (NEUTRALIZATION_IMAGE → Private-LLM) auf, um sensible Inhalte in Bildern zu erkennen/entfernen. Kein externer Provider. Modell nicht verfügbar → Bild blockieren (nicht unbehandelt weiterreichen).

Ablauf nach MIME:

MIME Pfad
PDF, DOCX, XLSX, PPTX runExtraction → Text/Table-Parts durch _neutralizeText, Bild-Parts durch processImage → PDF in-place oder Office-Renderer
Text, JSON, CSV, XML _neutralizeText direkt (TextProcessor, ListProcessor, BinaryProcessor je nach Inhalt)
Bilder (image/*) processImage → internes Vision-Modell (NEUTRALIZATION_IMAGE). Nicht verfügbar → blockieren.
Video, Audio Nur internes Modell oder blockieren (analog Bilder, aber niedrigere Priorität)
Anderes Binary Skip (nicht unterstützt)

Mapping: Platzhalter [typ.uuid] → Attribute in DB. resolveText(text) für Rückübersetzung.


5. Modellauswahl

Operation Type Modelle Zweck
NEUTRALIZATION_TEXT poweron-text-general (Rating 9) Falls Engine ein LLM für Text braucht
NEUTRALIZATION_IMAGE poweron-vision-general (9), poweron-vision-deep (9) Medien bei Neutralisierungspflicht: nur intern

Registriert in aicorePluginPrivateLlm.py. Externe Provider haben keine NEUTRALIZATION_*-Ratings → werden nie für Neutralisierung gewählt.


6. Fail-safe

Situation Verhalten
Neutralisierung gefordert, Engine nicht verfügbar Content nicht weiterverarbeiten (blockieren)
Neutralisierung eines Teils schlägt fehl Teil entfernen, nicht im Rohzustand weiterleiten
Kein internes Modell für Medien verfügbar Medien-Part entfernen

7. Code-Karte

Bereich Pfad
Engine features/neutralization/serviceNeutralization/mainServiceNeutralization.py + subProcess*.py
Config + Attribute DB features/neutralization/datamodelFeatureNeutralizer.py, interfaceFeatureNeutralizer.py
Index (Data-at-rest) serviceCenter/services/serviceKnowledge/mainServiceKnowledge.py
Prompt-Neutralisierung serviceCenter/services/serviceAi/mainServiceAi.py (_shouldNeutralize, _neutralizeRequest)
Agent / DataSource / Feature serviceCenter/services/serviceAgent/mainServiceAgent.py
Workflow-Aktion workflows/methods/methodContext/actions/neutralizeData.py
Modelle / Enums datamodels/datamodelAi.py, aicore/aicorePluginPrivateLlm.py
Flags datamodelFiles.py (FileItem.neutralize), datamodelDataSource.py, datamodelFeatureDataSource.py
Context serviceCenter/context.py (ServiceCenterContext.requireNeutralization)

8. Umsetzungsplan

Schritt 1: processImage in Engine bauen

Datei: mainServiceNeutralization.py
Was: Neue Methode processImage(imageBytes: bytes, fileName: str, mimeType: str) -> Dict und processImageAsync.
Wie: Internes Vision-Modell aufrufen (NEUTRALIZATION_IMAGE via Model Selector / aiObjects). Prompt: sensible Inhalte im Bild erkennen und beschreiben, damit Caller entscheiden kann ob Bild blockiert wird. Kein internes Modell verfügbar → {'status': 'blocked'} zurückgeben.
Abhängigkeit: OperationTypeEnum.NEUTRALIZATION_IMAGE + Modell-Ratings in aicorePluginPrivateLlm.pybereits erledigt.

Schritt 2: _shouldNeutralize vereinfachen

Datei: mainServiceAi.py (Zeile ~560)
Ist: Prüft request.requireNeutralizationcontext.requireNeutralizationNeutralizationConfig.enabled (Mandant-Level Config). request.requireNeutralization=False bricht sofort ab.
Soll: Drei Quellen gemäss Abschnitt 2, kein False-Override:

  1. Feature-Instanz: NeutralizationConfig.enabled (hat featureInstanceId)
  2. Workflow/Session: context.requireNeutralization
  3. Request: request.requireNeutralization

Irgendein True → neutralisieren. False in einer Quelle hebt True in einer anderen nicht auf.
Änderung: if request.requireNeutralization is False: return False entfernen. Stattdessen OR-Verknüpfung aller drei Quellen.

Schritt 3: _neutralizeRequest auf Prompt/Messages beschränken

Datei: mainServiceAi.py (Zeile ~592)
Ist: Neutralisiert prompt, context, messages (String-Content).
Soll: Zusätzlich Text in contentParts und Text-Teile in multimodalen Messages (content-Liste mit type==text). Bild-Teile in Messages: bei Neutralisierungspflicht über processImage prüfen oder entfernen.
Wichtig: Hier geht es nur um Prompt-/Sessiondaten. File-Content aus RAG ist bereits neutralisiert (Schritt 5), muss hier nicht nochmal durch.

Schritt 4: indexFile — Bild-Chunks behandeln

Datei: mainServiceKnowledge.py (Zeile ~146 ff.)
Ist: Nur textObjects (contentType == "text") werden bei _shouldNeutralize durch processText geschickt. Bild-Chunks (contentType == "image") werden unverändert indexiert.
Soll: Bild-Chunks bei _shouldNeutralize über processImage (Schritt 1) prüfen. Ergebnis blocked → Bild-Chunk nicht indexieren. Ergebnis OK → Bild-Chunk indexieren (internes Modell hat es gesehen, kein externer Provider nötig).
Abhängigkeit: Schritt 1.

Schritt 5: Agent-Tool readFile — Content bei Extraktion neutralisieren

Datei: mainServiceAgent.py, Tool _readFile (Zeile ~540 ff.)
Ist: Liest aus Knowledge Store (bereits indexiert) oder extrahiert on-demand. Kein Neutralisierungs-Check.
Soll:

  • Knowledge Store Pfad (Zeile ~548): RAG-Chunks sind bereits neutralisiert wenn FileItem.neutralize=True war (Schritt 4) → nichts zu tun.
  • On-Demand Extraktion (Zeile ~630 ff.): Nach runExtraction und vor Rückgabe der Text-Objekte: FileItem.neutralize laden. Wenn True → Text-Objekte durch processText, Bild-Objekte durch processImage.

Schritt 6: Agent-Tool summarizeContent — File-Flag prüfen

Datei: mainServiceAgent.py, Tool _summarizeContent (Zeile ~1921 ff.)
Ist: Liest Content-Objects aus Knowledge Store, baut combinedText und ruft callAi auf. Kein Neutralisierungs-Check.
Soll: Content aus Knowledge Store ist bereits neutralisiert (Schritt 4) → nichts zu tun, sofern File indexiert war. Wenn nicht indexiert: File-Flag prüfen, Text vor callAi durch processText.
Hinweis: Durch Schritt 4 ist der Regelfall abgedeckt.

Schritt 7: Agent-Tool describeImage — File-Flag prüfen

Datei: mainServiceAgent.py, Tool _describeImage (Zeile ~2015 ff.)
Ist: Lädt Bild-Chunk oder Rohdaten, sendet per callAi mit IMAGE_ANALYSE an beliebigen Provider (inkl. extern). Kein Neutralisierungs-Check.
Soll: FileItem.neutralize laden (fileId ist bekannt). Wenn True:

  • operationType auf NEUTRALIZATION_IMAGE statt IMAGE_ANALYSE → Model Selector wählt nur internes Modell.
  • Kein internes Modell → Tool gibt Fehler zurück statt Bild an externen Provider zu senden.

Schritt 8: _processBinaryFile — Bild-Parts nicht mehr überspringen

Datei: mainServiceNeutralization.py (Zeile ~298)
Ist: if type_group in ('binary', 'image'): neutralized_parts.append(part); continue — Bild-Parts werden übersprungen.
Soll: binary weiterhin skip. image → durch processImage (Schritt 1). Ergebnis blocked → Part entfernen. Ergebnis OK → Part behalten.
Abhängigkeit: Schritt 1.

Schritt 9: Workflow-Aktion neutralizeData — Bild-Parts

Datei: neutralizeData.py (Zeile ~130 ff.)
Ist: Iteriert über ContentParts, neutralisiert nur Parts mit part.data (Text). typeGroup != text/table → unverändert durchgereicht.
Soll: Bild-Parts durch processImage. Ergebnis blocked → Part entfernen.
Abhängigkeit: Schritt 1.

Schritt 10: Tests

Test Was
T1 FileItem.neutralize=TrueindexFile → Text-Chunks neutralisiert, Bild-Chunks geprüft/blockiert
T2 readFile on-demand auf File mit neutralize=True → Text neutralisiert
T3 describeImage auf File mit neutralize=True → nur internes Modell
T4 Feature-Instanz Config enabled=True → Prompt in callAi neutralisiert
T5 Workflow requireNeutralization=True → Prompt neutralisiert
T6 processFile auf PDF mit Bildern → Text neutralisiert, Bild-Parts durch processImage
T7 Flag-Toggle → Index gelöscht → Re-Index im richtigen Zustand

Schritt 11: Logging

Alle Stellen (Schritte 29): Bei Neutralisierung loggen: welche Quelle (Feature-Instanz / Workflow / File-Flag), welche fileId falls vorhanden, Ergebnis (OK / Part entfernt / blockiert). Kein Klartext in Logs.