1. Cos’è il registry dei prompt
Il registry dei prompt è una libreria con scope a livello di workspace di messaggi di sistema riutilizzabili. Salvi un prompt una volta, colleghi qualsiasi chiave API ad esso (o invii unprompt_ref per richiesta), e il
gateway inietta quel prompt come messaggio di sistema prima di inoltrare la
richiesta al modello upstream.
Modificare un prompt aggiorna ogni chiave ad esso collegata alla
chiamata successiva. Nessun redeploy. Nessuna modifica al codice. Nessun
upgrade dell’SDK. Il binding vive nel gateway, non nella tua applicazione.
Questa è la stessa idea introdotta da Langfuse e LangSmith, con una
differenza: OrcaRouter è il livello di consegna. Il codice della tua
applicazione chiama /v1/chat/completions esattamente come prima; il
gateway risolve e inietta il prompt. Non c’è nulla da installare
nell’applicazione.
I prompt hanno scope a livello di workspace — ogni membro vede i prompt
del workspace; nulla attraversa i confini di tenant.
2. Quickstart — collega il tuo primo prompt in 5 passi
Creare un prompt
/console/prompts e fai clic su New prompt.
Chiamalo support-agent. Incolla il messaggio di sistema:“Sei un agente di supporto conciso per Acme. Rispondi in 2 frasi o meno.”Salva — questo crea la versione 1.
Collegare una chiave
/console/token, crea o modifica una chiave API, seleziona
support-agent dal menu a tendina Prompt e production dal menu
a tendina Label.Inviare una richiesta
X-Orca-Prompt: support-agent@production:v1 conferma quale prompt è
stato iniettato.Modificare il prompt
/console/prompts, modifica support-agent — cambia il
messaggio di sistema. Salva — la versione 2 viene creata
automaticamente; production punta ancora a v1.3. Concetti: prompt, versioni, etichette
| Concetto | Definizione | Mutabilità |
|---|---|---|
| Prompt | Una voce nominata, con scope a livello di workspace. Identificatore: name (regex ^[a-zA-Z0-9._-]{1,128}$). | Soft-eliminabile (cestino di 30 giorni + purge). |
| Versione | Uno snapshot immutabile del contenuto del prompt. Creata automaticamente a ogni salvataggio. Identificatore: int monotonico. | Immutabile — mai modificata, mai riutilizzata. |
| Etichetta | Un puntatore mobile a una versione (es. production → v7). | Mobile atomicamente via Promote; il log di audit registra ogni spostamento. |
Etichette riservate
productionè auto-fissata a v1 alla prima versione di ogni nuovo prompt. Spostarla è un cambio di traffico di produzione — RBAC solo per Owner.latestè mantenuta automaticamente dal gateway e punta sempre alla versione più recente. Non puoi spostarelatestmanualmente.
staging, canary,
eu-prod) successivamente tramite il dialog Labels e collegare chiavi
ad esse. Finché un’etichetta non è fissata a una versione, una chiave
collegata a name@<quella-etichetta> fallisce open senza iniezione.
Perché questa forma
La separazione tra versioni immutabili ed etichette mobili è la primitiva del deploy-senza-codice. Il codice dell’applicazione fa riferimento a un’etichetta (implicitamente, tramite il binding della chiave, o esplicitamente tramiteprompt_ref). Promuovere sposta l’etichetta —
l’applicazione vede il nuovo contenuto alla chiamata successiva senza
modifiche al codice. Fare rollback significa semplicemente promuovere una
versione più vecchia sull’etichetta.
4. Pattern di produzione: promote, rollback, rilascio scaglionato
Promote
Apri Labels sulla riga di un prompt, scegli la versione target, fai clic su Promote. Lo spostamento dell’etichetta è atomico e auditato (il log di audit mostra chi ha spostato quale etichetta, da quale versione a quale versione, quando). Ogni chiave collegata aname@<label> prende la nuova
versione alla richiesta successiva.
POST /api/prompt/:id/label). Developer
e Viewer vedono l’elenco delle etichette e la cronologia di audit ma non
il pulsante Promote; il dialog mostra un suggerimento inline “ask an
Owner” così che la restrizione sia visibile anziché silenziosa.Rollback
Restore su una versione più vecchia nel cassetto History. Restore copia il contenuto di quella versione in avanti come una nuova versione (la cronologia non viene mai mutata) e spostalatest su di essa. Affinché
il traffico effettivamente torni indietro, Promote l’etichetta rilevante
sulla versione ripristinata.
Rilascio scaglionato
Collega le tue chiavi canary aname@staging, le tue chiavi di produzione
a name@production. Promuovi staging a una nuova versione, osserva in
Insights, poi promuovi production quando sei soddisfatto. Nessuna
modifica alle chiavi, nessun deploy, nessun aggiornamento dell’SDK.
Split di traffico A/B
Il dialog Label ha un toggle Split traffic. Attivalo per puntare una singola etichetta a più versioni con distribuzione pesata (es. v7: 60 %, v8: 40 %). Il bucketing è deterministico per(workspace, token, request-id) così che una singola conversazione resta
nello stesso bucket attraverso i retry.
5. Templating: sostituzione {{var}}
Il contenuto del prompt supporta placeholder {{var}} in stile Mustache.
I valori del chiamante provengono da prompt_ref.variables
(vedi §6).
Regole:
- Sostituzione single-pass. I valori delle variabili sono emessi come
testo letterale. NON vengono rivalutati come template — questo previene
prompt injection in cui un valore fornito dal chiamante prova a iniettare
ulteriori direttive
{{...}}. - I placeholder sconosciuti restano verbatim. Se un placeholder
{{foo}}non ha una variabile corrispondente, il letterale{{foo}}viene emesso (e viene loggato un warning). Le richieste non falliscono mai per una variabile mancante. - Accesso con punto.
{{user.name}}percorre oggetti annidati quando il chiamante passa una mappa annidata. - Sezioni.
{{#flag}}...{{/flag}}mostra il blocco solo quandoflagè truthy. Le sezioni invertite ({{^flag}}...) mostrano il blocco quandoflagè mancante/falsy. - Limite di dimensione del testo renderizzato: 256 KiB. Se il testo
finale renderizzato supera questa soglia, l’intera iniezione viene
saltata (la risposta non porta l’header
X-Orca-Prompt) e la richiesta viene inoltrata invariata — protezione contro l’amplificazione da esplosione di variabili.
- I prompt Langfuse usano la stessa sintassi Mustache
{{var}}. - I prompt LangSmith dichiarano
template_format: f-string | mustachenel loro manifest. Il gateway rispetta tale dichiarazione.
6. Override per richiesta: prompt_ref
Sovrascrivi o seleziona un prompt per richiesta senza modificare il
binding della chiave. Aggiungi un campo prompt_ref di primo livello al
body della richiesta:
prompt_ref della richiesta > binding
della chiave (PromptId/PromptLabel nativo o PromptProviderId) >
SystemPrompt del canale > nessuno.
prompt_ref è consumato dal gateway e rimosso prima dell’inoltro
upstream — i provider stretti non vedono mai il campo sconosciuto.
Forma:
7. Prompt in forma di chat (system + few-shot)
La maggior parte dei prompt è una singola stringa di sistema. Ma a volte vuoi che il gateway inietti un template più ricco — un messaggio di sistema più una sequenza few-shot di turni user/assistant. Il registry supporta questo comekind: 'chat'.
Il modal Create prompt della console espone un toggle Text / Chat.
Quando scegli Chat, l’editor del contenuto diventa un elenco di righe
{role, content} (system, user, assistant) — aggiungine quante ne servono.
Al salvataggio, le righe sono persistite come messages_json. Una volta
creato, kind è immutabile.
Comportamento all’iniezione:
- Nessun messaggio di sistema nella richiesta ⇒ il gateway antepone il messaggio di sistema del template e i turni few-shot del template compaiono prima dei messaggi del chiamante.
- Messaggio di sistema nella richiesta ⇒ l’iniezione segue il default
dell’adattatore di formato. Per richieste in forma OpenAI, il messaggio
di sistema del template viene anteposto; per richieste in forma Claude,
il sistema del template va nel parametro nativo
system.
8. Relazione con il resto del gateway
| Superficie | Come si compone con i Prompt? |
|---|---|
| Modelli | I prompt sono agnostici rispetto al modello. Lo stesso prompt viaggia su GPT-5, Claude, Gemini. Il routing sceglie il modello upstream in base al model della richiesta e al gruppo della chiave — Prompts non sovrascrive mai questo. |
| Routing | Il routing gira per primo; il resolver dei prompt gira dopo. Quindi il prompt risolto viaggia sul canale scelto dal router, incluso attraverso una catena di fallback. |
| Guardrails | I guardrails sono un gate indipendente che ispeziona e redige il contenuto. I prompt iniettano un messaggio di sistema; non bypassano la policy. Una richiesta può portare entrambi — i guardrails girano sempre. |
| Chiavi API | Una chiave si collega a un prompt a un’etichetta (es. support-agent@production). Il binding vive sulla chiave nel gateway, quindi promuovere una nuova versione sposta tutte le chiavi su quell’etichetta contemporaneamente. |
| Insights | Ogni richiesta stampa prompt_id, prompt_version, prompt_label sulla sua riga di log. Insights segmenta per prompt — utilizzo, tasso di errore, latenza, costo. |
config (Langfuse config.model, LangSmith
model_config) — il gateway ignora quei campi. I prompt iniettano solo
testo; la selezione del modello è compito del router.
9. Sorgenti esterne: Langfuse, LangSmith, HTTP generico
Federazione: collega una sorgente di prompt esterna una volta, poi collega chiavi o inviaprompt_ref contro nomi ospitati lì. I prompt nativi ed
esterni si collegano e servono in modo identico — differisce solo il
backend del resolver.
Sorgenti supportate:
- Langfuse —
GET {base}/api/public/v2/prompts/{name}?label=..., Basic auth dalla tua coppiapublic:secret. Prompt text e chat. - LangSmith —
GET {base}/commits/{owner}/{name}/{tag|hash|latest}, headerx-api-key. Il gateway analizza il manifest serializzato per estrarre messaggi/testo e la dichiarazionetemplate_format. I campi incorporatimodel_config/model_providervengono rimossi (defense in depth: il registry serve solo testo). - HTTP generico — connettore configurato dall’operatore per qualsiasi registry di prompt che esponga una singola chiamata HTTP per fetch. Vedi sotto per i campi configurabili.
Campi del connettore HTTP generico
Una sorgente HTTP generica è un adattatore “descrivi una chiamata HTTP e una forma di risposta”. Usata per archivi di prompt self-hosted E per piattaforme di terze parti che non necessitano di una propria integrazione backend (PromptLayer, semplici API personalizzate, ecc.). I campi sono deliberatamente ridotti — flussi multi-step o protocolli specifici di provider sono fuori scope.| Campo | Default | Cosa fa |
|---|---|---|
| URL template | richiesto | L’URL completo della richiesta con placeholder {name} / {label} / {version}. I placeholder nel path usano PathEscape; i placeholder nella query string usano QueryEscape così che &/= in un nome prompt non possano iniettare parametri di query aggiuntivi. |
| HTTP method | GET | GET o POST. Scegli POST quando la piattaforma richiede un body di richiesta. |
| Auth header name | Authorization | L’header HTTP in cui viene inviato il segreto. Imposta a X-API-KEY (o simile) per provider che usano un header personalizzato. |
| Auth scheme prefix | Bearer (con spazio finale) | Stringa anteposta al segreto nel valore dell’header. Imposta vuoto se la piattaforma si aspetta una chiave API grezza, oppure Token / un altro prefisso personalizzato. |
| Body template | vuoto | Solo POST. Il body grezzo della richiesta con due famiglie di placeholder. Verbatim: {name} / {label} / {version} sostituiscono il valore letterale (usa per body form-encoded, XML o template — sei tu responsabile dell’escaping). JSON-safe: {name_json} / {label_json} / {version_json} sostituiscono un literal di stringa JSON completamente quotato (es. "hello") — usali ALL’INTERNO di body JSON così che un nome prompt lato richiesta contenente " / \ / caratteri di controllo non possa iniettare campi fratelli upstream. |
| Response JSON path | vuoto | Path opzionale con punto nel JSON di risposta dove vive il payload del prompt (es. data.0.template.messages). Vuoto = auto-detect delle forme top-level text / prompt / messages. |
Resilienza
- Cache TTL (default 60s) così che le modifiche ai prompt si propagano entro un minuto.
- Stale-while-revalidate — il valore in cache serve mentre il refresh successivo gira in background.
- Stale-on-error — se la sorgente esterna restituisce 5xx o va in timeout, il gateway serve l’ultima risposta nota buona. Il traffico utente non viene mai hard-failed da un’interruzione del provider.
10. Osservabilità
Ogni richiesta con prompt iniettato lascia quattro briciole di pane.Header di risposta
- Nativo:
name@label:vN (native)(oppurename@label (native)quando l’intero di versione è sconosciuto). - Esterno:
name@label:<provider-version-tag> (langfuse)ecc. - Etichetta omessa ⇒ nessun segmento
@label.
Colonne di log
Log.PromptId, Log.PromptVersion, Log.PromptLabel — colonne tipizzate,
indicizzate per query Insights.
Drilldown di Insights
In/console/insights, la riga dei filtri ha una facet Prompt —
scegli un prompt e ogni tab (latenza, errori, costo) filtra su quel
prompt_id. Questa è la chiusura del cerchio per “ho modificato un prompt
— cos’è cambiato nel traffico?”.
Audit
Ogni spostamento di etichetta e rollback è registrato nella cronologia Promote del prompt con id utente attore, timestamp, versione di partenza e versione di arrivo. Visibile a ogni membro; la mutazione è limitata al ruolo Owner.11. Riferimento API
Tutte le rotte hanno scope a livello di workspace tramite l’headerX-Workspace-Id. RBAC viene applicato in modo coerente: le letture sono
aperte a ogni membro; le scritture sono Developer+; le modifiche al
traffico di produzione (spostamenti di etichetta, rollback, configurazione
provider, webhook) sono solo Owner.
Prompts
| Metodo & path | Ruolo | Scopo |
|---|---|---|
GET /api/prompt/ | Member | Elenca prompt (paginato, supporta ?tag=). |
GET /api/prompt/?in_trash=true | Owner | Elenca prompt soft-eliminati (solo Owner — classe recovery). |
GET /api/prompt/search | Member | Ricerca keyword + tag (rate-limited). |
GET /api/prompt/tags | Member | Typeahead di tag per il workspace. |
GET /api/prompt/:id | Member | Dettaglio di un singolo prompt. |
GET /api/prompt/:id/versions | Member | Cronologia versioni (più recente per prima). |
GET /api/prompt/:id/labels | Member | Mappa corrente etichetta → versione. |
GET /api/prompt/:id/tags | Member | Insieme dei tag per un prompt. |
GET /api/prompt/:id/label_history | Member | Log di audit delle promozioni. |
GET /api/prompt/:id/analytics | Member | Dati del grafico di utilizzo per prompt. |
GET /api/prompt/analytics/top | Member | Prompt più usati a livello workspace. |
POST /api/prompt/ | Developer+ | Crea prompt (text o chat). |
PUT /api/prompt/ | Developer+ | Aggiorna prompt (crea una nuova versione). |
POST /api/prompt/:id/tags | Developer+ | Sostituisce l’insieme dei tag. |
POST /api/prompt/:id/run | Developer+ | “Try it” del Playground (rate-limited 30/min/workspace). |
DELETE /api/prompt/:id | Developer+ | Soft-delete nel cestino (default); ?purge=true è hard delete solo Owner. |
POST /api/prompt/:id/restore | Owner | Ripristina dal cestino. |
POST /api/prompt/:id/rollback | Owner | Ripristina una versione più vecchia come nuova versione. |
POST /api/prompt/:id/label | Owner | Sposta un’etichetta a una versione (atomico, auditato; accetta anche un payload split per A/B). |
Provider di prompt (federazione)
| Metodo & path | Ruolo | Scopo |
|---|---|---|
GET /api/prompt_provider/ | Member | Elenca sorgenti connesse (segreti mascherati). |
POST /api/prompt_provider/ | Owner | Collega una sorgente. |
PUT /api/prompt_provider/ | Owner | Aggiorna una sorgente. |
DELETE /api/prompt_provider/:id | Owner | Disconnetti. |
POST /api/prompt_provider/test | Owner | Risoluzione a vuoto prima del salvataggio. |
GET /api/prompt_provider/:id/prompts | Member | Elenca i prompt disponibili in una sorgente esterna. |
POST /api/prompt_provider/:id/prompts/import | Developer+ | Importa un prompt esterno nel registry locale. |
Webhook dei prompt
| Metodo & path | Ruolo | Scopo |
|---|---|---|
GET /api/prompt_webhook/ | Member | Elenca webhook. |
POST /api/prompt_webhook/ | Owner | Aggiungi un webhook (segreto restituito una volta). |
PUT /api/prompt_webhook/:id | Owner | Modifica. |
DELETE /api/prompt_webhook/:id | Owner | Rimuovi. |
POST /api/prompt_webhook/:id/test | Owner | Invia un evento di esempio. |
Consegna degli eventi webhook
Ogni consegna invia in POST una busta JSON all’URL che hai configurato:prompt.created, prompt.updated, prompt.deleted,
label.promoted, version.rolled_back.
Header presenti in ogni consegna:
X-Orca-Webhook-Id— l’id del tuo webhook (usalo per la deduplica).X-Orca-Event— uguale al campoeventdella busta.X-Orca-Signature— nel formatosha256=<hex>, dove<hex>è l’HMAC-SHA256 del body grezzo della richiesta, firmato con il webhook secret. Confronta in tempo costante.
Aggiunta al payload della richiesta
12. FAQ
Cosa succede se nessun prompt si risolve su una richiesta?
Cosa succede se nessun prompt si risolve su una richiesta?
prompt_ref è presente e nessun default di canale è impostato, il
gateway non effettua modifiche. La risposta non porta l’header
X-Orca-Prompt. Le colonne di log sono NULL.Questa è la garanzia di non regressione: il resolver è un no-op
verificato quando nulla è collegato.Come interagisce SystemPromptOverride con il registry?
Come interagisce SystemPromptOverride con il registry?
SystemPromptOverride è il default esistente di system-prompt a
livello di canale. Un prompt del registry collegato sovrascrive il
default del canale — documentato e intenzionale. Quando nulla si
risolve, il default del canale funziona ancora esattamente come prima.Quando la richiesta del chiamante include già un messaggio di
sistema, il comportamento è deciso dall’adattatore di formato: le
richieste in forma OpenAI ricevono il messaggio di sistema del
template anteposto; le richieste in forma Claude collocano il sistema
del template nel parametro nativo system.Posso limitare quali prompt una chiave specifica può usare?
Posso limitare quali prompt una chiave specifica può usare?
prompt_ref di qualsiasi prompt
nel proprio workspace. Questo corrisponde al modello di chiave con
scope workspace di Langfuse e LangSmith. L’accesso cross-workspace è
negato a livello di resolver (ricontrollato nel relay path; non ci si
fida mai di un binding obsoleto).Le allowlist di prompt per chiave sono una possibile aggiunta futura.I token dei prompt iniettati vengono fatturati?
I token dei prompt iniettati vengono fatturati?
Il registry sovrascrive il modello?
Il registry sovrascrive il modello?
config.model / model_config dei provider esterni
vengono ignorati. La selezione del modello resta l’unica autorità del
router — Prompts inietta solo testo.Cosa succede a una chiave collegata a un prompt eliminato?
Cosa succede a una chiave collegata a un prompt eliminato?
Quanto velocemente si propagano gli spostamenti di etichetta?
Quanto velocemente si propagano gli spostamenti di etichetta?
Posso modificare i prompt chat nell'UI?
Posso modificare i prompt chat nell'UI?
Text / Chat; la
modalità chat mostra un editor strutturato {role, content}. Una
volta creato un prompt, il suo kind è immutabile (creeresti un
nuovo prompt per cambiare forma).Dove finiscono le briciole di pane dei prompt?
Dove finiscono le briciole di pane dei prompt?
- Header di risposta
X-Orca-Promptsulla risposta lato utente. - Colonne
Log.PromptId/PromptVersion/PromptLabelsulla riga di log della richiesta. - Facet di filtro Prompt di Insights — scegli un prompt; ogni tab
di Insights filtra su quel
prompt_id.
Come ruoto un segreto di webhook?
Come ruoto un segreto di webhook?
PUT /api/prompt_webhook/:id e fornisci
un nuovo valore di secret. Il nuovo segreto viene mostrato una
volta nella risposta — copialo allora; in seguito il segreto è
mascherato. (Non esiste un endpoint dedicato per la rotazione; la
rotazione è una normale modifica.)