Zurück zur Bibliothek
Architektur

RFQ-Engine-Architektur: Warum Verfügbarkeits-Reservierungen und Stornierungs-Snapshots wichtig sind

Zuletzt aktualisiert: 2026年7月13日

Das Problem, das die meisten RFQ-Automatisierungen übersehen

Wenn Teams RFQ-Workflows automatisieren, konzentrieren sie sich typischerweise auf das Frontend: Käuferanfrage parsen, Katalog durchsuchen, Produkte matchen, Preise anwenden. Diese Arbeit ist real, und Tools existieren dafür — KI extrahiert Anforderungen, während deterministische Regeln Preise, Genehmigungen und SLA-Tracking verarbeiten, wie GEP in seiner Beschaffungsautomatisierungsanalyse beschreibt. Der Ivalua 2026 Sourcing-Guide bestätigt dasselbe Muster: KI verarbeitet Extraktion und Matching, Regeln verarbeiten Governance.

Aber zwei Probleme brechen dieses Modell in Produktion, und die meisten Automatisierungen adressieren sie nicht:

  1. Verfügbarkeits-Drift. Ein Angebot, dessen Verhandlung drei Tage dauert, ist ein Angebot gegen Inventar, das zum angebotenen Preis möglicherweise nicht mehr existiert. Wenn der Agent 50 Einheiten zu $12,40 zusagt und der Lieferant 12 hat, wenn der Käufer annimmt, war das Angebot nie lieferbar. Der Agent hat nicht gelogen — die Welt hat sich unter ihm verändert.

  2. Richtlinien-Drift. Eine Stornierungsstrafe, die 30 Tage im Voraus zitiert wurde, kann sich von der bei Buchung geltenden Strafe unterscheiden. Wenn der Lieferant die Bedingungen mitten in der Verhandlung verschärft und der Agent die Richtlinie zum Angebotszeitpunkt nicht erfasst, bestreitet der Käufer die Gebühr später. Der Einspruch ist berechtigt — die Bedingungen haben sich bewegt.

Die Architektur, die beides löst, ist eine RFQ-Engine mit zwei Mechanismen: atomare Verfügbarkeits-Reservierungen, die eingeschränktes Inventar für ein Zeitfenster reservieren, und Stornierungs-Richtlinien-Snapshots, die die Geschäftsbedingungen zum Zeitpunkt des Angebots einfrieren. Dies sind keine an ein Angebotstool angeboltenen Features. Sie sind strukturelle Verpflichtungen im Datenmodell — Felder, Zustandsübergänge und Lebenszyklusoperationen, die die Engine erzwingt.

Das Entitätsmodell, das es funktioniert

Eine Produktions-RFQ-Engine braucht mehr als eine Anfrage und ein Angebot. Das Entitätsmodell muss die Käuferabsicht von der Lieferantenantwort trennen und muss eingeschränktes Angebot unabhängig vom Katalog verfolgen. Die folgenden Entitäten bilden das Rückgrat:

Request — die Käuferabsicht: Kontakt, Titel, Positionen, Rechnungs- und Lieferadressen, Ablauf, Status. Eine Anfrage bewegt sich durch eine definierte Zustandsmaschine: initialin_progressconfirmedcompleted, mit modified als Wiedereintrittspunkt, wenn Positionen sich ändern, nachdem Angebote existieren.

Item — das Katalogprodukt, das der Käufer will. Items sind generisch; sie haben eine UUID, einen Typ, einen Preisierungsmodus und Maßeinheiten. Dasselbe Item mappt zu mehreren Lieferanten-Items.

ProviderItem — das spezifische Angebot des Lieferanten für dieses Item, mit einem Basispreis pro Maßeinheit. Ein Lieferanten-Item gehört zu einem Lieferantenunternehmen und kann mehrere Chargen haben.

ProviderItemBatch — die eingeschränkte Inventareinheit. Jede Charge hat eine Chargennummer, Produktionsdatum, Verfallsdatum, Kosten pro Einheit, ein Lagerkennzeichen und ein slow_move_item-Kennzeichen für langsam drehendes Inventar. Chargen sind die Granularität, bei der Verfügbarkeit geprüft und reserviert wird.

Quote — die bepreiste Antwort des Lieferanten auf eine bestätigte Anfrage. Ein Angebot hat einen Lieferanten, einen Vertriebsmitarbeiter, Versandmethode und -betrag, Währung, FX-Kurs und FX-Sperrzeitstempel, Verhandlungsrundenzähler (automatisch berechnet) und eine Zustandsmaschine: initialin_progressconfirmedcompleted oder disapproved.

QuoteItem — eine Zeile im Angebot, die ein Lieferanten-Item und eine Charge mit einer Menge, Einheitspreis, Zwischensumme, Rabatt und End-Zwischensumme verknüpft. Kritisch: das Angebots-Item trägt hold_token, hold_expires_at, guardrail_price_per_uom und slow_move_item — die Felder, die Verfügbarkeits-Reservierungen und Rentabilitäts-Guardrails auf Zeilenebene sichtbar machen.

CancellationPolicy — die Bedingungen, unter denen eine Buchung storniert werden kann, mit Stufen, Fristen und Strafregeln, pro Lieferanten-Item zugeordnet.

Installment — der Zahlungsplan, der mit einem bestätigten Angebot verknüpft ist, mit Priorität, geplantem Datum, Betrag, Verhältnis und einer Zustandsmaschine: pendingpaid oder cancelled.

Dies ist keine flache Tabelle. Es ist ein typisierter Graph mit verschachtelten Resolvern — eine Anfrage löst ihre Angebote auf, ein Angebot löst seine Items auf, ein Angebots-Item löst sein Lieferanten-Item und seine Charge auf. Die Engine verwendet DataLoader-basiertes Batch-Laden, damit ein Angebot mit 20 Positionen nicht 20 sequenzielle Datenbank-Lookups auslöst.

Verfügbarkeits-Reservierungen: Kapazität atomar reservieren

Die Verfügbarkeits-Reservierung ist der Mechanismus, der Verfügbarkeits-Drift verhindert. Ohne sie zitiert ein Agent gegen ein Inventar-Snapshot, der zum Zeitpunkt der Käuferentscheidung veraltet sein kann. Mit ihr reserviert der Agent Kapazität für ein Zeitfenster und das Angebot wird durch echtes, dekrementiertes Angebot gestützt.

Der Reservierungs-Lebenszyklus hat vier Zustände und strikte Übergangsregeln:

Zustand Bedeutung Erlaubte Übergänge
held Kapazität dekrementiert, Reservierungs-Token mit TTL (15 Minuten) ausgestellt confirmed, released, expired
confirmed Buchung committed, kein zweites Kapazitäts-Dekrement terminal
released Reservierung storniert, Kapazität wiederhergestellt (idempotent) terminal
expired TTL abgelaufen, Kapazität wiederhergestellt (idempotent) terminal

Die kritische Designentscheidung liegt im confirmed-Übergang: kein zweites Kapazitäts-Dekrement. Die Reservierung hat die Kapazität bereits reserviert. Die Bestätigung der Buchung konvertiert die Reservierung in einen bestätigten Zustand, ohne den Inventarzähler erneut zu berühren. Dies verhindert Doppelzählung — den Bug, bei dem eine Reservierung Kapazität dekrementiert, dann eine Bestätigung sie erneut dekrementiert und das System denkt, es habe weniger Angebot als tatsächlich.

Die Reservierung ist atomar. Die acquireAvailabilityHold-Mutation dekrementiert verfügbare Kapazität und gibt ein hold_token mit einem expires_at-Zeitstempel zurück. Wenn die Kapazität unzureichend ist, schlägt die Operation ohne Seiteneffekte fehl — keine teilweise Reservierung, kein unsauberer Zustand. Die releaseAvailabilityHold- und expireAvailabilityHold-Mutationen stellen Kapazität wieder her und sind idempotent: zweimaliges Aufrufen desselben Tokens gibt dasselbe Ergebnis. Dies ist wichtig für Fehlertoleranz — wenn ein Netzwerk-Timeout einen Retry verursacht, überpflegt das System die Kapazität nicht.

Wie dies zu einem Angebots-Workflow mappt

Betrachten Sie einen Distributor, der 200 Einheiten einer Industriepumpe bei einem Lieferanten mit drei Chargen unterschiedlichen Verfallsdatums und Kosten anbietet. Der Agent:

  1. Ruft check_availability mit der Lieferanten-Item-UUID, dem Service-Fenster und der Menge auf — erhält passende Chargen und verfügbare Menge.
  2. Ruft acquire_availability_hold auf — Kapazität wird atomar dekrementiert, ein hold_token mit 15-Minuten-TTL wird zurückgegeben.
  3. Das Angebots-Item trägt nun hold_token und hold_expires_at. Der Käufer sieht ein durch echtes Inventar gestütztes Angebot, keine Katalog-Schätzung.
  4. Wenn der Käufer innerhalb von 15 Minuten annimmt, ruft der Agent confirm_availability_hold auf — die Reservierung wechselt zu confirmed, Kapazität gesperrt, kein zweites Dekrement.
  5. Wenn der Käufer ablehnt oder die TTL abläuft, ruft der Agent release_availability_hold auf oder lässt sie ablaufen — Kapazität wird wiederhergestellt, das nächste Angebot kann sie nutzen.

Das hold_token ist ein explizites Handle. Das Modell gibt es als Argument, nicht als versteckten Session-Zustand. Dies ist dasselbe Explizite-Handle-Muster, das der MCP 2026-07-28 Release Candidate formalisiert: Zustand, den ein Agent über Tool-Aufrufe hinweg benötigt, wird zu einem sichtbaren, prüfbaren Handle statt zu Transport-Schicht-Metadaten.

Stornierungs-Snapshots: Bedingungen einfrieren

Stornierungs-Richtlinien-Drift ist der zweite Fehlermodus. Ein Lieferant kann Stornierungsstrafen zwischen Angebot und Buchung ändern — eine 10%-Strafe 30 Tage im Voraus wird 50% 7 Tage im Voraus. Wenn der Agent die alte Strafe zitiert hat und der Käufer angenommen hat, bestreitet der Käufer die neue Gebühr. Der Einspruch ist korrekt.

Die Architektur löst dies, indem sie die Stornierungs-Richtlinie zum Angebotszeitpunkt snapshottet. Die CancellationPolicy-Entität hat tiers (eine JSON-Struktur mit Fristen und Strafprozenten), ein label, eine description und einen status. Wenn der Agent ein Angebot generiert, ruft er die aktive Stornierungs-Richtlinie für jedes Lieferanten-Item ab und hängt die Richtlinien-Bedingungen an das Angebot an. Die Richtlinien-UUID und ihre Stufen werden eingefroren — selbst wenn der Lieferant die Richtlinie später aktualisiert, trägt das Angebot die Bedingungen, die bei Ausstellung galten.

Das search_cancellation_policies-Tool filtert nach Lieferanten-Item und Status, sodass der Agent die aktive Richtlinie für jede Position abrufen kann. Die Richtlinie wird dann mit dem Angebots-Item verknüpft, nicht nur per Fremdschlüssel referenziert — der Snapshot ist die Richtlinie, kein Pointer auf einen veränderlichen Datensatz.

Dieses Muster generalisiert über Stornierung hinaus. FX-Kurse verwenden denselben Ansatz: Der QuoteType trägt fx_rate und fx_rate_locked_at — der Wechselkurs wird zum Angebotszeitpunkt gesperrt, nicht bei Buchung nachgeschlagen. Wenn die Anzeigewährung des Käufers von der Lieferanten-Angebots-Währung abweicht, ist der gesperrte Kurs der Kurs, den der Käufer sieht, unabhängig von Marktveränderungen.

Preis-Stufen, Segment-Lookup und Guardrails

Preis ist kein flaches Feld. Die Engine löst Preis-Stufen nach Kundensegment, Menge und Lieferanten-Item auf. Das get_item_price_tiers-Tool nimmt eine Kunden-E-Mail und eine Liste von Angebots-Items (jedes mit Item-UUID, Lieferanten-Item-UUID und Menge), sucht das Kundensegment über Segment-Kontakte und batch-lädt alle passenden Preis-Stufen in einer einzigen Abfrage. Stufen werden auf Datenbankebene nach Mengenschwellen gefiltert — nur Stufen, bei denen quantity_greater_then und quantity_less_then die angeforderte Menge umrahmen, werden zurückgegeben.

Rabatt-Prompts funktionieren genauso, mit einem hierarchischen Scope-System: GLOBAL (gilt für alle Angebote), SEGMENT (gilt für ein Kundensegment), ITEM (gilt für ein spezifisches Item) und PROVIDER_ITEM (gilt für ein spezifisches Lieferanten-Angebot eines Items). Das get_discount_prompts-Tool lädt aus allen vier Scopes, dedupliziert und gibt die kombinierte Menge mit Bedingungen und Regeln zurück. Das bedeutet, dass ein Angebot gleichzeitig einen Mengenrabatt (Segment-Scope), eine saisonale Werbeaktion (Item-Scope) und einen lieferantenspezifischen Clearance-Angebot (Lieferanten-Item-Scope) anwenden kann — jeweils mit eigener Priorität.

Das guardrail_price_per_uom-Feld auf dem Angebots-Item ist das Rentabilitäts-Guardrail — der minimal akzeptable Preis für das Item, geladen aus der Lieferanten-Item-Charge. Wenn der Agent einen Rabatt anwendet, der den Preis unter das Guardrail fallen lässt, schlägt die Operation nicht fehl (der Agent kann einen legitimen Grund haben), aber das Flag wird in der Angebots-Item-Antwort sichtbar. Das slow_move_item-Flag markiert Inventar, das zu lange im Bestand war — der Agent kann dies nutzen, um tiefere Rabatte anzuwenden, aber das Guardrail verhindert unrentable Preisgestaltung.

Die Zustandsmaschinen, die ungültige Operationen verhindern

Eine RFQ-Engine ohne Zustandserzwingung ist eine Tabelle. Die Engine erzwingt vier Zustandsmaschinen, jede mit expliziten Übergangsregeln und Operations-Guards:

Request: initialin_progressconfirmedcompleted, mit modified als Wiedereintrittspunkt. Der RequestOperationGuard erzwingt, dass Angebote nur aus confirmed-Anfragen erstellt werden können und Positionsänderungen nur in initial-, in_progress- oder modified-Zuständen erlaubt sind.

Quote: initialin_progressconfirmedcompleted oder disapproved. Der QuoteOperationGuard erzwingt, dass Positionsänderungen nur in initial oder in_progress erlaubt sind und Raten nur aus confirmed-Angeboten erstellt werden können.

Verfügbarkeits-Reservierung: heldconfirmed / released / expired. Alle drei Zielzustände sind terminal.

Installment: pendingpaid oder cancelled. Beide Zielzustände sind terminal.

Wenn die Positionen einer bestätigten Anfrage sich ändern und bereits Angebote existieren, wechselt die Anfrage zu modified und alle bestehenden Angebote werden automatisch abgelehnt — der Käufer muss neue Angebote gegen die aktualisierten Positionen erhalten. Dies verhindert, dass veraltete Angebote angenommen werden, nachdem die Anfrage, die sie generiert hat, sich geändert hat.

Wenn alle nicht-stornierten Raten eines Angebots bezahlt sind, wechselt das Angebot automatisch zu completed. Wenn mindestens ein Angebot einer Anfrage abgeschlossen ist, wechselt die Anfrage automatisch zu completed. Die Zustandsmaschinen sind nicht beratend — die Engine validiert jeden Übergang und löst einen VALIDATION_FAILED-Fehler mit dem aktuellen Status und den erlaubten Übergängen aus, wenn die Operation ungültig ist.

Das Modul-Muster: 38 Tools, 11 Domain-Mixins

Die Referenzimplementierung dieser Architektur ist ein einzelnes MCP-Modul — mcp_hospirfq_processor — mit 38 registrierten Tools, zusammengesetzt aus 11 Domain-Mixins: Request, Item, Availability, Quote, Pricing, Installment, Bundle, Cancellation, File, Segment und Catalog. Die Mixins teilen sich eine GraphQLBackedProcessor-Basisklasse, die den GraphQL-Client, Logger und Settings bereitstellt. Jedes Mixin steuert seine eigenen Tool-Methoden bei und greift nur auf self.logger, self.setting und self._execute_graphql_query zu.

Die Tools werden über einen Konfigurationsblock (MCP_CONFIGURATION) registriert, der den Namen jedes Tools, die Beschreibung, das Eingabe-Schema (JSON Schema) und den Modul-Link (Klassenname, Funktionsname, Rückgabetyp) deklariert. Die MCP-Runtime lädt diese Konfiguration beim Start und dispatcht Tool-Aufrufe an die entsprechenden Mixin-Methoden. Der @handle_errors-Decorator umschließt jeden Tool-Aufruf mit strukturierter Fehlerbehandlung und erzeugt typisierte Fehlerantworten mit Codes wie GRAPHQL_QUERY_FAILED, VALIDATION_FAILED, HOLD_NOT_FOUND, HOLD_ALREADY_EXPIRED, AVAILABILITY_INSUFFICIENT und PRICING_MODE_UNSUPPORTED.

Die 38 Tools umfassen den gesamten RFQ-Lebenszyklus:

Domain Tools Schlüsseloperationen
Anfrage-Management 8 Einreichen, aktualisieren, abrufen, suchen, Items hinzufügen/entfernen, Lieferanten-Items zuweisen/entfernen
Item-Management 3 Items suchen, Item abrufen, Lieferanten-Items mit Chargeninfo abrufen
Angebot-Management 4 Angebot aktualisieren, Angebot abrufen, Angebote suchen, Angebots-Item aktualisieren
Preisgestaltung 3 Preis-Stufen abrufen, Rabatt-Prompts abrufen, Angebotspreis berechnen
Raten 4 Erstellen, aktualisieren, Zeitplan erstellen, Raten abrufen
Verfügbarkeit 5 Prüfen, Reservierung erwerben, freigeben, bestätigen, ablaufen lassen
Bundles 3 Bundles suchen, Bundle abrufen, Komponenten suchen
Stornierung 2 Richtlinie abrufen, Richtlinien suchen
Katalog 1 Katalog abfragen (Knowledge-Graph-Suche)
Segment 1 Segment-Kontakte abrufen
Datei 2 Hochladen, Dateien abrufen
Workflow 2 Anfrage bestätigen + Angebote erstellen, Angebot bestätigen + Raten erstellen

Die beiden Workflow-Tools — confirm_request_and_create_quotes und confirm_quote_and_create_installments — sind Convenience-Operationen, die mehrere atomare Tools in einen einzigen Aufruf komponieren. Das erste bestätigt eine Anfrage und erstellt Angebote für ausgewählte Lieferanten in einer Operation. Das zweite bestätigt ein Angebot und erstellt den Ratenplan in einer Operation. Diese reduzieren die Anzahl der Round-Trips, die ein Agent für die häufigsten Multi-Step-Workflows benötigt.

Das inquire_catalog-Tool ist die Brücke zum Knowledge-Graph. Es nimmt eine Natural-Language-Abfrage, einen optionalen Namespace (hotel, flight, activity) und ein Limit und gibt rangierte Ergebnisse aus der Knowledge-Graph-Engine zurück. So entdeckt der Agent Produkte vor dem Angebotieren — nicht durch SQL-Abfragen gegen eine Produkttabelle, sondern durch semantische Suche über einen Katalog-Graph, der Substitute, Kompatibilität und Verfügbarkeit kennt.

Warum diese Architektur generalisiert

Die Referenzimplementierung wurde für Travel und Hospitality gebaut — datumsbeschränktes Inventar, Belegungsregeln, Per-Pax-Preisgestaltung, Bundles, Deposits, Stornierungsbedingungen. Das ist der Stresstest. Wenn die Engine ein Hotelzimmer für spezifische Daten anbieten und buchen, die Verfügbarkeit mit einem TTL reservieren, die Stornierungs-Richtlinie snapshotten, den FX-Kurs sperren, segment-spezifische Preis-Stufen anwenden und an einen Ratenplan übergeben kann, kann sie jeden B2B-RFQ-Workflow mit Lieferanten, Käufern, eingeschränktem Inventar und Geschäftsbedingungen unterstützen.

Die Generalisierung ist strukturell:

  • Vertrieb und Großhandel: Hotelzimmer durch Lagerbestand ersetzen, Lieferanten-Items durch Lieferanten-SKUs, Chargen durch Chargennummern und Verfallsdaten. Die Verfügbarkeits-Reservierung reserviert Bestand; der Stornierungs-Snapshot bewahrt Rückgabebedingungen.
  • Beschaffung: Reisepakete durch Teile und Materialien ersetzen. Segmentbasierte Preis-Stufen wenden ausgehandelte Vertragsraten an; der Guardrail-Preis verhindert unrentable Beschaffung.
  • Fertigung: Service-Fenster durch Produktions-Slots ersetzen. Die Verfügbarkeits-Reservierung reserviert Kapazität auf einer Produktionslinie; die Stornierungs-Richtlinie bewahrt die Umbuchungsstrafe.
  • Field Services: Hotel-Daten durch Termin-Fenster ersetzen. Die Verfügbarkeits-Reservierung reserviert das Zeitfenster eines Technikers; der Ratenplan strukturiert den Zahlungszeitplan.

Das Entitätsmodell — Request, Item, ProviderItem, ProviderItemBatch, Quote, QuoteItem, CancellationPolicy, Installment — ist industrieunabhängig. Die Domain-Mixins sind komponierbar: Ein Beschaffungs-Deployment könnte das Bundle-Mixin entfernen und den Rest behalten. Ein Fertigungs-Deployment könnte ein ProductionSlot-Mixin neben Availability hinzufügen. Das Modul-Muster, die Zustandsmaschinen und der Explizite-Handle-Ansatz bleiben gleich.


Ein Distributor, der NetSuite, BigCommerce und drei Lieferantenkataloge betreibt, bekommt einen Agenten, der ein RFQ per E-Mail oder Portal erhält, Produkte und Substitute gegen den Katalog-Graph auflöst, Preise pro Kundensegment anwendet, Bestand mit Ablauf reserviert, Stornierungsbedingungen snapshottet, den FX-Kurs sperrt und das angenommene Angebot nach NetSuite zurückschreibt — mit jedem Tool-Aufruf protokolliert und jedem Zustandsübergang validiert. Dieser Build ist Phase 2-3 der Vier-Schritte-Methode und ist typischerweise in 5-8 Wochen live.

Angebotenen Build anfordern. Einwöchiges Discovery. Sie erhalten ein Systeminventar, eine Workflow-Mappe und einen festen Scope — ob Sie mit uns bauen oder nicht.

Möchten Sie dies für Ihre Systeme gebaut?

Jedes Dokument hier stammt aus echter Produktionsarbeit. Wenn Sie ein Zielsystem und einen Workflow im Sinn haben, können wir in einer Woche einen Build umreißen.

Build mit festem Umfang anfragen

Einwöchiges Discovery. Sie erhalten ein Systeminventar, eine Workflow-Mappe und einen festen Umfang — unabhängig davon, ob Sie mit uns bauen.