Módulo 1: Qué cambia cuando un componente es no determinista
El LLM es un componente, no el sistema
Descripción
Hay una tentación poderosa cuando descubres lo capaz que es un LLM: dejar que haga todo. Que lea el ticket del cliente, decida el reembolso, y lo ejecute. Que interprete la búsqueda, elija los productos, y arme la página. Que el modelo sea el sistema, porque es tan inteligente que parece un desperdicio ponerle capas alrededor. Esta lección desarma esa tentación con una distinción arquitectónica que sostiene toda la guía: el LLM es un componente que vive tras una frontera, no el sistema entero. Su trabajo es proponer. El trabajo de disponer —de decidir qué de esa propuesta se ejecuta de verdad, sobre dinero, sobre estado, sobre la confianza del usuario— es de una capa determinista que lo rodea.
En la lección 2 escribiste satisfies_contract, la función que verifica las propiedades de una salida. Aquí ves dónde vive esa función y por qué su ubicación lo es todo: no está dentro del modelo, está en la frontera entre el modelo y el sistema. El modelo empuja una propuesta contra esa frontera; la frontera la examina contra las reglas de negocio; y solo lo que pasa el examen toca el sistema. Vas a ver, ejecutado, el antipatrón en el que no hay frontera —el modelo ejecuta su propia salida y "reembolsa" $9999 alucinados— contra el patrón en el que la cáscara determinista de Mercado valida cada propuesta y bloquea tres de cada cuatro.
Conexión con el módulo. La lección 1 dijo "el LLM propone, la cáscara dispone"; la 2 mostró cómo se verifica una salida; esta lección ubica esa verificación en la arquitectura: el LLM como componente acotado tras una frontera. Es la primera vez que ves la forma completa —núcleo que propone, cáscara que dispone— que la lección 5 nombrará como metáfora central y el módulo 6 desarrollará a fondo. La frontera con AI Engineering es especialmente importante aquí y hay que decirla fuerte: no vamos a construir el agente de soporte. Cómo se diseña el bucle de razonamiento del agente, cómo se le dan herramientas, cómo se le escribe el prompt —eso es AI Engineering—. Aquí solo tratamos su propiedad arquitectónica: que sea un componente que propone, ubicado tras una frontera que valida, y que nunca toque la caja fuerte directamente. La cáscara a fondo (más reglas, más patrones de contención) es el módulo 6; los guardrails de entrada y la frontera de confianza del prompt injection son el módulo 4.
Una analogía: el cajero y el gerente
Entras a un banco a pedir que te reembolsen un cargo que consideras un error.
El escenario malo: el cajero decide y ejecuta. El cajero te escucha, le pareces convincente, abre la caja y te entrega el dinero. Sin verificar si el cargo existía, sin revisar la política, sin que nadie más lo apruebe. Es rapidísimo y muy amable. También es un desastre esperando a ocurrir: basta un cliente persuasivo —o mentiroso— para vaciar la caja. El cajero es brillante tratando con personas, pero no debería tener la autoridad de disponer del dinero por su cuenta.
El escenario bueno: el cajero propone, el sistema del banco dispone. El cajero te escucha, entiende tu caso, y propone un reembolso en el sistema: "cliente X, cargo Y, monto Z". Ahí interviene una capa que el cajero no controla: el sistema verifica que el cargo Y exista, que esté dentro de la ventana de reembolso, que el monto Z no exceda el cargo original ni el límite de política. Si todo cuadra, se ejecuta. Si no, se bloquea —y el cajero, por más convencido que esté, no puede pasar por encima—. El cajero aporta lo que hace bien (entender a la persona, el matiz, el caso); el sistema aporta lo que hace bien (aplicar reglas duras, sin excepción, sobre el dinero).
Aquí está el punto: un LLM es el cajero, no el banco. Es excelente entendiendo el lenguaje, el matiz, la intención; y es exactamente por eso que quieres usarlo de cara al cliente. Pero darle la autoridad de disponer —ejecutar el reembolso, mover el estado, tocar el dinero— es el escenario malo: un componente persuasible y falible con las llaves de la caja. El diseño correcto es el escenario bueno: el LLM propone, una capa determinista dispone. En Mercado, el agente de soporte es el cajero; la política de reembolsos codificada en reglas es el sistema del banco; y la frontera entre ambos es lo que impide que una alucinación —o un cliente malicioso— vacíe la caja.
Ejemplo trabajado: la cáscara bloquea la propuesta alucinada
Vamos a modelar los dos escenarios en código. El ai_component es de nuevo un stub: simula un LLM de soporte que lee un ticket y propone un reembolso. A propósito lo hacemos proponer una mezcla realista —a veces bien, a veces un pedido que no es reembolsable, a veces un monto alucinado, a veces un pedido que ni existe—, porque el punto es ver qué hace la arquitectura con cada caso. El estado autoritativo (los pedidos, la política) vive en estructuras deterministas que el modelo nunca toca.
# Lección 3: el LLM como COMPONENTE tras una frontera, no como el sistema.
# El modelo PROPONE; una capa determinista (la cáscara) DISPONE.
# Nota de frontera: aquí NO construimos el agente de soporte (eso es AI Eng);
# solo mostramos la PROPIEDAD arquitectónica de ubicarlo tras una frontera.
import random
_RNG = random.Random(7)
# Estado del sistema (determinista, autoritativo). El LLM NUNCA lo toca.
ORDERS = {
"A-100": {"total": 45.00, "refundable": True},
"A-101": {"total": 12.50, "refundable": False}, # ya fuera de ventana
}
REFUND_POLICY_MAX = 50.00
# --- El componente de IA, SIMULADO. Solo PROPONE una accion. ---
def ai_component(ticket):
# SIMULA un LLM de soporte que lee un ticket y propone un reembolso.
# A veces propone bien; a veces alucina un monto o un pedido inexistente.
proposals = [
{"order_id": "A-100", "amount": 45.00}, # correcto
{"order_id": "A-101", "amount": 12.50}, # pedido NO reembolsable
{"order_id": "A-100", "amount": 9999.00}, # monto alucinado
{"order_id": "Z-999", "amount": 20.00}, # pedido inexistente
]
return _RNG.choice(proposals)
# --- Cascara determinista: valida la propuesta ANTES de tocar dinero. ---
def deterministic_shell(proposal):
oid = proposal["order_id"]
amount = proposal["amount"]
order = ORDERS.get(oid)
if order is None:
return (False, f"pedido {oid} no existe")
if not order["refundable"]:
return (False, f"pedido {oid} fuera de ventana de reembolso")
if amount > order["total"]:
return (False, f"monto {amount} excede el total {order['total']}")
if amount > REFUND_POLICY_MAX:
return (False, f"monto {amount} excede el maximo de politica {REFUND_POLICY_MAX}")
return (True, f"reembolso de {amount} para {oid} APROBADO")
# --- Antipatron: el LLM ES el sistema (ejecuta su salida directo). ---
def llm_is_the_system(proposal):
# Sin frontera: lo que el modelo diga, se ejecuta. Peligroso.
return f"EJECUTADO sin validar: reembolso {proposal['amount']} -> {proposal['order_id']}"
print("=== Antipatron: el LLM ejecuta su propia salida (sin cascara) ===")
_RNG.seed(7)
for _ in range(4):
p = ai_component("cliente pide reembolso")
print(" ", llm_is_the_system(p))
print()
print("=== Patron: el LLM propone, la cascara determinista dispone ===")
_RNG.seed(7)
approved = blocked = 0
for _ in range(4):
p = ai_component("cliente pide reembolso")
ok, reason = deterministic_shell(p)
tag = "APROBADO" if ok else "BLOQUEADO"
if ok:
approved += 1
else:
blocked += 1
print(f" propuesta {p['order_id']:<6} {p['amount']:>8.2f} -> {tag}: {reason}")
print()
print(f"Resumen: {approved} aprobadas, {blocked} bloqueadas por la cascara.")
print("Ni un solo peso salio del sistema sin pasar por reglas deterministas.")
Qué esperar. Al correr el archivo, la salida es exactamente esta:
=== Antipatron: el LLM ejecuta su propia salida (sin cascara) ===
EJECUTADO sin validar: reembolso 9999.0 -> A-100
EJECUTADO sin validar: reembolso 12.5 -> A-101
EJECUTADO sin validar: reembolso 20.0 -> Z-999
EJECUTADO sin validar: reembolso 45.0 -> A-100
=== Patron: el LLM propone, la cascara determinista dispone ===
propuesta A-100 9999.00 -> BLOQUEADO: monto 9999.0 excede el total 45.0
propuesta A-101 12.50 -> BLOQUEADO: pedido A-101 fuera de ventana de reembolso
propuesta Z-999 20.00 -> BLOQUEADO: pedido Z-999 no existe
propuesta A-100 45.00 -> APROBADO: reembolso de 45.0 para A-100 APROBADO
Resumen: 1 aprobadas, 3 bloqueadas por la cascara.
Ni un solo peso salio del sistema sin pasar por reglas deterministas.
Lee las dos secciones en contraste, porque ahí está toda la lección.
En el antipatrón, el LLM es el sistema: lo que propone, se ejecuta. Y mira lo que se ejecutó: un reembolso de $9999 sobre un pedido de $45 (una alucinación de monto), un reembolso sobre un pedido que no era reembolsable, y un reembolso sobre el pedido Z-999 que ni existe. Tres de las cuatro operaciones que salieron habrían sido pérdidas o errores reales. El modelo no es "malo" —hace lo que un modelo probabilístico hace, proponer con confianza cosas que a veces están mal—; lo malo es la arquitectura sin frontera, que convirtió cada propuesta equivocada en una acción ejecutada.
En el patrón, el mismo LLM propone exactamente lo mismo —el stub usa la misma semilla—, pero ahora cada propuesta choca contra la deterministic_shell antes de tocar dinero. El $9999 se bloquea por exceder el total; el pedido no reembolsable se bloquea por política; el Z-999 se bloquea porque no existe. Solo la propuesta legítima —$45 sobre A-100, dentro de política— se aprueba. Una aprobada, tres bloqueadas. El resumen lo dice literal: ni un solo peso salió del sistema sin pasar por reglas deterministas.
Fíjate en lo que no cambió entre los dos escenarios: el modelo. Es idéntico, igual de falible en ambos. Lo único que cambió es que en el segundo hay una frontera. Esa es la tesis de la lección hecha número: la seguridad de un sistema de IA no viene de que el modelo sea perfecto (nunca lo será), viene de dónde lo ubicas y de qué lo separa del dinero y del estado.
Profundización: la propiedad "propone, no dispone"
Vale la pena hacer explícita la anatomía, porque es un patrón que vas a aplicar a cada componente de IA de aquí en adelante.
entrada del usuario (no confiable)
│
▼
┌───────────────────┐
│ ai_component │ NÚCLEO probabilístico
│ (el LLM: stub) │ → solo PROPONE. No toca estado ni dinero.
└───────────────────┘
│ propuesta {order_id, amount}
▼
┌───────────────────┐
│ deterministic_ │ FRONTERA / CÁSCARA determinista
│ shell │ → valida contra reglas de negocio.
└───────────────────┘
│ │
APROBADO BLOQUEADO
│ │
▼ ▼
estado / dinero (nada se ejecuta)
El LLM nunca tiene autoridad de escritura. Es la regla dura. El modelo produce una propuesta —una estructura de datos que describe una acción deseada—, no ejecuta la acción. Entre la propuesta y la ejecución hay siempre una capa determinista que puede decir que no. Compáralo con permisos de un sistema operativo: el modelo corre en "modo usuario", sin privilegios sobre el dinero o el estado; la cáscara corre en "modo núcleo" y es la única que puede efectuar cambios, y solo después de validar. Si en tu diseño la salida del LLM llega directo a algo que escribe —una llamada a la API de pagos, un UPDATE a la base de datos, un correo que se envía—, no tienes esta propiedad, y tienes el antipatrón.
La cáscara es determinista y testeable con assert exacto. Esto es clave y a veces se pasa por alto: aunque el sistema como un todo tiene un componente no determinista, la frontera que lo contiene es 100% determinista. deterministic_shell(propuesta) con la misma propuesta da siempre el mismo veredicto. Eso significa que la parte más importante para la seguridad —la que decide qué toca el dinero— la puedes probar con los tests de igualdad exacta de toda la vida: assert deterministic_shell({"order_id": "A-100", "amount": 9999.0})[0] is False. El núcleo probabilístico es incierto; la frontera que lo contiene es certera. Diseñas para que la incertidumbre viva en un lugar pequeño y acotado, rodeado de certeza verificable.
"Componente" implica reemplazable y acotado. Tratar el LLM como un componente —no como el sistema— tiene una consecuencia práctica valiosa: si mañana llega un modelo mejor (de Haiku a Sonnet, de una versión a otra, o incluso a un enfoque sin LLM para un caso simple), lo cambias detrás de la misma frontera sin tocar el resto del sistema. La cáscara, las reglas de negocio, el contrato de la propuesta —todo eso permanece—. Si en cambio el modelo es el sistema, entrelazado con todo, cambiarlo es rehacer todo. Ubicar el LLM como componente tras una frontera no solo lo hace seguro; lo hace sustituible, que es una de las cosas más valiosas que la arquitectura te puede dar frente a una tecnología que cambia rápido.
Dónde termina esta lección y empieza el módulo 6. Aquí mostramos la forma del patrón con una cáscara mínima: unas cuantas reglas de política de reembolso. El módulo 6 la desarrolla a fondo —qué reglas, cómo mantener el núcleo pequeño, cómo componer varias validaciones, el patrón completo de contención—. Y el módulo 4 añade la otra mitad de la frontera: no solo validar la salida del modelo (lo que hicimos aquí), sino la entrada —porque el ticket del cliente que el modelo lee es una frontera de confianza, y un prompt injection ahí es un vector de ataque—. Por ahora quédate con la propiedad: propone, no dispone; tras una frontera, no como el sistema.
Errores comunes
Conectar la salida del LLM directo a una acción con efectos. Qué pasa: para "simplificar", el equipo cablea la respuesta del agente directo a la API de reembolsos, o a un send_email, o a un UPDATE de inventario —lo que el modelo diga, se hace—. Funciona en la demo y explota en producción el día que el modelo alucina o alguien inyecta instrucciones. Por qué pasa: agregar la frontera se siente como burocracia innecesaria cuando el modelo "casi siempre acierta". Cómo detectarlo: traza el camino desde la salida del LLM hasta el primer efecto secundario (dinero, estado, un mensaje que sale); si no hay una validación determinista en medio, tienes el antipatrón. Cómo corregirlo: inserta la cáscara. El modelo produce una propuesta (datos), nunca ejecuta la acción. Una capa determinista valida la propuesta contra las reglas de negocio y es la única que efectúa el cambio. Como en el ejemplo: el $9999 alucinado se bloquea porque la frontera existe.
Hacer la cáscara tan "lista" que necesite otro LLM para validar. Qué pasa: alguien razona "las reglas de negocio son complejas, mejor que otro modelo valide la propuesta del primero", y termina con un LLM revisando a otro LLM. Por qué pasa: se confunde "validar" con "entender", y entender es lo que un LLM hace bien. Cómo detectarlo: tu capa de validación es en sí misma no determinista —da veredictos distintos para la misma propuesta—. Cómo corregirlo: la frontera debe ser determinista, justo para que sea certera y testeable. Las reglas que validan un reembolso (¿existe el pedido?, ¿está en ventana?, ¿el monto no excede el total?) son condiciones duras, no juicios matizados; escríbelas como código determinista. Si de verdad una parte del juicio requiere un modelo, esa parte es otro componente que propone y necesita su propia frontera determinista —no puedes cerrar el sistema con una cadena infinita de modelos revisándose entre sí—. La certeza tiene que venir, en algún punto, de reglas deterministas.
Dejar que el LLM sea el sistema "porque es más simple". Qué pasa: en un prototipo, el modelo hace todo de punta a punta y el equipo decide llevarlo así a producción porque "ya funciona y agregar capas es trabajo extra". Por qué pasa: la arquitectura sin frontera es genuinamente más simple de escribir, y su fragilidad no se ve hasta que hay usuarios reales, dinero real y actores maliciosos reales. Cómo detectarlo: no puedes nombrar cuál capa determinista impediría que una alucinación toque el dinero —porque no existe—. Cómo corregirlo: acepta que la frontera no es trabajo extra opcional, es la parte del sistema que lo vuelve seguro. La complejidad que ahorras al quitarla reaparece, multiplicada, como incidentes. El módulo 5 (fallos) y el 6 (cáscara) muestran cuánto de la robustez de un sistema de IA vive precisamente en esas capas alrededor del modelo.
Ejercicios
Ejercicio 1 — Encuentra la frontera que falta. Para cada diseño de Mercado, di si tiene la propiedad "propone, no dispone" o si es el antipatrón, y si falta la frontera, describe qué capa determinista habría que insertar: (a) la búsqueda semántica devuelve una lista de IDs de producto que se pasan directo a la página de resultados; (b) el agente de soporte genera un correo y el sistema lo envía tal cual al cliente; (c) "describe tu producto" genera una descripción que se publica automáticamente sin que el vendedor la vea; (d) el agente propone cambiar el precio de un producto.
Ver solución
- (a) Búsqueda → IDs → página. Casi seguro necesita una frontera delgada, no ninguna. Los IDs deben pasar por una validación determinista: ¿existen esos productos?, ¿están activos (no retirados)?, ¿el usuario tiene permiso de verlos? El modelo propone un orden de resultados; la cáscara filtra los que no deben mostrarse. No toca dinero, así que la cáscara es delgada, pero no es cero.
- (b) Agente → correo → cliente. Antipatrón si el correo sale tal cual. La salida del modelo va directo a un efecto (un mensaje que sale al cliente, que es reputación de Mercado). Frontera a insertar: un guardrail que valide el correo —sin claims prohibidos, sin datos de otro cliente, dentro de un tono/formato— antes de enviarlo. Para acciones sensibles, incluso revisión humana.
- (c) "Describe tu producto" → publicación automática. Antipatrón. Una descripción alucinada (un claim falso, un dato inventado) se publica con la marca de Mercado sin que nadie la revise. Frontera: la cáscara valida contenido (claims prohibidos, longitud) y exige que el vendedor apruebe antes de publicar —un humano en el lazo—. El modelo propone el borrador; el vendedor y las reglas disponen.
- (d) Agente → cambiar precio. El antipatrón más peligroso de los cuatro: tocar precio es tocar dinero directamente. Jamás debe ejecutarse la propuesta del modelo directo. Frontera: reglas duras (¿el nuevo precio está dentro de un rango permitido respecto al actual?, ¿quién autoriza cambios de precio?) y muy probablemente aprobación humana. El modelo, aquí, ni siquiera debería proponer cambios de precio sin una razón de negocio muy clara; es un caso donde conviene preguntarse si el LLM debe estar involucrado.
Ejercicio 2 — La cáscara es testeable. El equipo dice: "no podemos escribir tests confiables para el agente de reembolsos porque el LLM es no determinista". Explica por qué esa afirmación es falsa, e identifica exactamente qué parte del sistema sí se puede testear con assert exacto. Escribe dos de esos asserts para la deterministic_shell del ejemplo.
Ver solución
La afirmación es falsa porque confunde "el sistema tiene un componente no determinista" con "todo el sistema es no determinista". El núcleo (el LLM) es no determinista y no lo pruebas con assert exacto —usas el contrato por propiedades de la lección 2 y el eval del módulo 3—. Pero la cáscara determinista, que es la que decide qué toca el dinero, es 100% determinista: con la misma propuesta da siempre el mismo veredicto. Esa parte —la más crítica para la seguridad— se prueba con los tests de igualdad exacta de toda la vida:
# Una propuesta alucinada (monto que excede el total) SIEMPRE se bloquea.
ok, reason = deterministic_shell({"order_id": "A-100", "amount": 9999.0})
assert ok is False
# Una propuesta legitima dentro de politica SIEMPRE se aprueba.
ok, reason = deterministic_shell({"order_id": "A-100", "amount": 45.0})
assert ok is True
# Un pedido inexistente SIEMPRE se bloquea.
ok, reason = deterministic_shell({"order_id": "Z-999", "amount": 20.0})
assert ok is False
Estos asserts pasan siempre, sin importar qué haga el modelo, porque prueban la frontera, no el modelo. La lección del diseño es justo esta: al meter la incertidumbre en un núcleo pequeño rodeado de una frontera determinista, la parte que garantiza la seguridad vuelve a ser testeable como cualquier código normal. No pruebas que el LLM nunca alucine (imposible); pruebas que cuando alucine, la cáscara lo bloquee (garantizable).
Ejercicio 3 — Sustituible por diseño. Mercado empezó con un modelo grande para el agente de soporte. Ahora quiere probar si un modelo más pequeño y barato basta para la mayoría de los tickets. Explica por qué, si el LLM está ubicado como componente tras una frontera, este cambio es de bajo riesgo, y qué tendría que ser cierto del diseño para que el cambio no obligue a re-verificar la seguridad de los reembolsos.
Ver solución
El cambio es de bajo riesgo porque, en el patrón "componente tras una frontera", el modelo es reemplazable: vive detrás de un contrato claro (recibe un ticket, devuelve una propuesta {order_id, amount}) y la cáscara determinista que valida esa propuesta no depende de cuál modelo la generó. Cambiar el modelo grande por uno pequeño cambia la calidad de las propuestas (quizás el pequeño propone más reembolsos malos), pero no cambia quién tiene la autoridad de disponer: sigue siendo la cáscara.
Para que el cambio no obligue a re-verificar la seguridad de los reembolsos, tienen que ser ciertas dos cosas del diseño:
- La cáscara no confía en el modelo. Valida toda propuesta contra las reglas de negocio, venga del modelo que venga. Si un modelo peor propone más basura, la cáscara simplemente bloquea más —la garantía "ningún reembolso fuera de política se ejecuta" se mantiene, porque no depende de la calidad del modelo—. La seguridad ya estaba en la frontera, no en el modelo.
- El contrato de la propuesta es estable. El modelo nuevo debe producir el mismo formato de propuesta (
{order_id, amount}) que la cáscara sabe validar. Eso se verifica con el contrato por propiedades de la lección 2, y es lo único del cambio que sí hay que comprobar.
Lo que sí cambia y hay que medir es la calidad (cuántas buenas propuestas hace el modelo pequeño), y eso se mide con el eval del módulo 3 y, si el costo/latencia es el motor, con el model cascade del módulo 2. Pero la seguridad —que nada fuera de política se ejecute— no se re-verifica, porque nunca dependió del modelo. Esa es la ventaja de tratar el LLM como componente y no como sistema: separas "¿qué tan bueno es?" (calidad, cambia con el modelo) de "¿puede hacer daño?" (seguridad, garantizada por la frontera).
Resumen y siguiente paso
En esta lección instalaste la distinción arquitectónica que sostiene toda la guía: el LLM es un componente que vive tras una frontera, no el sistema entero. Su trabajo es proponer; el de disponer —decidir qué toca el dinero, el estado, la confianza— es de una capa determinista que lo rodea. Lo viste ejecutado: el mismo modelo falible, sin frontera, ejecutó $9999 alucinados y reembolsos sobre pedidos que no existían; con la frontera, la cáscara bloqueó tres de cada cuatro propuestas y solo dejó pasar la legítima. La seguridad no vino de un modelo perfecto —imposible— sino de dónde lo ubicaste. Y viste tres consecuencias: la frontera es determinista y testeable con assert exacto; el componente es sustituible sin rehacer el sistema; y la certeza, en algún punto, tiene que venir de reglas deterministas, no de más modelos.
Antes de avanzar deberías poder: dibujar la anatomía núcleo-que-propone / cáscara-que-dispone; explicar por qué el LLM nunca debe tener autoridad de escritura directa; identificar en un diseño dónde falta la frontera; y argumentar por qué la parte crítica para la seguridad sigue siendo testeable aunque el sistema tenga un componente no determinista.
La lección 4 sube un nivel y hace la pregunta que cierra la primera mitad del módulo: si meter un LLM es todo esto —una frontera, una cáscara, un contrato nuevo—, ¿por qué tanta gente cree que "es solo una llamada a una API"? Vas a ver, contadas y ejecutadas, las cinco propiedades que entran de golpe con esa "sola línea de código" —latencia, costo, no-determinación, nuevos modos de fallo y la frontera de confianza— y a qué módulo de la guía va cada una. El iceberg completo bajo la línea visible.
Recursos
- Anthropic, "Building Effective Agents" (2024) — anthropic.com/engineering/building-effective-agents. El principio de mantener el componente de IA acotado y con autoridad limitada, y de separar lo que el modelo propone de lo que el sistema ejecuta, es exactamente la propiedad de esta lección. Léelo por su postura arquitectónica; el cómo construir el agente es la frontera con AI Eng. En inglés.
- Martin Fowler y Bharani Subramaniam, "Emerging Patterns in Building GenAI Apps" — martinfowler.com/articles/gen-ai-patterns. El patrón de un componente de IA rodeado de código determinista que valida sus salidas atraviesa todo el artículo. En inglés.
- Chip Huyen, AI Engineering (O'Reilly, 2024). Los capítulos sobre arquitectura de aplicaciones con modelos de fundación describen la separación entre el modelo y la lógica de aplicación que lo contiene —el "componente, no el sistema" de esta lección—. En inglés.
- Documentación de Claude, uso de herramientas (tool use) — docs.anthropic.com. Útil para ver, a nivel conceptual, cómo un modelo propone llamadas a herramientas que tu código decide ejecutar o no —el mecanismo concreto detrás del "propone, no dispone"—, sin fijarte en una versión de modelo. La lógica de cuándo ejecutarlas es tuya (la cáscara). En inglés.