Versionar tool schemas de agentes: cambios solo aditivos y rollout sin romper producción
Resumen
El modelo es un cliente que no lee changelogs: un parámetro renombrado o vuelto requerido rompe agentes en silencio. Contrato de versionado para tool schemas —cambios solo aditivos, toolset_version visible y rollout shadow → canary → deprecación— con strict mode, matriz de cambios y checklist de release.

Qué resuelve
Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.
El modelo es un cliente que no lee changelogs. Cuando renombras un parámetro de un tool, vuelves requerido un campo opcional o cambias un enum, el agente no recibe un error de compilación: recibe un schema distinto al que aprendió en el system prompt y falla en producción con llamadas malformadas, argumentos inventados o silencio. Versionar tool schemas es el contrato que evita eso: cambios solo aditivos, versión del toolset visible en cada llamada y rollout en tres fases —shadow, canary, deprecación—.
No es reintentos. Reintentar recupera una llamada que falló; versionar evita que la llamada falle porque el contrato cambió bajo los pies del agente. No es idempotencia: idempotente significa que repetir el efecto es seguro; versionado significa que el formato del efecto sigue siendo el que el modelo espera. Y no es evaluar si el agente funciona: los evals detectan la regresión después del deploy; el versionado impide introducirla. En todos rige la misma higiene: cero volcar el schema crudo al contexto como documentación.
Contrato: todo cambio de schema es aditivo o lleva versión nueva. El modelo nunca adivina: si el schema cambió de forma incompatible, el nombre o la versión del tool lo dicen explícito.
Qué es breaking para un modelo (y no lo es para un humano)
Un humano lee el diff del PR. El modelo solo ve el schema que le pasas en cada request más los ejemplos del prompt. Esta asimetría define la matriz:
| Cambio | ¿Breaking para el agente? | Por qué |
|---|---|---|
| Agregar parámetro opcional con default | No | El modelo puede ignorarlo; el backend usa el default |
| Agregar valor a un enum de salida | No | El modelo sigue emitiendo los valores que conoce |
| Agregar campo opcional a la respuesta | No | El parser del agente ignora claves desconocidas si está bien escrito |
| Renombrar un parámetro | Sí | El modelo sigue emitiendo el nombre viejo que vio en ejemplos |
| Volver requerido un campo opcional | Sí | Las llamadas que lo omitían ahora fallan en validación |
| Quitar un valor de un enum | Sí | El modelo puede seguir emitiéndolo por hábito del prompt |
Cambiar tipo (string → number) | Sí | El validador rechaza lo que antes aceptaba |
Endurecer formato (nuevo regex, additionalProperties: false) | Sí | Llamadas antes válidas ahora se rechazan |
La regla operativa: si un log histórico de llamadas válidas podría fallar contra el schema nuevo, es breaking. Esa prueba se automatiza: guarda una muestra de argumentos reales por tool y revalídalos contra el schema candidato en CI antes de publicar.

Strict mode: el schema como contrato exigible
OpenAI y Anthropic soportan strict: true en la definición de tools: con strict activo, la llamada del modelo garantiza conformar exactamente al schema (OpenAI lo implementa sobre Structured Outputs; Anthropic documenta strict tool use para definiciones custom). Úsalo como candado, no como decoración:
{
"name": "buscar_pedido",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"pedido_id": { "type": "string" },
"incluir_historial": { "type": "boolean", "default": false }
},
"required": ["pedido_id"],
"additionalProperties": false
}
}
Tres consecuencias prácticas. Primera: con strict: true y additionalProperties: false, agregar un parámetro opcional sigue siendo seguro, pero quitar o renombrar rompe en validación en vez de pasar silencioso —el fallo se vuelve visible, que es lo que quieres. Segunda: el prompt nunca documenta el schema ("el parámetro pedido_id es el folio..."); el schema se autodescribe con description por campo y el prompt solo explica intención y criterio. Tercera: congela el schema que ve el modelo por versión de toolset (siguiente sección), porque strict valida contra el schema que enviaste en ese request, no contra "el actual".
toolset_version: el modelo siempre sabe qué contrato usa
El error clásico: un solo nombre buscar_pedido cuyo schema cambia con cada deploy, mientras el system prompt del agente describe la versión de hace tres semanas. La corrección es exponer la versión del toolset donde el modelo y la observabilidad la vean:
- Versión global del toolset (
toolset_version: "2026-09-01") enviada como campo en cada request o como prefijo en logs y trazas. Cuando un fallo aparece, la primera pregunta —"¿contra qué versión del schema falló?"— ya tiene respuesta. - Nombres versionados solo para breaking:
buscar_pedido(estable) convive conbuscar_pedido_v2durante la migración. Los cambios aditivos no versionan el nombre; los breaking sí, sin excepción. - El prompt referencia la versión, no el schema: "Usas el toolset 2026-09-01;
buscar_pedido_v2reemplaza abuscar_pedidopara búsquedas con historial" —una línea, no una copia del JSON.
Esta disciplina conecta directo con ejecución durable: un workflow que hace resume días después debe reanudar contra el mismo toolset_version con el que empezó, no contra el schema que haya hoy en producción. Guarda la versión en el checkpoint junto al estado.
Rollout en tres fases: shadow, canary, deprecación
Ningún schema breaking entra directo a producción. El camino:
Fase 1 — Shadow. La versión nueva corre en paralelo sin efectos: recibe copia de los argumentos reales, valida, loguea el diff contra la versión estable y descarta el resultado. Una semana de shadow te dice qué porcentaje de llamadas históricas fallaría con el schema nuevo, con datos reales y cero riesgo. Si el shadow reporta más de un 1% de divergencia, el schema vuelve a diseño.
Fase 2 — Canary. La versión nueva atiende un porcentaje pequeño de tráfico real (5–10%), con efectos reales pero acotados y rollback de un flag. Aquí mides tasa de error de validación, latencia y —lo más importante— evals de tarea completa, no solo "el JSON validó". Un schema que valida perfecto pero confunde al modelo (nombres ambiguos, enums crípticos) se detecta en canary con evals, no con el validador.
Fase 3 — Deprecación con fecha. La versión vieja anuncia deprecated: true más fecha de apagado (mínimo 30 días), los logs cuentan quién la sigue llamando y el apagado solo ocurre cuando el conteo llega a cero. Apagar por calendario con consumidores activos es el breaking silencioso más común.

Checklist de release de schema
- El cambio pasa la prueba del log histórico: ninguna llamada válida anterior falla contra el schema nuevo, o el cambio lleva versión nueva.
-
strict: trueactivo yadditionalProperties: falsedonde el proveedor lo soporta. - Ningún ejemplo del system prompt usa nombres o formatos viejos (grep de nombres de parámetros en prompts antes de mergear).
-
toolset_versionvisible en request, logs y checkpoints de workflows largos. - Shadow de al menos una semana con reporte de divergencia para cambios breaking.
- Canary con evals de tarea completa, no solo validación de schema.
- Deprecación con fecha y conteo de consumidores antes de apagar la versión vieja.
- Cero copiar el schema JSON al prompt como documentación; el schema vive en código, el prompt describe intención.
FAQ
¿Versiono cada tool por separado o todo el toolset junto? El toolset lleva la versión global para observabilidad y checkpoints; los nombres versionados (_v2) solo aparecen en el tool que rompió compatibilidad. Versionar los veinte tools porque uno cambió multiplica el ruido en el prompt.
¿Y si el proveedor cambia su API de tools? Es el mismo problema un nivel arriba: pinnea la versión de la API del proveedor (header de versión, SDK pineado) y trata su changelog como un schema breaking más. El shadow también aplica: valida tus llamadas contra la versión nueva antes de migrar.
¿Cuánto dura un shadow razonable? Hasta cubrir un ciclo completo de uso real: una semana para tráfico diario uniforme, un mes si hay patrones semanales fuertes. El criterio de salida es estadístico (divergencia < 1%), no calendario.
¿El modelo puede elegir versión solo? No. El agente nunca selecciona schema: el orquestador fija toolset_version y expone exactamente un schema por intención. Dos versiones del mismo tool visibles a la vez garantizan que el modelo elija la equivocada la mitad de las veces.
El modelo es un cliente que no lee changelogs, así que el changelog tiene que estar en el diseño: aditivo por defecto, versión visible siempre y rollout en tres fases. Si quieres el siguiente eslabón de operación, el hub de seguridad, coste y operación reúne las guías de AgentOps, y el curso de instalar tu agente te lleva de la teoría al runtime.
Lecturas relacionadas
Sigue explorando AgentOps y otras piezas para builders.

LLM-as-judge para agentes: rúbrica, schema y calibración (el juez no es la verdad)

Circuit breaker y kill switch en agentes: cortar la dependencia, no el proceso

Ejecución durable para agentes largos: checkpoint por paso, resume sin repetir
