El agente elige

La tabla que prometía demasiado

La semana pasada prometí volver a r, y a quién elige cuando el que elige no es una persona. Hace un par de semanas, al presentar esta serie, dibujé un mapa con una fila esperando esta historia: “el agente que elige la tabla por su nombre”. Acá está: un agente que construyó un modelo entero sobre la tabla equivocada, por el nombre de la tabla.

Pasó en un conglomerado empresarial de Centroamérica (comercio y distribución): un agente construyó un modelo de inventarios sobre la tabla equivocada. Nadie se lo pidió. Se lo pidió el nombre.

El agente era Claude, Opus 5.5, dirigido por uno de los consultores junior de Primus. Lo digo de entrada por dos razones. Es cierto, y este post también se está escribiendo con Claude. Sería raro esconder una cosa y no la otra.

El pedido era un modelo de inventarios: existencias, costo y el kardex detrás de los dos, cada movimiento que suma o resta una unidad o su costo de la bodega. En el sistema fuente hay una tabla que acá voy a llamar inventory_movements: movimientos de inventario. Leé el nombre otra vez. ¿Dónde irías a buscar el kardex? El agente fue ahí también. Construyó plata sobre esa tabla, después oro, después el modelo semántico, e hizo un trabajo prolijo: nombres legibles, relaciones sensatas, medidas que funcionaban.

Después los números llegaron al modelo semántico, y el mismo junior vio que no tenían sentido para la operación. Hay que reconocerlo: el agente no lo detectó. La persona sí.

Esto es lo que nadie sabía todavía. inventory_movements no tiene todos los movimientos de inventario, como pasa en la mayoría de los ERP. Tiene los que ningún otro documento explica: los movimientos físicos dentro de la bodega. Una venta también mueve inventario. Una compra también. Una revaluación mueve el valor sin mover una sola unidad. El kardex real es un UNION ALL de seis tablas (ventas, compras, revaluaciones y movimientos de inventario entre ellas), y no vive en ninguna tabla. Vive en código. Además, cada una de esas tablas habla su propio dialecto: en ventas el costo está en total_cost, que cumple el papel que total_amount cumple en compras, y las revaluaciones ni siquiera usan cantidad.

En su defensa, a nadie se le ocurrió comparar la cantidad de transacciones de venta contra la cantidad de movimientos. Ventas ni siquiera estaba en plata. La evidencia apareció en bronce, donde las líneas de factura superaban por mucho a los movimientos. La verdad estaba en la única capa que nadie había promovido.

El junior y Claude armaron un plan de remediación: reconstruir el kardex en oro como un UNION ALL. Tenía parte de razón. El consultor senior del proyecto no estaba seguro, y el tema terminó en mi escritorio.

Fijate qué tipo de error es este, porque no es el que esta serie viene contando. inventory_movements no es ROT. Está viva, carga todos los días, y cada fila es correcta. Su único problema es un nombre que promete más de lo que la tabla tiene. Y la respuesta correcta, el kardex completo, ni siquiera era una tabla. No tenía nombre. La vez pasada cerré diciendo que nadie dibujó el mapa. Esta vez la tienda correcta ni siquiera estaba en el mapa, y una tienda que no está en el mapa ni siquiera es una de las opciones. Nadie entra, ni una persona ni un agente.

Una cosa más, que cobro después: durante la primera hora, yo pensé que los equivocados eran el junior y Claude.

Lo que no te conté del mapa

La vez pasada te conté de los puntos rojos y azules en Guadalajara. Dejé una pieza afuera, porque le toca acá.

Un área de influencia atrae clientes desde algún lugar, y en México ese lugar tenía nombre: la AGEB. El INEGI, el instituto nacional de estadística, divide las ciudades en Áreas Geoestadísticas Básicas, unidades de hasta unas cuantas decenas de manzanas cada una, y las publica con un detalle sorprendente: el polígono, más la población y las características de las viviendas que tiene adentro. Parte de mis dos semanas se fue en leer esos shapefiles, cargarlos en la beta de SQL Server 2008 y dejar que los nuevos tipos espaciales calcularan centroides, áreas y distancias. Nuestros clientes no venían de puntos en un mapa. Venían de AGEBs.

Eso importa por la fórmula. Newton, la fórmula que usé la vez pasada, solo tiene una masa que tira de otra. En 1963 David Huff, un geógrafo, escribió lo que al comercio le faltaba: un cliente que elige entre tiendas. Convirtió la atracción en probabilidad: no “este cliente va a esa tienda” sino “este cliente va a esa tienda tantas veces”. La escribe así:

P(i→j) = (Aⱼ / Dᵢⱼ^β) / Σₖ (Aₖ / Dᵢₖ^β)

j es una tienda. A es qué tan atractiva es. D es la distancia desde el origen del cliente, i, hasta la tienda (la r de la vez pasada, con otra letra), y β dice qué tan rápido se apaga la atracción con esa distancia. El denominador suma todas las tiendas a las que ese cliente podría llegar. Lo que sale no es un veredicto, es una proporción: de la gente que vive en i, cuántos terminan en j.

La letra que quiero que mirés es i. Es el origen, y en nuestro modelo el origen era la AGEB: un centroide desde donde medir la distancia, y una unidad censal que te decía quién vivía ahí. Con eso, la pregunta cambia. Deja de ser “¿qué tan atractiva es esta sucursal?” y pasa a ser “¿qué tan atractiva es esta sucursal para la gente que vive acá?”. Una casa de empeño no significa lo mismo en todos los barrios.

(Me estoy tomando una licencia, y prefiero decirlo. En la fórmula de Huff, A es de la tienda, la misma para todos. Dejar que dependa de quién mira es una licencia mía, no de Huff.)

En datos, el origen es una comunidad de consumo: gente que comparte un vocabulario, unas habilidades y un propósito. Muchas veces es un departamento, no siempre. Mi lista de lo que atrae a un usuario hacia un modelo arrancaba con “nombres en lenguaje de negocio”. Bien. ¿De qué negocio? Para la bodega, “movimientos de inventario” son cajas que se mueven entre ubicaciones. Para contabilidad, es el kardex. Mismo nombre, dos comunidades, dos significados, y los dos son correctos.

La lección: lo atractivo no es una propiedad de la tabla. Es una propiedad de la tabla y de quien la mira.

Y eso deja la pregunta de fondo de este post. ¿Qué pasa cuando el que mira no tiene ningún perfil?

Cada copia es una tienda nueva

Antes de llegar ahí, una cosa más que me enseñó el mapa en 2008: el canibalismo.

Monte de Piedad quería 80 sucursales nuevas, y la primera tentación con una lista así es ponerlas donde ya te va bien. La fórmula castiga eso. Abrí una sucursal al lado de una propia y el denominador crece para cada cliente de la zona. La sucursal nueva le quita participación a la competencia, sí, pero también a tu propia sucursal de la otra cuadra. Podés perder clientes contra vos mismo. Y en la fórmula, vale para cualquier tienda: una nueva no tiene que ganarle a la mejor para hacerle daño. Solo tiene que existir y verse aceptable.

Ahora cambiá sucursales por tablas. Pedís las ventas del último trimestre y responden cuatro candidatas al nombre: sales, la tabla certificada en oro; sales_final_v2, la copia de un analista, congelada en marzo; fact_sales, del warehouse viejo, que dejó de cargar después de la migración; y sales_bkp_2023, un snapshot completo, la más pesada de las cuatro. Todas están en el denominador. Cada una se lleva un pedazo de la probabilidad que era de sales.

En el post anterior dije que un grupo de copias suma peso sin sumar atracción. Esta es la otra mitad: compite por la atracción que la tabla buena ya tenía. Y cómo compite depende de quién elige.

Una persona que conoce ese negocio no ve cuatro tablas. Ve una tabla y tres copias. “Esas son las viejas.” Primero elige entre la de verdad y las copias, y solo después, si acaso, entre las copias. Agregar una cuarta copia casi no le mueve las probabilidades. La fórmula no sabe hacer eso. Para Huff cada alternativa compite por su cuenta, y una cuarta copia le quita su parte a todas, siempre.

(Los economistas lo conocen como el problema del bus rojo y el bus azul: agregá un bus azul idéntico al rojo y el modelo cree que inventaste una nueva forma de viajar. El arreglo, de los años setenta, es agrupar las alternativas parecidas en nidos y elegir primero entre nidos, el nested logit, que es exactamente lo que hace sin pensarlo la persona con contexto.)

Entonces, para el agente, cada copia cuyo nombre no la delata es una tienda nueva. Para la persona, cada copia es un estante más en la misma tienda de siempre.

O sea que Huff, escrito en 1963 para describir compradores, no describe muy bien al humano que conoce los datos. Describe al agente frente a copias con buenos nombres.

Un origen sin perfil

Volvé a la fórmula y poné un agente en el lugar del cliente.

Empezá por D.

Madrid y Barcelona me enseñaron qué mide D. En los años 2010 hice ese viaje decenas de veces, y casi siempre tomé el AVE, el tren de alta velocidad. En el papel gana el avión: más o menos una hora y cuarto en el aire, contra dos horas y media en tren. Pero el tren me dejaba llegar cinco minutos antes de la salida, a una estación en medio de la ciudad, y trabajar desde el primer minuto. El avión era aeropuerto, seguridad, abordaje y una laptop cerrada hasta que se apagaba la señal del cinturón. (Tomé el Puente Aéreo, el vuelo sin reserva, una sola vez.)

Yo no era la excepción. Desde que abrió el AVE en 2008, le quitó al avión la mayor parte de ese mercado, cerca de tres de cada cuatro pasajeros para 2023, sin acortar un solo kilómetro. Lo que acortó fue el esfuerzo.

Acordate del Excel de mi laptop, el asteroide que atrae más que el lakehouse porque está ahí. Para una persona, la distancia es esfuerzo, y el esfuerzo puede jugar para los dos lados: mantiene cerca el Excel viejo, y lejos la tabla muerta. Para el agente, esa distancia desaparece. Todo lo que hay en el esquema que le dieron está a un paso. Sin ticket, sin búsqueda, sin colega a quien preguntarle. D vale uno para todas las tablas, y β se va con ella: valga lo que valga, uno elevado a cualquier potencia sigue siendo uno. Lo único que queda en la fórmula es A. (Cuando el esquema es demasiado grande y el agente primero busca en él, D vuelve, como un ranking de búsqueda. Y el ranking lo decide lo mismo: el nombre y la descripción.)

Una persona paga r en planilla. El agente no paga en distancia. Cada tabla en su alcance es una cosa más que leer, ROT incluido, así que paga en tokens, y en respuestas equivocadas.

En el post anterior dije que la atracción es lo que te hace caminar hasta ahí, y la luz es lo que encontrás cuando llegás. El ROT tiene lo primero y no lo segundo. Una persona que llega a fact_sales capaz nota que las fechas se cortan el año pasado. El agente no mira. Lee la etiqueta y se pone a trabajar.

Después mirá i: un origen sin perfil. No pertenece a la bodega ni a contabilidad. No sabe cuáles tablas “son las viejas”. Juzga qué tan atractiva es cada una con lo único que puede ver, el esquema: los nombres, las columnas y, si alguien la escribió, la descripción. O sea, con el promedio de lo que un nombre significa para cualquiera, y ese es el terreno donde mejor compite el ROT.

Hay evidencia de que el nombre pesa mucho. Unos investigadores tomaron un benchmark estándar de text-to-SQL y reescribieron las preguntas, cambiando las palabras que apuntaban a tablas y columnas por sinónimos naturales, nada más, y la precisión de los modelos cayó entre 20 y 30 puntos, más o menos. (Gan y colegas, ACL 2021, el paper de Spider-Syn. Su frase es que los modelos “dependen de la coincidencia léxica” entre la pregunta y el esquema.)

Esa es la falla vista de un lado: quitale el nombre que coincide y se pierden. Dala vuelta y tenés el kardex: dale a la tabla equivocada el nombre que coincide, y esa misma dependencia manda al agente directo a ella.

Para ser justo, los modelos nuevos lo hacen mejor de lo que sugiere ese paper. Un estudio de 2024 encontró que los modelos fuertes en razonamiento pueden encontrar el esquema relevante aunque les des un montón de tablas irrelevantes (Maamari y colegas, “The Death of Schema Linking?”). Lo creo. Pero lo irrelevante no es el problema. bkp_customers_old es irrelevante, y cualquier modelo decente la descarta. fact_sales no es irrelevante. Responde la pregunta. Solo que la responde con los datos del año pasado.

Acordate de la lista del post anterior: el ROT puede igualar a los datos buenos en cinco de seis atributos (los nombres, la facilidad de navegación, los metadatos, la calidad, la complejidad oculta) y el que no puede fingir es la relevancia, que no aparece en el esquema. El agente juzga exactamente esos cinco, solo con el esquema. La guía de la propia Microsoft para los agentes de datos de Fabric lo dice en palabras simples: no metás tablas de staging archivadas en el alcance del agente, y si dos de los objetos que elegiste tienen datos parecidos, decile al agente cuál es la fuente autorizada. En sus palabras: “No dependás solo de los nombres”.

El perfil equivocado

Ahora, la hora que prometí.

Cuando el senior me trajo el plan de remediación, lo leí y pensé que el junior y Claude se habían perdido. En mi cabeza, inventory_movements era el kardex. No tuve que pensarlo. Estudié economía, mis primeros años de trabajo fueron en administración, y para cualquiera que creció cerca de la contabilidad, “movimientos de inventario” es cada asiento que cambia la cantidad o el valor de lo que hay en el estante. Eso es el kardex. En ese sistema, son cajas que se mueven dentro de la bodega.

Yo tuve la misma lectura que el agente. Peor: el agente adivinaba por el nombre, sin perfil. Yo tenía un perfil, de otra comunidad, y eso me dio seguridad. La adivinanza del agente la puede agarrar cualquiera que mire los números. Mi seguridad la tenía que agarrar yo.

Lo que me hizo cambiar de idea no fue un argumento. Fue un patrón. En todos los modelos de inventario que he construido, el kardex es por lo menos tan largo como ventas y compras juntas, porque cada línea de factura saca algo de un estante o lo pone en uno. Así que volví a bronce y perfilé los datos yo mismo, y no necesité más que el conteo de filas. Para la operación de una empresa de ese tamaño, la tabla tenía demasiado pocas filas. Al lado de ventas y compras, no se acercaba ni de lejos. Ahí terminó la hora.

Lo demás fue confirmación. Le llevé los números al equipo de TI del cliente, y estuvieron de acuerdo: inventory_movements solo tenía los movimientos propios de la bodega. Después, cuando tuve acceso a su código, encontré el UNION ALL. El kardex había estado ahí todo el tiempo. Solo que vivía en código, donde ningún mapa lo podía ver.

La lección: no tener perfil es un riesgo. Tener el perfil equivocado puede ser uno más grande, porque no se siente como una adivinanza.

Una vez que lo vi, el junior y Claude tenían razón en el qué. El kardex tenía que existir como algo con nombre. Donde no estuve de acuerdo fue en el dónde. Su plan lo construía en oro, dentro de un modelo, y yo quiero que las reglas de negocio vivan en plata, definidas una vez, para que los científicos de datos, los agentes y el oro las reutilicen, en vez de que cada uno reconstruya la lógica en un esquema que solo sirve para su propio uso. Así que el concepto se fue a plata, al business vault: construido una vez, no ingerido, con vistas para los científicos de datos y para la estrella de oro. Bronce no cambió.

Esa es la parte que me importa más que el modelado. Un UNION ALL escondido en código tiene cero atracción, porque no tiene nombre. Ponerle nombre pone la tienda correcta en el mapa. Y dónde lo ponés importa: en oro, es el conocimiento privado de un modelo. En plata, todas las comunidades (la bodega, contabilidad, el próximo agente) pasan por la misma puerta.

Anthropic encontró lo mismo desde adentro, en el artículo que recomendé antes de que arrancara esta serie. Le dieron a su agente acceso con grep a miles de archivos SQL, todo el trabajo previo que tenían, y la precisión se movió menos de un punto: “nuestro cuello de botella no era el acceso al trabajo previo, era la estructura”. El kardex estuvo en código todo el tiempo. El código no es un nombre.

La versión ROT, con números

El kardex era el caso donde la respuesta correcta no tenía nombre. En mi experiencia, el ROT es el caso más común: rara vez me encuentro una empresa con un plan de archivo. Y es el peor: la respuesta correcta tiene nombre, y tres impostores también.

Acá están otra vez las cuatro tablas de ventas, con números. Una advertencia antes de que las mirés: esto es un modelo mental, no una medición. Los puntajes son inventados, y nadie calibró Huff para tablas. Puse β en 1. En Huff se estima con datos, y 1 es la elección conservadora: un decaimiento más empinado, digamos el cuadrado de Newton, solo agranda la brecha. La persona sube a 76%, el agente no se mueve. Lo que importa es la forma, no los decimales.

Tabla Qué es en realidad Persona con contexto: A / D Agente: A (solo el esquema), D = 1
sales Oro, certificada. La correcta 8 / 1 = 8 4 (“tabla de ventas”, genérico)
sales_final_v2 Copia de un analista, congelada en marzo 2 / 1 = 2 (está en su workspace) 3 (“final” suena definitivo)
fact_sales Warehouse viejo, dejó de cargar 0,5 / 2 = 0,25 (“esa está muerta”) 3,5 (fact_ se ve oficial)
sales_bkp_2023 Snapshot completo, la más pesada 1,5 / 2 = 0,75 0,5 (“bkp” la delata)
Probabilidad de elegir bien 8 / 11 = 73% 4 / 11 = 36%

Uso Huff para las dos columnas para que se puedan comparar. Para la persona, D es esfuerzo: 1 para lo que está en un workspace que ya abre, 2 para el warehouse viejo y el archivo, que tendría que salir a buscar. La persona real lo hace mejor que 73%: agrupa en nidos, y las copias casi no cuentan. El 36% del agente es lo que Huff predice de verdad.

Poné la D de la persona en 1 y todavía le da 67% (8 de 12). No es la distancia lo que los separa. Es el perfil.

Mirá la última fila y después la tabla más pesada. El backup, el que más pesa, es el menos peligroso: su nombre lo delata. La peligrosa es fact_sales, chica y atractiva. El ROT peligroso no es el pesado. Es el atractivo. La masa explica el costo y la exposición; la atracción explica el otro riesgo.

Ahora las palancas, con los mismos números inventados, aplicadas al agente:

Qué hacés Probabilidad de que el agente elija bien
Nada 36%
Decir que sales está certificada donde el agente lo lee: su descripción (A de 4 a 8) 53%
Además, marcar fact_sales como deprecada (A de 3,5 a 0,5) 67%
Sacar fact_sales y el backup del alcance del agente 73%
Retirar también sales_final_v2 (queda solo sales) 100%

Certificar y deprecar llevan al agente de 36 a 67, y ahí se quedan. Eso es ranking: la tabla mala sigue en la carrera, solo que más atrás. Llegar al 73% de la persona exige elegibilidad: sacar cosas del alcance, para que los impostores nunca entren al denominador. La versión de Anthropic es estructural: para sus datasets canónicos, “el agente se dirige estructuralmente a ellos primero”, con herramientas, con CI y por mandato.

El 100% es un resultado trivial del modelo: una tienda, nada que elegir. Dura exactamente lo que dura el alcance. Dale al agente toda la plata en vez de las puertas que elegiste para él, y el denominador se vuelve a llenar. El alcance es una decisión con dueño, no una configuración.

Los proveedores están construyendo esas dos primeras. Fabric muestra los elementos avalados con una insignia y los pone primero en algunos lugares; Databricks te deja marcar una tabla como certificada o deprecada y dice que eso ayuda a Genie One a priorizar los activos que tu organización respalda; y muchas herramientas de búsqueda de catálogo ordenan los resultados por popularidad. Todas útiles. Pero fijate en la última: si todo el mundo usa sales_final_v2, la popularidad la sube. Un ranking por uso premia al ROT atractivo.

Y con el tiempo empeora. Digamos que sales_final_v2 fue la tabla correcta durante seis meses, y todo el mundo aprendió a usarla. Después aparece sales_final_v3. ¿Qué debería hacer el agente? Por nombre, v3 se ve más nueva, así que un agente curioso salta a ella el día que aparece, validada o no. Por popularidad, v2 sigue arriba durante meses después de que dejó de ser la correcta. Ninguna de las dos señales responde la pregunta, porque la respuesta es una decisión: quién certificó v3, y cuándo se retira v2. Un sufijo de versión es una decisión que nadie escribió.

Las copias no son los únicos impostores. El tiempo también los fabrica: las filas del año pasado, todavía en la tabla correcta. Esas hay que borrarlas, y borrar no tiene que ser definitivo. En los últimos años dejé de escribir los SLA de oro como “datos desde 2020”. Una fecha de inicio fija es un contrato que se llena de ROT un poco más cada año. Ahora los escribo como una ventana, normalmente los últimos cinco a siete años calendario. El 1° de enero de 2027, la carga deja de traer 2020 a oro y quita lo que había. La capa de abajo no cambia: plata, el data vault y el business vault, o el warehouse, cuando la arquitectura es un warehouse con data marts encima. Los marts usan la misma ventana. La historia se queda donde está gobernada. Solo sale del estante donde compran los usuarios y los agentes.

Anthropic marca los modelos deprecados en su grafo de linaje, y por lo que dice su artículo, no los borra. Marcar algo como viejo es una decisión que cualquiera puede tomar. Borrarlo necesita un dueño, y también lo necesita cualquier corte que saque algo del estante sin borrarlo. La vez pasada, la tabla de clientes tuvo uno: el dueño de producto firmó un subconjunto para cuentas por cobrar. No se borró nada, y es la misma jugada de elegibilidad, hecha para un modelo en vez de para un agente.

Tu planilla del lunes

Probabilidad de elegir bien. Veinte minutos, una pregunta.

  1. Elegí una pregunta que les hacen seguido a tus usuarios o a tu agente. “Ventas del último trimestre” sirve.
  2. Listá todas las tablas o datasets cuyo nombre la respondería. Incluí todas las versiones, no solo la última.
  3. Dale a cada una una A de 0 a 10, dos veces: una como alguien que conoce el negocio, otra leyendo solo el esquema.
  4. Para la columna de la persona, dale a cada una una D de 1 a 3 (1 = ya está en mi workspace, 2 = tendría que salir a buscarla, 3 = necesitaría un ticket). La D del agente es 1, salvo que primero busque en el esquema; en ese caso puntuá la búsqueda, no la distancia.
  5. Calculá el A/D de cada tabla, y la proporción de la correcta en las dos columnas.
  6. Decidí por fila: hacer visible su certificación, deprecarla, sacarla del alcance del agente o retirarla. Volvé a puntuar.
  7. Antes de confiar en cualquier tabla, hacé el chequeo que nadie hizo en el caso del kardex: compará su conteo de filas contra algo cuyo tamaño ya conocés. Líneas de factura contra movimientos lo habría agarrado en cinco minutos.

Mi regla práctica: si con tus propios puntajes el agente tiene más chance de elegir una tabla equivocada que la correcta (menos de 50% en la columna del agente), todavía no apuntés un agente a esa área. El número es tan grueso como tus puntajes. La comparación no.

Y una pregunta que la planilla no te puede responder: cuando puntuaste “como alguien que conoce el negocio”, ¿de qué negocio eras?

¿Quién decidió qué ve el agente?

El agente construyó un modelo sobre inventory_movements porque el nombre se lo prometía. ¿Quién decidió que el kardex iba a vivir en código, sin nombre, donde nada lo podía elegir? ¿Quién decidió qué tablas iba a ver el agente, y a cuáles de ellas les iba a creer? Nadie. Alguien le pasó un esquema, y los nombres hicieron el resto.

En 2008 el mapa tenía todas las sucursales, y la gente que conocía el negocio discutía sobre él. En ese conglomerado la tienda correcta no estaba en el mapa, y el único que discutía era un junior que miró los números y no se los creyó. Tenía razón. Yo necesité una hora para alcanzarlo.

Una última cosa, porque es el próximo post. Supongamos que, para ayudar al próximo agente, alguien le pide a un LLM que escriba la descripción de inventory_movements. Estoy bastante seguro de lo que escribiría: “Contiene todos los movimientos de inventario.” El próximo agente la leería y se la creería, esta vez con una descripción que lo respalda. ¿Quién escribió esa descripción?

Este es el segundo de diez posts de ¿Quién lo decidió? La nube y la AI abarataron crear, copiar y guardar datos. No abarataron decidir.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *