AV
angelvelasquez.dev
Applied AI & Automation 29 de septiembre de 2026 • 8 min de lectura

Agentes de IA Deterministas: Arquitectura de Tool Calling sin Alucinaciones en Producción

Patrones de diseño en producción para orquestar LLMs (Gemini, Claude, GPT) mediante esquemas JSON estrictos, ejecución determinista de herramientas y reversión transaccional.

#Applied AI #Tool Calling #Gemini 3.7 #Claude #LLMs #JSON Schema #Zod #Webhooks

La mayoría de los fracasos en implementaciones comerciales con agentes de IA se originan en un error conceptual: asumir que los Modelos de Lenguaje (LLMs) son cerebros autónomos capaces de tomar decisiones críticas mediante prosa conversacional.

Cuando le confías a un LLM la toma de decisiones empresariales mediante instrucciones en lenguaje natural, el resultado es predecible: alucinaciones, olvido de restricciones bajo saturación de contexto y discrepancias sutiles en los datos que terminan corrompiendo tus APIs.

En software de producción, los LLMs deben tratarse como enrutadores semánticos probabilistas. Su función se limita a interpretar la intención del usuario y mapearla hacia argumentos fuertemente tipados; la ejecución y la persistencia deben gobernarse por código 100% determinista.

Te comparto la arquitectura de producción que utilizo para erradicar alucinaciones en agentes de IA.


1. El Principio Fundamental: El LLM como Enrutador Semántico

Entrada del Usuario / Webhook
        │
        ▼
┌────────────────────────┐
│  LLM (Router Semántico)│ ──> Emite llamada a herramienta + argumentos tipados
└────────────────────────┘
        │
        ▼ (Interceptado ANTES de ejecutar)
┌────────────────────────┐
│  Validador Zod/Schema  │ ──> Rechaza tipos incorrectos antes de tocar backend
└────────────────────────┘
        │
        ▼ (Si es válido)
┌────────────────────────┐
│  Motor Determinista    │ ──> Ejecuta APIs transaccionales con rollbacks
└────────────────────────┘

El modelo nunca escribe directamente en tu base de datos ni despacha peticiones HTTP externas por su cuenta. Solo puede seleccionar una función predefinida y rellenar un esquema JSON estructurado.


2. Definición Estricta de Esquemas con Zod y JSON Schema

Cada herramienta expuesta al modelo debe declarar un esquema de entrada cerrado y tipado:

import { z } from 'zod';

export const ProcessInvoiceToolSchema = z.object({
  invoiceNumber: z.string().regex(/^INV-\d{4}-\d{5}$/, 'Formato de factura inválido'),
  vendorTaxId: z.string().min(8).max(15),
  totalAmountCents: z.number().int().positive(),
  currency: z.enum(['USD', 'EUR', 'PEN']),
  lineItems: z.array(
    z.object({
      description: z.string().min(3),
      unitPriceCents: z.number().int().positive(),
      quantity: z.number().int().positive(),
    })
  ).nonempty(),
  action: z.enum(['APPROVE', 'FLAG_FOR_AUDIT', 'REJECT']),
});

export type ProcessInvoiceInput = z.infer<typeof ProcessInvoiceToolSchema>;

Este esquema se transforma en la definición formal consumida por motores como Gemini 3.7 Flash o Claude:

export const ProcessInvoiceToolDefinition = {
  name: 'process_invoice',
  description: 'Valida y concilia una factura de proveedor frente a órdenes de compra del ERP.',
  parameters: zodToJsonSchema(ProcessInvoiceToolSchema),
};

3. Intercepción en Tiempo de Ejecución y Autocorrección

Si el modelo entrega un payload incompleto o viola una restricción de validación, no interrumpas el flujo abruptamente. Intercepta el fallo en la frontera de ejecución y reenvía el detalle exacto al modelo para una corrección en un único turno adicional:

export async function executeToolWithGuardrails(
  toolName: string,
  rawArgs: unknown,
  executor: (args: ProcessInvoiceInput) => Promise<ToolResult>
): Promise<ToolResult> {
  const parseResult = ProcessInvoiceToolSchema.safeParse(rawArgs);

  if (!parseResult.success) {
    const errorDetails = parseResult.error.issues
      .map(i => `${i.path.join('.')}: ${i.message}`)
      .join('; ');

    return {
      status: 'VALIDATION_FAILED',
      errorMessage: `Validación rechazada: ${errorDetails}. Reextrae los datos cumpliendo estrictamente los tipos requeridos.`,
    };
  }

  try {
    return await executor(parseResult.data);
  } catch (error) {
    return {
      status: 'EXECUTION_ERROR',
      errorMessage: error instanceof Error ? error.message : 'Fallo de ejecución desconocido',
    };
  }
}

4. Idempotencia y Transacciones Compensatorias

En flujos automatizados con agentes, las caídas de red o reintentos automáticos son habituales. Cada herramienta ejecutada debe ser estrictamente idempotente:

  1. Claves de Idempotencia: Genera un hash SHA-256 a partir del ID de sesión, el nombre de la herramienta y los datos parseados:
    const idempotencyKey = crypto
      .createHash('sha256')
      .update(`${sessionId}:${toolName}:${JSON.stringify(parseResult.data)}`)
      .digest('hex');
  2. Two-Phase Commit: Registra una entrada de auditoría con estado PENDING antes de contactar sistemas externos (Stripe, ERP, pasarelas de correo).
  3. Acciones de Compensación: Si una llamada posterior falla, ejecuta de forma atómica la reversión correspondiente (anular el borrador creado o cancelar la reserva).

5. Caso de Producción: Motor Autónomo de Agentes de IA

Implementé esta arquitectura en el Motor Autónomo de Agentes de IA, orquestando flujos empresariales integrados con ERPs, webhooks y túneles de Cloudflare:

  • 99.8% de precisión en esquemas: El parseo estricto con Zod eliminó escrituras corruptas en bases de datos.
  • Cero incidentes por alucinaciones: Dado que las operaciones externas son deterministas y tipadas, el modelo no tiene capacidad de inventar registros ni alterar saldos.
  • Reducción del 80% en tiempos de gestión: Las conciliaciones de documentos y altas en el sistema se ejecutan en menos de 3 segundos sin intervención manual.

Conclusión Pragmática

No le pidas a un LLM que opere tu lógica de negocio; utilízalo para estructurar información en esquemas estrictos y deja que el software determinista se encargue del resto.