Módulo 8: Proyecto — arquitecta una feature de IA en Mercado
Ubica el componente y su contrato
Descripción
El método empieza donde empezó la guía: ubicar el componente de IA. Antes de ponerle un presupuesto, un eval o un guardrail, hay que responder tres preguntas del módulo 1 para el agente de soporte de Mercado —la feature del capstone—: ¿cuánta no-determinación tolera?, ¿cómo se parte en núcleo y cáscara?, y ¿cuál es el contrato de su salida? De las respuestas sale la hoja de propiedades, el artefacto de diez campos que las lecciones 3 a 7 van a llenar y que la lección 8 va a ejecutar entero. Esta lección hace ese paso 1 completo, ejecutado.
Y hay una decisión de fondo que se toma aquí y gobierna todo el resto: el agente de soporte es la feature intolerante de la guía. En el módulo 1 la clasificaste con tolerancia 3 de 15 —toca dinero directo, un error le duele muchísimo al negocio, y su radio de impacto es todo el sistema de pagos y la confianza del cliente—. Esa tolerancia baja no es un dato curioso: es lo que dicta que su cáscara sea gruesa, que necesite todos los mecanismos de la guía y no una versión ligera. Ubicar bien el componente es lo que hace que en las próximas lecciones no te preguntes "¿necesito un eval gate para esto?, ¿necesito validar cada propuesta?" —la tolerancia ya respondió que sí—.
Conexión con el módulo. Esta es la lección-cimiento del capstone. La lección 1 te dio el mapa y el teaser; esta pone la primera piedra: la hoja de propiedades que estructura todo el proyecto. Cada campo de la hoja apunta a una lección que viene: latency_budget/cost_budget → lección 3, eval_gate → lección 4, guardrail → lección 5, fallback → lección 6, deterministic_shell y feedback_loop → lección 7. Al terminar esta lección tendrás la feature ubicada, con su contrato claro y su hoja emitida —lista para que las capas siguientes llenen bien cada campo—. Y la frontera se respeta desde el primer paso: ubicamos el componente y definimos el contrato de su salida; no construimos el núcleo que la produce (eso es AI Engineering). El ai_component de esta lección, como en toda la guía, es un stub que propone.
Una analogía: el expediente de un empleado antes de darle un puesto
Cuando una empresa va a contratar a alguien para un puesto sensible —digamos, alguien que va a manejar reembolsos a clientes— no lo sienta en el escritorio el primer día y le da acceso a la caja. Primero le abre un expediente: define su puesto (¿dónde encaja en el organigrama?, ¿de quién depende?), su nivel de autoridad (¿puede aprobar solo, o todo lo que proponga lo revisa un supervisor?), su presupuesto (¿cuánto puede mover sin autorización?), y las reglas que lo enmarcan (¿qué pasa si se equivoca?, ¿quién lo cubre si falta?). Ese expediente no describe cómo la persona hace su trabajo —eso lo sabe ella—; describe dónde encaja y qué la contiene. Y se llena antes de darle una sola responsabilidad real, porque el expediente es justo lo que hace seguro darle responsabilidades.
La hoja de propiedades de un componente de IA es ese expediente. No describe cómo el agente de soporte genera sus respuestas —eso es AI Engineering, el "cómo hace su trabajo la persona"—; describe dónde vive, cuánta autoridad tiene (su tolerancia, que dicta el grosor de su cáscara), su presupuesto de latencia y costo, y las reglas que lo enmarcan (su eval gate, sus guardrails, su fallback). Y como el expediente, se llena antes de que el componente toque nada real, porque es lo que hace seguro conectarlo al sistema de reembolsos. Un arquitecto que mete una feature de IA sin su hoja es como un gerente que le da la caja a un empleado sin expediente: puede que salga bien, pero nadie decidió por qué debería salir bien. En este capstone, la hoja es lo primero que produces, y todo lo demás la llena.
Ejemplo trabajado: ubicar el agente de soporte y emitir su hoja
Vamos a ejecutar el paso 1 del método en cuatro partes: clasificar la tolerancia del agente (para saber el grosor de su cáscara), separar núcleo y cáscara, demostrar su contrato probabilístico, y emitir la hoja. Todo con el LLM simulado por un stub determinista, salida literal.
# M8 Leccion 2 — ubicar el componente y su contrato.
# Feature del capstone: el AGENTE DE SOPORTE de Mercado (la intolerante).
# 1) Su tolerancia a la no-determinacion (M1) -> cascara GRUESA.
# 2) Nucleo (propone) vs cascara (dispone).
# 3) El contrato PROBABILISTICO (M1): el mismo mensaje da propuestas distintas;
# el assert exacto se rompe; el contrato por propiedades pasa.
# Todo SIMULADO con stubs deterministas. Cero red, cero API, cero claves.
import random
from dataclasses import dataclass, asdict
_RNG = random.Random(8)
# ------------------------------------------------------------------
# Paso 1 — Tolerancia a la no-determinacion (M1).
# ------------------------------------------------------------------
touches_money_or_state, error_cost, blast_if_wrong = 5, 5, 5
nd_tolerance = 18 - (touches_money_or_state + error_cost + blast_if_wrong)
print("=== Paso 1: tolerancia a la no-determinacion (M1) ===")
print(f" touches_money_or_state={touches_money_or_state} "
f"error_cost={error_cost} blast_if_wrong={blast_if_wrong}")
print(f" nd_tolerance = {nd_tolerance}/15 -> feature INTOLERANTE, cascara GRUESA")
print(" (toca dinero directo: cada propuesta debe validarse contra la politica)")
# ------------------------------------------------------------------
# Paso 2 — Nucleo probabilistico vs cascara determinista (M1/M6).
# ------------------------------------------------------------------
print()
print("=== Paso 2: nucleo (LLM) vs cascara (determinista) ===")
print(" nucleo : leer el ticket y PROPONER una accion (refund/reply)")
print(" cascara : validar el schema, la politica, la frontera de confianza,")
print(" el presupuesto, el eval-gate, el fallback y el feedback")
# ------------------------------------------------------------------
# Paso 3 — El contrato probabilistico (M1): propuestas, no texto libre.
# ------------------------------------------------------------------
# El mismo ticket -> propuestas ESTRUCTURADAS distintas (mismo sentido, forma
# distinta). No afirmamos la propuesta exacta; afirmamos sus PROPIEDADES.
_PROPOSALS = [
{"action": "refund", "order_id": "A-1001", "amount": 50.0},
{"action": "refund", "order_id": "A-1001", "amount": 50.0, "reason": "roto"},
{"action": "refund", "order_id": "A-1001", "amount": 50},
]
_RNG.shuffle(_PROPOSALS)
_i = 0
def ai_component(ticket):
# SIMULA el nucleo: mismo ticket -> propuestas estructuradas distintas.
global _i
p = _PROPOSALS[_i % len(_PROPOSALS)]
_i += 1
return p
KNOWN_ACTIONS = {"refund", "reply"}
outs = [ai_component("Mi pedido A-1001 llego roto") for _ in range(3)]
print()
print("=== Paso 3: el contrato probabilistico (M1) ===")
for k, o in enumerate(outs, 1):
print(f" propuesta {k}: {o}")
try:
assert outs[0] == outs[1]
print(" assert outs[0] == outs[1] -> PASA")
except AssertionError:
print(" assert exacto outs[0] == outs[1] -> se ROMPE (no-determinismo)")
def satisfies_contract(p):
# El contrato NO es la igualdad exacta; es un conjunto de propiedades.
if not isinstance(p, dict):
return False
if p.get("action") not in KNOWN_ACTIONS:
return False
if p["action"] == "refund":
return ("order_id" in p and isinstance(p.get("amount"), (int, float))
and p["amount"] > 0)
return isinstance(p.get("text"), str)
assert all(satisfies_contract(o) for o in outs)
print(" contrato por propiedades (accion conocida, order_id, monto>0) -> PASA para las 3")
# ------------------------------------------------------------------
# Paso 4 — La hoja de propiedades del componente (M1, ahora completa).
# ------------------------------------------------------------------
@dataclass
class AIComponentSheet:
name: str
location: str
nd_tolerance: int
latency_budget_ms: int
cost_budget_usd_month: int
eval_gate: str
guardrail: str
fallback: str
deterministic_shell: str
feedback_loop: str
sheet = AIComponentSheet(
name="support_agent",
location="detras de support-service; el LLM NUNCA toca la API de reembolsos",
nd_tolerance=nd_tolerance,
latency_budget_ms=4000,
cost_budget_usd_month=3000,
eval_gate="eval-set de tickets; score < 0.80 -> bloquea el deploy",
guardrail="entrada: senal de inyeccion; salida: schema + frontera determinista",
fallback="modelo -> plantilla FAQ -> escalar a humano (nunca auto-aprueba)",
deterministic_shell="gruesa: valida cada propuesta de reembolso contra la politica",
feedback_loop="thumbs/correcciones del agente humano alimentan el eval-set",
)
print()
print("=== Paso 4: hoja de propiedades del componente (M1) ===")
for field, value in asdict(sheet).items():
if field == "name":
continue
print(f" {field:<22} {value}")
print()
print("Cada campo apunta a un modulo: budget->M2, eval->M3, guardrail->M4,")
print("fallback->M5, shell->M6, feedback->M7. El resto del modulo LLENA la hoja.")
Qué esperar. Al correr el archivo, la salida es exactamente esta:
=== Paso 1: tolerancia a la no-determinacion (M1) ===
touches_money_or_state=5 error_cost=5 blast_if_wrong=5
nd_tolerance = 3/15 -> feature INTOLERANTE, cascara GRUESA
(toca dinero directo: cada propuesta debe validarse contra la politica)
=== Paso 2: nucleo (LLM) vs cascara (determinista) ===
nucleo : leer el ticket y PROPONER una accion (refund/reply)
cascara : validar el schema, la politica, la frontera de confianza,
el presupuesto, el eval-gate, el fallback y el feedback
=== Paso 3: el contrato probabilistico (M1) ===
propuesta 1: {'action': 'refund', 'order_id': 'A-1001', 'amount': 50}
propuesta 2: {'action': 'refund', 'order_id': 'A-1001', 'amount': 50.0, 'reason': 'roto'}
propuesta 3: {'action': 'refund', 'order_id': 'A-1001', 'amount': 50.0}
assert exacto outs[0] == outs[1] -> se ROMPE (no-determinismo)
contrato por propiedades (accion conocida, order_id, monto>0) -> PASA para las 3
=== Paso 4: hoja de propiedades del componente (M1) ===
location detras de support-service; el LLM NUNCA toca la API de reembolsos
nd_tolerance 3
latency_budget_ms 4000
cost_budget_usd_month 3000
eval_gate eval-set de tickets; score < 0.80 -> bloquea el deploy
guardrail entrada: senal de inyeccion; salida: schema + frontera determinista
fallback modelo -> plantilla FAQ -> escalar a humano (nunca auto-aprueba)
deterministic_shell gruesa: valida cada propuesta de reembolso contra la politica
feedback_loop thumbs/correcciones del agente humano alimentan el eval-set
Cada campo apunta a un modulo: budget->M2, eval->M3, guardrail->M4,
fallback->M5, shell->M6, feedback->M7. El resto del modulo LLENA la hoja.
Recorramos la salida paso por paso, porque cada bloque es una decisión de arquitectura.
Paso 1 — la tolerancia, que dicta el grosor de la cáscara. El agente de soporte puntúa 5 en los tres ejes al mismo tiempo: touches_money_or_state=5 (ejecuta reembolsos, toca dinero directo), error_cost=5 (un reembolso mal calculado le duele muchísimo al negocio y a la confianza del cliente), y blast_if_wrong=5 (su radio de impacto es todo el sistema de pagos). Tolerancia = 18 − 15 = 3 de 15: la feature intolerante, la de cáscara gruesa. Y esa cifra es la que gobierna el resto del capstone: como la feature no tolera casi nada de no-determinación sin contención, va a necesitar todos los mecanismos —no una versión ligera—. La búsqueda semántica, con tolerancia alta, se conformaría con una cáscara delgada; el agente de reembolsos, no.
Paso 2 — la partición núcleo/cáscara. La responsabilidad del núcleo se enuncia en una línea: leer el ticket y proponer una acción (refund o reply). Eso, y nada más, es lo único que el LLM aporta. Todo lo demás —validar el schema, la política, la frontera de confianza, el presupuesto, el eval gate, el fallback y el feedback— es la cáscara, determinista. Fíjate en la asimetría: el núcleo tiene una responsabilidad; la cáscara tiene siete. Ese desbalance es a propósito y es la regla del reactor del módulo 1: núcleo pequeño y contenido, cáscara robusta. El capstone entero es construir esa cáscara de siete capas alrededor de un núcleo de una sola responsabilidad.
Paso 3 — el contrato probabilístico. El mismo ticket ("Mi pedido A-1001 llegó roto") entra tres veces al ai_component y salen tres propuestas distintas: una con amount: 50 (entero), otra con un campo reason extra, otra con amount: 50.0 (flotante). Las tres proponen lo mismo —reembolsar 50 de A-1001— pero en formas distintas. El assert outs[0] == outs[1] —el reflejo de código normal— se rompe. Y aquí hay un matiz importante del capstone frente al módulo 1: el contrato de una feature que propone acciones no verifica propiedades de un texto, sino de una propuesta estructurada —que la acción sea conocida (refund o reply), que un refund traiga order_id y un amount numérico positivo—. Ese contrato pasa para las tres propuestas. No afirmas la propuesta exacta; afirmas que es una propuesta válida y despachable. Es lo que hace que la cáscara pueda validarla en las lecciones siguientes.
Paso 4 — la hoja, con sus diez campos. La hoja resume todo el diseño y —crucial— cada campo apunta a la lección que lo va a llenar bien. La location deja explícita la decisión de contención más importante: el LLM vive detrás de support-service y nunca toca la API de reembolsos directamente. La nd_tolerance (3) justifica el grosor de todo lo demás. Y los otros ocho campos son promesas que las lecciones 3 a 7 van a cumplir: el presupuesto (M2), el eval gate (M3), los guardrails (M4), el fallback (M5), la cáscara determinista (M6), el feedback loop (M7). Ahora mismo son enunciados de una línea; al terminar el módulo serán mecanismos ejecutados.
Profundización: por qué la hoja va antes que cualquier mecanismo
La hoja es el contrato arquitectónico, no la implementación. Es tentador saltarse la hoja y empezar directo a montar el eval gate o los guardrails —"lo importante es el código, no el papel"—. Pero la hoja hace un trabajo que ningún mecanismo suelto hace: decide qué mecanismos necesita la feature y por qué, antes de construir ninguno. Sin la hoja, montas mecanismos por costumbre (o los olvidas por descuido). Con la hoja, cada mecanismo existe porque un campo lo pidió, y cada campo existe porque la tolerancia lo justificó. Es la diferencia entre "le puse un eval gate porque sí" y "le puse un eval gate porque su error_cost es 5 y un cambio que degrade la calidad no puede llegar a producción sin ser bloqueado".
La tolerancia es la variable maestra. De los diez campos, la nd_tolerance es el que gobierna a los demás. Una tolerancia de 3 (soporte) exige la cáscara más gruesa: guardrails en entrada y salida, una frontera determinista que valide cada propuesta contra la política, un fallback que degrade a humano (nunca auto-aprueba), y un eval gate estricto. Una tolerancia de 12 (como "describe tu producto") permitiría campos más ligeros: una cáscara media, un guardrail de dos reglas, un fallback a una plantilla. El mismo método, dimensionado al riesgo. Por eso el paso 1 va primero: fija la escala de todo lo que sigue. Diseñar la cáscara antes de medir la tolerancia es como comprar la caja fuerte antes de saber cuánto dinero vas a guardar.
El contrato estructurado es lo que hace despachable la propuesta. Un detalle que el paso 3 dejó ver y que vale subrayar: el núcleo no propone texto libre que alguien interpreta, sino una propuesta estructurada —un comando con nombre (action) y campos tipados (order_id, amount)—. Esto no es un capricho; es lo que permite que la cáscara la valide de forma determinista. Un {"action": "refund", "order_id": "A-1001", "amount": 50.0} se puede validar contra la política campo por campo; un "creo que deberíamos reembolsarle unos 50 pesos a este cliente" no. El contrato probabilístico del capstone, entonces, tiene dos capas: la propuesta debe ser estructuralmente válida (schema, lección 5) y conforme a la política (la cáscara, lección 7). El paso 3 establece la primera; el resto del módulo construye la segunda.
Errores comunes
Emitir la hoja con campos en blanco "porque todavía no los diseñé". Qué pasa: el alumno llena location y nd_tolerance y deja eval_gate, fallback o feedback_loop vacíos, pensando "esos son de lecciones que aún no vi". Por qué pasa: se confunde "no lo he construido" con "no lo puedo enunciar". Cómo detectarlo: tu hoja tiene campos vacíos. Cómo corregirlo: los diez campos llevan un enunciado desde el paso 1, aunque sea de una línea. La hoja es una declaración de intención —"esta feature tendrá un eval gate con umbral 0.80"—, no la implementación. Las lecciones 3 a 7 convierten cada enunciado en un mecanismo ejecutado, pero el enunciado existe desde el principio, porque es lo que te dice qué te falta construir. Una hoja con huecos es un expediente incompleto: no sabes qué autoridad tiene el empleado.
Fijar la tolerancia "a ojo" en vez de con los tres ejes. Qué pasa: el alumno declara "el agente de soporte es riesgoso, cáscara gruesa" sin pasar por los tres ejes (touches_money_or_state, error_cost, blast_if_wrong). Llega a la conclusión correcta, pero sin el razonamiento que la sostiene. Por qué pasa: la conclusión parece obvia, así que se salta el cálculo. Cómo detectarlo: no puedes decir por qué la tolerancia es 3 y no 8. Cómo corregirlo: puntúa los tres ejes explícitamente. El valor no es lo importante; lo importante es que el número esté justificado, porque cuando alguien pregunte "¿por qué esta feature necesita tanta ceremonia?" la respuesta es "porque puntúa 5-5-5 en los tres ejes de riesgo", no "porque a mí me parece riesgosa". El módulo 1 insistió en esto: medir la tolerancia, no opinarla.
Testear la propuesta del núcleo con assert exacto. Qué pasa: al validar el paso 3, el alumno escribe assert ai_component(ticket) == {"action": "refund", "order_id": "A-1001", "amount": 50.0} y se frustra porque falla intermitentemente. Por qué pasa: es el reflejo de código normal, y el módulo 1 advirtió contra él —solo que aquí la salida es una propuesta estructurada, no un texto, lo que lo hace aún más tentador (parece que un dict sí se puede afirmar)—. Cómo detectarlo: tu test del núcleo fija una propuesta esperada exacta. Cómo corregirlo: verifica propiedades de la propuesta —acción conocida, campos requeridos, tipos correctos, monto positivo—, no su igualdad literal. satisfies_contract pasa para cualquier propuesta válida (los tres formatos distintos) y falla solo cuando la propuesta de verdad no sirve. Es la lección 2 del módulo 1, reafirmada para propuestas estructuradas.
Ejercicios
Ejercicio 1 — Cambia la feature, recalcula la tolerancia. Toma la búsqueda semántica de Mercado (interpreta consultas y devuelve productos, no toca dinero) y recalcula su nd_tolerance con los tres ejes. Luego di qué campos de su hoja serían más ligeros que los del agente de soporte, y cuál sería casi idéntico.
Ver solución
La búsqueda semántica en los tres ejes: touches_money_or_state=1 (no toca dinero ni estado; reordena resultados), error_cost=2 (un resultado poco relevante molesta, pero no cuesta dinero ni rompe la confianza), blast_if_wrong=2 (afecta a una búsqueda, no a media plataforma). Tolerancia = 18 − 5 = 13 de 15: feature tolerante, cáscara delgada.
Campos más ligeros que en el agente de soporte:
deterministic_shell: delgada, no gruesa. No hay una acción que toca dinero que validar; el modelo propone un orden de resultados, y la cáscara solo filtra productos retirados o sin permiso. Es la diferencia más grande.guardrail: solo salida (filtrar resultados prohibidos), sin la frontera de confianza fuerte del soporte —la búsqueda no ejecuta acciones, así que una inyección tiene mucho menos que ganar—.fallback: degrada a keywords (determinista, sin IA), no a un humano —una búsqueda por palabras es un fallback barato y suficiente; escalar a un humano sería absurdo para una búsqueda—.
Campo casi idéntico:
eval_gate: las dos features necesitan un eval gate que bloquee un cambio que degrade la calidad. La búsqueda mide relevancia y el soporte mide corrección, pero la forma del mecanismo —un score contra un umbral que gobierna el deploy— es la misma. La calidad hay que gobernarla igual, sea la feature tolerante o no.
La moraleja del módulo 1: la tolerancia dimensiona la cáscara. Menos tolerancia, cáscara más gruesa; misma forma del método, distinto grosor.
Ejercicio 2 — El contrato de un reply. El contrato del paso 3 verifica un refund (acción conocida, order_id, amount numérico positivo). Diseña el contrato por propiedades para una propuesta de tipo reply —cuando el agente responde una duda en vez de reembolsar—, y explica por qué sigue siendo un contrato por propiedades y no un assert exacto.
Ver solución
Un contrato por propiedades para un reply razonable:
def satisfies_reply_contract(p):
return (isinstance(p, dict)
and p.get("action") == "reply"
and isinstance(p.get("text"), str)
and 0 < len(p["text"]) <= 500 # no vacio, dentro de un limite
and "\n\n\n" not in p["text"]) # sin ruido de formato excesivo
Verifica que la propuesta sea un reply, que traiga un text que es una cadena, no vacía, dentro de un límite de longitud, y sin ruido evidente. (En la lección 5 se le añade que el texto no contenga el system prompt —la frontera de confianza—.)
Por qué sigue siendo un contrato por propiedades y no un assert exacto: porque el mismo ticket puede producir muchas respuestas válidas distintas —"Puedes ver el tracking en tu perfil", "Encuentra el seguimiento de tu pedido en la sección Perfil", etc., todas correctas—. No existe la respuesta esperada que puedas fijar con ==; existe un conjunto de propiedades que una buena respuesta cumple (no vacía, acotada, sin ruido, sin fugar el prompt). Afirmar p["text"] == "una respuesta exacta" fallaría con la primera variación legítima, exactamente el error del módulo 1. El contrato correcto verifica que la respuesta sirva, no que sea una cadena específica. La diferencia con el refund es solo qué propiedades verificas (un texto acotado vs una acción tipada), no la naturaleza del contrato: en los dos casos, propiedades, no igualdad.
Ejercicio 3 — La hoja como argumento de contención. Un compañero mira la hoja del agente de soporte y dice: "esto es mucha ceremonia para una feature; démosle acceso directo a la API de reembolsos y ya, el modelo es bueno". Usando dos campos concretos de la hoja, arma el argumento de por qué la ceremonia no es opcional para esta feature.
Ver solución
El argumento, anclado en dos campos de la hoja:
-
nd_tolerance = 3. La hoja registra que esta feature puntúa 5 en los tres ejes de riesgo: toca dinero directo, un error le duele muchísimo, y su radio de impacto es todo el sistema de pagos. Una tolerancia de 3 significa, por definición, que la feature no aguanta que el modelo varíe o se equivoque sin contención —cada propuesta puede convertirse en dinero real que sale mal—. "Darle acceso directo a la API de reembolsos" es exactamente lo que una tolerancia de 3 prohíbe. La ceremonia no es opcional porque el riesgo, medido, es máximo. -
deterministic_shell = "gruesa: valida cada propuesta contra la politica". La hoja registra que la contención elegida es una cáscara gruesa donde el modelo propone y la cáscara dispone. Quitarla —conectar el modelo directo a la API— es el antipatrón raíz del módulo 6: acoplar la ejecución a la salida del modelo. El día que el modelo proponga un reembolso de 9999 (por alucinación o por un prompt injection), ese dinero sale, porque no hay cáscara que lo valide. La hoja no describe "ceremonia"; describe la única diferencia entre un sistema que se cae con la primera inyección creativa y uno que aguanta.
El cierre del argumento: la hoja es la respuesta a "¿por qué tanta ceremonia?". Cada campo existe porque un riesgo medido lo pidió. Para una feature tolerante (búsqueda semántica) la hoja sería ligera y el compañero tendría parte de razón; para esta feature, tolerancia 3, la hoja gruesa es lo que hace legalmente responsable meterla a producción. La ceremonia no es exceso: es proporcional al riesgo que la hoja documenta.
Resumen y siguiente paso
En esta lección ejecutaste el paso 1 del método para la feature del capstone: ubicaste el agente de soporte y le diste su contrato. Clasificaste su tolerancia con los tres ejes (5-5-5 → 3 de 15, la feature intolerante, cáscara gruesa), separaste su núcleo (proponer una acción) de su cáscara (las siete responsabilidades que la contienen), demostraste su contrato probabilístico —el mismo ticket dio tres propuestas estructuradas distintas, el assert exacto se rompió y el contrato por propiedades pasó para las tres—, y emitiste su hoja de propiedades con los diez campos, cada uno apuntando a la lección que lo va a llenar. La feature quedó ubicada, con su contrato claro y su expediente abierto —lista para que las capas siguientes conviertan cada enunciado de la hoja en un mecanismo ejecutado—.
Antes de avanzar deberías poder: clasificar la tolerancia de una feature con los tres ejes y derivar de ahí el grosor de su cáscara; separar el núcleo (una responsabilidad: proponer) de la cáscara (todo lo que contiene); escribir un contrato por propiedades para una propuesta estructurada; y emitir una hoja de propiedades con los diez campos enunciados.
La lección 3 toma los dos primeros campos de la hoja —latency_budget y cost_budget— y los vuelve arquitectura de primera clase: el presupuesto, el cascade y la caché. Vas a ver, medido sobre 1000 tickets, cómo el agente de soporte —lento y caro— se mete en su presupuesto con un model cascade (barato primero) y una caché, y una lección honesta que el módulo 2 anticipó: ninguna palanca sola basta —el cascade recorta pero no alcanza, y solo cascade + caché mete la feature en su margen de costo—. El componente ya está ubicado; ahora aprendes a pagarlo.
Recursos
- Anthropic, "Building Effective Agents" (2024) — anthropic.com/engineering/building-effective-agents. La referencia para ubicar bien un componente de IA: mantener el núcleo acotado (una responsabilidad: proponer) y cargar la contención en lo que lo rodea. La partición núcleo/cáscara de esta lección es una aplicación directa de ese principio. En inglés.
- Michael Nygard, "Documenting Architecture Decisions" (2011) — cognitect.com/blog/2011/11/15/documenting-architecture-decisions. La hoja de propiedades es pariente del ADR que la lección 8 escribe completo; documentar la decisión de ubicación antes de construir es la misma disciplina. En inglés.
- Martin Fowler y Bharani Subramaniam, "Emerging Patterns in Building GenAI Apps" — martinfowler.com/articles/gen-ai-patterns. El tratamiento del componente de IA como una pieza con propiedades arquitectónicas —contrato, frontera, contención— que la hoja de esta lección resume. En inglés.
- Chip Huyen, AI Engineering (O'Reilly, 2024). Para cuando cruces la frontera y quieras construir el núcleo que aquí solo ubicaste —el prompt del agente, su tool use, su RAG—: ese es el libro del otro lado de la frontera. En inglés.