Módulo 8: Proyecto — arquitecta una feature de IA en Mercado
La cáscara determinista y el lazo de datos
Descripción
Las cinco lecciones anteriores llenaron ocho de los diez campos de la hoja. Esta lección llena los dos que faltan, los que cierran la contención: deterministic_shell (M6) y feedback_loop (M7). Son las dos piezas que convierten el agente de soporte de "un modelo con protecciones" en "un sistema AI-native completo": la cáscara determinista contiene lo que el modelo propone —el modelo propone, el sistema dispone, medido en dinero— y el lazo de datos cierra el círculo —la observabilidad ve la calidad, y el feedback realimenta el eval-set de la lección 4—.
Estas dos piezas parecen distintas —una protege el dinero, la otra mejora la calidad— pero comparten el corazón del método: una capa determinista alrededor del núcleo probabilístico. La cáscara es esa capa validando acciones; el lazo de datos es esa capa observando la calidad y realimentándola. Y hay una conexión que esta lección hace explícita: la misma cáscara que bloquea un reembolso peligroso genera la traza que el lazo de datos usa para mejorar el sistema. Contener y mejorar no son dos sistemas separados; son dos caras de la misma cáscara determinista.
Conexión con el módulo. Esta lección es la que cierra el ciclo del capstone. La cáscara determinista es la garantía dura que las lecciones 4 y 5 anticiparon —la frontera que valida cada propuesta contra la política, ahora medida en el dinero que protege—. Y el lazo de datos conecta de vuelta con la lección 4: los thumbs_down que la observabilidad captura en vivo se convierten en casos nuevos del eval-set, que la próxima corrida del eval gate usará. Con esto, los diez campos de la hoja quedan llenos y el sistema está completo —listo para la lección 8, que lo corre entero—. La frontera con AI Engineering se mantiene: aquí el lazo es la decisión de arquitectura (montar el feedback loop); cómo entrenar un modelo con los datos que el lazo acumula es AI Engineering.
Una analogía: el gerente que autoriza y el buzón que mejora la tienda
Vuelve a la tienda de Mercado, pero mira dos cosas que un buen gerente hace, distintas pero conectadas.
La primera: el gerente autoriza los reembolsos. Un empleado brillante atiende a los clientes y, cuando alguien pide un reembolso, no lo ejecuta él —le lleva la solicitud al gerente—. El gerente la revisa contra las reglas de la tienda: ¿el pedido existe?, ¿está en ventana?, ¿el monto es correcto? Solo si pasa, el gerente autoriza y el dinero se mueve. El empleado propone; el gerente dispone. Y aquí está el valor medible: cuando el empleado, confundido o engañado, propone un reembolso de $9999 por un pedido de $75, el gerente lo detiene antes de que salga un peso. El gerente no hace al empleado más listo; le quita el poder de mover el dinero solo.
La segunda: el gerente lee el buzón de quejas. Cada cliente que se fue insatisfecho —el empleado no supo responder su pregunta— dejó una nota en el buzón. El gerente las lee, y cada queja se convierte en algo concreto: una pregunta que el empleado debería saber responder la próxima vez, que se agrega al manual de capacitación. La tienda mejora porque el gerente cierra ese lazo —lee el buzón y actualiza el manual—. Un gerente que pusiera el buzón pero nunca lo leyera tendría la ilusión de mejorar sin mejorar: las quejas se acumularían sin cambiar nada.
Fíjate en la conexión entre las dos: es el mismo gerente. La autorización de reembolsos (contener) y la lectura del buzón (mejorar) las hace la misma persona, con la misma información. De hecho, la solicitud de reembolso que el gerente autorizó también le dice algo sobre qué está pasando en la tienda —qué productos se devuelven más, qué preguntas surgen—. En el agente de soporte, la cáscara determinista es el gerente que autoriza, y el lazo de datos es el mismo gerente leyendo el buzón. Esta lección monta las dos, y muestra que son la misma cáscara determinista con dos trabajos.
Ejemplo trabajado: la cáscara protege el dinero, el lazo cierra el círculo
Vamos a ejecutar las dos piezas en un solo programa. La Parte A mide la cáscara determinista: toma seis propuestas del modelo (buenas y malas mezcladas) y compara dos diseños —el ingenuo, donde el modelo ejecuta directo, y el de cáscara, donde el modelo propone y la cáscara dispone—, midiendo el dinero que la cáscara protege. La Parte B cierra el lazo de datos: la observabilidad agrega la señal de calidad en vivo (approval_rate), y cada thumbs_down se convierte en un caso nuevo del eval-set del módulo 3.
# M8 Leccion 7 — la CASCARA DETERMINISTA (M6) contiene, y el LAZO DE DATOS (M7)
# cierra el circulo. Parte A: el modelo propone, la cascara dispone, medido en
# dinero. Parte B: observabilidad (approval_rate) + el feedback que realimenta
# el EVAL-SET del M3. STUB del modelo; datos fijos; sin red ni APIs.
# ==================================================================
# PARTE A — La cascara determinista contiene las malas propuestas (M6).
# ==================================================================
ORDERS = {
"A-1001": {"total": 50.00, "days_since_delivery": 3, "refunded": False},
"A-1002": {"total": 120.00, "days_since_delivery": 45, "refunded": False},
"A-1003": {"total": 30.00, "days_since_delivery": 5, "refunded": True},
"A-1005": {"total": 75.00, "days_since_delivery": 8, "refunded": False},
}
MAX_REFUND = 100.00
RETURN_WINDOW_DAYS = 30
# Las mismas propuestas del nucleo probabilistico: buenas y malas mezcladas.
PROPOSALS = [
{"action": "refund", "order_id": "A-1001", "amount": 50.00},
{"action": "refund", "order_id": "A-1002", "amount": 120.00},
{"action": "refund", "order_id": "A-1003", "amount": 30.00},
{"action": "refund", "order_id": "A-9999", "amount": 40.00},
{"action": "refund", "order_id": "A-1005", "amount": 5000.00},
{"action": "refund", "order_id": "A-1005", "amount": 75.00},
]
def deterministic_shell(p):
oid, amount = p["order_id"], p["amount"]
if oid not in ORDERS:
return (False, "pedido no existe")
order = ORDERS[oid]
if order["refunded"]:
return (False, "ya reembolsado")
if order["days_since_delivery"] > RETURN_WINDOW_DAYS:
return (False, "fuera de ventana")
if amount > order["total"]:
return (False, "monto > total")
if amount > MAX_REFUND:
return (False, "monto > limite")
return (True, "aprobado")
paid_naive = sum(p["amount"] for p in PROPOSALS) # el LLM ejecuta directo
paid_shell = sum(p["amount"] for p in PROPOSALS if deterministic_shell(p)[0])
print("=== Parte A: la cascara determinista (M6) ===")
print(f" sin cascara (el LLM ejecuta): pago {paid_naive:.2f} ({len(PROPOSALS)} acciones)")
executed = sum(1 for p in PROPOSALS if deterministic_shell(p)[0])
print(f" con cascara (propone/dispone): pago {paid_shell:.2f} ({executed} acciones)")
print(f" dinero protegido: {paid_naive - paid_shell:.2f} "
f"(propuestas peligrosas bloqueadas antes de tocar el dinero)")
# ==================================================================
# PARTE B — El lazo de datos: observabilidad + feedback -> eval-set (M7 -> M3).
# ==================================================================
# El eval-set del M3 arranca con estos casos (los mismos que la compuerta usa).
EVAL_SET = [
{"id": "q1", "question": "donde esta mi pedido", "must_contain": "tracking"},
{"id": "q2", "question": "como devuelvo un producto", "must_contain": "devolucion"},
{"id": "q3", "question": "cuanto tarda el envio", "must_contain": "3 a 5 dias"},
]
# El trafico en vivo: una fila por ticket resuelto, con tokens, costo y el
# thumbs del agente humano (la senal de calidad). Datos fijos.
LIVE_TRAFFIC = [
# (ticket, respuesta_del_agente, tokens, cost_usd, thumbs)
("donde esta mi pedido", "Puedes ver el tracking en tu perfil.", 180, 0.0016, "up"),
("como devuelvo un producto", "Entra a tu pedido y pulsa Devolver.", 175, 0.0015, "up"),
("mi cupon de regalo no aplica", "No tengo informacion sobre eso.", 160, 0.0014, "down"),
("puedo recoger en tienda", "No estoy seguro de eso.", 150, 0.0013, "down"),
("cuanto tarda el envio", "El envio tarda de 3 a 5 dias habiles.", 170, 0.0015, "up"),
("como reporto un vendedor", "Lo siento, no puedo ayudarte con eso.", 155, 0.0013, "down"),
]
ups = sum(1 for t in LIVE_TRAFFIC if t[4] == "up")
approval_rate = ups / len(LIVE_TRAFFIC)
avg_tokens = sum(t[2] for t in LIVE_TRAFFIC) / len(LIVE_TRAFFIC)
total_cost = sum(t[3] for t in LIVE_TRAFFIC)
print()
print("=== Parte B: observabilidad para IA (M7) ===")
print(f" tickets : {len(LIVE_TRAFFIC)}")
print(f" approval_rate : {approval_rate:.0%} "
f"({'ALERTA: calidad baja' if approval_rate < 0.80 else 'OK'})")
print(f" avg_tokens : {avg_tokens:.0f}")
print(f" costo total (vivo) : ${total_cost:.4f}")
# El lazo CIERRA: cada thumbs_down se vuelve un caso nuevo del eval-set.
new_cases = [t[0] for t in LIVE_TRAFFIC if t[4] == "down"]
print()
print("=== El lazo de datos cierra: feedback -> eval-set (M7 -> M3) ===")
print(f" eval-set antes : {len(EVAL_SET)} casos")
for i, question in enumerate(new_cases, start=len(EVAL_SET) + 1):
EVAL_SET.append({"id": f"q{i}", "question": question, "must_contain": "?"})
print(f" + caso nuevo del feedback: {question!r}")
print(f" eval-set despues: {len(EVAL_SET)} casos")
print()
print("Los thumbs_down en vivo se volvieron casos del eval-set. Al arreglarlos,")
print("la compuerta del M3 subira y el flywheel del M7 da otra vuelta. La misma")
print("cascara que protege el dinero (Parte A) alimenta la calidad (Parte B).")
Qué esperar. Al correr el archivo, la salida es exactamente esta:
=== Parte A: la cascara determinista (M6) ===
sin cascara (el LLM ejecuta): pago 5315.00 (6 acciones)
con cascara (propone/dispone): pago 125.00 (2 acciones)
dinero protegido: 5190.00 (propuestas peligrosas bloqueadas antes de tocar el dinero)
=== Parte B: observabilidad para IA (M7) ===
tickets : 6
approval_rate : 50% (ALERTA: calidad baja)
avg_tokens : 165
costo total (vivo) : $0.0086
=== El lazo de datos cierra: feedback -> eval-set (M7 -> M3) ===
eval-set antes : 3 casos
+ caso nuevo del feedback: 'mi cupon de regalo no aplica'
+ caso nuevo del feedback: 'puedo recoger en tienda'
+ caso nuevo del feedback: 'como reporto un vendedor'
eval-set despues: 6 casos
Los thumbs_down en vivo se volvieron casos del eval-set. Al arreglarlos,
la compuerta del M3 subira y el flywheel del M7 da otra vuelta. La misma
cascara que protege el dinero (Parte A) alimenta la calidad (Parte B).
Recorramos las dos partes, porque juntas cierran la contención del capstone.
Parte A — la cáscara protege $5,190. Las seis propuestas incluyen dos legítimas (A-1001 por $50, A-1005 por $75) y cuatro peligrosas (un pedido fuera de ventana, un doble reembolso, un pedido inexistente, y un reembolso de $5000 de un pedido de $75). En el diseño ingenuo, donde el modelo ejecuta directo, salen los seis reembolsos: $5,315. En el diseño de cáscara, donde el modelo propone y la cáscara valida cada propuesta contra la política antes de ejecutar, solo pasan las dos legítimas: $125. La diferencia —$5,190 protegidos— es el valor exacto de mover el poder de ejecutar del modelo a la cáscara. Y fíjate en lo esencial, la tesis del módulo 6: no hicimos nada para mejorar el modelo —es el mismo modelo, las mismas propuestas—; solo le quitamos el poder de ejecutar directo y se lo dimos a una capa determinista. La seguridad no vino de un modelo mejor; vino de que el modelo no ejecute.
Parte B — la observabilidad ve lo que un log de servidor no ve. La observabilidad agrega la señal de calidad en vivo: de los seis tickets, tres recibieron thumbs_down, dando un approval_rate de 50% —marcado ALERTA: calidad baja—. Aquí está lo que un log de servidor clásico se perdería: esos seis tickets devolvieron todos su respuesta (status 200, si midieras el servidor), pero tres de las respuestas eran malas ("No tengo información sobre eso"). El status HTTP dice que el servicio respondió; el approval_rate dice que respondió mal a la mitad. Solo la señal de calidad —que alguien tuvo que diseñar para capturarla— revela la degradación. Y la observabilidad también agrega los tokens y el costo en vivo, las métricas del presupuesto de la lección 3 vigiladas en producción.
Parte B — el lazo cierra: el feedback alimenta el eval-set. Y aquí está la conexión que cierra el capstone. Los tres thumbs_down —"mi cupón de regalo no aplica", "¿puedo recoger en tienda?", "¿cómo reporto un vendedor?"— eran preguntas que el agente no supo responder. El lazo de datos los convierte en tres casos nuevos del eval-set, que crece de 3 a 6 casos. La próxima vez que corras el eval gate de la lección 4, esos casos estarán ahí: si el equipo arregla el agente para responderlos, el score sube; si no, el gate los sigue marcando como fallos. Así gira el flywheel del módulo 7: el uso genera feedback, el feedback alimenta el eval-set, un agente mejor pasa el gate, y el sistema mejora. La bola de nieve recogió su primer puñado de nieve.
Y la conexión entre las dos partes, que es el punto de la lección: es la misma cáscara. La Parte A (contener) y la Parte B (mejorar) no son dos sistemas separados. La cáscara determinista que valida cada propuesta de reembolso (Parte A) genera, en cada validación, una traza —qué propuso el modelo, qué decidió la cáscara, qué feedback dio el humano— y esa traza es exactamente lo que el lazo de datos observa y realimenta (Parte B). El gerente que autoriza los reembolsos es el mismo que lee el buzón. Contener y mejorar son dos trabajos de la misma capa determinista alrededor del núcleo probabilístico.
Profundización: contener y mejorar son la misma cáscara
Validar sin poder de veto no cuenta como cáscara. Un error sutil que la Parte A deja implícito y vale explicitar: la cáscara solo protege si su "no" detiene la ejecución. Un sistema que loguea "esta propuesta parece fuera de política" mientras la ejecuta de todos modos —"lo estamos monitoreando"— no está conteniendo; está haciendo una autopsia con buena documentación. Monitorear un desfalco mientras ocurre no es contenerlo. En el código, la diferencia es que paid_shell solo suma dentro de la rama donde deterministic_shell(p)[0] es True —la validación tiene poder de veto sobre el pago—. Si la validación corriera después del pago (como en el diseño ingenuo, que solo etiquetaría el daño), no protegería nada: los $5000 ya habrían salido. La validación va antes de la ejecución y su "no" detiene, o no es cáscara.
La observabilidad de IA necesita una señal que un log clásico no tiene. La Parte B mostró el approval_rate, y vale entender por qué es la métrica que lo cambia todo. Un log de servidor clásico mide si el servicio respondió (status 2xx, latencia). Para un componente de IA eso no basta: una respuesta alucinada o irrelevante también devuelve HTTP 200. La observabilidad de IA agrega tres columnas que el log clásico no tiene —tokens (que son costo y latencia), costo (la factura por feature), y la señal de calidad (el approval_rate, si respondió bien)—. La señal de calidad es la verdaderamente nueva: sin ella, tu feature de IA es una caja negra que reporta "respondí" sin reportar "respondí bien", y una feature puede degradarse durante semanas con el tablero en verde. El approval_rate de la observabilidad es la versión en vivo de lo que el eval-set de la lección 4 mide contra casos fijos: el eval te deja no desplegar algo malo, la observabilidad te deja detectar que algo bueno se degradó en producción.
El lazo solo gira si se cierra. La Parte B convirtió los thumbs_down en casos del eval-set —ese es el cierre—. Pero el flywheel del módulo 7 solo compone si el lazo de verdad se cierra: capturar el feedback no basta. Un equipo que pone el thumbs up/down, ve que los usuarios lo usan, y asume que "ya tiene el flywheel" tiene una bola de nieve sobre hielo —se mueve pero no crece—, porque los datos se acumulan sin realimentarse. El cierre es lo que hace la Parte B: cada thumbs_down se convierte en un caso del eval-set, que la próxima corrida del gate usará. Sin ese paso, la observabilidad sería un termómetro que mide sin mejorar nada. Capturar es visible (aparece un botón); cerrar es invisible (el dato llega al eval-set), y es lo que de verdad hace girar la rueda.
La misma traza sirve a la contención y a la mejora. Esta es la idea que une las dos partes y cierra el método. Cada vez que la cáscara valida una propuesta (Parte A), produce una traza: el ticket que llegó, la propuesta del modelo, la decisión de la cáscara (aprobó/bloqueó y por qué), y —si hubo humano— su feedback. Esa traza tiene doble valor: para la contención, es el registro de auditoría (quién aprobó qué, por qué se bloqueó un reembolso); para la mejora, es el dato que alimenta el eval-set y la observabilidad. Diseñar la cáscara para que emita esa traza es lo que hace que contener y mejorar sean el mismo sistema. Un arquitecto que monta la cáscara sin pensar en la traza tiene contención sin mejora; uno que la diseña para observar tiene las dos con la misma pieza.
Errores comunes
Poner la validación después de ejecutar, no antes. Qué pasa: el equipo sí valida las propuestas de reembolso, pero lo hace después de mover el dinero —"reembolsamos y luego revisamos si estuvo bien"—. Como las acciones son irreversibles, la validación tardía solo descubre el daño; no lo evita. Por qué pasa: a veces por diseño (parece más simple ejecutar primero), a veces por un mal orden de las operaciones. Cómo detectarlo: en tu flujo, ¿el if que decide si la propuesta es válida corre antes o después de la línea que la ejecuta? Si es después, estás haciendo autopsias. Cómo corregirlo: la validación va antes de la ejecución, siempre; la acción solo se ejecuta en la rama donde la validación pasó. Es la diferencia entre los $125 y los $5,315 del ejemplo.
Capturar feedback y no cerrarlo. Qué pasa: el equipo pone el thumbs up/down, ve que los clientes lo usan, y asume que "ya tenemos el flywheel". Pero los thumbs_down se acumulan sin convertirse en casos del eval-set ni ajustar nada, y la calidad de la feature se queda plana —la bola de nieve sobre hielo—. Por qué pasa: capturar es visible (aparece un botón) y se confunde con cerrar (que es invisible). Cómo detectarlo: tienes semanas de feedback guardado y tu curva de calidad es plana. Cómo corregirlo: cierra el lazo —cada thumbs_down debe convertirse en un caso del eval-set (como en la Parte B), y de ahí guiar la corrección—. Capturar sin cerrar no mueve la aguja; el flywheel gira solo cuando el lazo se cierra.
Monitorear como servidor clásico, sin señal de calidad. Qué pasa: el equipo monitorea la feature de IA con el mismo stack de sus servicios clásicos —status, latencia, tasa de error— y nunca agrega una señal de calidad. La feature se degrada (un cambio de modelo, drift, un prompt que alguien tocó) y el tablero sigue en verde porque las respuestas malas también devuelven 200. El problema se descubre por quejas de clientes, semanas después. Por qué pasa: el instinto es reusar el monitoreo que ya se tiene, y ese monitoreo nunca tuvo que medir "¿estuvo bien la respuesta?". Cómo detectarlo: tu tablero de la feature de IA no tiene una columna de calidad (approval_rate o equivalente). Cómo corregirlo: agrega la señal de calidad al tablero —el status dice si respondió, la calidad dice si respondió bien, y para una feature de IA son cosas distintas—.
Ejercicios
Ejercicio 1 — Por qué el mismo modelo pagó $5,315 y $125. Los dos diseños de la Parte A usan las mismas seis propuestas del modelo. Explica por qué uno pagó $5,315 y el otro $125, qué elemento tiene el diseño de cáscara que el ingenuo no, y a qué corresponde en el código.
Ver solución
Los dos diseños usan las mismas propuestas porque el modelo propone exactamente lo mismo en ambos —las mismas seis acciones, con los mismos cuatro errores—. La diferencia no está en el modelo; está en si existe un paso de aprobación entre la propuesta y la ejecución.
El diseño de cáscara tiene lo que el ingenuo no: la validación con poder de veto antes de mover el dinero. En el ingenuo, cada propuesta se ejecuta directo (el modelo dispone); en el de cáscara, cada propuesta se valida contra la política y solo se ejecuta si pasa (el código dispone). Los cuatro errores —el pedido fuera de ventana ($120), el doble reembolso ($30), el pedido inexistente ($40) y el reembolso de $5000 de un pedido de $75— pasan en el ingenuo (suman a los $5,315) y se bloquean en el de cáscara (solo quedan los $125 legítimos).
En el código, ese "paso de aprobación" es la diferencia entre las dos sumas: paid_naive suma p["amount"] para toda propuesta, mientras que paid_shell suma solo for p in PROPOSALS if deterministic_shell(p)[0] —solo las que la cáscara aprobó—. Esa condición —la validación con poder de veto antes de mover el dinero— es el gerente que autoriza. Sin ella, el modelo tiene la tarjeta; con ella, el modelo trae la cuenta y el código autoriza. Y lo esencial: no cambiamos el modelo entre los dos diseños; la seguridad no vino de un modelo mejor, vino de que el modelo no ejecute.
Ejercicio 2 — El thumbs_down que ordena las prioridades. En la Parte B, tres tickets recibieron thumbs_down. Imagina que en un mes de tráfico real, "mi cupón no aplica" recibe 400 thumbs_down, "recoger en tienda" recibe 50, y "reportar un vendedor" recibe 15. ¿En qué orden arreglarías los tres, y por qué el volumen del feedback es una señal de prioridad y no solo de qué está roto?
Ver solución
El orden de arreglo sería: "mi cupón no aplica" (400) primero, "recoger en tienda" (50) segundo, "reportar un vendedor" (15) último. Se arregla primero lo que más gente reporta.
Por qué el volumen es una señal de prioridad y no solo de qué está roto: los tres tickets están rotos por igual (el agente no supo responder ninguno), así que "qué está roto" no los distingue —los tres son fallos—. Lo que los distingue es a cuánta gente le duele cada fallo, y eso lo dice el volumen del feedback. "Mi cupón no aplica" con 400 thumbs_down afecta a 400 clientes al mes; "reportar un vendedor" con 15 afecta a 15. Arreglar primero el de 400 mejora la experiencia de mucha más gente por el mismo esfuerzo de arreglo. El volumen convierte una lista de fallos (todos "rotos") en una lista priorizada (rotos, ordenados por impacto).
Esta es una propiedad valiosa del feedback real que el módulo 7 destacó: el lazo de datos no solo te dice qué está roto (los casos que fallan), sino qué arreglar primero (los que más volumen de feedback generan). Un equipo que ignora el volumen y arregla los fallos en el orden que le llegan podría gastar una semana arreglando el de 15 antes que el de 400. El volumen del feedback es la brújula de prioridad, gratis, que sale de cerrar el lazo. Y todo esto rinde cuentas al eval gate: los casos arreglados suben el score, y los de más volumen lo suben más (si el eval-set pesa los casos por frecuencia real).
Ejercicio 3 — La traza que sirve a la contención y a la mejora. La profundización dijo que la misma traza de la cáscara sirve para contener (auditoría) y para mejorar (feedback). Diseña qué campos tendría la traza que emite la cáscara al validar una propuesta de reembolso, y muestra cómo cada campo sirve a uno de los dos usos (o a los dos).
Ver solución
Una traza razonable que la cáscara emite al validar cada propuesta:
trace = {
"ticket_id": "T-8842", # el ticket que originó la propuesta
"customer_message": "...", # el mensaje del cliente (frontera de confianza)
"model": "cheap", # a qué modelo se enrutó (cascade, M2)
"proposal": {"action": "refund", "order_id": "A-1005", "amount": 5000.0},
"shell_decision": "BLOCKED", # aprobó / bloqueó
"shell_reason": "monto > total", # por qué
"tokens": 210, "cost_usd": 0.0018, # observabilidad (M2/M7)
"human_feedback": None, # thumbs / corrección, si hubo (M7)
"injection_flagged": False, # el guardrail de entrada marcó algo (M4)
}
Cómo cada campo sirve a uno o a los dos usos:
- Contención (auditoría):
shell_decisionyshell_reasonson el registro de por qué se aprobó o bloqueó cada reembolso —la auditoría que responde "¿por qué no salió este reembolso de $5000?"—.proposalycustomer_messagedocumentan qué propuso el modelo y ante qué entrada.injection_flaggedregistra los intentos de ataque. Estos campos existen para poder rendir cuentas de cada decisión que tocó (o casi tocó) el dinero. - Mejora (feedback):
human_feedback(el thumbs o la corrección) es lo que alimenta el eval-set —un thumbs_down se vuelve un caso nuevo, como en la Parte B—.tokensycost_usdalimentan la observabilidad de costo (¿un cambio disparó los tokens?).modeldeja ver si las queries enrutadas al barato (cascade) se responden peor —cruzando con el feedback—. - A los dos:
proposalyshell_reasonsirven a la auditoría y a la mejora: un patrón de propuestas bloqueadas por la misma razón ("monto > total" repetido) puede indicar que el modelo tiene un problema sistemático que hay que arreglar (mejora), además de ser el registro de cada bloqueo (auditoría).
La lección: diseñar la traza con estos campos es lo que hace que contener y mejorar sean el mismo sistema. La cáscara no solo decide (contención); emite la traza que el lazo de datos consume (mejora). Un arquitecto que monta la cáscara sin la traza tiene un gerente que autoriza pero no lee el buzón —contención sin mejora—.
Resumen y siguiente paso
En esta lección llenaste los dos últimos campos de la hoja: deterministic_shell y feedback_loop. Con el gerente que autoriza reembolsos y lee el buzón de quejas, viste que contener y mejorar son dos trabajos de la misma capa determinista. Y lo ejecutaste en dos partes: la cáscara determinista protegió $5,190 —el modelo propuso seis acciones, cuatro peligrosas, y la cáscara solo dejó pasar las dos legítimas, sin hacer al modelo mejor, solo quitándole el poder de ejecutar—; y el lazo de datos cerró el círculo —la observabilidad reveló un approval_rate de 50% que un log de servidor no vería, y los tres thumbs_down se convirtieron en casos nuevos del eval-set del módulo 3—. La conexión que cierra el método: es la misma cáscara: la que valida las propuestas emite la traza que el lazo de datos observa y realimenta. Con esto, los diez campos de la hoja quedan llenos y el sistema está completo.
Antes de avanzar deberías poder: explicar por qué la validación con poder de veto va antes de ejecutar; medir el dinero que una cáscara protege; distinguir la observabilidad de IA (con señal de calidad) de un log de servidor clásico; y explicar cómo el feedback cierra el lazo hacia el eval-set y por qué el volumen del feedback prioriza las correcciones.
La lección 8 es el entregable del capstone y el cierre de toda la guía: arquitecta la feature de IA en Mercado. Vas a correr el sistema completo —cache, cascade, guardrails, eval, fallback, circuit breaker, cáscara y feedback, todos juntos— sobre tickets variados y una caída del modelo, con el diagrama de la feature, un ADR completo y el argumento de por qué la no-determinación queda contenida. Los diez campos de la hoja, ejecutados como un solo sistema.
Recursos
- Anthropic, "Building Effective Agents" (2024) — anthropic.com/engineering/building-effective-agents. La distinción entre un modelo que sugiere una acción y un sistema que decide ejecutarla es el eje del diseño de agentes seguros; la cáscara de esta lección es esa distinción, medida. En inglés.
- Chip Huyen, AI Engineering (O'Reilly, 2024). Su discusión sobre el control de las acciones de un agente y sobre el data flywheel como motor de mejora de un sistema de IA respalda las dos partes de esta lección. En inglés.
- Chip Huyen, Designing Machine Learning Systems (O'Reilly, 2022). Los capítulos sobre feedback loops y monitoreo distinguen las métricas operativas (del servicio) de las de calidad (del modelo) —exactamente la distinción de la observabilidad de la Parte B—. En inglés.
architecture-for-ai-native-systems-guide, Módulos 6 y 7 (este ecosistema) — el tratamiento a fondo de la cáscara determinista (propone/dispone, acción estructurada, capabilities) y del lazo de datos (flywheel, observabilidad, captura de feedback). Esta lección integra al agente de soporte lo que M6 y M7 desarrollaron. En español.