Pedalion

Eine Agent-Runtime, die die zweite Anfrage übersteht

Berechtigungsgebundene Tools, dauerhafte Befehle und die unbequeme Lücke zwischen einem Timeout und einer ausgeführten Aktion.

Technische Radierung in Elfenbein und Kupfer mit einem Zugangstor, einem Befehlsjournal und einem Ausführungspfad mit Wiederholungsschleife.

Der erste Tool-Aufruf ist der einfache. Schwierig wird der nächste Versuch, nachdem das CRM eine Änderung angenommen hat, die Netzwerkverbindung die Antwort verloren hat und der Worker neu gestartet ist. An diesem Punkt sagt Ihnen weder eine flüssige Antwort noch ein längerer System-Prompt, ob die Geschäftsaktion stattgefunden hat. Sie haben ein Problem verteilter Systeme – mit einem probabilistischen Planer obendrauf.

Nehmen wir einen Agenten, der eine Notiz für einen Kundendatensatz vorbereitet. Eine doppelte Notiz mag harmlos wirken, doch dasselbe Ausführungsmuster erreicht irgendwann die Auftragserstellung, eine Kontoänderung oder eine Finanztransaktion. Die Runtime sollte ihre Zustellsemantik nicht erst in dem Moment lernen, in dem die Aktion teuer wird.

Dieses Referenzdesign trennt fünf Verantwortlichkeiten: authentifizierter Request-Eingang, Evidenzabruf, Modellplanung, Befehlszulassung und Ausführung von Seiteneffekten. Nur die letzte Komponente besitzt eine eng begrenzte Connector-Berechtigung. Der Planer erhält niemals allgemeine Zugangsdaten, und weder ein abgerufenes Dokument noch ein Tool-Ergebnis kann ihm neue Berechtigungen verleihen.

1. Die Autoritätsgrenze ausführbar machen

Das Modell darf einen Aktionsnamen und Argumente vorschlagen. Alles andere stammt aus vertrauenswürdigen Diensten. Ermitteln Sie Tenant und Principal aus einer verifizierten Session, validieren Sie die Aktion gegen eine versionierte Allowlist und die Argumente gegen ein geschlossenes Schema. Weisen Sie unbekannte Eigenschaften und überlange Eingaben ab. Lösen Sie die Zielressource innerhalb desselben Tenants auf, bevor Sie einen Befehl zulassen.

Das ist wichtig, weil ein syntaktisch gültiger Tool-Aufruf noch kein autorisierter ist. OWASP stuft indirekte Prompt Injection über externe Inhalte als Risiko ein. Ein Dokument, das einen Assistenten auffordert, Datensätze zu exportieren, bleibt ein Dokument – keine Autorität. Trennzeichen, Retrieval-Grounding und Anweisungstexte sind nützliche Schichten, aber keine davon ersetzt die Durchsetzung an der Connector-Grenze.

Der folgende Vertrag gehört hinter Validierung und Freigabe. Sein Typ dient der Dokumentation, nicht der Sicherheit: TypeScript-Typen verschwinden zur Laufzeit. Nur der Zulassungsdienst sollte diesen Datensatz erstellen und persistieren, und der Dispatcher muss ihn aus vertrauenswürdigem Speicher laden, statt ein vom Modell geliefertes Objekt zu akzeptieren.

type ApprovedCommand = Readonly<{
  tenantId: string;
  operationId: string;
  principalId: string;
  action: "crm.note.create";
  resourceId: string;
  payload: Readonly<{ body: string }>;
  requestHash: string;
  expectedRevision: string;
  authorizationDecisionId: string;
  policyVersion: string;
  expiresAt: string;
}>;

type ExecutionOutcome =
  | { state: "succeeded"; receipt: string }
  | { state: "denied" | "expired"; reason: string }
  | { state: "unknown"; operationId: string };

2. Einen Befehl freigeben, nicht eine Konversation

Eine Freigabe sollte genau den Tenant, Principal, die Aktion, das Ziel, die Argumente und die erwartete Ressourcenrevision identifizieren. Berechnen Sie serverseitig einen Digest über eine kanonische Darstellung dieser validierten Felder. Speichern Sie Freigabeentscheidung, Policy-Version und Ablaufzeit gemeinsam damit. Hashen Sie keinen beliebigen JSON-String in der Annahme, dass unterschiedliche Reihenfolgen der Eigenschaften unterschiedliche Anfragen bedeuten.

Die Freigabeoberfläche sollte die konkret vorgeschlagene Änderung und die zur Beurteilung nötigen Belege zeigen. Frieren Sie den Befehl nach der Freigabe ein. Wenn das Modell den Inhalt überarbeitet, sich der Zieldatensatz ändert oder die geschäftliche Vorbedingung abläuft, erstellen Sie einen neuen Vorschlag und holen die entsprechende Entscheidung erneut ein. Verwenden Sie die alte Freigabe nicht stillschweigend für eine neue Payload weiter.

Prüfen Sie beim Dispatch, ob die Entscheidung noch gültig ist, und kontrollieren Sie die aktuelle Zugriffsrichtlinie erneut. Eine entzogene Berechtigung sollte eine Aktion in der Warteschlange stoppen. Wo das Geschäftssystem bedingte Schreibvorgänge unterstützt, senden Sie die erwartete Revision als Vorbedingung, damit kein anderer Akteur den Datensatz zwischen Prüfung und Änderung verändern kann. Eine fehlgeschlagene Vorbedingung geht zurück in die Prüfung – sie ist kein Grund, die Bedingung zu streichen und es erneut zu versuchen.

Eine menschliche Freigabe ist persistenter Zustand, keine gehaltene Datenbanksperre. Persistieren Sie die Anfrage und geben Sie Ressourcen frei, während Sie warten. PostgreSQL-Sperren gelten normalerweise bis zum Ende der Transaktion; eine Transaktion offen zu lassen, während ein Mensch entscheidet, erzeugt Konflikte, ohne das entfernte System Teil dieser Transaktion zu machen.

3. Der Absicht eine dauerhafte Identität geben

Wählen Sie einmalig eine Operations-ID für die angenommene Geschäftsabsicht, vor dem ersten Dispatch. Ein Retry behält diese ID bei. Beschränken Sie ihre Eindeutigkeit auf den Tenant und speichern Sie einen Request-Hash dazu. Gleicher Schlüssel und gleicher Hash bedeuten eine Wiederholung; gleicher Schlüssel mit anderem Hash ist ein Konflikt, der abgelehnt werden muss – und nicht als Update interpretiert werden darf.

Die minimale Speicherstruktur unten trennt das Befehls-Ledger von der Outbox. Die Outbox bedeutet, dass das Committen eines Befehls auch die Verpflichtung committet, ihn zu dispatchen. Sie bedeutet nicht, dass die nachgelagerte Aktion stattgefunden hat. Speichern Sie nur die Felder, die zur Ausführung und Prüfung der Operation nötig sind; die tatsächliche Speicherung von Payloads erfordert Verschlüsselung, Zugriffsbeschränkungen und eine Aufbewahrungsrichtlinie.

CREATE TABLE agent_command (
  tenant_id uuid NOT NULL,
  operation_id uuid NOT NULL,
  request_hash bytea NOT NULL,
  command jsonb NOT NULL,
  state text NOT NULL CHECK (state IN (
    'pending', 'dispatching', 'succeeded',
    'denied', 'expired', 'unknown'
  )),
  provider_receipt text,
  lease_until timestamptz,
  created_at timestamptz NOT NULL DEFAULT now(),
  PRIMARY KEY (tenant_id, operation_id)
);

CREATE TABLE command_outbox (
  tenant_id uuid NOT NULL,
  operation_id uuid NOT NULL,
  available_at timestamptz NOT NULL DEFAULT now(),
  PRIMARY KEY (tenant_id, operation_id),
  FOREIGN KEY (tenant_id, operation_id)
    REFERENCES agent_command (tenant_id, operation_id)
);

4. Einmal zulassen, mit begrenztem Lease dispatchen

Die Zulassungstransaktion fügt die Ledger-Zeile und ihren Outbox-Eintrag gemeinsam ein. PostgreSQLs ON CONFLICT DO NOTHING verhindert, dass ein doppelter Primärschlüssel einen zweiten Befehl erzeugt. RETURNING liefert nur tatsächlich eingefügte Zeilen, sodass nur die erste Zulassung eine Dispatch-Verpflichtung hinzufügt. Verwenden Sie gebundene Parameter auf einer einzigen Datenbankverbindung, mit Transaktions-Timeout und Rollback im Fehlerfall.

Dieser Auszug setzt voraus, dass Authentifizierung, Autorisierung, Freigabeprüfungen und Payload-Kanonisierung bereits erfolgreich waren. Er veranschaulicht ausschließlich die Zulassung. Isolation auf Zeilenebene, Dispatch-Abfragen, Verschlüsselung und Lebenszyklusberechtigungen liegen bewusst außerhalb des Auszugs; eine tenant_id-Spalte allein ist noch keine Mandantenkontrolle.

BEGIN ISOLATION LEVEL READ COMMITTED;

WITH admitted AS (
  INSERT INTO agent_command (
    tenant_id, operation_id, request_hash, command, state
  ) VALUES ($1, $2, $3, $4, 'pending')
  ON CONFLICT (tenant_id, operation_id) DO NOTHING
  RETURNING tenant_id, operation_id
)
INSERT INTO command_outbox (tenant_id, operation_id)
SELECT tenant_id, operation_id FROM admitted;

SELECT request_hash, state, provider_receipt
FROM agent_command
WHERE tenant_id = $1 AND operation_id = $2;

COMMIT;

Vergleichen Sie den zurückgegebenen Hash mit dem übermittelten Hash, bevor Sie die Zulassung bestätigen. Eine Abweichung ist ein Konflikt im Sinne von HTTP 409. Die zweite Anweisung erhält unter Read Committed einen neuen Snapshot und kann daher eine konkurrierende Einfügung sehen, nachdem die Eindeutigkeitsprüfung auf diese gewartet hat. Löschen Sie die Ledger-Zeile nicht, solange noch ein Replay eintreffen kann; Transaktionswiederholungen auf strengeren Isolationsstufen erfordern eine eigene Behandlung.

Ein Worker übernimmt einen ausstehenden Befehl in einer kurzen Transaktion, setzt den Status auf dispatching und hinterlegt vor dem Commit einen zeitlich begrenzten Lease. Parallele Worker können für die Übernahme aus der Queue Zeilensperren und SKIP LOCKED nutzen. Die Übernahme muss den aktuellen Zustand atomar prüfen, und der Abschluss muss an das Claim-Token des Workers gebunden sein. Produktivspeicher benötigt daher zusätzlich zum hier gezeigten vereinfachten Schema ein Claim-Token oder eine Fencing-Generation.

Geben Sie Datenbanksperren vor dem Netzwerkaufruf frei. Das entfernte System kann nicht an dieser lokalen Transaktion teilnehmen. Ein abgelaufener Lease beweist nicht, dass der ursprüngliche Worker angehalten hat, und ein lokales Fencing-Token kann keine nachgelagerte API stoppen, die es nicht versteht. Die Wiederherstellung muss dem Idempotenzvertrag des nachgelagerten Systems folgen, statt einfach jeden abgelaufenen Lease auf pending zurückzusetzen.

5. Unknown ist ein vollwertiges Ergebnis

Ein Timeout bedeutet, dass der Aufrufer keine eindeutige Antwort erhalten hat. Es bedeutet nicht, dass der Server ein Rollback durchgeführt hat. Unterstützt der Anbieter Idempotenz, senden Sie den stabilen Operationsschlüssel mit derselben Anfrage und beachten Sie dabei den vom Anbieter dokumentierten Geltungsbereich und die Aufbewahrungsdauer des Schlüssels. Speichern Sie die resultierende Quittung dauerhaft, bevor Sie das Queue-Element bestätigen.

Ein Absturz zwischen dem erfolgreichen Remote-Aufruf und dem Schreiben der lokalen Quittung bleibt möglich. Die Wiederherstellung kann den Anbieter anhand des Operationsschlüssels abfragen oder exakt dieselbe Anfrage wiederholen, sofern der Anbieter Replay-Sicherheit garantiert. Ist beides nicht möglich, setzen Sie den Befehl auf unknown und verlangen Sie einen Abgleich. Wer einen neuen Schlüssel erzeugt, um der Unsicherheit zu entgehen, verursacht genau den doppelten Seiteneffekt, den das Ledger verhindern sollte.

Führen Sie den Planner nicht erneut aus, um einen Retry zu rekonstruieren. Eine neue Modellantwort kann selbst bei identischem Prompt einen anderen Payload oder ein anderes Ziel wählen. Spielen Sie den persistierten Befehl erneut ab und protokollieren Sie jeden Ausführungsversuch separat. Sobald ein Befehl einen Endzustand erreicht hat, sollte jede weitere Zustellung sein gespeichertes Ergebnis zurückgeben, ohne einen weiteren Outbox-Eintrag zu erzeugen.

Eine Eindeutigkeitsbedingung in der Datenbank und eine Outbox sorgen für dauerhafte Absicht und kontrollierte Zustellung. Sie erzeugen jedoch nicht auf magische Weise Exactly-once-Seiteneffekte in einem fremden System. Dieses stärkere Ergebnis hängt von der nachgelagerten Operation ab, von ihrer Atomarität, ihrem Deduplizierungsverhalten und davon, wie lange sie sich den Schlüssel merkt.

6. Die Laufzeit begrenzen, dann die Grenzen instrumentieren

Ein Workflow braucht Budgets für Modell-Tokens, Tool-Aufrufe, verstrichene Zeit und parallele Arbeit. Setzen Sie diese im Code außerhalb des Planners durch. Reservieren Sie Budget atomar, bevor Sie parallele Arbeit zulassen, damit nicht mehrere Worker denselben Restbetrag sehen. Geben Sie ungenutzte Reservierungen nach einem verbindlichen Abschlussereignis frei; berücksichtigen Sie Retries, Retrieval und menschliche Prüfung im Betriebskostenmodell.

Verwenden Sie OpenTelemetry-Spans für Retrieval, Planung, Autorisierung, Zulassung und Dispatch. Propagieren Sie den Kontext, wo sinnvoll, über die Queue hinweg, und nutzen Sie Span-Links, um asynchrone Versuche oder später fortgesetzte Traces miteinander zu verknüpfen. Legen Sie Operationskennungen in kontrollierten Trace-Attributen oder einem zugriffsgeschützten Audit-Speicher ab, nicht in unbegrenzten Metrik-Labels.

Ein Trace ist nicht das Audit-Ledger. Traces können gesampelt, verworfen oder nach einer anderen Aufbewahrungsrichtlinie gelöscht werden. Der dauerhafte Datensatz sollte belegen, welcher freigegebene Befehl versucht wurde, welche Richtlinienentscheidung ihn erlaubt hat, was das nachgelagerte System gemeldet hat und ob ein Abgleich stattgefunden hat. Rohe Prompts, Zugriffstokens und vollständige Geschäftsdatensätze sollten nicht der Standardinhalt der Telemetrie sein.

Modellwechsel sollten diese Ausführungsverträge wahren. Vergleichen Sie Kandidaten anhand eines festen, versionierten Evaluationssets, das auch Ablehnung, Eskalation und die Genauigkeit von Tool-Argumenten abdeckt. Eine Replay-Evaluation muss Mutationen durch Stubs ersetzen; ein Shadow-Run darf keine Schreibvorgänge in der Produktion auslösen. Bessere Sprachqualität ist kein Grund, den Umfang eines Tools zu erweitern.

7. Die Stellen testen, an denen der Prozess auseinanderbrechen kann

Die Fehler-Testsuite sollte die Ausführung an bestimmten Grenzen unterbrechen: bevor die Zulassung committet wird, nach dem Commit, aber vor dem Dispatch, nach dem Remote-Schreibvorgang, aber vor der Persistierung der Quittung, und nach der Persistierung, aber vor der Bestätigung in der Queue. Ergänzen Sie parallele Retries mit demselben Schlüssel, abweichende Payload-Hashes und zwei Worker, die um denselben Befehl konkurrieren.

Die Prüfungen betreffen Zustand und Wirkungen, nicht nur HTTP-Statuscodes. Pro mandantenbezogenem Schlüssel sollte es genau einen zugelassenen Befehl geben; eine Hash-Abweichung darf niemals dessen Payload verändern; ein als erfolgreich erfasster Befehl darf nicht erneut zugestellt werden. Bei einem simulierten Anbieter mit gültigem Idempotenzvertrag sollte ein Replay genau eine Wirkung erzeugen. Bei einem nicht idempotenten Anbieter und einer verlorenen Antwort ist das erwartete Ergebnis ein ungeklärter Befehl, kein erfundener Erfolg.

Lassen Sie außerdem die Freigabe ablaufen, während der Befehl in der Queue wartet, entziehen Sie den Zugriff vor dem Dispatch, ändern Sie die Ressourcenrevision und platzieren Sie anweisungsähnlichen Text in abgerufenen Dokumenten. Prüfen Sie, dass keiner dieser Pfade die Fähigkeiten des Connectors erweitert. Testen Sie die Erschöpfung des Budgets, während parallele Schritte noch laufen, und stellen Sie sicher, dass die Laufzeit keine neue Arbeit mehr einplant, statt das Modell einen weiteren Versuch aushandeln zu lassen.

Das ist der technische Maßstab, den ich anlegen würde: Das System kann erklären, was vorgeschlagen wurde, was erlaubt wurde, was versucht wurde und was nachweislich geschehen ist. Das Modell kann sich ändern. Die Grenze um die geschäftliche Aktion sollte explizit bleiben.

Quellen & Kontext

Referenzarchitektur und Beispielcode – keine Beschreibung einer ausgelieferten Pedalion-Runtime und keine sofort einsetzbare Produktionsimplementierung. Sicherheit, Mandantenfähigkeit, Aufbewahrung und Anbieterverträge erfordern eine implementierungsspezifische Prüfung.

Weiterlesen

Lassen Sie uns Ihr Unternehmen gemeinsam agentifizieren

Kontaktieren Sie uns

Hinterlassen Sie unten Ihre E-Mail-Adresse, wir melden uns in Kürze

Mit einem Klick auf Senden stimmen Sie zu, dass Pedalion Sie kontaktiert.

Allgemeine Anfragencontact@pedalion.com

Presseanfragenpress@pedalion.com

Wir verarbeiten Ihre Angaben, um Ihre Anfrage zu beantworten. Siehe unsere Datenschutzerklärung (Englisch).