Probé si el Prep-for-AI cambia las respuestas de un Fabric Data Agent (y me llevé una sorpresa)

csalcedodatabi Microsoft Fabric Data Agents AI Power BI
El panel 'Prep data for AI' de Power BI Desktop con la sección 'Add AI instructions' abierta, mostrando las instrucciones de IA escritas para el modelo semántico Contoso — el titular pregunta si esto cambia las respuestas de un Fabric Data Agent, medido con un A/B de con y sin Prep-for-AI

Todo el mundo repite que para que un Fabric Data Agent responda bien hay que “preparar el modelo para IA” — el famoso Prep-for-AI. Yo también lo repetía. Así que hice lo obvio y que casi nadie hace: medirlo.

Monté un A/B controlado, con el mismo dato y la misma pregunta, cambiando una sola variable. Y me llevé dos sorpresas: una sobre lo que el Prep-for-AI realmente aporta, y otra —más útil todavía— sobre dónde estaba mirando yo las respuestas.

En resumen — Con y sin Prep-for-AI dieron lo mismo en todo lo medible: números, moneda e idioma. Los números, la moneda y el idioma salen del modelo, no de las instrucciones. Una batería por el endpoint MCP insinuó un delta (nombres de columna en el DAX mostrado), pero al re-testarlo a mano contra el query ejecutado no se replicó — así que lo descarto, no era Prep-for-AI. Dos lecciones que sí quedan: evalúa en “Test data agent” o por la API, nunca en “Build agent with AI”; y no te fíes del DAX que el chat muestra — vale el que ejecuta.

El montaje

Dos modelos semánticos con exactamente el mismo dato (un Contoso retail sintético, ~126 mil líneas de venta, en pesos mexicanos):

  • ContosoRetailcon Prep-for-AI (instrucciones de IA + verified answers autoradas sobre el modelo).
  • ContosoRetail V2 — una copia sin Prep-for-AI.

Un Data Agent apuntando a uno u otro, con las mismas tres preguntas de negocio: ventas totales, margen y ventas por categoría. Cambio la fuente, publico, pregunto, y capturo tanto la respuesta como el DAX que genera.

¿Y qué es exactamente el “Prep-for-AI”? Vive en Power BI Desktop, no en el agente:

Panel "Prep data for AI" en Power BI Desktop, con la sección Add AI instructions y el contador de caracteres

Home → Prep data for AI en la cinta de Power BI Desktop. ② De sus cuatro secciones, la que nos ocupa es Add AI instructions. ③ Y un detalle que casi nadie menciona: el límite duro es de 10.000 caracteres. Nota: esta captura es posterior al ablation — ya incluye las dos instrucciones de jerga (Seasonal campaigns, Internal segments) que agregué después para los tests de la siguiente entrega. Durante el A/B de este post el modelo no las tenía.

Nota

La clave de un A/B honesto es cambiar una variable. Aquí el dato es idéntico; lo único que se mueve es la presencia del Prep-for-AI en el modelo.

Ronda 1 y 2: con las instrucciones puestas

Con las instrucciones del agente cargadas (moneda MXN, margen no-aditivo, categorías en español), ambos respondieron bien. Mismos números, misma moneda, mismas categorías.

Estas primeras rondas las corrí por el endpoint MCP del agente publicado (una batería programática, no clics en el portal). Y ahí apareció algo que parecía un delta: en el DAX que la respuesta mostraba para “ventas por categoría”, el agente sin Prep escribió una columna que no existe, y el que tenía Prep el nombre real. Adelanto: no sobrevivió al re-test manual — lo dejo porque el error es la parte útil:

Batería MCP · agente SIN Prep — DAX mostrado (hipótesis luego descartada)
EVALUATE
SUMMARIZECOLUMNS(
  'DimProduct'[Category],          -- ❌ esa columna no existe
  FILTER('DimDate', 'DimDate'[Year] = 2024),
  "Total Sales", [Total Sales]
)
Batería MCP · agente CON Prep — DAX mostrado (hipótesis luego descartada)
EVALUATE
SUMMARIZECOLUMNS(
  DimProduct[CategoryName],        -- ✅ el nombre exacto del modelo
  FILTER(DimDate, YEAR(DimDate[Date]) = 2024),
  "Total Sales", [Total Sales]
)

Parecía el aporte del Prep-for-AI. Pero no aguantó al re-test.

Fui al portal a reproducirlo a mano, en Test data agent, mirando el query realmente ejecutado (el panel Execution and output, no el texto que la respuesta narra). Y no pude replicarlo: ahí los agentes usaron el nombre correcto DimProduct[CategoryName]. Los números, además, habían sido idénticos todo el tiempo en las dos ramas.

Advertencia

Dos canales, dos historias — y esa es la lección. El bloque de DAX que un Data Agent te muestra es una reconstrucción del LLM, no el query literal que ejecutó; por eso puede variar entre corridas sin que nada del modelo haya cambiado. Un patrón visto en el DAX mostrado no es un hallazgo hasta que se replica contra el query ejecutado. Este no se replicó → lo descarto, no lo publico como efecto del Prep-for-AI.

Ronda 3: el control de verdad

“Pero las reglas estaban en las instrucciones del agente”, pensé. “Quítalas y ahí el Prep-for-AI tendrá que sostener todo.” Así que dejé el prompt pelado —“Eres un analista de ventas de Contoso. Responde con el modelo ContosoRetail.”— en los dos agentes.

La sorpresa: igual respondieron con el número correcto, en MXN, con las categorías en español. ¿Cómo, sin ninguna regla?

Importante

Porque esas tres cosas nunca venían de las instrucciones. Salen del modelo: la moneda vive en el format string de la medida; el idioma son los datos (la categoría se llama “Electrónica”); y el margen no-aditivo ya está resuelto en la definición de la medida [Margin %].

Cuatro combinaciones (instrucciones completas o peladas × con o sin Prep-for-AI) dieron los mismos números, la misma moneda y el mismo idioma. En el DAX mostrado volvió a asomar la diferencia de nombres — pero es exactamente la señal que ya no había sobrevivido al re-test manual, así que no la cuento como hallazgo.

Ronda 4: preguntas ambiguas… y la trampa

Hasta aquí las preguntas eran demasiado limpias. Probé dos ambiguas: “¿cuál es el margen?” (¿absoluto o porcentaje?) y “¿ventas del último trimestre?” (el dato termina en 2024).

Aquí es donde casi saco la conclusión equivocada. En un panel del portal, el agente con Prep-for-AI se puso a dudar, propuso SQL crudo y terminó diciendo “no puedo ejecutar, cópiala y ejecútala en tu entorno”. El agente sin Prep, en cambio, ejecutó y respondió. Parecía que el Prep-for-AI lo empeoraba.

Menos mal que verifiqué por la API antes de escribir eso.

Advertencia

Yo estaba mirando “Build agent with AI” — el copiloto que te ayuda a configurar el agente. Ese panel chatea, ilustra en SQL, pide precisiones y puede no ejecutar. No es el runtime.

El panel correcto es “Test data agent”. Ahí el mismo agente con Prep-for-AI ejecutó DAX limpio y respondió de una: margen = $3,938,789 MXN | 19.8%, devolviendo ambos con las medidas reales [Gross Margin] y [Margin %]. Y por el endpoint MCP (lo que consumen las apps) los dos agentes respondieron idéntico y correcto, verificado contra DAX directo.

Panel "Build agent with AI": ante "¿cuál es el margen?" el agente duda, pide precisiones y propone SQL crudo sin ejecutar

El copiloto de autoría “Build agent with AI”: a la misma pregunta duda, pide tres precisiones y muestra SQL que no ejecuta. No es el runtime.

Panel "Test data agent": la misma pregunta se ejecuta con DAX limpio usando [Gross Margin] y [Margin %], y devuelve $3,938,789 MXN | 19.8%

El panel “Test data agent”: la misma pregunta ejecuta DAX limpio con las medidas reales [Gross Margin] y [Margin %], y responde de una: $3,938,789 MXN | 19.8%.

¿Entonces para qué sirve el Prep-for-AI? (fui a la fuente)

Antes de sacar conclusiones apresuradas, revisé la documentación de Microsoft. Y nuestro resultado nulo coincide con lo documentado — no lo contradice.

El Prep-for-AI es la capa de grounding del modelo para todas las experiencias de IA sobre ese semantic model: Copilot Q&A y los Fabric Data Agents, que lo honran cuando el modelo es fuente. No es “otra cosa que no aplica a Data Agents”. Y trae dos frases que valen oro:

Nota

Microsoft documenta que la herramienta de generación de DAX del Data Agent se basa solo en la metadata del modelo + el Prep-for-AI, e ignora las instrucciones a nivel de agente para generar el DAX. Por eso pelar las Agent instructions no cambió nada: es comportamiento documentado, no un accidente. (Add a semantic model to a data agent)

Y sobre cuándo el Prep-for-AI mueve la aguja: cuando hay algo que resolver — ambigüedad (varias medidas “ventas”), jerga de negocio que no está en el modelo (“temporada alta” = jun–ago), una verified answer que hace match con la pregunta, modelos grandes y ruidosos, varias columnas de fecha (best practices para Data Agent). Nuestro modelo era limpio, pequeño y las preguntas literales → no había ambigüedad que resolver, así que el Prep no tenía nada que aportar. Medimos el caso de bajo impacto, y salió bajo impacto.

Lo que me llevo

Importante

Evalúa un Data Agent en “Test data agent” o por su endpoint MCP — nunca en “Build agent with AI”. Juzgarlo por el copiloto de autoría es como sacas un veredicto falso de “no sabe responder”.

Y sobre el Prep-for-AI: en estas preguntas no encontré una diferencia reproducible — con o sin él, mismos números y mismo DAX ejecutado. No es que no sirva; es que en un modelo bien construido buena parte del grounding ya está horneado en el modelo (format strings, valores de datos, definiciones de medida), y estas preguntas eran demasiado limpias para exigirle más — justo como anticipa la documentación. La forma de verlo brillar es meter ambigüedad a propósito: medidas duplicadas (“Ventas” vs “Ventas Netas”), una jerga de negocio que no esté en el modelo, o una verified answer con sus trigger phrases, y luego preguntar algo que sin Prep se interpretaría mal. Ese es el siguiente experimento — y la lección de método es no declarar un efecto sin medirlo contra el query ejecutado.

Esto es el complemento empírico de Anatomía de un Fabric Data Agent, donde desgloso las 8 partes que escribes para que un agente responda bien. Aquí medí cuánto pesa una de ellas.

Reprodúcelo tú mismo

Un resultado que no puedes repetir no sirve de nada, así que te dejo el material:

  • Los datos — el Contoso retail sintético completo (7 tablas en Parquet: FactSales, DimDate, DimProduct, DimStore, DimCustomer, DimCurrency, DimCurrencyExchange), en un repo público: CSalcedoDataBI/SampleDataSets → contoso-retail. Son datos sintéticos: nada confidencial, úsalos como quieras.
  • Las instrucciones de Prep-for-AI — el bloque exacto que ves en la captura de arriba, con la tabla de cómo verifiqué cada línea contra el TMDL y los datos reales: descargar ai-instructions-verificadas.md.

Importante

De ese documento, la parte que más me sirvió es la fila de la moneda. Un borrador anterior le decía al agente que “convirtiera monedas con DimCurrencyExchange” — suena razonable y es falso: los datos tienen una sola moneda (MXN) y esa tabla está desconectada. Verificarlo contra los datos convirtió una instrucción dañina en una correcta. Una instrucción plausible pero falsa es peor que ninguna: no se queda callada, dirige mal al agente.

Para pegarlas: Power BI Desktop → Home → Prep data for AI → Add AI instructions → pegar → ApplyGuardarPublicar. Ojo con el gotcha: publicar el modelo no basta para que el agente las vea — hay que re-sincronizar la fuente y publicar el agente (y darle unos minutos).

Nota

Un caveat honesto: son pocas preguntas y un modelo. El “DAX exacto” que muestra el agente no siempre es el query literal (es una reconstrucción del LLM); lo fiable son los números —cruzados contra DAX directo— y el query del panel Execution and output.

¿Te resultó útil este artículo?

Tu apoyo me permite seguir creando contenido de calidad.

¡Contáctame!