1. Qué es el registro de prompts
El registro de prompts es una biblioteca con alcance de espacio de trabajo de mensajes de sistema reutilizables. Guardas un prompt una vez, vinculas cualquier clave API a él (o envías unprompt_ref por solicitud), y el
gateway inyecta ese prompt como mensaje de sistema antes de reenviar la
solicitud al modelo upstream.
Editar un prompt actualiza cada clave vinculada a él en la siguiente
llamada. Sin redespliegue. Sin cambio de código. Sin actualización del SDK.
La vinculación vive en el gateway, no en tu aplicación.
Esta es la misma idea que Langfuse y LangSmith inauguraron, pero con una
diferencia: OrcaRouter es la capa de entrega. El código de tu aplicación
llama a /v1/chat/completions exactamente como antes; el gateway resuelve e
inyecta el prompt. No hay nada que instalar en la aplicación.
Los prompts tienen alcance de espacio de trabajo — cada miembro ve los prompts
del espacio de trabajo; nada cruza límites de tenant.
2. Inicio rápido — vincula tu primer prompt en 5 pasos
Crear un prompt
/console/prompts y haz clic en New prompt.
Nómbralo support-agent. Pega el mensaje de sistema:“Eres un agente de soporte conciso para Acme. Responde en 2 frases o menos.”Guarda — esto crea la versión 1.
Vincular una clave
/console/token, crea o edita una clave API, selecciona
support-agent del desplegable Prompt y production del desplegable
Label.Enviar una solicitud
X-Orca-Prompt: support-agent@production:v1
confirma qué prompt fue inyectado.Editar el prompt
/console/prompts, edita support-agent — cambia el
mensaje de sistema. Guarda — la versión 2 se crea automáticamente;
production aún apunta a v1.3. Conceptos: prompts, versiones, etiquetas
| Concepto | Definición | Mutabilidad |
|---|---|---|
| Prompt | Una entrada con nombre, con alcance de espacio de trabajo. Identificador: name (regex ^[a-zA-Z0-9._-]{1,128}$). | Eliminación suave (papelera de 30 días + purga). |
| Versión | Una instantánea inmutable del contenido del prompt. Creada automáticamente en cada guardado. Identificador: int monotónico. | Inmutable — nunca editada, nunca reutilizada. |
| Etiqueta | Un puntero movible a una versión (p. ej. production → v7). | Movible atómicamente vía Promote; el registro de auditoría graba cada movimiento. |
Etiquetas reservadas
productionestá fijada automáticamente a v1 en la primera versión de cada nuevo prompt. Moverla es un cambio de tráfico de producción — RBAC solo para Owners.latestes mantenida automáticamente por el gateway y siempre apunta a la versión más reciente. No puedes moverlatestmanualmente.
staging, canary,
eu-prod) más tarde vía el diálogo Labels y vincular claves a ellas.
Hasta que una etiqueta esté fijada a una versión, una clave vinculada a
name@<esa-etiqueta> falla abierta sin inyección.
Por qué esta forma
La separación entre versiones inmutables y etiquetas movibles es la primitiva de despliegue-sin-código. El código de la aplicación se refiere a una etiqueta (implícitamente, vía la vinculación de clave, o explícitamente víaprompt_ref). Promover mueve la etiqueta — la aplicación ve el nuevo
contenido en la siguiente llamada sin cambio de código. Hacer rollback es
simplemente promover una versión más antigua sobre la etiqueta.
4. Patrones de producción: promoción, rollback, lanzamiento por etapas
Promover
Abre Labels en la fila de un prompt, elige la versión objetivo, haz clic en Promote. El movimiento de etiqueta es atómico y auditado (el registro de auditoría muestra quién movió qué etiqueta, de qué versión a qué versión, cuándo). Cada clave vinculada aname@<label> toma la nueva versión en la
siguiente solicitud.
POST /api/prompt/:id/label). Los Developers y Viewers ven la lista de
etiquetas y el historial de auditoría pero no el botón Promote; el diálogo
muestra una pista en línea “ask an Owner” para que la restricción sea visible
en vez de silenciosa.Rollback
Restore sobre una versión más antigua en el cajón History. Restaurar copia el contenido de esa versión hacia adelante como una nueva versión (el historial nunca se muta) y muevelatest a ella. Para que el tráfico
realmente retroceda, Promote la etiqueta relevante a la versión restaurada.
Lanzamiento por etapas
Vincula tus claves canary aname@staging, tus claves de producción a
name@production. Promueve staging a una nueva versión, observa en
Insights, luego promueve production cuando estés satisfecho. Sin
ediciones de clave, sin despliegue, sin actualización de SDK.
División de tráfico A/B
El diálogo Label tiene un toggle Split traffic. Actívalo para apuntar una sola etiqueta a múltiples versiones con distribución ponderada (p. ej. v7: 60 %, v8: 40 %). El bucketing es determinista por(workspace, token, request-id) para que una sola conversación permanezca en
el mismo bucket a través de los reintentos.
5. Plantillas: sustitución {{var}}
El contenido del prompt soporta marcadores {{var}} estilo Mustache. Los
valores del llamador provienen de prompt_ref.variables
(ver §6).
Reglas:
- Sustitución de un solo paso. Los valores de las variables se emiten
como texto literal. NO se reevalúan como plantilla — esto previene la
inyección de prompts donde un valor proporcionado por el llamador intenta
inyectar más directivas
{{...}}. - Los marcadores desconocidos permanecen literales. Si un marcador
{{foo}}no tiene una variable correspondiente, se emite el literal{{foo}}(y se registra un aviso). Las solicitudes nunca fallan porque falte una variable. - Acceso con punto.
{{user.name}}recorre objetos anidados cuando el llamador pasa un mapa anidado. - Secciones.
{{#flag}}...{{/flag}}muestra el bloque solo cuandoflages truthy. Las secciones invertidas ({{^flag}}...) muestran el bloque cuandoflages ausente/falsy. - Tope de tamaño renderizado: 256 KiB. Si el texto final renderizado
excede este umbral, toda la inyección se omite (la respuesta no lleva
cabecera
X-Orca-Prompt) y la solicitud se reenvía sin cambios — protección contra la amplificación por explosión de variables.
- Los prompts de Langfuse usan la misma sintaxis Mustache
{{var}}. - Los prompts de LangSmith declaran
template_format: f-string | mustacheen su manifiesto. El gateway respeta esa declaración.
6. Sobrescritura por solicitud: prompt_ref
Sobrescribe o selecciona un prompt por solicitud sin cambiar la
vinculación de clave. Añade un campo prompt_ref de nivel superior al cuerpo
de la solicitud:
prompt_ref de la solicitud > vinculación
de clave (PromptId/PromptLabel nativos o PromptProviderId) >
SystemPrompt del canal > ninguno.
prompt_ref es consumido por el gateway y eliminado antes del reenvío
upstream — los proveedores estrictos nunca ven el campo desconocido.
Forma:
7. Prompts con forma de chat (sistema + few-shot)
La mayoría de los prompts son una sola cadena de sistema. Pero a veces quieres que el gateway inyecte una plantilla más rica — un mensaje de sistema más una secuencia few-shot de turnos user/assistant. El registro soporta esto comokind: 'chat'.
El modal Create prompt de la consola expone un toggle Text / Chat.
Cuando eliges Chat, el editor de contenido se convierte en una lista de
filas {role, content} (system, user, assistant) — añade tantas como
necesites. Al guardar, las filas se persisten como messages_json. Una vez
creado, kind es inmutable.
Comportamiento en la inyección:
- Sin mensaje de sistema en la solicitud ⇒ el gateway antepone el mensaje de sistema de la plantilla y los turnos few-shot de la plantilla aparecen antes de los mensajes del llamador.
- Mensaje de sistema en la solicitud ⇒ la inyección sigue el valor por
defecto del adaptador de formato. Para solicitudes con forma OpenAI, el
mensaje de sistema de la plantilla se antepone; para solicitudes con
forma Claude, el system de la plantilla va al parámetro nativo
system.
8. Relación con el resto del gateway
| Superficie | ¿Cómo se compone con Prompts? |
|---|---|
| Modelos | Los prompts son agnósticos del modelo. El mismo prompt viaja sobre GPT-5, Claude, Gemini. El enrutamiento elige el modelo upstream basándose en el model de la solicitud y el grupo de la clave — Prompts nunca sobrescribe eso. |
| Enrutamiento | El enrutamiento se ejecuta primero; el resolvedor de prompt se ejecuta después. Así, el prompt resuelto viaja por el canal que el router eligió, incluso a través de una cadena de fallback. |
| Guardrails | Los guardrails son una puerta independiente que inspecciona y redacta contenido. Los prompts inyectan un mensaje de sistema; no eluden la política. Una solicitud puede llevar ambos — los guardrails siempre se ejecutan. |
| Claves API | Una clave se vincula a un prompt en una etiqueta (p. ej. support-agent@production). La vinculación vive en la clave dentro del gateway, por lo que promover una nueva versión cambia todas las claves con esa etiqueta a la vez. |
| Insights | Cada solicitud estampa prompt_id, prompt_version, prompt_label en su fila de log. Insights segmenta por prompt — uso, tasa de error, latencia, coste. |
config (Langfuse config.model, LangSmith
model_config) — el gateway ignora esos campos. Los prompts inyectan texto
únicamente; la selección de modelo es trabajo del router.
9. Fuentes externas: Langfuse, LangSmith, HTTP genérico
Federación: conecta una fuente externa de prompts una vez, luego vincula claves o envíaprompt_ref contra nombres alojados allí. Los prompts
nativos y externos se vinculan y sirven idénticamente — solo difiere el
backend del resolvedor.
Fuentes soportadas:
- Langfuse —
GET {base}/api/public/v2/prompts/{name}?label=..., autenticación Basic desde tu parpublic:secret. Prompts de texto y chat. - LangSmith —
GET {base}/commits/{owner}/{name}/{tag|hash|latest}, cabecerax-api-key. El gateway analiza el manifiesto serializado para extraer mensajes/texto y la declaracióntemplate_format. Los campos incrustadosmodel_config/model_providerse eliminan (defensa en profundidad: el registro sirve solo texto). - HTTP genérico — conector configurado por el operador para cualquier registro de prompts que exponga una sola llamada HTTP por fetch. Ver abajo los campos configurables.
Campos del conector HTTP genérico
Una fuente HTTP genérica es un adaptador “describe una llamada HTTP y una forma de respuesta”. Usada para almacenes de prompts auto-hospedados Y para plataformas de terceros que no necesitan su propia integración backend (PromptLayer, APIs personalizadas simples, etc.). Los campos son deliberadamente pequeños — los flujos de múltiples pasos o los protocolos específicos de proveedor están fuera del alcance.| Campo | Por defecto | Qué hace |
|---|---|---|
| URL template | requerido | La URL de solicitud completa con marcadores {name} / {label} / {version}. Los marcadores en la ruta usan PathEscape; los marcadores en el query string usan QueryEscape para que &/= en un nombre de prompt no puedan inyectar parámetros de consulta adicionales. |
| HTTP method | GET | GET o POST. Elige POST cuando la plataforma requiera un cuerpo de solicitud. |
| Auth header name | Authorization | La cabecera HTTP en la que se envía el secreto. Establecer a X-API-KEY (o similar) para proveedores que usen una cabecera personalizada. |
| Auth scheme prefix | Bearer (con espacio final) | Cadena antepuesta al secreto en el valor de la cabecera. Establecer vacío si la plataforma espera una clave API en bruto, o Token / otro prefijo personalizado. |
| Body template | vacío | Solo POST. El cuerpo de solicitud crudo con dos familias de marcadores. Verbatim: {name} / {label} / {version} sustituyen el valor literal (usar para cuerpos form-encoded, XML o plantilla — tú te encargas del escape). JSON-safe: {name_json} / {label_json} / {version_json} sustituyen un literal de cadena JSON totalmente entrecomillado (p. ej. "hello") — usar estos DENTRO de cuerpos JSON para que un nombre de prompt del lado de la solicitud que contenga " / \ / caracteres de control no pueda inyectar campos hermanos upstream. |
| Response JSON path | vacío | Ruta opcional con punto en el JSON de respuesta donde vive el payload del prompt (p. ej. data.0.template.messages). Vacío = autodetección de formas de nivel superior text / prompt / messages. |
Resiliencia
- Caché TTL (60s por defecto) para que las ediciones de prompts se propaguen en menos de un minuto.
- Stale-while-revalidate — el valor en caché sirve mientras la siguiente actualización se ejecuta en segundo plano.
- Stale-on-error — si la fuente externa devuelve 5xx o agota el tiempo, el gateway sirve la última respuesta conocida como buena. El tráfico de usuario nunca falla duro por una interrupción del proveedor.
10. Observabilidad
Cada solicitud con prompt inyectado deja cuatro migas de pan.Cabecera de respuesta
- Nativo:
name@label:vN (native)(oname@label (native)cuando el entero de versión es desconocido). - Externo:
name@label:<provider-version-tag> (langfuse), etc. - Etiqueta omitida ⇒ sin segmento
@label.
Columnas de log
Log.PromptId, Log.PromptVersion, Log.PromptLabel — columnas tipadas,
indexadas para consultas de Insights.
Drilldown de Insights
En/console/insights, la fila de filtros tiene una faceta Prompt —
elige un prompt y cada pestaña (latencia, errores, coste) filtra por ese
prompt_id. Este es el cierre de bucle para “edité un prompt — ¿qué cambió
en el tráfico?”.
Auditoría
Cada movimiento de etiqueta y rollback se registra en el historial Promote del prompt con el id del usuario actor, marca de tiempo, versión origen y versión destino. Visible para cada miembro; la mutación está restringida al rol Owner.11. Referencia de la API
Todas las rutas tienen alcance de espacio de trabajo vía la cabeceraX-Workspace-Id. RBAC se aplica de manera consistente: las lecturas están
abiertas a cada miembro; las escrituras son Developer+; los cambios de
tráfico de producción (movimientos de etiqueta, rollbacks, configuración de
proveedor, webhooks) son solo para Owners.
Prompts
| Método y ruta | Rol | Propósito |
|---|---|---|
GET /api/prompt/ | Member | Lista prompts (paginado, soporta ?tag=). |
GET /api/prompt/?in_trash=true | Owner | Lista prompts eliminados (solo Owner — clase de recuperación). |
GET /api/prompt/search | Member | Búsqueda por palabra clave + tag (rate-limited). |
GET /api/prompt/tags | Member | Typeahead de tags para el espacio de trabajo. |
GET /api/prompt/:id | Member | Detalle de un solo prompt. |
GET /api/prompt/:id/versions | Member | Historial de versiones (más nueva primero). |
GET /api/prompt/:id/labels | Member | Mapa actual etiqueta → versión. |
GET /api/prompt/:id/tags | Member | Conjunto de tags para un prompt. |
GET /api/prompt/:id/label_history | Member | Log de auditoría de promociones. |
GET /api/prompt/:id/analytics | Member | Datos de gráfico de uso por prompt. |
GET /api/prompt/analytics/top | Member | Prompts más usados a nivel de espacio de trabajo. |
POST /api/prompt/ | Developer+ | Crear prompt (texto o chat). |
PUT /api/prompt/ | Developer+ | Actualizar prompt (crea una nueva versión). |
POST /api/prompt/:id/tags | Developer+ | Reemplazar el conjunto de tags. |
POST /api/prompt/:id/run | Developer+ | “Try it” del Playground (rate-limited 30/min/workspace). |
DELETE /api/prompt/:id | Developer+ | Eliminación suave a la papelera (por defecto); ?purge=true es eliminación dura solo para Owner. |
POST /api/prompt/:id/restore | Owner | Restaurar desde la papelera. |
POST /api/prompt/:id/rollback | Owner | Restaurar una versión más antigua como nueva versión. |
POST /api/prompt/:id/label | Owner | Mover una etiqueta a una versión (atómico, auditado; también acepta un payload split para A/B). |
Proveedores de prompts (federación)
| Método y ruta | Rol | Propósito |
|---|---|---|
GET /api/prompt_provider/ | Member | Lista fuentes conectadas (secretos enmascarados). |
POST /api/prompt_provider/ | Owner | Conectar una fuente. |
PUT /api/prompt_provider/ | Owner | Actualizar una fuente. |
DELETE /api/prompt_provider/:id | Owner | Desconectar. |
POST /api/prompt_provider/test | Owner | Resolución en seco antes de guardar. |
GET /api/prompt_provider/:id/prompts | Member | Lista prompts disponibles en una fuente externa. |
POST /api/prompt_provider/:id/prompts/import | Developer+ | Importa un prompt externo al registro local. |
Webhooks de prompts
| Método y ruta | Rol | Propósito |
|---|---|---|
GET /api/prompt_webhook/ | Member | Lista webhooks. |
POST /api/prompt_webhook/ | Owner | Añadir un webhook (secreto devuelto una vez). |
PUT /api/prompt_webhook/:id | Owner | Editar. |
DELETE /api/prompt_webhook/:id | Owner | Eliminar. |
POST /api/prompt_webhook/:id/test | Owner | Enviar un evento de muestra. |
Entrega de eventos del webhook
Cada entrega envía un POST con un sobre JSON a la URL que hayas configurado:prompt.created, prompt.updated, prompt.deleted,
label.promoted, version.rolled_back.
Cabeceras en cada entrega:
X-Orca-Webhook-Id— el id de tu webhook (úsalo para deduplicar).X-Orca-Event— igual al campoeventdel sobre.X-Orca-Signature— con formatosha256=<hex>, donde<hex>es el HMAC-SHA256 del cuerpo en bruto de la solicitud, usando el webhook secret como clave. Compara en tiempo constante.
Adición al payload de solicitud
12. FAQ
¿Qué pasa si no se resuelve ningún prompt en una solicitud?
¿Qué pasa si no se resuelve ningún prompt en una solicitud?
prompt_ref presente y no hay valor por defecto del canal establecido,
el gateway no hace modificaciones. La respuesta no lleva cabecera
X-Orca-Prompt. Las columnas de log son NULL.Esta es la garantía de no regresión: el resolvedor es un no-op
verificado cuando nada está vinculado.¿Cómo interactúa SystemPromptOverride con el registro?
¿Cómo interactúa SystemPromptOverride con el registro?
SystemPromptOverride es el valor por defecto existente de mensaje de
sistema a nivel de canal. Un prompt vinculado del registro sobrescribe
el valor por defecto del canal — documentado e intencional. Cuando nada
se resuelve, el valor por defecto del canal sigue funcionando
exactamente como antes.Cuando la solicitud del llamador ya incluye un mensaje de sistema, el
comportamiento lo decide el adaptador de formato: las solicitudes con
forma OpenAI reciben el mensaje de sistema de la plantilla
antepuesto; las solicitudes con forma Claude colocan el system de la
plantilla en el parámetro nativo system.¿Puedo limitar qué prompts puede usar una clave específica?
¿Puedo limitar qué prompts puede usar una clave específica?
prompt_ref cualquier prompt en su
propio espacio de trabajo. Esto coincide con el modelo de clave con
alcance de espacio de trabajo de Langfuse y LangSmith. El acceso entre
espacios de trabajo se deniega a nivel del resolvedor (revalidado en la
ruta de relay; nunca se confía en una vinculación obsoleta).Las allowlists de prompts por clave son una posible adición futura.¿Se facturan los tokens de prompt inyectados?
¿Se facturan los tokens de prompt inyectados?
¿Sobrescribe el registro el modelo?
¿Sobrescribe el registro el modelo?
config.model / model_config de proveedores externos
se ignoran. La selección de modelo sigue siendo la única autoridad del
router — Prompts inyecta texto únicamente.¿Qué le pasa a una clave vinculada a un prompt eliminado?
¿Qué le pasa a una clave vinculada a un prompt eliminado?
¿Qué tan rápido se propagan los movimientos de etiqueta?
¿Qué tan rápido se propagan los movimientos de etiqueta?
¿Puedo editar prompts de chat en la UI?
¿Puedo editar prompts de chat en la UI?
Text / Chat; el modo
chat muestra un editor estructurado {role, content}. Una vez creado
un prompt, su kind es inmutable (crearías un nuevo prompt para
cambiar de forma).¿Dónde acaban las migas de pan de los prompts?
¿Dónde acaban las migas de pan de los prompts?
- Cabecera de respuesta
X-Orca-Prompten la respuesta dirigida al usuario. - Columnas
Log.PromptId/PromptVersion/PromptLabelen la fila de log de la solicitud. - Faceta de filtro Prompt de Insights — elige un prompt; cada
pestaña de Insights filtra por ese
prompt_id.
¿Cómo roto un secreto de webhook?
¿Cómo roto un secreto de webhook?
PUT /api/prompt_webhook/:id y proporciona un
nuevo valor de secret. El nuevo secreto se muestra una vez en la
respuesta — cópialo entonces; después el secreto queda enmascarado.
(No hay un endpoint dedicado de rotación; rotar es una edición
normal.)