datos, agentes

El Substrato que los Agentes necesitan: de la Fuente a un Dato Consultable

El Substrato que los Agentes necesitan: de la Fuente a un Dato Consultable

El Substrato que los Agentes necesitan: de la Fuente a un Dato Consultable

Joaquin Diez

Los agentes de IA tienen una restricción operacional que los humanos no comparten: necesitan que el mundo no cambie bajo sus pies durante una conversación.

Un humano puede mirar un dashboard, refrescarlo, ver que cambió una cifra, y ajustar su lectura. Un agente que en un mismo turno lee una cifra, la usa para calcular un ratio, y después encuentra que la base cambió, produce un resultado internamente contradictorio y no puede reconciliarlo.

Por eso el primer problema al construir una plataforma donde los agentes son la unidad de ejecución no es la capa semántica. Es el substrato. Si el substrato es ruidoso, la semántica más elegante del mundo no salva a nadie.

Este es el segundo artículo de la serie. En el primero presentamos la tesis; acá entramos en cómo se construye la base.


La trampa de "basta cargar los datos"

La arquitectura analítica moderna tiene un vicio de origen: asume que los datos "cargados" son datos "usables". En un stack tradicional:

  1. Un connector trae filas de una fuente externa (Stripe, Postgres, S3).

  2. Las filas llegan a un staging schema en el warehouse.

  3. Algún dbt job las transforma en tablas analíticas.

  4. Un BI tool las lee.

Cuatro pasos, cuatro equipos, cuatro fuentes potenciales de inconsistencia. Si un analista abre Looker mientras el job de dbt está corriendo, puede ver un mundo incoherente. En la era de los dashboards eso se tolera con una frase mágica: "refrescá en 5 minutos y fijate". En la era de los agentes, no.

Un agente que consulta un mundo incoherente construye argumentos incoherentes. Y la cadena de razonamiento del agente tiene la propiedad desagradable de que los errores no se quedan quietos — se amplifican. Una cifra errónea en el turno 1 se vuelve una recomendación errónea en el turno 3.

La solución no es hacer los pipelines más rápidos. La solución es exponer un substrato que por diseño no puede ser incoherente.


El pipeline de Calliope: cinco fases explícitas

En Calliope, el pipeline de ingestión tiene cinco fases con nombres propios. No es detalle de implementación; es contrato con el agente.


Capturar Estructurar Cargar Generar ontología Generar ejemplos
Capturar Estructurar Cargar Generar ontología Generar ejemplos
Capturar Estructurar Cargar Generar ontología Generar ejemplos


Vamos una por una.


Fase 1 — Capturar datos crudos

Un conector (Airbyte, integraciones nativas, S3) trae datos crudos desde la fuente y los escribe en un storage inmutable. No hay transformación. No hay casting de tipos. No hay intento de interpretar. Si la fuente emite basura, el storage tiene la basura idéntica.

Por qué importa: el raw data es el fallback auditable. Si algún día un agente genera una respuesta rara y el equipo pregunta "¿de dónde salió esto?", el raw data es la verdad de origen contra la que se puede comparar todo el resto.


Fase 2 — Estructurar en formato analítico

Los datos crudos se convierten a Parquet columnar. Se infieren tipos, se normalizan nombres, se manejan deduplicaciones según la estrategia configurada (in-place dedup o full reload). El output es un set de archivos Parquet particionados.

Por qué importa: Parquet es el formato que mejor balancea rendimiento analítico + portabilidad. Si algún día el cliente necesita exportar el substrato a su warehouse, los Parquet se mueven tal cual. Si Calliope se cae, los Parquet siguen siendo leíbles por cualquier herramienta que hable Parquet (Spark, DuckDB, pandas, lo que sea). Esto es importante para una categoría nueva: los clientes no van a apostar por una plataforma que los encierra en un formato propietario.


Fase 3 — Cargar al motor analítico

Los Parquet se cargan en una base DuckDB embebida que funciona como motor analítico. DuckDB fue una decisión consciente: queríamos una base columnar rápida, sin servidor, que corre in-process, con el estado guardado en archivos inmutables baratos de congelar, y que no requiere un cluster para arrancar.

Dos propiedades de este motor son esenciales para el framing agent-first:

  1. Barato de congelar. El estado del motor vive en archivos inmutables en disco. Duplicarlo cuesta I/O, no compute. Congelar el estado del mundo es una copia de archivo.

  2. Lecturas aisladas. El agente puede abrir una sesión contra ese estado congelado y leerlo durante toda la conversación sin que otro proceso le mueva el suelo. Es, literalmente, una lectura contra un mundo congelado.


Fase 4 — Generar la ontología

Acá es donde el pipeline deja de parecerse a un pipeline tradicional. En la mayoría de los stacks, "la capa semántica" es un proyecto paralelo que alguien mantiene a mano en otro repositorio. En Calliope, la capa semántica es parte del pipeline de ingestión.

Cada vez que los datos cambian materialmente — nuevas tablas, columnas nuevas, esquemas modificados — el pipeline le pasa el delta a un LLM que regenera descripciones semánticas para las tablas y columnas nuevas o modificadas. Y acá está la decisión crítica: las ediciones humanas se preservan. Si David, el steward, escribió a mano que customer_revenue excluye devoluciones, la regeneración no sobrescribe eso. La regeneración se limita a lo que no tenía descripción humana.

Eso resuelve el problema de mantenimiento que hunde la mayoría de los semantic layers: nadie quiere pasarse dos horas por semana escribiendo descriptions a mano, y nadie quiere que un cron job se las sobrescriba cuando se distrajeron. La ontología se mantiene sola donde el LLM es suficiente, y se queda quieta donde el humano sabe más.

El artículo siguiente de esta serie es enteramente sobre qué hace la ontología dentro del framing agent-first. Por ahora basta con decir: es el tool schema que el agente va a leer antes de cada query.


Fase 5 — Generar los ejemplos

La última fase es la más agente-céntrica de todas. Calliope toma pares pregunta→SQL que fueron marcados como correctos (ejemplos validados por humanos previamente) o que acaban de ser confirmados en la conversación, y los hace parte del contexto que el agente carga en su próxima invocación.

Esto es memoria procedural. El agente no empieza cada conversación desde cero; empieza con una librería de ejemplos que saben cómo resolver las preguntas típicas de la organización, en los términos exactos que la organización usa.

Y este paso es lo que convierte al pipeline en un loop de aprendizaje continuo. Cada corrección humana se vuelve ejemplo. Cada ejemplo mejora al siguiente turno. El pipeline no es un proceso batch que termina: es un proceso que hace al agente mejor cada vez que corre.


Un mundo congelado por conversación

Por debajo del pipeline, cada conversación corre contra una instancia de DuckDB que no se mueve mientras el agente piensa. No es una conexión viva a un warehouse que puede estar rebuildeándose. No es un dashboard que pudo haber refrescado entre turnos. Es una vista in-process, de solo lectura, que se queda quieta hasta que termina la conversación.

Esa propiedad — el mundo no se mueve a mitad de conversación — es lo que mantiene internamente consistente al razonamiento multi-turno. Un ratio calculado en el turno 1 sigue siendo válido en el turno 3. Un filtro aplicado al principio sigue significando lo mismo cinco preguntas después. Suena menor; es la diferencia entre un agente que puede sostener un argumento y uno que se contradice sin querer.

Esto es lo que funciona hoy.


Qué habilita este substrato

Elegir un motor cuyo estado vive en archivos inmutables no fue solo por la consistencia intra-conversación. Como el estado del mundo se guarda en archivos baratos de copiar y retener, el substrato queda listo para un conjunto de capacidades que estamos construyendo:

  • Reproducibilidad point-in-time. Re-ejecutar una pregunta contra el estado exacto que el agente vio el mes pasado y obtener la respuesta idéntica.

  • Auditoría histórica. Responder "¿qué datos vio el agente cuando dijo X en junio?" con un puntero verificable.

  • Rollback semántico. Si una regeneración de ontología o un cambio de reglas rompe el comportamiento, revertir pasa a ser una operación a nivel de archivo en vez de una migración.

No son features injertadas a la arquitectura después — el substrato está hecho para ellas. Pero hoy, la única garantía que damos es la que abrimos arriba: durante una conversación, el mundo se queda quieto.


Lo que hicimos diferente a propósito

Hay tres decisiones de diseño en el substrato que vale la pena hacer explícitas, porque son las que se rompen primero si uno copia la arquitectura sin pensar:

  1. DuckDB embebido en vez de un warehouse managed. Aceptamos que esto nos obliga a federar para cargas muy grandes. Lo aceptamos porque los snapshots baratos y las lecturas in-process son lo que hace posible el framing agent-first a un costo operacional razonable. Si algún día un cliente necesita escalar más allá de lo que DuckDB sirve, federamos hacia el warehouse del cliente sin cambiar la interfaz del agente.

  2. Parquet como formato pivot. No usamos Iceberg ni Delta Lake. No los descartamos a futuro, pero al inicio quisimos una dependencia más simple y una salida de escape clara — si un cliente se quiere ir, los Parquet son suyos.

  3. La capa semántica es parte del pipeline, no un job paralelo. Esto es contracultural en el mundo dbt. Pero en el framing agent-first, la semántica es un artefacto del pipeline, no un proyecto aparte.

  4. Agnóstico a modelo y a cloud. DuckDB es embebido. Parquet es un formato abierto. La ontología se genera con cualquier LLM. Nada en el substrato te ata a un hyperscaler ni a un proveedor de modelos. Si mañana un modelo nuevo genera mejores descripciones semánticas o un cloud ofrece mejores precios, simplemente lo cambiás. En un mercado que se mueve cada seis meses, esa independencia es una decisión de arquitectura, no un detalle.


¿Y si lo vemos juntos?

El substrato es la base. Lo interesante empieza cuando el agente lo usa. Solicita una demo y te lo mostramos sobre datos reales, en vivo.

Los agentes de IA tienen una restricción operacional que los humanos no comparten: necesitan que el mundo no cambie bajo sus pies durante una conversación.

Un humano puede mirar un dashboard, refrescarlo, ver que cambió una cifra, y ajustar su lectura. Un agente que en un mismo turno lee una cifra, la usa para calcular un ratio, y después encuentra que la base cambió, produce un resultado internamente contradictorio y no puede reconciliarlo.

Por eso el primer problema al construir una plataforma donde los agentes son la unidad de ejecución no es la capa semántica. Es el substrato. Si el substrato es ruidoso, la semántica más elegante del mundo no salva a nadie.

Este es el segundo artículo de la serie. En el primero presentamos la tesis; acá entramos en cómo se construye la base.


La trampa de "basta cargar los datos"

La arquitectura analítica moderna tiene un vicio de origen: asume que los datos "cargados" son datos "usables". En un stack tradicional:

  1. Un connector trae filas de una fuente externa (Stripe, Postgres, S3).

  2. Las filas llegan a un staging schema en el warehouse.

  3. Algún dbt job las transforma en tablas analíticas.

  4. Un BI tool las lee.

Cuatro pasos, cuatro equipos, cuatro fuentes potenciales de inconsistencia. Si un analista abre Looker mientras el job de dbt está corriendo, puede ver un mundo incoherente. En la era de los dashboards eso se tolera con una frase mágica: "refrescá en 5 minutos y fijate". En la era de los agentes, no.

Un agente que consulta un mundo incoherente construye argumentos incoherentes. Y la cadena de razonamiento del agente tiene la propiedad desagradable de que los errores no se quedan quietos — se amplifican. Una cifra errónea en el turno 1 se vuelve una recomendación errónea en el turno 3.

La solución no es hacer los pipelines más rápidos. La solución es exponer un substrato que por diseño no puede ser incoherente.


El pipeline de Calliope: cinco fases explícitas

En Calliope, el pipeline de ingestión tiene cinco fases con nombres propios. No es detalle de implementación; es contrato con el agente.


Capturar Estructurar Cargar Generar ontología Generar ejemplos


Vamos una por una.


Fase 1 — Capturar datos crudos

Un conector (Airbyte, integraciones nativas, S3) trae datos crudos desde la fuente y los escribe en un storage inmutable. No hay transformación. No hay casting de tipos. No hay intento de interpretar. Si la fuente emite basura, el storage tiene la basura idéntica.

Por qué importa: el raw data es el fallback auditable. Si algún día un agente genera una respuesta rara y el equipo pregunta "¿de dónde salió esto?", el raw data es la verdad de origen contra la que se puede comparar todo el resto.


Fase 2 — Estructurar en formato analítico

Los datos crudos se convierten a Parquet columnar. Se infieren tipos, se normalizan nombres, se manejan deduplicaciones según la estrategia configurada (in-place dedup o full reload). El output es un set de archivos Parquet particionados.

Por qué importa: Parquet es el formato que mejor balancea rendimiento analítico + portabilidad. Si algún día el cliente necesita exportar el substrato a su warehouse, los Parquet se mueven tal cual. Si Calliope se cae, los Parquet siguen siendo leíbles por cualquier herramienta que hable Parquet (Spark, DuckDB, pandas, lo que sea). Esto es importante para una categoría nueva: los clientes no van a apostar por una plataforma que los encierra en un formato propietario.


Fase 3 — Cargar al motor analítico

Los Parquet se cargan en una base DuckDB embebida que funciona como motor analítico. DuckDB fue una decisión consciente: queríamos una base columnar rápida, sin servidor, que corre in-process, con el estado guardado en archivos inmutables baratos de congelar, y que no requiere un cluster para arrancar.

Dos propiedades de este motor son esenciales para el framing agent-first:

  1. Barato de congelar. El estado del motor vive en archivos inmutables en disco. Duplicarlo cuesta I/O, no compute. Congelar el estado del mundo es una copia de archivo.

  2. Lecturas aisladas. El agente puede abrir una sesión contra ese estado congelado y leerlo durante toda la conversación sin que otro proceso le mueva el suelo. Es, literalmente, una lectura contra un mundo congelado.


Fase 4 — Generar la ontología

Acá es donde el pipeline deja de parecerse a un pipeline tradicional. En la mayoría de los stacks, "la capa semántica" es un proyecto paralelo que alguien mantiene a mano en otro repositorio. En Calliope, la capa semántica es parte del pipeline de ingestión.

Cada vez que los datos cambian materialmente — nuevas tablas, columnas nuevas, esquemas modificados — el pipeline le pasa el delta a un LLM que regenera descripciones semánticas para las tablas y columnas nuevas o modificadas. Y acá está la decisión crítica: las ediciones humanas se preservan. Si David, el steward, escribió a mano que customer_revenue excluye devoluciones, la regeneración no sobrescribe eso. La regeneración se limita a lo que no tenía descripción humana.

Eso resuelve el problema de mantenimiento que hunde la mayoría de los semantic layers: nadie quiere pasarse dos horas por semana escribiendo descriptions a mano, y nadie quiere que un cron job se las sobrescriba cuando se distrajeron. La ontología se mantiene sola donde el LLM es suficiente, y se queda quieta donde el humano sabe más.

El artículo siguiente de esta serie es enteramente sobre qué hace la ontología dentro del framing agent-first. Por ahora basta con decir: es el tool schema que el agente va a leer antes de cada query.


Fase 5 — Generar los ejemplos

La última fase es la más agente-céntrica de todas. Calliope toma pares pregunta→SQL que fueron marcados como correctos (ejemplos validados por humanos previamente) o que acaban de ser confirmados en la conversación, y los hace parte del contexto que el agente carga en su próxima invocación.

Esto es memoria procedural. El agente no empieza cada conversación desde cero; empieza con una librería de ejemplos que saben cómo resolver las preguntas típicas de la organización, en los términos exactos que la organización usa.

Y este paso es lo que convierte al pipeline en un loop de aprendizaje continuo. Cada corrección humana se vuelve ejemplo. Cada ejemplo mejora al siguiente turno. El pipeline no es un proceso batch que termina: es un proceso que hace al agente mejor cada vez que corre.


Un mundo congelado por conversación

Por debajo del pipeline, cada conversación corre contra una instancia de DuckDB que no se mueve mientras el agente piensa. No es una conexión viva a un warehouse que puede estar rebuildeándose. No es un dashboard que pudo haber refrescado entre turnos. Es una vista in-process, de solo lectura, que se queda quieta hasta que termina la conversación.

Esa propiedad — el mundo no se mueve a mitad de conversación — es lo que mantiene internamente consistente al razonamiento multi-turno. Un ratio calculado en el turno 1 sigue siendo válido en el turno 3. Un filtro aplicado al principio sigue significando lo mismo cinco preguntas después. Suena menor; es la diferencia entre un agente que puede sostener un argumento y uno que se contradice sin querer.

Esto es lo que funciona hoy.


Qué habilita este substrato

Elegir un motor cuyo estado vive en archivos inmutables no fue solo por la consistencia intra-conversación. Como el estado del mundo se guarda en archivos baratos de copiar y retener, el substrato queda listo para un conjunto de capacidades que estamos construyendo:

  • Reproducibilidad point-in-time. Re-ejecutar una pregunta contra el estado exacto que el agente vio el mes pasado y obtener la respuesta idéntica.

  • Auditoría histórica. Responder "¿qué datos vio el agente cuando dijo X en junio?" con un puntero verificable.

  • Rollback semántico. Si una regeneración de ontología o un cambio de reglas rompe el comportamiento, revertir pasa a ser una operación a nivel de archivo en vez de una migración.

No son features injertadas a la arquitectura después — el substrato está hecho para ellas. Pero hoy, la única garantía que damos es la que abrimos arriba: durante una conversación, el mundo se queda quieto.


Lo que hicimos diferente a propósito

Hay tres decisiones de diseño en el substrato que vale la pena hacer explícitas, porque son las que se rompen primero si uno copia la arquitectura sin pensar:

  1. DuckDB embebido en vez de un warehouse managed. Aceptamos que esto nos obliga a federar para cargas muy grandes. Lo aceptamos porque los snapshots baratos y las lecturas in-process son lo que hace posible el framing agent-first a un costo operacional razonable. Si algún día un cliente necesita escalar más allá de lo que DuckDB sirve, federamos hacia el warehouse del cliente sin cambiar la interfaz del agente.

  2. Parquet como formato pivot. No usamos Iceberg ni Delta Lake. No los descartamos a futuro, pero al inicio quisimos una dependencia más simple y una salida de escape clara — si un cliente se quiere ir, los Parquet son suyos.

  3. La capa semántica es parte del pipeline, no un job paralelo. Esto es contracultural en el mundo dbt. Pero en el framing agent-first, la semántica es un artefacto del pipeline, no un proyecto aparte.

  4. Agnóstico a modelo y a cloud. DuckDB es embebido. Parquet es un formato abierto. La ontología se genera con cualquier LLM. Nada en el substrato te ata a un hyperscaler ni a un proveedor de modelos. Si mañana un modelo nuevo genera mejores descripciones semánticas o un cloud ofrece mejores precios, simplemente lo cambiás. En un mercado que se mueve cada seis meses, esa independencia es una decisión de arquitectura, no un detalle.


¿Y si lo vemos juntos?

El substrato es la base. Lo interesante empieza cuando el agente lo usa. Solicita una demo y te lo mostramos sobre datos reales, en vivo.

Tu Analista de Negocio con IA

Toma decisiones con los insights correctos

Tu Analista de Negocio con IA

Toma decisiones con los insights correctos

Tu Analista de Negocio con IA

Toma decisiones con los insights correctos