Direkt zum Hauptinhalt

Konfigurationsreferenz

Der Standalone-Host (MesoAibe.Service) bindet den Abschnitt Aibe aus appsettings.json (Beispiel: MesoAibe.Service/appsettings.json) auf AibeServiceKonfiguration. Die globalen Aibe:Ki-Zugaenge (Extraktion/Embedding/Rerank) gelten fuer alle Mandanten; Aibe:Mandanten traegt je Eintrag genau einen Mandanten mit seiner Beleganlage-Staffel, seinen Belegfeldern, optional Fremdsprachen-Mapping und kundenspezifischen Artikelaufloesungen, seinem WebService-Zugang und seinen Postfaechern.

{
  "ConnectionStrings": {
    "WinLineXPOSystemConnection": "XpoProvider=MSSqlServer;Server=<SERVER>;Database=CWLSYSTEM;..."
  },
  "Aibe": {
    "IntervallSekunden": 60,
    "Ki": {
      // Cloud-Variante; fuer lokale Modelle stattdessen ExtraktionBaseUrl/RerankBaseUrl setzen
      // (siehe Abschnitt "KI-Zugaenge") oder DOTNET_ENVIRONMENT=Demo verwenden.
      "AnthropicApiKey": "<ANTHROPIC_API_KEY>",
      "ExtraktionModel": "claude-opus-4-8",
      "EmbeddingBaseUrl": "https://api.openai.com/v1",
      "EmbeddingApiKey": "<EMBEDDING_API_KEY>",
      "EmbeddingModel": "text-embedding-3-small",
      "RerankModel": "claude-opus-4-8"
    },
    "Mandanten": [
      {
        "Mandant": "500M",
        "VkVorlage": "WS_Auftrag",
        "Anlage": { "AnlegenAbKonfidenz": 60, "DruckenAbKonfidenz": 80, "DruckOption": "PrintAsOrder" },
        "WebService": { "MesonicServerUrl": "http://<MESONIC_SERVER>:80", "Benutzer": "meso", "Passwort": "<MESONIC_PASSWORT>" },
        "Postfaecher": [
          { "Typ": "Ordner", "Quelle": "./eingang", "MaxProLauf": 10, "VerarbeitetOrdner": "Verarbeitet", "FehlerOrdner": "Fehler" }
        ]
      }
    ]
  }
}

Globale Dienst-Einstellungen (Aibe)

Direkt unter Aibe (nicht unter Aibe:Mandanten[]) gelesen, ausserhalb der AibeServiceKonfiguration-Bindung — siehe MesoAibe.Service/Program.cs:

Feld Bedeutung
LogOrdner Zielordner der rollierenden Logdatei (mesoaibe-.log, taeglich neu). Default "logs" (relativ zum Programmverzeichnis).
LogLevel Minimales Serilog-Log-Level (Verbose|Debug|Information|Warning|Error|Fatal). Ungueltiger oder fehlender Wert faellt auf "Information" zurueck. Debug schaltet zusaetzlich die LLM-Requests und -Antworten frei (siehe unten). Das Hosting-Framework (Microsoft.*) ist fest auf Warning gedaempft, damit Debug benutzbar bleibt.
IntervallSekunden Abstand zwischen zwei Verarbeitungslaeufen aller Mandanten/Postfaecher. Default 60.
StammdatenCacheMinuten Wie lange Artikel, Preise und Ersatznummern je Mandant zwischengespeichert werden, bevor sie neu aus der Datenbank gelesen werden. Ohne Angabe 5 Minuten, 0 liest bei jedem Zugriff neu. Bis zum Ablauf ist eine frisch in WinLine angelegte Artikelnummer für alle Matching-Stufen unsichtbar, auch für die Fuzzy- und Nummernstufen, die gar nicht am Embedding-Index hängen. Kürzer setzen, wenn Stammdaten häufig während des Betriebs geändert werden — jeder Ablauf kostet einen erneuten Katalog-Load.

Protokollierung

Je verarbeitetem Dokument entsteht ein abgegrenzter Block: eine Kopfzeile mit Mandant und Kurzbezeichner (Betreff und Absender — nicht der technische Dateiname, der bei Graph-Postfaechern die rund 150 Zeichen lange Message-ID ist), darunter die sechs Schritte mit Ergebnis und Dauer:

────────────────────────────────────────────────────────────
500M  "Bestellung 4711" von Austria Sports
  1/6 Extraktion      2 Position(en)  (12,4 s)
                      genannt: Partnernr=10004, Name=Austria Sports
  2/6 Kunde           10004 Austria Sports GmbH [Kundennummer, 95]  (0,1 s)
  3/6 Artikel         2 von 2 Position(en) zugeordnet  (3,8 s)
                      1. 3 x Laufschuh Pro 42 -> ART-1042 [Embedding+Rerank, 91]
                      2. 1 x ART-7788 -> ART-7788 [Artikelnummer, 100]
  4/6 Ansprechpartner 7 (Rerank ueber Absendername, 4 Kandidat(en))  (1,9 s)
  5/6 Anreicherung    1 Hinweis(e)  (0,2 s)
                      Offenes Angebot AN-2291 passt zu dieser Bestellung: Bestellreferenz
  6/6 Entscheid       Gesamt-Konfidenz 93 -> AnlegenUndDrucken
                      WS-Import-XML -> ...\20260829_104812_123_bestellung_10004.xml
                      WinLine-Beleg angelegt: Belegnummer 100234
                      Bericht -> ...\20260829_104812_123_bestellung_10004.txt
────────────────────────────────────────────────────────────

Die Schrittzeilen tragen bewusst keinen eigenen Bezeichner. Das ist zulaessig, weil der AibeWorker Dokumente strikt sequentiell abarbeitet — eine spaetere Parallelisierung muesste den Bezeichner wieder je Zeile setzen.

Leerlauf (keine neuen Nachrichten) liegt auf Debug und flutet das Log damit nicht mehr im Abfrageintervall.

LLM-Requests und -Antworten erscheinen bei "LogLevel": "Debug". Bei einem OpenAI-kompatiblen Endpunkt ist das der tatsaechlich gesendete Request-Body; beim Claude-Client der fachliche Request (Modell, Inhaltsbloecke, Prompt, Schema), weil das Anthropic-SDK den Wire-Body nicht herausgibt. Beide Texte werden bei 4000 Zeichen gekuerzt. Voraussetzung ist MesoXPO.Business ab der Version, die das Prompt-Logging mitbringt.

KI-Zugaenge (Aibe:Ki)

Gelten fuer alle Mandanten. Alle drei Stufen koennen wahlweise gegen die Cloud oder gegen einen OpenAI-kompatiblen Endpunkt (Ollama, vLLM, LM Studio ...) laufen:

Feld Bedeutung
AnthropicApiKey Key fuer Claude — versorgt Extraktion und Rerank, wenn keine BaseUrl gesetzt ist.
ExtraktionBaseUrl OpenAI-kompatibler Chat-Endpunkt fuer die Extraktion. Gesetzt gewinnt sie vor AnthropicApiKey.
ExtraktionApiKey Key fuer ExtraktionBaseUrl; leer lassen, wenn der Endpunkt keinen verlangt.
ExtraktionModel Modellname. Default claude-opus-4-8. Bei gesetzter ExtraktionBaseUrl zwingend auf das lokale Modell setzen.
MaxTokens Obergrenze der Antwort-Tokens je Extraktionsaufruf. Default 16384 (Bibliothek ab 4.79-beta34; davor 4096); 0 oder fehlend behaelt den Default. Das Extraktionsschema traegt je Position alle Felder, rund 100 Tokens je Position — 4096 reichten im Pilot fuer 60 Positionen nicht. Eine abgeschnittene Antwort meldet der Dienst als Extraktionsfehler MaxTokens erreicht.
PdfImmerUeberOcr Schickt PDFs auch beim Claude-Client ueber den Text-/OCR-Aufbereiter, statt sie nativ hochzuladen — die Option fuer "Cloud-Modell nutzen, Dokument aber nicht hochladen". Default false; bei gesetzter ExtraktionBaseUrl ohne Wirkung, weil dieser Pfad dort ohnehin gilt.
PdfAlsBildFuerExtraktion Rendert PDFs auf dem lokalen Extraktionspfad (ExtraktionBaseUrl gesetzt oder PdfImmerUeberOcr) seitenweise zu PNG-Bildern (PdfZuBildAufbereiter/DocnetPdfBildQuelle, MesoAibe.Core) und schickt sie einem Vision-faehigen Modell, statt sie ueber den (siehe unten) unwirksamen Tesseract-OCR-Pfad in Text zu wandeln. Erfordert ein Vision-faehiges ExtraktionModel (z.B. qwen2.5vl ueber Ollama). Ohne ExtraktionBaseUrl/PdfImmerUeberOcr (reine Claude-Extraktion, liest PDF nativ) ohne Wirkung. Default false.
PositionsanzahlPruefen Plausibilitaetspruefung der Positionsanzahl: ein zweiter, kleiner LLM-Aufruf zaehlt die Bestellpositionen im Dokument. Weicht die Zaehlung von der extrahierten Anzahl ab, wird einmal neu extrahiert; passt es dann nicht, gilt das Dokument als Extraktionsfehler (Fehlerordner, manuelle Pruefung) statt als verkuerzter Beleg in die Anlage zu gehen. Hintergrund: im Pilot kam eine 60-Positionen-Bestellung einmal als eine Position zurueck. Default true.
PositionsanzahlToleranz Erlaubte Abweichung zwischen gezaehlter und extrahierter Positionsanzahl, z.B. 1 bei Bestellungen mit Fracht- oder Summenzeilen, die das Modell mal zaehlt und mal nicht. Default 0.
EmbeddingBaseUrl OpenAI-kompatibler Embedding-Endpunkt (/embeddings).
EmbeddingApiKey Key fuer den Embedding-Endpunkt. Darf nicht leer sein — sonst gilt die Embedding-Stufe als unkonfiguriert und das Artikelmatching faellt still auf die reine Kaskade zurueck. Bei Endpunkten ohne Key-Pflicht (Ollama) einen beliebigen Dummy eintragen.
EmbeddingModel Modellname der Embedding-Erzeugung.
RerankBaseUrl OpenAI-kompatibler Chat-Endpunkt fuer die Rerank-Stufe. Gesetzt gewinnt sie vor AnthropicApiKey.
RerankApiKey Key fuer RerankBaseUrl; leer lassen, wenn der Endpunkt keinen verlangt.
RerankModel Modellname der Rerank-Stufe. Default claude-haiku-4-5-20251001nicht identisch mit ExtraktionModel; wer den Schluessel weglaesst, faehrt anders als wer das Beispiel oben kopiert. Bei gesetzter RerankBaseUrl zwingend auf das lokale Modell setzen.

Stellschrauben der Semantik-Stufe (Aibe:Ki, optional)

Diese Schlüssel stehen nicht in der ausgelieferten appsettings.json — sie sind Feinjustierung, und ein dort eingefrorener Wert würde spätere Verbesserungen der Bibliotheks-Defaults blockieren. Wer einen Schlüssel weglässt, fährt den Default; wer ihn setzt, übersteuert ihn.

Schlüssel Bedeutung Default
MinAehnlichkeit Mindest-Kosinusähnlichkeit, unter der ein Embedding-Kandidat verworfen wird. Modellabhängig — siehe Hinweis unten. 0.35
AutoAcceptKonfidenz Ab dieser Konfidenz gilt ein Treffer als sicher und löst keinen Rerank aus. 90
AmbiguitaetsAbstand Mindestabstand zwischen bestem und zweitbestem Kandidat, sonst gilt das Ergebnis als mehrdeutig. 10
RerankBestaetigtKonfidenz Konfidenz, auf die ein vom Rerank bestätigter Treffer gehoben wird. 90
MaxRerankKandidaten Wie viele Kandidaten je Position an das Rerank-Modell gehen. 5
IndexTtl Gültigkeitsdauer des im Speicher gehaltenen Vektorindex, z.B. "00:05:00". 5 Minuten
IndexFehlerSperre Sperrzeit nach einem fehlgeschlagenen Index-Aufbau, z.B. "00:02:00". 2 Minuten
IndexZwischenspeicherAlle Blockgröße beim Embedding des Index-Deltas; 0 schaltet das Zwischenspeichern ab und ist ein gültiger Wert. 500

MinAehnlichkeit gehört zum Modell, nicht zur Installation. Ein Embedding erzeugt keine absolute Skala: manche Modelle bewerten auch völlig unverwandte deutsche Texte mit 0,6 bis 0,9, andere spreizen weiter. Bei einem Modell mit hohem Grundniveau wird bei 0.35 praktisch jeder Artikel Kandidat — die Semantik-Stufe liefert dann Rauschen statt Signal, und der Rerank bekommt lauter gleich aussehende Vorschläge. Nach einem Wechsel des Embedding-Modells deshalb nicht nur prüfen, ob der richtige Artikel gefunden wird, sondern wie weit richtige und falsche Paare auseinanderliegen, und die Schwelle entsprechend nachziehen.

Ist weder AnthropicApiKey noch RerankBaseUrl gesetzt, registriert der Kern einen NullKontaktReranker — der Dienst bleibt startfaehig, der Ansprechpartner-Schritt degradiert aber auf "nur E-Mail-exakt".

Sobald ExtraktionBaseUrl gesetzt oder PdfImmerUeberOcr aktiv ist, liest kein Client mehr PDF nativ: PDFs laufen dann ueber den PdfZuTextAufbereiter. Der liest je Seite den eingebetteten Textlayer (PdfPig); Seiten ohne Textlayer (Scans) wuerde er ueber PDFium rendern und per Tesseract erkennen. Diese OCR-Stufe ist derzeit inaktiv, weil der Kern OcrPdfTextQuelle ohne tessdata-Verzeichnis registriert. Folgen:

  • Reines Scan-PDF — kein Text, PdfZuTextAufbereiter wirft, die Verarbeitung des Dokuments bricht ab (PDF '<Dateiname>' lieferte keinen Text (OCR fehlgeschlagen)).
  • Gemischtes PDF (digitale Seiten + Scan-Anhang) — die Scan-Seiten fallen still weg, das Modell sieht nur die Textseiten. Kein Fehler, aber unvollstaendige Extraktion.
  • Digital erzeugtes PDF — unauffaellig, der Normalfall bei ERP-Bestellungen.

Alternative zur (derzeit inaktiven) Tesseract-Stufe: PdfAlsBildFuerExtraktion (oben) ersetzt den Text-Aufbereiter durch PdfZuBildAufbereiter — jede PDF-Seite wird per PDFium (Docnet) zu einem PNG gerendert und als Bild an ein Vision-faehiges Modell geschickt (auch Scan-PDFs, ohne Tesseract/tessdata). Voraussetzung ist ein Vision-faehiges ExtraktionModel; ohne eines liefert das Modell auf die Bild-Anhaenge vermutlich keine brauchbare Extraktion.

Betrieb mit lokalen Modellen (DOTNET_ENVIRONMENT=Demo)

Fuer Praesentationen und den datenschutzkritischen Betrieb liegt eine fertige, geheimnisfreie Schicht bei: MesoAibe.Service/appsettings.Demo.json richtet alle drei Stufen auf einen lokalen Ollama-Endpunkt aus. Aktiviert wird sie ueber die Umgebungsvariable:

$env:DOTNET_ENVIRONMENT = "Demo"
.\MesoAibe.Service.exe

Die Schichtung ist appsettings.jsonappsettings.Development.jsonappsettings.<Umgebung>.json → Umgebungsvariablen. Die Umgebungsdatei liegt also ueber der Development.json und ersetzt sie nicht: sie uebersteuert nur Aibe:Ki, waehrend Datenbank-, WebService- und Postfach-Zugangsdaten weiter aus der gitignorierten Development.json kommen. DOTNET_ENVIRONMENT=Development fuegt keine weitere Schicht hinzu — die Development-Datei ist ohnehin fester Bestandteil der Kette.

Vorbereitung auf der Ollama-Seite:

ollama pull qwen2.5:14b-instruct   # Extraktion + Rerank
ollama pull bge-m3                 # Embedding (mehrsprachig)

Laeuft MesoAibe selbst im Container, zeigt localhost:11434 auf den falschen Container — die Basis-URLs dann per Umgebungsvariable auf den Ollama-Service (http://ollama:11434/v1) oder den Host (host.docker.internal) umbiegen; Compose-Beispiel in der Installationsanleitung, Abschnitt „Lokale Modelle im Container".

Der Ollama-Container braucht ausserdem OLLAMA_CONTEXT_LENGTH (z.B. 16384). Mit dem Default schneidet Ollama den Prompt aus E-Mail-Text, OCR-gewandeltem PDF und JSON-Schema still ab — das Ergebnis sind leere oder halbe Extrakte ohne Fehlermeldung.

Beleganlage-Staffel (Aibe:Mandanten[].Anlage)

Die Staffel entscheidet anhand der Gesamtkonfidenz des Belegvorschlags (0-100), was mit ihm passiert — mit einer eigenen, niedrigeren Druckschwelle:

Feld Bedeutung
AnlegenAbKonfidenz Ab dieser Konfidenz wird der Beleg automatisch angelegt. 0 = nie automatisch anlegen (immer nur Vorschlag).
DruckenAbKonfidenz Ab dieser (hoeheren) Konfidenz wird der angelegte Beleg zusaetzlich gedruckt. 0 = nie drucken. Wenn gesetzt, muss der Wert >= AnlegenAbKonfidenz sein.
DruckOption Druckform beim Erreichen der Druckschwelle (VoucherPrintOptionEnumeration-Name, Default PrintAsOrder).

Beispiel 60/80/PrintAsOrder:

Gesamtkonfidenz Aktion
unter 60 Nur Vorschlag — kein Beleg wird angelegt
60-79 Beleg wird angelegt, ohne zu drucken
ab 80 Beleg wird angelegt und gedruckt (PrintAsOrder)

Ohne vollstaendigen Vorschlag (Extraktion/Matching liefert kein BelegImportDto, z.B. weil der Kunde nicht eindeutig zugeordnet werden konnte) ist die Aktion unabhaengig von der Staffel immer NurVorschlag.

Weitere Mandanten-Felder (Aibe:Mandanten[])

Feld Bedeutung
AnsprechpartnerFeld Ziel-Kopffeld fuer den ermittelten Ansprechpartner-Key. Default "Ansprechpartner".
ExtraktionPrompt Eigener Extraktions-Prompt fuer diesen Mandanten. Nicht gesetzt/null = BelegfeldOptionen.StandardPrompt. Siehe Eigener Extraktions-Prompt.
BestelldokumentAnhaengen Haengt das eingegangene Bestelldokument (PDF-Anhaenge der Mail, sonst die Roh-.eml) als Beleganhang an. Default true.
BestelldokumentFormular Formularnummer fuer den Bestelldokument-Anhang. Default 0.
ImportXmlOrdner Ordner, in dem die WebService-Import-XMLs archiviert werden (dient der Nachvollziehbarkeit, auch bei NurVorschlag). Nicht gesetzt/null = kein Archiv.
BerichtOrdner Ordner fuer die Textberichte (.txt) dieses Mandanten (ein Bericht je verarbeitetem Dokument). Nicht gesetzt/null = kein Bericht.

Eigener Extraktions-Prompt (ExtraktionPrompt)

Der Standard-Prompt (BelegfeldOptionen.StandardPrompt in MesoXPO.Business) ist bewusst allgemein: er verbietet das Raten von Artikelnummern und ordnet bei tabellarischen Bestellungen die Spaltenwerte den Spaltenkoepfen zu. Was er nicht kennen kann, ist die Beschriftung und der Aufbau der Artikelnummern dieses Mandanten. Genau das ist der Grund fuer einen eigenen Prompt — er ersetzt den Standard-Prompt vollstaendig, uebernimm ihn also mit.

Typischer Fehlerfall: die Bestellung nennt die eigene Artikelnummer unter einem mehrdeutigen Label wie „Best.-Nr." (das genauso die Bestellnummer des Kunden bezeichnen koennte), und daneben steht eine kundeneigene Materialnummer. Ohne Hinweis greift die Extraktion die falsche Spalte. Zwei Bausteine helfen: die Liste der Labels, unter denen die eigene Nummer im Kundendokument auftaucht, und ihr Aufbau als Muster samt Beispiel.

Beispiel fuer Artikelnummern der Form vier Ziffern, Leerzeichen, acht Ziffern (7000 00758345):

"ExtraktionPrompt": "Du extrahierst eine Kundenbestellung. Gib NUR die Daten zurueck, die im Dokument stehen — loese nichts gegen Stammdaten auf, rate keine Artikelnummern. Fehlende Felder: Textfelder leer, Zahlen und Daten null.\nBei tabellarischen Bestellungen ordne die Spaltenwerte den Spaltenkoepfen zu: der Wert einer Artikel-/Art.-Nr.-Spalte gehoert nach artikelNummerGenannt (nicht als Menge lesen).\n\nUnsere Artikelnummer (artikelNummerGenannt):\n- Sie steht im Kundendokument unter Beschriftungen wie \"Best.-Nr.\", \"Bestell-Nr.\", \"Ihre Art.-Nr.\", \"Lieferanten-Art.-Nr.\" und ist aufgebaut als vier Ziffern, Leerzeichen, acht Ziffern (Beispiel: \"7000 00758345\").\n- Uebernimm sie mit Leerzeichen nach der vierten Ziffer, auch wenn sie im Dokument ohne Leerzeichen oder mit Bindestrich geschrieben ist. Sonst nichts ergaenzen oder entfernen.\n- NICHT nach artikelNummerGenannt gehoeren: Positions- und Zeilennummern, die Bestellnummer des Kunden im Belegkopf, kundeneigene Materialnummern (\"Mat.-Nr.\"), Zeichnungs- und Normnummern sowie EAN/GTIN (die gehoert nach eanGenannt).\n- Nennt eine Zeile nur eine kundeneigene Nummer und keine unserer Nummern, lass artikelNummerGenannt leer — dann matcht die Bezeichnung."

Regeln, die sich im Pilot bewaehrt haben:

  • Das Zielformat ist das WinLine-Format. Steht die Nummer im Artikelstamm mit Leerzeichen, muss der Prompt die Nummer in dieses Format bringen — die Nummernstufen des Matchings vergleichen exakt (nur Trim und Gross-/Kleinschreibung), ein innenliegendes Leerzeichen entscheidet also ueber Treffer oder Nicht-Treffer.
  • Negativliste mitgeben. „Was gehoert nicht dorthin" wirkt bei mehrdeutigen Labels staerker als eine weitere Positivbeschreibung.
  • Braucht der Beleg die kundeneigene Nummer, ist ein internes Extrakt-Feld der richtige Ort (siehe Belegfelder) — nicht artikelNummerGenannt als Sammelbecken.
  • Zahlendreher muss der Prompt nicht mehr abfangen. Seit MesoXPO.Business 4.79 ist das Matching auf der Nummer fehlertolerant: eine Nummer, die sich nur in Trennzeichen unterscheidet, trifft mit Konfidenz 94 und wird ohne LLM-Aufruf übernommen; ein Zahlendreher oder ein einzelnes falsches Zeichen erzeugt einen Kandidaten mit Konfidenz 70, der bewusst unter der Auto-Accept-Schwelle liegt und darum geprüft wird — die Rerank-Stufe bekommt dazu jetzt auch die genannte Nummer. Die Zeile „Übernimm sie mit Leerzeichen nach der vierten Ziffer" im Beispiel oben bleibt trotzdem sinnvoll: ein exakter Treffer erreicht 100 und ist belastbarer als ein Schreibweise-Treffer mit 94.

WebService-Zugang (Aibe:Mandanten[].WebService)

Feld Bedeutung
MesonicServerUrl Basis-URL des Mesonic Server WebService, z.B. "http://server:80".
Benutzer WinLine-Benutzername. Optional, wenn VorhandeneSessionId gesetzt ist.
Passwort WinLine-Passwort. Optional, wenn VorhandeneSessionId gesetzt ist.
VorhandeneSessionId Alternativ zu Benutzer/Passwort: eine bereits bestehende WinLine-Session-ID. Nicht gesetzt = Anmeldung mit Benutzerdaten.

Der Mandant kommt nicht aus diesem Abschnitt, sondern aus Aibe:Mandanten[].Mandant.

Angebotssuche (Aibe:Mandanten[].AngebotSuche)

Optionaler Anreicherungsschritt: sucht offene VK-Angebote des gematchten Kunden, die zur eingegangenen Bestellung passen, und meldet sie als Belegreferenz samt Hinweis. Die Ueberleitung Angebot → Auftrag gehoert bewusst nicht dazu — der Schritt informiert, er bucht nicht.

Fehlt der Abschnitt vollstaendig, ist der Schritt aus (es wird gar kein Anreicherer registriert). Ein vorhandener Abschnitt mit "Aktiv": false verhaelt sich zur Laufzeit ebenso.

Die Bewertung laeuft in zwei Phasen:

  1. Referenzkriterium — Bestellreferenz bzw. Angebotsnummer, geprueft ueber alle offenen Angebote des Kunden. Das staerkere Kriterium darf nicht an einem Deckel scheitern.
  2. Positionskriterium — Ueberschneidung der Artikel, nur fuer die verbliebenen Kandidaten (neueste zuerst) und begrenzt durch MaxKandidaten, weil hier je Angebot eine Zeilenabfrage anfaellt.
Feld Bedeutung
Aktiv Schaltet den Schritt ab, ohne den Abschnitt zu entfernen. Default true.
ReferenzExtraktFeld Name des Extrakt-Felds, das die Bestellreferenz des Kunden traegt (z.B. "bestellreferenz"). Nicht gesetzt = Phase 1 prueft nur den Mail-Betreff.
PositionsSchwelle Mindestanteil der gematchten Vorschlagspositionen, die im Angebot vorkommen muessen (0..1). Default 0.5.
ZielKopffeld Kopf-Zusatzfeld, in das die Laufnummer des ersten gemeldeten Treffers geschrieben wird (durch die Phasenreihenfolge bevorzugt ein Referenztreffer). Nicht gesetzt = kein Feld.
MaxKandidaten Deckel fuer Phase 2. Default 20. Auf Phase 1 hat er keine Wirkung.

Belegfelder (Kopffelder/Positionsfelder)

Kopffelder und Positionsfelder sind konfigurierbare Zusatzfelder, die zusaetzlich zu den vom Belegvorschlag gelieferten Kernfeldern in die WinLine-Vorlage geschrieben werden. Jedes Feld braucht genau eine Wertquelle und — ausser bei internen Extrakt-Feldern (siehe unten) — ein Ziel-Vorlagenfeld:

Quelle Felder Bedeutung
KI-extrahiert Extrakt + Typ Extrakt ist der JSON-Property-Name aus der KI-Extraktion, Typ einer von date|string|decimal|int (bei dieser Quelle Pflicht). Beschreibung ist ein optionaler Hinweis fuer Schema und Prompt.
Meta-Formatstring Quelle Formatstring mit Platzhaltern {absender}, {absendername}, {betreff}, {dateiname}, {empfangsdatum}.
Konstante Vorgabe Fester Vorgabewert.

MaxLaenge (optional) kuerzt den Endwert auf N Zeichen. Ist nicht genau eine Quelle gesetzt, fehlt bei Extrakt der Typ oder fehlt bei Quelle/Vorgabe das Vorlagenfeld, scheitert AibeOptionen.Validiere() beim Start des Mandanten.

Interne Felder: Ein Extrakt-Feld darf ohne Vorlagenfeld stehen. Es wird dann extrahiert (Schema und Prompt), aber in keinen Beleg geschrieben — es steht nur den Anreicherern zur Verfuegung, z.B. der kundenspezifischen Artikelaufloesung (siehe unten) als laenge.

Grenze der Extrakt-Felder (Claude-Extraktion): Die Anthropic-API lehnt das Extraktionsschema ab (Schema is too complex, jede Mail landet im Fehlerordner), wenn zu viele optionale Felder zusammenkommen. Gemessen am 2026-09-03 mit claude-opus-4-8 und claude-opus-5: mit zwei Kopf-Extraktfeldern sind acht Positions-Properties (sechs feste plus zwei Extrakt-Felder) noch zulaessig, neun nicht — unabhaengig von Typ, Beschreibung oder date-Format. Ursache ist die Zahl optionaler Properties je Objekt (die Grammatik muss jede Reihenfolge zulassen); die Bibliothek deklariert Extrakt-Felder als optional. Wer mehr Positionsfelder braucht, muss bis zu einer Bibliotheksaenderung (Felder als required deklarieren, siehe Spec) Felder streichen oder den OpenAI-kompatiblen Extraktionspfad nutzen.

Beispiel (ein Kopffeld "Vertragsnummer" aus der KI-Extraktion):

"Kopffelder": [
  {
    "Vorlagenfeld": "Vertragsnummer",
    "Extrakt": "Vertragsnummer",
    "Typ": "string",
    "Beschreibung": "Vom Kunden genannte Vertrags-/Bestellnummer"
  }
]

Stammdaten-Fallback (Stammfeld, Gruppe)

WinLine-Importsemantik: Ein in der ExIm-Vorlage angezeigtes Feld wird beim Import erwartet und bei leerem Wert leer importiert; nur nicht angezeigte Felder fuellt WinLine selbst aus den Stammdaten. Wer abweichende Lieferangaben aus der Bestellung uebernehmen will, fuehrt die Lief.*-Felder in der Vorlage und gibt jedem ein Stammfeld als Fallback: ein XPO-Property-Pfad auf das ermittelte Personenkonto (Konto.<Pfad>, z.B. Konto.Kontoname) oder den Ansprechpartner (Ansprechpartner.<Pfad>). Regel je Feld: Extrakt, sonst Stammwert, sonst leer — ein Feld mit Stammfeld wird immer geschrieben. Gruppe haelt eine Adresse zusammen: liefert die Extraktion fuer ein Feld der Gruppe einen Wert, bekommen die uebrigen Gruppenfelder leer statt Stammwert (keine gemischten Adressen). Jedes Feld einer Gruppe braucht ein Stammfeld; Stammfeld ist nur an Kopffeldern zulaessig. Die Pfade prueft AibeOptionen.Validiere() beim Start; die Stammwerte laedt der immer registrierte StammfeldAnreicherer der Bibliothek. Wird das Konto nicht gefunden, bleiben die Werte leer und der Bericht enthaelt einen Hinweis.

Beispiel (Lieferadresse aus der Bestellung, Fallback auf das Personenkonto):

"Kopffelder": [
  { "Vorlagenfeld": "Lief.Name",    "Extrakt": "liefName",    "Typ": "string", "Gruppe": "Lief", "Stammfeld": "Konto.Kontoname",
    "Beschreibung": "Abweichender Lieferempfaenger, sonst weglassen" },
  { "Vorlagenfeld": "Lief.Strasse", "Extrakt": "liefStrasse", "Typ": "string", "Gruppe": "Lief", "Stammfeld": "Konto.Strasse" },
  { "Vorlagenfeld": "Lief.PLZ",     "Extrakt": "liefPlz",     "Typ": "string", "Gruppe": "Lief", "Stammfeld": "Konto.Postleitzahl" },
  { "Vorlagenfeld": "Lief.Ort",     "Extrakt": "liefOrt",     "Typ": "string", "Gruppe": "Lief", "Stammfeld": "Konto.Ort" }
]

Property-Namen der Stammfelder an den MesoXPO-Modellen (ViewKontenstamm, KontakteStamm) pruefen; die Pfade werden beim Start validiert, ein Tippfehler faellt also sofort auf. Offen (Pilotlauf): Der Nachweis der Importsemantik gegen eine Vorlage mit angezeigten Lief.*-Feldern steht noch aus.

Fremdsprachige Bestellungen (Aibe:Mandanten[].Fremdsprachen)

Fremdsprachige Bestellungen treffen die deutsche Artikelbezeichnung nur schwach. Liegt die Uebersetzung beim Kunden in einem frei nutzbaren Artikel-Textfeld (Zusatzfeld, Notiz, Langtext), schaltet ein Mapping Sprache → Feld dieses Feld als zusaetzlichen Vergleichstext frei (Stufe 5b der Matching-Kaskade in MesoXPO.Business). Die Dokumentsprache erkennt die Extraktion (ISO 639-1, z.B. en); der Orchestrator reicht sie an das Matching durch. Ohne Sprache, bei de oder ohne Mapping fuer die Sprache bleibt das Verhalten unveraendert. Fehlt der Abschnitt oder ist FeldJeSprache leer, wird die Stufe gar nicht registriert.

Feld Bedeutung
FeldJeSprache ISO-Sprachcode → Feldname der Artikelview: Zusatzfeld1..30, Notiz1..10, Langtext1, Langtext2. Andere Feldnamen oder de als Sprache scheitern beim Start.
FremdtextDeckel Konfidenz-Deckel eines Treffers auf dem Fremdtext (1..85). Default 80 — bewusst unter den 85 der deutschen Bezeichnung, weil Fremdsprachenfelder erfahrungsgemaess weniger konsistent gepflegt sind.
FremdtextImSuchdokument Nimmt die Fremdtexte zusaetzlich ins Embedding-Suchdokument auf. Aendert den Doc-Hash und loest einmalig ein Neu-Embedden der betroffenen Artikel aus. Default false.
"Fremdsprachen": {
  "FeldJeSprache": { "en": "Notiz3", "fr": "Zusatzfeld12" },
  "FremdtextDeckel": 80
}

Im Bericht erscheint ein solcher Treffer mit Matchgrund Bezeichnung en (Fuzzy).

Kundenspezifische Artikelaufloesung (Aibe:Mandanten[].ProzedurAufloesungen)

Generischer Anreicherungsschritt fuer Zuordnungsregeln, die nicht in den Dienst gehoeren — Referenzfall: eine bestellte Kabellaenge auf die passende Charge aufloesen (in WinLine ein eigener Auspraegungsartikel Haupt<Trennzeichen>NNNNN, Trennzeichen je Mandant in T300 C015). Je Position mit Treffer ruft der Dienst eine Stored Procedure in der Mandanten-Datenbank mit dem gesamten Vorgangskontext (JSON) auf; sie liefert die endgueltige Artikelnummer. Konfiguriert wird nur der Prozedurname — alles Kundenspezifische (Feldnamen, Muster, Einheiten, Regeln) lebt in appsettings, Prompt-Text und Prozedur, nicht im Dienst. Je Listeneintrag entsteht ein Schritt, die Reihenfolge ist die Kettenreihenfolge (nach der Angebotssuche).

Feld Bedeutung
Prozedur Prozedurname in der Mandanten-DB, optional schema.name. Nur Bezeichner — kein freies SQL. Pflicht.
NurWennFeld Nur aufrufen, wenn die Position dieses Extrakt-Feld traegt (z.B. "laenge"). Nicht gesetzt = jede Position mit Treffer.
NurChargenartikel Nur bei Treffern auf Chargenartikel (T024 C014 = 1, C025 in {0,3,4}). Default false.
KonfidenzOhneAufloesung Konfidenz-Deckel der Position, wenn die Prozedur keine oder mehrere Zeilen liefert oder fehlschlaegt (0..100). Bibliotheks-Default 70. Muss unter Anlage.AnlegenAbKonfidenz liegen (sonst scheitert Validiere() beim Start), damit die Degradierung die automatische Anlage tatsaechlich verhindert — mit der Vorlagen-Staffel 60/80 also hoechstens 59, z.B. 50.
MaxKandidaten Anzahl Kandidaten der Position im Parameter @kandidaten. Default 5.
Aktiv Schaltet den Schritt ab, ohne den Eintrag zu entfernen. Default true.

Verhalten: Genau eine Ergebniszeile ersetzt den Treffer (Konfidenz bleibt, Matchgrund + Prozedur <Name>, der alte Treffer bleibt als UrspruenglicherTreffer sichtbar; das Protokoll zeigt Treffer ersetzt: alt -> neu). Keine Zeile, mehrere Zeilen und jeder Prozedurfehler degradieren geschlossen: die Position wird auf KonfidenzOhneAufloesung gedeckelt, ein Hinweis landet im Bericht, die uebrigen Positionen laufen weiter. Weil die Gesamtkonfidenz das Minimum ueber alle Positionen ist, faellt ein Beleg mit ungeloester Position damit unter AnlegenAbKonfidenz und landet in der manuellen Pruefung statt in der automatischen Anlage — gewollt. Der Dienst erzwingt diese Beziehung: liegt KonfidenzOhneAufloesung nicht unter Anlage.AnlegenAbKonfidenz (bei Staffel > 0), startet der Mandant nicht.

Vertrag der Prozedur (Details und eine Referenzprozedur fuer den Kabel-Fall: README von MesoXPO.Business, Abschnitt "Prozedur-Artikelaufloesung"):

  • Parameter @mandant, @kontonummer, @artikelnummer, @konfidenz, @positionsindex, @position, @beleg, @dokument, @kandidatenbenannt gebunden, die Deklarationsreihenfolge in der Prozedur ist frei. @position traegt alle Extrakt-Felder der Position unter ihrem Prompt-Namen (JSON_VALUE(@position, '$.laenge')), @beleg den Kopf mit sprache und allen Positionen.
  • Ergebnis: Spalte Artikelnummer (Pflicht), optional Bezeichnung, Hinweis. Gelesen wird nur das erste Resultset; SET NOCOUNT ON wird erwartet.
  • Voraussetzung JSON_VALUE/OPENJSON: SQL Server 2016 oder neuer.

Beispiel (Kabel-Fall: internes Positionsfeld laenge plus Prozedur):

"Positionsfelder": [
  {
    "Extrakt": "laenge",
    "Typ": "decimal",
    "Beschreibung": "Bestellte Laenge in Metern, falls die Position eine Laenge nennt (z.B. '305 m', '0,3 km' -> 300). Sonst weglassen."
  }
],
"ProzedurAufloesungen": [
  { "Prozedur": "CSS_AibeChargeWaehlen", "NurWennFeld": "laenge", "NurChargenartikel": true, "KonfidenzOhneAufloesung": 50 }
]

Postfaecher (Aibe:Mandanten[].Postfaecher)

Je Eintrag ein Typ (Ordner | Imap | Graph) mit den passenden Feldern (siehe PostfachOptionen): Ordner braucht nur Quelle (Eingangsverzeichnis); Imap zusaetzlich ImapHost/ImapPort/ImapSsl/ImapBenutzer/ImapPasswort; Graph zusaetzlich GraphTenantId/GraphClientId/GraphClientSecret/GraphPostfach (App-Permission Mail.ReadWrite). MaxProLauf (Default 10) deckelt die pro Lauf gelesenen Dokumente je Postfach.

Schluessel Bedeutung
Quelle Ordner: das Eingangsverzeichnis. Imap/Graph: der ueberwachte Ordner im Postfach, Default Inbox. Unterordner mit / getrennt, z.B. Inbox/Bestellungen; bei Graph steht Inbox als erste Ebene fuer den Posteingang unabhaengig von seinem Anzeigenamen (Posteingang). Bei allen Typen wird nur dieser eine Ordner gelesen, nicht seine Unterordner.
VerarbeitetOrdner Unterordner der Quelle fuer Dokumente, aus denen ein Beleg angelegt wurde. Default Verarbeitet. Wird bei Bedarf angelegt.
FehlerOrdner Unterordner der Quelle fuer Dokumente, deren Verarbeitung oder Beleganlage gescheitert ist. Default Fehler. Wird bei Bedarf angelegt.
VorschlagOrdner Unterordner der Quelle fuer Dokumente, die unter AnlegenAbKonfidenz blieben — es wurde nur ein Vorschlag gemeldet, kein Beleg angelegt. Nicht gesetzt = sie landen im VerarbeitetOrdner und sind dort von echten Belegen nicht zu unterscheiden. Fuer eine Pilotphase mit manueller Nachkontrolle empfiehlt sich ein eigener Ordner, z.B. Vorschlag.

Die drei Ablageordner liegen bei allen Typen unterhalb der Quelle — ein ueberwachter Ordner Inbox/Bestellungen bekommt also die Unterordner Bestellungen/Verarbeitet, Bestellungen/Fehler und ggf. Bestellungen/Vorschlag.