14 KiB
Neutralisierung
Stand: 2026-04-16
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, FileFolder.neutralize, DataSource.neutralize, FeatureDataSource.neutralize, FeatureDataSource.neutralizeFields |
Dieses konkrete Objekt: Content daraus wird neutralisiert, egal ob die Feature-Instanz oder der Workflow es sonst fordern würden. FileFolder.neutralize propagiert auf alle enthaltenen Dateien. neutralizeFields ermoeglicht Feld-Level-Maskierung bei DB-Queries. |
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 (Tabelle) | Wenn eine FeatureDataSource.neutralize=True hat → Content aus diesem Sub-Agent-Call wird neutralisiert. |
mainServiceAgent._queryFeatureInstance setzt requireNeutralization=True |
| FeatureDataSource-Abfrage (Feld) | FeatureDataSource.neutralizeFields definiert Spalten, deren Werte in FeatureDataProvider mit deterministischen Platzhaltern [NEUT.<field>.<hash>] ersetzt werden, bevor Daten den Sub-Agent erreichen. |
featureDataProvider._applyFieldNeutralization |
| Ordner-Neutralisierung | FileFolder.neutralize=True propagiert auf alle enthaltenen Dateien (rekursiv). Neue/verschobene Dateien erben das Flag. Index-Purge + Re-Index wie bei einzelnen Dateien. |
routeDataFiles.updateFolderNeutralize |
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) / processImageAsync |
Bild-Datei oder Bild-ContentPart (image/png, image/jpeg, …) | Ist (seit ~2026 Q1) |
Ist-Zustand Bilder (aktualisiert 2026-04-05): processImageAsync ist implementiert und nutzt NEUTRALIZATION_IMAGE (Private LLM Vision). _processBinaryFile verarbeitet jetzt Bild-Parts ueber processImageAsync. Einschraenkung: Eigenstaendige Bild-Dateien (image/* MIME direkt an processFile) werden in _isBinaryMimeType weiterhin als Skip behandelt.
Ist (aktualisiert): processImageAsync existiert als 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.py — bereits erledigt.
Schritt 2: _shouldNeutralize vereinfachen
Datei: mainServiceAi.py (Zeile ~560)
Ist: Prüft request.requireNeutralization → context.requireNeutralization → NeutralizationConfig.enabled (Mandant-Level Config). request.requireNeutralization=False bricht sofort ab.
Soll: Drei Quellen gemäss Abschnitt 2, kein False-Override:
- Feature-Instanz:
NeutralizationConfig.enabled(hatfeatureInstanceId) - Workflow/Session:
context.requireNeutralization - 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=Truewar (Schritt 4) → nichts zu tun. - On-Demand Extraktion (Zeile ~630 ff.): Nach
runExtractionund vor Rückgabe der Text-Objekte:FileItem.neutralizeladen. WennTrue→ Text-Objekte durchprocessText, Bild-Objekte durchprocessImage.
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:
operationTypeaufNEUTRALIZATION_IMAGEstattIMAGE_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=True → indexFile → 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 2–9): Bei Neutralisierung loggen: welche Quelle (Feature-Instanz / Workflow / File-Flag), welche fileId falls vorhanden, Ergebnis (OK / Part entfernt / blockiert). Kein Klartext in Logs.