CCDV-F · Ingeniería de prompts y de contexto
Formato garantizado no es contenido correcto: validar y desconfiar
Un equipo activa la salida estructurada y borra su capa de validación porque “ahora siempre cumple el esquema”. Al mes, algunos parseos fallan y otras facturas pasan con renglones que no suman el total. Otro equipo aprueba solo los códigos con confianza mayor a 0,95 y la auditoría encuentra errores con 0,99. Las dos historias tienen la misma lección: un JSON bien formado no es un JSON correcto.
Qué garantiza la salida estructurada
La salida estructurada (structured outputs) restringe la generación a tu esquema: con output_config.format para la respuesta, o con strict: true en una herramienta para sus parámetros. Si la respuesta termina normalmente, es JSON válido, con los campos obligatorios y los tipos correctos.
Lo que no garantiza:
- Que la respuesta haya terminado. Si el motivo de corte (stop_reason) es
max_tokens, el JSON puede quedar incompleto. Si esrefusal, el modelo se negó y la salida puede no seguir el esquema. - Todas las restricciones del esquema. Algunas (mínimos, máximos, largos de texto) no se pueden imponer; los helpers del SDK las pasan a la descripción y validan del lado del cliente.
- Que el contenido sea verdad. El monto puede estar mal, la categoría puede ser otra, los renglones pueden no sumar el total.
Validar en capas
La validación de la respuesta (response validation) va en este orden:
- Revisar
stop_reasonantes de parsear.end_turn: seguir.max_tokens: reintentar con más espacio.refusal: manejarlo como caso aparte, no como error de parseo. - Validar contra el esquema en tu código (con Pydantic, Zod o similar), sobre todo si no usás salida estructurada o si el esquema tiene restricciones que la API no impone.
- Validar reglas de negocio: que los renglones sumen el total, que la fecha de entrega no sea anterior a la de envío, que el código exista en el catálogo.
- Decidir qué hacer con lo inválido: reintentar pasándole al modelo el error concreto, mandarlo a revisión humana o apartarlo en una cola de cuarentena.
Parseo defensivo
El parseo defensivo (defensive parsing) tolera lo que no importa y exige lo que sí:
- Ignorar campos de más en lugar de rechazar todo el registro porque apareció un
notesinesperado. - Exigir los obligatorios y sus tipos.
- Normalizar diferencias menores, como mayúsculas en un valor de una lista cerrada.
- Apartar los fallos sin frenar el pipeline: un registro malo va a cuarentena, el lote sigue.
Un try/except amplio que descarta en silencio no es defensivo: perdés datos sin enterarte.
Desconfiar de la seguridad
La confianza que el modelo declara (“0,98”) es otro texto que genera, no una probabilidad medida: es confianza no calibrada (uncalibrated confidence). Una explicación larga y precisa, con citas del documento, tampoco prueba que la respuesta esté bien.
Para decidir qué se aprueba solo, medí la precisión real contra un set etiquetado (por categoría, por tipo de caso) y fijá las reglas con ese dato. Lo que no tenga evidencia suficiente va a revisión humana.
Las trampas típicas
- Sacar la validación porque se activó la salida estructurada.
- Parsear sin mirar
stop_reason. - Pedir en el prompt “revisá cada monto” como control principal.
- Un parser estricto que tira el lote entero por un campo extra.
- Saltear en silencio lo que no parsea.
- Aprobar automáticamente según la confianza que reporta el modelo, o subir el umbral a 0,99.
En el examen
Si el JSON venía bien formado y lo que rompió fue un campo extra, buscá parseo tolerante con cuarentena. Si el parseo falla en respuestas con stop_reason distinto de end_turn, buscá revisarlo antes de parsear. Si el formato está bien pero los datos no, buscá validaciones de negocio. Y si hay un puntaje de confianza del modelo, desconfiá: la respuesta correcta mide contra datos etiquetados.
Pregunta rápida
Una pregunta del simulacro sobre este dominio. Cuenta para tu progreso.
An insurance company's digital team runs a claims assistant on the Claude API. The system prompt sets a formal tone and says the assistant must never estimate payout amounts. Every user message is wrapped in a template that a different team maintains, and that template now begins with: "Be friendly and casual, and give the customer a rough idea of what they might receive."
Support leads report inconsistent behavior: some replies are formal and refuse to estimate, while others are chatty and quote approximate payouts. The two teams sit in different departments and each edits its own piece of the prompt.
The template also carries the customer's policy details and the question itself, which change on every request.
What should the developers change?