4 min de lecturaParte 2

Por qué los agentes necesitan un runtime determinista

Los modelos probabilísticos son excelentes para razonar, pero pésimos para ejecutar. Por qué la infraestructura debe hacer cumplir la frontera de ejecución.

J

José Vásquez

Fundador e Ingeniero Principal @ Invariant

#AI Agents#Runtime#Durable Execution#Architecture
Serie de ArtículosArquitectura de Agentes Confiables
Parte 2Por qué los agentes necesitan un runtime determinista

En ingeniería de software hemos pasado cinco décadas construyendo sistemas deterministas: bases de datos relacionales con garantías ACID, compiladores con sistemas de tipos estrictos y orquestadores distribuidos diseñados alrededor de entrega at-least-once e idempotencia.

El auge de los Modelos de Lenguaje Grande introduce el no-determinismo en el núcleo de la aplicación.

El no-determinismo es valioso cuando se trata de comprender lenguaje natural, formular hipótesis y evaluar alternativas abiertas. Pero cuando el no-determinismo se filtra en la ejecución—invocar APIs, gestionar transacciones financieras y mutar estado—el software se vuelve impredecible y riesgoso.

Tesis Principal

Los modelos razonan probabilísticamente. La infraestructura ejecuta determinísticamente. El rol fundamental de un runtime de agentes es hacer cumplir esta frontera.


La fragilidad de los bucles de herramientas sin restricciones

En las arquitecturas de agentes convencionales, el LLM se conecta directamente a la ejecución de herramientas mediante un bucle síncrono:

[Petición Usuario] ──> [Prompt LLM] ──> [Ejecución Directa de Herramienta] ──> [Repetir]

Cuando un LLM ejecuta herramientas de forma directa, surgen tres fallas críticas:

1. Autoridad no validada

El modelo decide tanto qué hacer como cuándo ejecutarlo. Si el modelo alucina un parámetro inválido o invoca una mutación destructiva fuera de orden, el runtime no tiene un motor de políticas para interceptar o rechazar la llamada antes de que cause daños irreversibles.

2. Falta de idempotencia y vulnerabilidad a fallos parciales

¿Qué sucede cuando la herramienta #3 de una secuencia de 5 pasos falla por un timeout de red?

  • ¿El webhook externo llegó a procesarse o no?
  • Si reintentas la llamada al LLM, ¿generará exactamente el mismo payload o mutará ligeramente provocando un cobro duplicado?

Sin primitivas transaccionales, reintentar un bucle de agentes con LLMs es equivalente a jugar a los dados con los efectos secundarios de tu negocio.

3. Incapacidad de suspensión durable para revisión humana

Los sistemas reales requieren aprobaciones humanas para acciones de alto impacto (por ejemplo, transferencias superiores a $10,000 USD). Si tu runtime es un simple bucle while(true) corriendo en un contenedor efímero, no puedes suspender la ejecución durante 48 horas esperando la firma de un ejecutivo sin mantener servidores bloqueados.

La Frontera Probabilística vs. DeterministaInvariant Architecture
PROBABILISTIC REASONING (LLM)Non-Deterministic
  • Intent interpretation & goal formulation
  • Action proposal (structured schema)
  • Reasoning over hydrated session view
  • Should NOT execute side effects directly
  • Should NOT hold persistent state authority
DURABLE CONTROL PLANE (INVARIANT)100% Deterministic
  • Schema & permission boundary validation
  • Transactional Outbox + Idempotent execution
  • Immutable Event Sourced State (PostgreSQL)
  • Deterministic session hydration & crash replay
  • Human-in-the-loop durable suspensions
Authority & Execution Boundary
Figura 1: Desacoplando el razonamiento del modelo de la ejecución determinista en infraestructura.

Requisitos arquitectónicos de un runtime para agentes

Un runtime de agentes listo para producción requiere cuatro pilares estructurales:

1. La Frontera Validada (Propuestas de Acción)

El modelo nunca debe invocar efectos secundarios directamente. En su lugar, emite una Propuesta de Acción. El runtime intercepta esta propuesta, la valida contra esquemas tipados y políticas organizacionales, y decide si procede, requiere intervención humana o se rechaza.

2. Patrón Transactional Outbox

El estado de ejecución, los eventos durables y la intención del efecto se confirman atómicamente antes de despachar la capability. El dispatcher de la Beta actual corre en proceso; un proceso nuevo no puede reclamar comandos pendientes ni adjuntarse a la ejecución mediante una API portable. Se requieren idempotencia del proveedor y recuperación propiedad de la aplicación ante caídas.

3. Reproducción Determinista e Hidratación

El historial de eventos puede reconstruir la verdad confirmada sin repetir llamadas del modelo que ya produjeron eventos durables (Ejecución Durable). Reconstruir no adjunta por sí solo un host nuevo a la ejecución ni vuelve a despachar comandos pendientes.

4. Suspensiones Durables

El runtime puede persistir una frontera .wait() y aceptar la entrada correspondiente mediante la Session viva. El attach portable cross-process y la programación automática de timers no forman parte de la Beta actual.

| Dimensión | Enfoque Tradicional de Prompts / Bucles | Arquitectura de Control Plane de Invariant | | :--- | :--- | :--- | | Llamada a Herramientas | Invocación directa desde el bucle LLM | Propuesta de Acción → Frontera Validada → Transactional Outbox | | Recuperación ante Caídas | Pérdida de progreso o reintento de todo el prompt | Primitivas de replay durable; continuación cross-process a cargo de la aplicación en Beta | | Human-in-the-Loop | Bucles en memoria bloqueantes o tablas ad-hoc | Frontera de espera persistida; entrada mediante Session viva en Beta | | Auditabilidad | Logs de texto no estructurados | Flujo de eventos inmutable con trazabilidad completa |


Implementación con Invariant

Con Invariant, escribes flujos y agentes en TypeScript que hacen cumplir esta frontera de forma nativa:

import { invariant } from '@invariant-tech/sdk';
import { sqlite } from '@invariant-tech/sqlite';
import { z } from 'zod';

const app = invariant({ storage: sqlite('./data/transfers.db') });

// 1. Definir un workflow durable con nodos explícitos de espera y capacidad
export const flujoNomina = app.workflow('transfer-funds', {
  description: 'Ejecuta transferencias bancarias de nómina con revisión ejecutiva si supera $10,000',
  inputSchema: z.object({ transferId: z.string(), amount: z.number() }),
})
  .step('check-amount', ({ input }) => ({
    requiresApproval: input.amount > 10_000,
  }))
  .branch('approval-branch', ({ state }) => (state.requiresApproval ? 'REQUIRE_REVIEW' : 'AUTO_EXECUTE'), {
    REQUIRE_REVIEW: app.fragment('review').wait('await-executive-approval', {
      schema: z.object({ approved: z.boolean(), approvedBy: z.string() }),
      presentation: { prompt: 'La transferencia supera $10,000. Se requiere aprobación.' },
    }),
    AUTO_EXECUTE: app.fragment('pass').step('bypass', () => ({ approved: true })),
  })
  .capability('execute-transfer', {
    idempotencyKey: 'transfer:{{runId}}',
    handler: async ({ input }) => {
      return await paymentGateway.charge(input);
    },
  });

// 2. El agente propone acciones; el runtime valida revisión y esquema antes de ejecutar
export const agenteFinanzas = app.agent('finance-assistant', {
  workflows: [flujoNomina],
});

Conclusión

No necesitamos que los modelos se vuelvan deterministas. Necesitamos que nuestra infraestructura deje de pretender que lo son.

Al trasladar la ejecución, la gestión de estado y la autoridad fuera del prompt y hacia un runtime durable, obtenemos toda la capacidad de razonamiento de los LLMs con la confiabilidad de la infraestructura empresarial.

En la Parte 3, analizamos por qué los frameworks basados en prompts no son suficientes: Los frameworks de agentes no bastan para ejecución en producción.

J

José Vásquez

Fundador e Ingeniero Principal @ Invariant

Construyendo el motor de ejecución durable para agentes de IA en TypeScript. Mantén el razonamiento probabilístico, haz la ejecución predecible.