Módulo 8: Project The Reservo Agent In Production

Introducción del módulo: el capstone — el agente de Reservo en producción

Descripción

Siete módulos te dejaron con cuatro disciplinas construidas, probadas y ejecutadas por separado: observar un run completo con logging estructurado y un trace_id (Módulo 2); medir cuánto costó y cuánto tardó (Módulos 3 y 4); gatear — decidir, con un criterio determinista, si el agente sigue comportándose como se espera (Módulo 5); y endurecer + versionar — sobrevivir a fallos que persisten entre runs y decidir con evidencia si una versión nueva es segura (Módulos 6 y 7). Cada módulo construyó su pieza sobre el agente de Reservo que agent-fundamentals-and-tool-calling-guide M8 ya entregó, sin tocar una sola línea de su lógica. Este último módulo —el capstone— no agrega ninguna disciplina nueva. Hace lo único que faltaba: envolver el agente completo con las cuatro a la vez, ponerlo a resolver tráfico real con esa capa puesta, y entregarlo listo para operar.

Al final de este módulo vas a tener, en un directorio propio, la capa de operación completa —logger, calculadora de costo, modelo de latencia, harness de regresión, circuit breaker, registro de versiones— envolviendo a run_reservo_agent sin modificarlo, y cuatro artefactos reales, escritos a disco: RUN_LOG.jsonl, un resumen de métricas de costo y latencia, regression_report.json, y AGENT_CHANGELOG.md.

Conexión con el módulo

Este módulo tiene, con el resto de esta guía, la misma relación que el capstone de agent-fundamentals tuvo con sus siete módulos: no agrega una capa nueva, es la vista desde arriba de las capas que ya existen, funcionando juntas. Cada lección que sigue retoma, literalmente, código que ya ejecutaste en un módulo anterior de esta guía —traced_run, cost_for_run, total_run_latency_ms, run_regression_gate, CircuitBreaker, PROMPT_REGISTRY— y lo pone a trabajar sobre el mismo agente, al mismo tiempo. La única novedad genuina es la integración: como vas a ver en la Lección 5, dos piezas construidas por separado —el harness de regresión de M5 y el registro de versiones de M7— resuelven preguntas parecidas con fixtures ligeramente distintos, y saber cuál usar para qué pregunta es, en sí mismo, parte de operar un sistema real.


Analogía: el restaurante, un año después de la noche de apertura

agent-fundamentals M8 cerró con la noche de apertura del restaurante de Reservo: la cocina completa, el protocolo completo, el servicio completo, funcionando por primera vez, sirviendo a un cliente real de principio a fin. Esa noche salió bien. Pero un restaurante que sobrevive un año completo de servicio real no es el mismo que abrió esa noche — no porque la cocina haya cambiado, sino porque alrededor de la cocina apareció una capa entera de operación que la noche de apertura no necesitaba.

Ahora hay un inspector de salud que revisa, plato por plato, quién entró a la cocina y qué hizo — no porque el chef sea sospechoso, sino porque cuando algo sale mal a las tres de la mañana, alguien necesita reconstruir exactamente qué pasó, sin depender de la memoria de nadie (Módulo 2: logging estructurado y trace_id). Hay un contador que factura cada plato con su costo real de ingredientes, y un cronómetro en la cocina que mide cuánto tarda cada estación — no para apurar al chef, sino para saber, con números, dónde se va el dinero y el tiempo (Módulos 3 y 4: costo y latencia). Hay una inspección obligatoria antes de que cualquier cambio al menú salga a los clientes — un examen fijo, con los mismos platos de siempre, que confirma que nada que ya funcionaba se rompió (Módulo 5: el gate de regresión). Hay un generador de respaldo que se enciende solo, sin que nadie tenga que ir a revisar, cuando una estación de la cocina deja de responder — y un protocolo de sustitución de chef, con expedientes fechados de cada receta, para cuando alguien propone cambiar el menú y hace falta decidir, con evidencia, si el cambio es seguro o si hay que volver al chef de siempre (Módulos 6 y 7: resiliencia y versionado).

Ninguna de esas cinco cosas cambia lo que la cocina sabe cocinar. El menú es el mismo, las recetas son las mismas, los platos que sale son los mismos. Lo que cambió es todo lo que rodea a la cocina para que pueda sobrevivir, sin sorpresas, a un año entero de clientes reales. Este módulo es esa capa completa, puesta alrededor del mismo agente, funcionando a la vez.


Dónde estamos en el ecosistema

Agentes en producción — operar el agente de Reservo
├── Módulo 1: Por qué operar es distinto de construir
├── Módulo 2: Logging estructurado y trazado de un run          -> OBSERVAR
├── Módulo 3: Medir costo y tokens por run                       -> MEDIR
├── Módulo 4: Medir latencia con honestidad                      -> MEDIR
├── Módulo 5: Evals de regresión como gate de producción         -> GATEAR
├── Módulo 6: Fallos a escala -- backoff y circuit breakers      -> ENDURECER
├── Módulo 7: Versionado y rollout seguro                        -> VERSIONAR
└── Módulo 8: Proyecto -- el agente de Reservo en producción  ← ESTÁS AQUÍ
    → las cuatro disciplinas, envolviendo al mismo agente, a la vez;
      un run instrumentado + medido, el gate corrido, un rollout con
      NO-GO y rollback, un circuit breaker abriendo de verdad, y los
      cuatro artefactos finales, escritos a disco.

Fíjate en la columna de la derecha: los siete módulos anteriores no son siete temas sueltos — son cuatro disciplinas (observar, medir, gatear, endurecer+versionar), cada una construida, probada y ejecutada por separado. Este módulo no inventa una quinta disciplina — reúne a las cuatro alrededor del mismo agente, en el mismo directorio de trabajo, produciendo evidencia real de que, juntas, sostienen a Reservo frente a tráfico que no se comporta siempre como el guion perfecto de un módulo aislado.


Qué vas a construir

A lo largo de las ocho lecciones de este módulo vas a ensamblar un paquete de archivos, retomando —sin cambiar su lógica de fondo— lo que ya construiste en los Módulos 1-7 de esta guía y en agent-fundamentals M8:

# El agente, tal como agent-fundamentals M8 lo entregó -- SIN TOCAR
reservo_tools.py           -> las 4 funciones reales de Reservo, con su estado.
reservo_contracts.py       -> los 4 contratos + TOOLS + call_tool.
reservo_robust.py          -> dispatch_robust: valida, atrapa, reintenta.
reservo_agent.py           -> run_reservo_agent: el runner completo.

# La capa de operación, construida en M2-M7 de ESTA guía -- SIN TOCAR
observability/run_logger.py        -> M2: RunEvent, ToolCallEvent, traced_run.
observability/cost_calculator.py   -> M3: estimate_cost_cents, CostReport, cost_for_run.
observability/latency_model.py     -> M4: TOOL_LATENCY_MS, total_run_latency_ms, percentile.
regression/harness.py              -> M5: CaseResult, GateReport, run_case, run_regression_gate.
regression/golden_cases.json       -> M5: el CASE_SET fijo, cinco casos.
resilience/tool_circuit_breaker.py -> M6: retry_with_backoff, CircuitBreaker.
ops/versions/prompt_registry.py    -> M7: AgentVersion, hash_prompt, PROMPT_REGISTRY.

# Lo que este módulo agrega -- pura integración, ningún mecanismo nuevo
ops/rollout.py              -> rollout_decision + rollback (M8, ensambla lo que M7 dejó listo).
ops/metrics_summary.py      -> junta cost_for_run + latency_model en UN reporte por lote (M8).
RUN_LOG.jsonl               -> ENTREGABLE: el log estructurado de un lote real, escrito a disco.
regression_report.json      -> ENTREGABLE: el veredicto del gate, escrito a disco.
AGENT_CHANGELOG.md          -> ENTREGABLE: qué versión corre, y por qué, en texto legible.

Nueve de los once archivos son puro reuso: código que ya ejecutaste, con salida que ya viste, en un módulo anterior. Solo ops/rollout.py y ops/metrics_summary.py tienen ensamblaje genuinamente nuevo — y, como vas a comprobar en las Lecciones 4 y 5, ese ensamblaje es mínimo: funciones que llaman, en el orden correcto, a piezas que ya existen.


Ejemplo trabajado: el entorno, verificado, y el manifiesto de la capa completa

Antes de instrumentar un solo run, este primer paso confirma que el entorno es el que el DISEÑO.md de esta guía prometió, y que los siete archivos reusados —cuatro de agent-fundamentals, tres de M2-M7 de esta guía— importan sin conflicto en un directorio nuevo.

import sys
print("Python:", sys.version.split()[0])

# El agente, sin tocar
import reservo_tools as rt
import reservo_contracts as rc
import reservo_robust as rr
import reservo_agent as ra

# La capa de operación, sin tocar
import run_logger as rl
import cost_calculator as cc
import latency_model as lm
import harness as hn
from tool_circuit_breaker import CircuitBreaker, CLOSED, retry_with_backoff
from prompt_registry import PROMPT_REGISTRY, hash_prompt

print()
print("=== Manifiesto de la capa de operación ===")
print("tools de Reservo        :", list(rc.TOOLS.keys()))
print("ancla 1 -- Focus basic 3h:", rt.get_quote("Focus", "basic", 3))
print("ancla 2 -- Focus pro   3h:", rt.get_quote("Focus", "pro", 3))
print("TOOL_LATENCY_MS          :", lm.TOOL_LATENCY_MS)
print("pricing (centavos/1M tok):", cc.INPUT_PRICE_CENTS_PER_MILLION_TOKENS, "/", cc.OUTPUT_PRICE_CENTS_PER_MILLION_TOKENS)
print("CASE_SET del gate (M5)   :", len(hn.CASE_SET), "casos")
print("versiones en el registro :", list(PROMPT_REGISTRY.keys()))

breaker_demo = CircuitBreaker("book_room", failure_threshold=3, cooldown_calls=2)
print("circuit breaker arranca en:", breaker_demo.state, "(", CLOSED, ")")

Qué esperar:

Python: 3.14.0

=== Manifiesto de la capa de operación ===
tools de Reservo        : ['list_rooms', 'get_quote', 'book_room', 'cancel_booking']
ancla 1 -- Focus basic 3h: {'price_cents': 7500}
ancla 2 -- Focus pro   3h: {'price_cents': 6000}
TOOL_LATENCY_MS          : {'list_rooms': 40, 'get_quote': 25, 'book_room': 120, 'cancel_booking': 90}
pricing (centavos/1M tok): 300 / 1500
CASE_SET del gate (M5)   : 5 casos
versiones en el registro : ['v1', 'v2']
circuit breaker arranca en: CLOSED ( CLOSED )

Nada de esta salida es nueva: 7500/6000 son las mismas dos anclas de get_quote que acompañan la guía desde agent-fundamentals M2; TOOL_LATENCY_MS y el pricing son las mismas constantes fijadas en M4 y M3 de esta guía; PROMPT_REGISTRY tiene las mismas dos versiones que M7 construyó. El manifiesto no descubre nada — confirma que el terreno sobre el que vas a ensamblar la capa completa sigue siendo sólido, exactamente como hizo agent-fundamentals M8 antes de construir su propio capstone.


Cómo se apoyan los ocho módulos anteriores en este

M8 (esta guía)   Capstone -- CUATRO disciplinas, envolviendo al mismo agente, a la vez
     ▲
M7   Versionar    PROMPT_REGISTRY, rollout_decision, rollback -- comparar antes de desplegar
     ▲
M6   Endurecer    CircuitBreaker por tool -- memoria de fallos ENTRE runs
     ▲
M5   Gatear       run_regression_gate -- comparación LITERAL, nunca un juez
     ▲
M4   Medir        TOOL_LATENCY_MS, percentiles -- latencia modelada, nunca time.time()
     ▲
M3   Medir        estimate_cost_cents, cost_for_run -- costo estimado, pricing fijo
     ▲
M2   Observar     traced_run, trace_id determinista -- cada paso, según ocurre
     ▲
M1   El puente    run_and_observe -- la primera envoltura, y su límite exacto
     ▲
agent-fundamentals M1-M8   run_reservo_agent -- EL AGENTE, construido, sin tocar

Cada capa de esta pila depende, sin excepción, de la que tiene debajo — la misma disciplina de agent-fundamentals. traced_run (M2) envuelve dispatch_robust sin tocarlo; cost_for_run y latency_model (M3/M4) leen el history que run_reservo_agent produce, sin cambiar cómo lo produce; el gate de M5 corre sobre runs completos, usando cost_for_run/latency_for_run sin reconstruirlos; el CircuitBreaker de M6 envuelve la función real de una tool, por fuera del loop; y el registro de M7 identifica versiones del prompt que ese mismo loop usa. Este capstone no agrega una novena capa — es la evidencia ejecutada de que las ocho, juntas, no se pisan entre sí.


El mapa de las ocho lecciones

  • 02 — Ensamblando la capa de operación. El paquete completo de archivos de M2-M7, importado junto, con un chequeo rápido de que cada pieza sigue funcionando por su cuenta antes de ponerlas a trabajar juntas.
  • 03 — El run instrumentado. traced_run (M2) envolviendo run_reservo_agent, sobre un lote real de tareas de Reservo — RUN_LOG.jsonl real, escrito a disco, leído de vuelta sin ninguna variable de Python en memoria.
  • 04 — El reporte de costo y latencia. cost_for_run (M3) y el modelo de latencia (M4), sobre el mismo lote — costo en centavos, latencia total, p50/p95 sobre runs reales, un resumen único por lote.
  • 05 — El gate de regresión en el capstone. run_regression_gate (M5) corrido contra el agente tal como está — PASS. Después, el mismo criterio, aplicado a comparar una versión nueva del prompt (M7) — NO-GO, y el rollback ejecutado.
  • 06 — La capa de resiliencia. El CircuitBreaker de M6, sobre book_room fallando de verdad, integrado con el resto de la capa de operación — el ahorro de llamadas reales, medido con las herramientas de M3 y M4.
  • 07 — Lo que tu agente todavía necesita. El cierre de ecosistema: a dónde ir cuando este agente operado tenga que enfrentar incidentes de infraestructura, juicio semántico, reducción de costo, o endurecimiento contra ataques.
  • 08 — Proyecto: entrega el agente listo para producción. El checklist final, los cuatro artefactos generados de punta a punta en una sola corrida, y un reto que pone a prueba la capa completa con un escenario que no viste antes.

Por qué integrar la capa de operación es distinto de construir cada pieza

Cada uno de los Módulos 2 a 7 probó su pieza de forma aislada, con un guion diseñado a propósito para esa pieza. Eso es correcto y necesario — así se construye software de operación confiable, una capa a la vez. Pero integrar cuatro disciplinas construidas por separado tiene un costo silencioso, distinto del que ya viste en agent-fundamentals M8 (ahí, el costo era de formato de datosjson.dumps contra ast.literal_eval). Aquí, el costo es de preguntas: M5 construyó su gate de regresión —el CASE_SET de cinco casos, run_regression_gate— para confirmar que el agente de hoy sigue funcionando; M7, al comparar dos versiones de un prompt, no construyó ningún fixture nuevo — reusó exactamente ese mismo CASE_SET y esa misma función, con su parámetro overrides, para responder una pregunta relacionada pero distinta: "¿esta versión candidata es segura para reemplazar a la de hoy?". La Lección 5 de este módulo muestra las dos preguntas, ejecutadas sobre el mismo mecanismo, y traza la frontera con precisión — el mismo tipo de fricción de integración que ninguna lección aislada tenía motivo para encontrar.


Errores comunes

  1. Creer que este módulo enseña una plataforma de observabilidad. No hay ningún Datadog, LangSmith ni Sentry en este capstone — como en cada módulo anterior de esta guía, todo es Python puro sobre dicts, dataclasses y archivos JSON Lines. Los patrones (logging estructurado, trace_id, harness de regresión, circuit breaker) son idénticos con cualquier plataforma real; lo que cambia es dónde se envían los eventos, no su forma.

  2. Reescribir alguna de las nueve piezas reusadas "para que encajen mejor entre sí". El valor de este módulo está en la disciplina de no reescribir lo que ya funciona y ya se probó. Si cost_for_run y el CircuitBreaker parecen no encajar perfecto, la solución correcta es una función de ensamblaje nueva en ops/, nunca una edición silenciosa de observability/cost_calculator.py o resilience/tool_circuit_breaker.py.

  3. Pensar que M7 usa un CASE_SET distinto al de M5 para comparar versiones. No lo hace — reusa exactamente el mismo CASE_SET de cinco casos, y la misma run_regression_gate, con un overrides que sustituye el guion del caso puntual que la versión candidata cambiaría. Son dos preguntas reales, con propósitos distintos —correr el CASE_SET sin overrides confirma que el sistema de hoy sigue funcionando; correrlo con overrides confirma que una versión candidata es segura—, pero el mismo fixture responde a las dos. La Lección 5 nombra la diferencia con precisión; confundirlas produce un veredicto que no responde la pregunta que en realidad importaba.

  4. Pensar que "el gate pasó" significa "el agente está listo para producción para siempre". Un PASS de hoy es evidencia sobre el comportamiento de hoy, contra el set de casos de hoy — no una garantía permanente. Cada corrida nueva de este capstone es una confirmación puntual, no un certificado indefinido.

  5. Saltar directo a la Lección 8 sin pasar por 02-07. Los cuatro artefactos finales de la Lección 8 no tienen sentido sin haber visto, por separado, que cada disciplina —observar, medir, gatear, endurecer+versionar— funciona antes de juntarlas en una sola corrida.


Resumen y siguiente paso

  • Este módulo no agrega ninguna disciplina nueva: ensambla, alrededor del mismo agente de Reservo, las cuatro que M2-M7 construyeron y ejecutaron por separado — observar, medir, gatear, endurecer + versionar.
  • Confirmaste el entorno —Python 3.14.0— y que los siete archivos reusados (cuatro de agent-fundamentals, tres de esta guía) importan juntos sin conflicto, con las mismas constantes de siempre: las anclas de get_quote (7500/6000), TOOL_LATENCY_MS, el pricing fijo, y las dos versiones de PROMPT_REGISTRY.
  • El mapa de las ocho lecciones deja claro qué retoma cada una, y dónde aparece la fricción real de integración: la Lección 5, donde dos fixtures de M5 y M7 responden preguntas relacionadas pero distintas.

Siguiente lección: 02 — Ensamblando la capa de operación. Retomamos, uno junto al otro, los siete archivos de M2-M7 y confirmamos que cada pieza sigue funcionando por su cuenta antes de ponerlas a operar juntas sobre un run real.


Recursos adicionales

  1. Anthropic — Tool use (function calling) overview — El protocolo que la capa de operación de este módulo instrumenta, mide y gatea de punta a punta.
  2. Anthropic — Building effective agents — Por qué operar un agente que ya funciona es una disciplina propia, distinta de construirlo.
  3. Python 3.14 — What's New — La versión exacta con la que se ejecuta toda la ingeniería de esta guía.
  4. Python — Modules — Cómo Python resuelve el import entre los once archivos que vas a ensamblar en este directorio.