1. Was ist die Prompt-Registry
Die Prompt-Registry ist eine workspace-bezogene Bibliothek wiederverwendbarer System-Messages. Sie speichern einen Prompt einmal, binden einen beliebigen API-Key an ihn (oder senden pro Request einprompt_ref), und das Gateway injiziert diesen Prompt als System-Message,
bevor die Anfrage an das Upstream-Modell weitergeleitet wird.
Das Bearbeiten eines Prompts aktualisiert jeden daran gebundenen Key
beim allernächsten Aufruf. Kein Redeploy. Keine Codeänderung. Kein
SDK-Upgrade. Die Bindung lebt im Gateway, nicht in Ihrer Anwendung.
Das ist die gleiche Idee, die Langfuse und LangSmith eingeführt haben, mit
einem Unterschied: OrcaRouter ist die Auslieferungsschicht. Ihr
Anwendungscode ruft /v1/chat/completions genau wie zuvor auf; das Gateway
löst den Prompt auf und injiziert ihn. Es gibt nichts in der Anwendung zu
installieren.
Prompts sind workspace-bezogen — jedes Mitglied sieht die Prompts des
Workspaces; nichts überschreitet Tenant-Grenzen.
2. Schnellstart — binden Sie Ihren ersten Prompt in 5 Schritten
Einen Prompt erstellen
/console/prompts und klicken Sie auf
New prompt. Benennen Sie ihn support-agent. Fügen Sie die
System-Message ein:“Sie sind ein knapper Support-Agent für Acme. Antworten Sie in 2 Sätzen oder weniger.”Speichern — das erzeugt Version 1.
Einen Key binden
/console/token, erstellen oder bearbeiten Sie einen
API-Key, wählen Sie support-agent aus dem Dropdown Prompt und
production aus dem Dropdown Label.Eine Anfrage senden
X-Orca-Prompt: support-agent@production:v1 bestätigt, welcher Prompt
injiziert wurde.Den Prompt bearbeiten
/console/prompts support-agent — ändern Sie die
System-Message. Speichern — Version 2 wird automatisch erstellt;
production zeigt immer noch auf v1.3. Konzepte: Prompts, Versionen, Labels
| Konzept | Definition | Veränderbarkeit |
|---|---|---|
| Prompt | Ein benannter, workspace-bezogener Eintrag. Identifier: name (Regex ^[a-zA-Z0-9._-]{1,128}$). | Soft-löschbar (30-Tage-Papierkorb + Purge). |
| Version | Ein unveränderlicher Snapshot des Prompt-Inhalts. Wird bei jedem Speichern automatisch erstellt. Identifier: monotoner int. | Unveränderlich — nie bearbeitet, nie wiederverwendet. |
| Label | Ein verschiebbarer Zeiger auf eine Version (z. B. production → v7). | Atomar verschiebbar via Promote; das Audit-Log zeichnet jede Verschiebung auf. |
Reservierte Labels
productionwird bei der ersten Version jedes neuen Prompts automatisch an v1 geheftet. Es zu verschieben ist ein Wechsel des Produktions-Traffics — RBAC nur für Owner.latestwird vom Gateway automatisch gepflegt und zeigt immer auf die neueste Version. Sie könnenlatestnicht von Hand verschieben.
staging, canary,
eu-prod) später über den Dialog Labels hinzufügen und Keys daran
binden. Solange ein Label nicht an eine Version geheftet ist, failt ein
an name@<dieses-Label> gebundener Key fail-open ohne Injektion.
Warum diese Form
Die Trennung zwischen unveränderlichen Versionen und verschiebbaren Labels ist die Primitive für „Deploy ohne Code”. Anwendungscode bezieht sich auf ein Label (implizit über die Key-Bindung oder explizit überprompt_ref). Promoten verschiebt das Label — die Anwendung sieht den
neuen Inhalt beim nächsten Aufruf ohne Codeänderung. Ein Rollback heißt
einfach, eine ältere Version auf das Label zu promoten.
4. Produktionsmuster: Promote, Rollback, gestaffeltes Release
Promote
Öffnen Sie Labels in der Prompt-Zeile, wählen Sie die Zielversion, klicken Sie auf Promote. Die Label-Verschiebung ist atomar und auditiert (das Audit-Log zeigt, wer welches Label wann von welcher Version auf welche verschoben hat). Jeder anname@<label> gebundene Key übernimmt
beim nächsten Request die neue Version.
POST /api/prompt/:id/label). Developer
und Viewer sehen die Label-Liste und die Audit-Historie, aber keinen
Promote-Button; der Dialog zeigt einen Inline-Hinweis „ask an Owner”, so
dass die Sperre sichtbar statt stillschweigend ist.Rollback
Restore auf einer älteren Version im History-Drawer. Wiederherstellen kopiert den Inhalt dieser Version als neue Version nach vorne (die Historie wird nie mutiert) und verschiebtlatest darauf. Damit Traffic
tatsächlich zurückfällt, promoten Sie das relevante Label auf die
wiederhergestellte Version.
Gestaffeltes Release
Binden Sie Ihre Canary-Keys anname@staging, Ihre Prod-Keys an
name@production. Promoten Sie staging auf eine neue Version,
beobachten Sie in Insights, dann promoten Sie production, wenn Sie
zufrieden sind. Keine Key-Änderungen, kein Deploy, kein SDK-Update.
A/B-Traffic-Split
Der Label-Dialog hat einen Toggle Split traffic. Aktivieren Sie ihn, um ein einzelnes Label auf mehrere Versionen mit gewichteter Verteilung zu zeigen (z. B. v7: 60 %, v8: 40 %). Das Bucketing ist deterministisch pro(workspace, token, request-id), so dass eine einzelne Konversation bei
Retries im selben Bucket bleibt.
5. Templating: {{var}}-Substitution
Prompt-Inhalte unterstützen Mustache-artige {{var}}-Platzhalter. Werte
des Aufrufers stammen aus prompt_ref.variables
(siehe §6).
Regeln:
- Einmalige Substitution. Variablenwerte werden als literaler Text
ausgegeben. Sie werden NICHT erneut als Template ausgewertet — das
verhindert Prompt-Injection, bei der ein vom Aufrufer gelieferter Wert
weitere
{{...}}-Direktiven einschleusen will. - Unbekannte Platzhalter bleiben wortwörtlich. Wenn ein Platzhalter
{{foo}}keine passende Variable hat, wird das Literal{{foo}}ausgegeben (und eine Warnung geloggt). Requests schlagen nie fehl, weil eine Variable fehlte. - Punktzugriff.
{{user.name}}durchläuft verschachtelte Objekte, wenn der Aufrufer eine verschachtelte Map übergibt. - Sektionen.
{{#flag}}...{{/flag}}zeigt den Block nur, wennflagtruthy ist. Invertierte Sektionen ({{^flag}}...) zeigen den Block, wennflagfehlt/falsy ist. - Größenlimit für gerenderten Inhalt: 256 KiB. Wenn der final
gerenderte Text diese Schwelle überschreitet, wird die gesamte
Injektion übersprungen (die Antwort trägt keinen
X-Orca-Prompt-Header) und der Request unverändert weitergeleitet — Schutz vor Variable-Blowup-Verstärkung.
- Langfuse-Prompts nutzen dieselbe
{{var}}-Mustache-Syntax. - LangSmith-Prompts deklarieren
template_format: f-string | mustachein ihrem Manifest. Das Gateway respektiert diese Deklaration.
6. Override pro Anfrage: prompt_ref
Überschreiben oder wählen Sie einen Prompt pro Anfrage, ohne die
Key-Bindung zu ändern. Fügen Sie ein Top-Level-Feld prompt_ref zum
Request-Body hinzu:
prompt_ref > Key-Bindung (nativ
PromptId/PromptLabel oder PromptProviderId) > Channel-SystemPrompt
keiner.
prompt_ref wird vom Gateway konsumiert und vor dem Weiterleiten nach
Upstream entfernt — strikte Provider sehen das unbekannte Feld nie.
Form:
7. Chat-förmige Prompts (System + Few-Shot)
Die meisten Prompts sind ein einzelner System-String. Aber manchmal möchten Sie, dass das Gateway ein reicheres Template injiziert — eine System-Message plus eine Few-Shot-Sequenz aus User/Assistant-Turns. Die Registry unterstützt das alskind: 'chat'.
Das Create prompt-Modal der Konsole zeigt einen Text / Chat-Toggle.
Wenn Sie Chat wählen, wird der Inhaltseditor zu einer Liste von
{role, content}-Zeilen (system, user, assistant) — fügen Sie so viele
hinzu, wie Sie brauchen. Beim Speichern werden die Zeilen als
messages_json persistiert. Einmal erstellt, ist kind unveränderlich.
Verhalten bei der Injektion:
- Keine System-Message im Request ⇒ das Gateway stellt die System-Message des Templates voran, und die Few-Shot-Turns des Templates erscheinen vor den Messages des Aufrufers.
- System-Message im Request ⇒ die Injektion folgt dem Standard des
Format-Adapters. Bei OpenAI-förmigen Requests wird die System-Message
des Templates vorangestellt; bei Claude-förmigen Requests landet das
System des Templates im nativen
system-Parameter.
8. Verhältnis zum restlichen Gateway
| Oberfläche | Wie komponiert sie mit Prompts? |
|---|---|
| Modelle | Prompts sind modellunabhängig. Derselbe Prompt fährt über GPT-5, Claude, Gemini. Routing wählt das Upstream-Modell basierend auf dem model der Anfrage und der Gruppe des Keys — Prompts überschreibt das nie. |
| Routing | Routing läuft zuerst; der Prompt-Resolver läuft danach. Der aufgelöste Prompt fährt also auf dem Channel, den der Router gewählt hat, auch über eine Fallback-Kette. |
| Guardrails | Guardrails sind ein unabhängiges Gate, das Inhalte inspiziert und redigiert. Prompts injizieren eine System-Message; sie umgehen keine Policy. Eine Anfrage kann beides tragen — Guardrails laufen immer. |
| API-Keys | Ein Key bindet an einen Prompt an einem Label (z. B. support-agent@production). Die Bindung lebt am Key im Gateway, sodass das Promoten einer neuen Version alle Keys mit diesem Label gleichzeitig verschiebt. |
| Insights | Jeder Request stempelt prompt_id, prompt_version, prompt_label auf seine Log-Zeile. Insights segmentiert nach Prompt — Nutzung, Fehlerrate, Latenz, Kosten. |
config deklarieren (Langfuse config.model, LangSmith
model_config) — das Gateway ignoriert diese Felder. Prompts injizieren
nur Text; die Modellauswahl ist Sache des Routers.
9. Externe Quellen: Langfuse, LangSmith, generisches HTTP
Föderation: Verbinden Sie einmal eine externe Prompt-Quelle, binden Sie dann Keys oder senden Sieprompt_ref gegen dort gehostete Namen. Native
und externe Prompts binden und liefern identisch — nur das
Resolver-Backend unterscheidet sich.
Unterstützte Quellen:
- Langfuse —
GET {base}/api/public/v2/prompts/{name}?label=..., Basic-Auth aus Ihrempublic:secret-Paar. Text- und Chat-Prompts. - LangSmith —
GET {base}/commits/{owner}/{name}/{tag|hash|latest},x-api-key-Header. Das Gateway parst das serialisierte Manifest, um Messages/Text und dietemplate_format-Deklaration zu extrahieren. Eingebettetemodel_config/model_provider-Felder werden entfernt (Defense in Depth: die Registry liefert nur Text). - Generisches HTTP — vom Operator konfigurierter Konnektor für jede Prompt-Registry, die einen einzelnen HTTP-Aufruf pro Fetch bereitstellt. Siehe unten für die konfigurierbaren Felder.
Felder des generischen HTTP-Konnektors
Eine generische HTTP-Quelle ist ein Adapter nach dem Prinzip „beschreibe einen HTTP-Aufruf und eine Response-Form”. Verwendet für selbstgehostete Prompt-Stores UND für Drittanbieter-Plattformen, die keine eigene Backend-Integration brauchen (PromptLayer, einfache benutzerdefinierte APIs etc.). Die Felder sind absichtlich klein — mehrstufige Flows oder providerspezifische Protokolle sind außerhalb des Scopes.| Feld | Standard | Wirkung |
|---|---|---|
| URL template | erforderlich | Die vollständige Request-URL mit Platzhaltern {name} / {label} / {version}. Platzhalter im Pfad nutzen PathEscape; Platzhalter im Query-String nutzen QueryEscape, damit &/= in einem Prompt-Namen keine zusätzlichen Query-Parameter einschleusen können. |
| HTTP method | GET | GET oder POST. Wählen Sie POST, wenn die Plattform einen Request-Body verlangt. |
| Auth header name | Authorization | Der HTTP-Header, in dem das Secret gesendet wird. Auf X-API-KEY (oder ähnlich) setzen für Provider, die einen benutzerdefinierten Header verwenden. |
| Auth scheme prefix | Bearer (mit nachgestelltem Leerzeichen) | Zeichenkette, die dem Secret im Header-Wert vorangestellt wird. Leer lassen, wenn die Plattform einen rohen API-Key erwartet, oder auf Token / ein anderes benutzerdefiniertes Präfix setzen. |
| Body template | leer | Nur POST. Der rohe Request-Body mit zwei Platzhalter-Familien. Verbatim: {name} / {label} / {version} substituieren den literalen Wert (für form-codierte, XML- oder Template-Bodies — Sie sind für das Escaping verantwortlich). JSON-safe: {name_json} / {label_json} / {version_json} substituieren ein vollständig in Anführungszeichen gesetztes JSON-String-Literal (z. B. "hello") — INNERHALB von JSON-Bodies verwenden, damit ein anfrageseitiger Prompt-Name mit " / \ / Steuerzeichen keine Geschwisterfelder upstream einschleusen kann. |
| Response JSON path | leer | Optionaler Punktpfad in das Response-JSON, wo die Prompt-Payload liegt (z. B. data.0.template.messages). Leer = Auto-Erkennung von Top-Level-Formen text / prompt / messages. |
Resilienz
- TTL-Cache (Standard 60s), damit sich Prompt-Edits innerhalb einer Minute verbreiten.
- Stale-while-revalidate — der gecachte Wert liefert, während das nächste Refresh im Hintergrund läuft.
- Stale-on-error — wenn die externe Quelle 5xx zurückgibt oder das Timeout läuft, liefert das Gateway die letzte bekannte gute Antwort. User-Traffic schlägt nie hart durch einen Provider-Ausfall fehl.
10. Observability
Jede prompt-injizierte Anfrage hinterlässt vier Brotkrumen.Response-Header
- Nativ:
name@label:vN (native)(odername@label (native), wenn der Versions-Int unbekannt ist). - Extern:
name@label:<provider-version-tag> (langfuse)usw. - Label ausgelassen ⇒ kein
@label-Segment.
Log-Spalten
Log.PromptId, Log.PromptVersion, Log.PromptLabel — typisierte
Spalten, indiziert für Insights-Abfragen.
Insights-Drilldown
In/console/insights hat die Filterzeile eine Prompt-Facette —
wählen Sie einen Prompt, und jeder Tab (Latenz, Fehler, Kosten) filtert
auf diese prompt_id. Das ist der Schließkreis für „ich habe einen
Prompt bearbeitet — was hat sich am Traffic geändert?”.
Audit
Jede Label-Verschiebung und jeder Rollback wird in der Promote History des Prompts mit Akteur-User-ID, Zeitstempel, From-Version und To-Version aufgezeichnet. Für jedes Mitglied sichtbar; Mutation auf Owner-Rolle beschränkt.11. API-Referenz
Alle Routen sind workspace-bezogen über den HeaderX-Workspace-Id.
RBAC wird konsistent durchgesetzt: Lesen ist für jedes Mitglied offen;
Schreiben ist Developer+; Änderungen des Produktions-Traffics
(Label-Verschiebungen, Rollbacks, Provider-Konfiguration, Webhooks) sind
nur für Owner.
Prompts
| Methode & Pfad | Rolle | Zweck |
|---|---|---|
GET /api/prompt/ | Member | Listet Prompts (paginiert, unterstützt ?tag=). |
GET /api/prompt/?in_trash=true | Owner | Listet soft-gelöschte Prompts (nur Owner — Wiederherstellungsklasse). |
GET /api/prompt/search | Member | Keyword- + Tag-Suche (rate-limited). |
GET /api/prompt/tags | Member | Tag-Typeahead für den Workspace. |
GET /api/prompt/:id | Member | Detail eines einzelnen Prompts. |
GET /api/prompt/:id/versions | Member | Versionshistorie (neueste zuerst). |
GET /api/prompt/:id/labels | Member | Aktuelles Label → Versions-Mapping. |
GET /api/prompt/:id/tags | Member | Tag-Set für einen Prompt. |
GET /api/prompt/:id/label_history | Member | Audit-Log der Promotions. |
GET /api/prompt/:id/analytics | Member | Daten des Nutzungsgraphen pro Prompt. |
GET /api/prompt/analytics/top | Member | Workspace-weit meistgenutzte Prompts. |
POST /api/prompt/ | Developer+ | Prompt erstellen (Text oder Chat). |
PUT /api/prompt/ | Developer+ | Prompt aktualisieren (erzeugt eine neue Version). |
POST /api/prompt/:id/tags | Developer+ | Tag-Set ersetzen. |
POST /api/prompt/:id/run | Developer+ | Playground “Try it” (rate-limited 30/min/workspace). |
DELETE /api/prompt/:id | Developer+ | Soft-Delete in den Papierkorb (Standard); ?purge=true ist Owner-only Hard-Delete. |
POST /api/prompt/:id/restore | Owner | Aus Papierkorb wiederherstellen. |
POST /api/prompt/:id/rollback | Owner | Eine ältere Version als neue Version wiederherstellen. |
POST /api/prompt/:id/label | Owner | Ein Label auf eine Version verschieben (atomar, auditiert; akzeptiert auch ein split-Payload für A/B). |
Prompt-Provider (Föderation)
| Methode & Pfad | Rolle | Zweck |
|---|---|---|
GET /api/prompt_provider/ | Member | Listet verbundene Quellen (maskierte Secrets). |
POST /api/prompt_provider/ | Owner | Eine Quelle verbinden. |
PUT /api/prompt_provider/ | Owner | Eine Quelle aktualisieren. |
DELETE /api/prompt_provider/:id | Owner | Trennen. |
POST /api/prompt_provider/test | Owner | Trocken-Resolve vor dem Speichern. |
GET /api/prompt_provider/:id/prompts | Member | Listet Prompts, die in einer externen Quelle verfügbar sind. |
POST /api/prompt_provider/:id/prompts/import | Developer+ | Importiert einen externen Prompt in die lokale Registry. |
Prompt-Webhooks
| Methode & Pfad | Rolle | Zweck |
|---|---|---|
GET /api/prompt_webhook/ | Member | Listet Webhooks. |
POST /api/prompt_webhook/ | Owner | Webhook hinzufügen (Secret einmal zurückgegeben). |
PUT /api/prompt_webhook/:id | Owner | Bearbeiten. |
DELETE /api/prompt_webhook/:id | Owner | Entfernen. |
POST /api/prompt_webhook/:id/test | Owner | Ein Beispiel-Event senden. |
Webhook-Event-Zustellung
Jede Zustellung sendet einen JSON-Envelope per POST an deine konfigurierte URL:prompt.created, prompt.updated, prompt.deleted,
label.promoted, version.rolled_back.
Header bei jeder Zustellung:
X-Orca-Webhook-Id— die ID deines Webhooks (zur Deduplizierung).X-Orca-Event— identisch mit demevent-Feld des Envelopes.X-Orca-Signature— formatiert alssha256=<hex>, wobei<hex>der HMAC-SHA256 des rohen Request-Bodys ist, mit dem webhook secret als Schlüssel. Vergleich in konstanter Zeit durchführen.
Ergänzung zum Request-Payload
12. FAQ
Was passiert, wenn auf einer Anfrage kein Prompt aufgelöst wird?
Was passiert, wenn auf einer Anfrage kein Prompt aufgelöst wird?
prompt_ref
vorhanden ist und kein Channel-Default gesetzt ist, nimmt das Gateway
keine Änderungen vor. Die Antwort trägt keinen X-Orca-Prompt-Header.
Log-Spalten sind NULL.Das ist die Regressionsgarantie: Der Resolver ist ein verifizierter
No-Op, wenn nichts gebunden ist.Wie interagiert SystemPromptOverride mit der Registry?
Wie interagiert SystemPromptOverride mit der Registry?
SystemPromptOverride ist der existierende Channel-Level-Default für
die System-Prompt. Ein gebundener Registry-Prompt überschreibt den
Channel-Default — dokumentiert und beabsichtigt. Wenn nichts aufgelöst
wird, funktioniert der Channel-Default weiterhin genau wie zuvor.Wenn die Anfrage des Aufrufers bereits eine System-Message enthält,
entscheidet der Format-Adapter über das Verhalten: Bei OpenAI-förmigen
Requests wird die System-Message des Templates vorangestellt; bei
Claude-förmigen Requests landet das System des Templates im nativen
system-Parameter.Kann ich einschränken, welche Prompts ein bestimmter Key verwenden darf?
Kann ich einschränken, welche Prompts ein bestimmter Key verwenden darf?
prompt_ref jeden Prompt in seinem
eigenen Workspace verwenden. Das passt zum
workspace-bezogenen Key-Modell von Langfuse und LangSmith.
Cross-Workspace-Zugriff wird auf Resolver-Ebene verweigert (im
Relay-Pfad erneut geprüft; einer veralteten Bindung wird nie vertraut).Pro-Key-Prompt-Allowlists sind eine mögliche zukünftige Ergänzung.Werden injizierte Prompt-Tokens abgerechnet?
Werden injizierte Prompt-Tokens abgerechnet?
Überschreibt die Registry das Modell?
Überschreibt die Registry das Modell?
config.model / model_config externer Provider
werden ignoriert. Die Modellauswahl bleibt die alleinige Autorität des
Routers — Prompts injiziert nur Text.Was passiert mit einem Key, der an einen gelöschten Prompt gebunden ist?
Was passiert mit einem Key, der an einen gelöschten Prompt gebunden ist?
Wie schnell verbreiten sich Label-Verschiebungen?
Wie schnell verbreiten sich Label-Verschiebungen?
Kann ich Chat-Prompts in der UI bearbeiten?
Kann ich Chat-Prompts in der UI bearbeiten?
Text / Chat-Toggle;
der Chat-Modus zeigt einen strukturierten {role, content}-Editor.
Sobald ein Prompt erstellt ist, ist sein kind unveränderlich (Sie
würden einen neuen Prompt erstellen, um die Form zu ändern).Wo landen die Prompt-Stempel-Brotkrumen?
Wo landen die Prompt-Stempel-Brotkrumen?
- Response-Header
X-Orca-Promptauf der benutzerseitigen Antwort. Log.PromptId/PromptVersion/PromptLabel-Spalten auf der Request-Log-Zeile.- Insights-Prompt-Filterfacette — wählen Sie einen Prompt; jeder
Insights-Tab filtert auf diese
prompt_id.
Wie rotiere ich ein Webhook-Secret?
Wie rotiere ich ein Webhook-Secret?
PUT /api/prompt_webhook/:id und geben
Sie einen neuen secret-Wert an. Das neue Secret wird einmal in der
Response angezeigt — kopieren Sie es dann; danach ist das Secret
maskiert. (Es gibt keinen dedizierten Rotate-Endpoint; Rotation ist
eine normale Bearbeitung.)