Lo que un esquema no puede decirle a su agente: el formato de conocimiento abierto en BigQuery
Un experimento con BigQuery y Gemini ADK: los paquetes en formato Open Knowledge en Git le proporcionaron al agente lo que el esquema no podía, estabilizando las respuestas y corrigiendo un error del 29% en el GMV.
Fuentes: **What Your Schema Cannot Tell Your Agent, Open Knowledge Format Can**
El archivo de instrucciones del que nadie es dueño
Al conectar un agente de IA a un almacén de datos, tarde o temprano aparece un archivo de instrucciones. Al principio se trata de tres o cuatro líneas ordenadas en las instrucciones del sistema: excluir los reembolsos de los ingresos, el año fiscal comienza en abril, ignorar las cuentas de prueba internas. Con el paso de los meses, el archivo crece hasta llegar a unas cuatrocientas líneas. Solo un ingeniero se atreve a editarlo, mientras que el analista que realmente es responsable de las definiciones de las métricas ni siquiera lo ha visto.
El enorme tamaño es el problema menor. Lo realmente problemático es que nadie puede mantenerlo. Una cadena de instrucciones no tiene dueño designado, ni proceso de revisión, ni fecha de vencimiento. Si Finanzas publica una nueva política de ingresos en enero, el ingeniero nunca se entera, el analista no tiene forma de modificar el código, y las instrucciones nunca caducan por sí solas.
Bajo ese tipo de fricción, el conocimiento se vuelve obsoleto o nunca se completa, por lo que el agente funciona con definiciones parciales y suposiciones no expresadas. Además, las lagunas no hacen que los agentes fallen de manera visible: no hay caídas, ni errores de sintaxis SQL, ni resultados vacíos. El agente examina el esquema en bruto, adivina qué reglas de negocio faltan y entrega una cifra ordenada y creíble que termina en el panel de control ejecutivo. Un problema de mantenimiento se convierte silenciosamente en un problema de precisión.
El formato Open Knowledge (OKF) está diseñado precisamente para subsanar esa laguna. Las reglas de negocio dejan de existir en cadenas de comandos o almacenamientos vectoriales opacos y pasan a ser archivos Markdown simples con metadatos YAML almacenados en Git. La propiedad de los datos se vuelve explícita, los cambios se realizan a través de solicitudes de pull request, y las fechas de vencimiento son visibles tanto para analistas como para ingenieros.
Los escépticos sostienen que modelos más potentes y ventanas de contexto más amplias hacen esto innecesario, ya que se puede entregar al agente el esquema y los documentos en bruto y dejar que infiera las definiciones por sí mismo. Un experimento conciso probó cuánto valdría el conocimiento incompleto y qué cambios supondría la base de conocimiento OKF. Utilizó dos tablas de BigQuery, una única pregunta de negocio y un agente creado con el Google Agent Development Kit (ADK) bajo varias configuraciones de conocimiento.
El escenario de prueba
El entorno es un mercado en línea con una tabla orders y una tabla payments, además de una pregunta que un gerente de productos podría hacer cada lunes por la mañana.
¿Cuánto volumen de negocio total generaron los pagos QRIS que se liquidaron con éxito en Jabodetabek durante julio de 2026?
Tres términos necesitan una explicación. GMV significa Valor Bruto de las Mercancías, que es la suma de los productos vendidos en un período determinado. QRIS es el estándar nacional de pagos por QR en Indonesia. Jabodetabek es el nombre de la región metropolitana de Yakarta: Yakarta, Bogor, Depok, Tangerang y Bekasi.
Cada columna que la pregunta necesita existe en el almacén, pero el esquema no puede responderla. Hay cuatro decisiones ocultas dentro de la pregunta, y cada una fue tomada por una persona:
- El estado que demuestra que el dinero ha llegado. Los pagos incluyen tanto
status_codecomotransaction_status. El atractivostatus_code = 200solo indica que la llamada al gateway tuvo éxito, incluyendo las cancelaciones. Los fondos llegan a la cuenta del comerciante únicamente cuandotransaction_status = 'settlement'. Los valores de ejemplo reproducen la API pública de un verdadero gateway de pagos. - Los pedidos que realmente cuentan. Un pago liquidado asociado a un pedido devuelto representa efectivo que vuelve a salir, pero sigue registrándose como
settlementhasta que se procesa el reembolso. Por lo tanto, el filtro necesitaorders.order_status = 'completed', y el esquema no lo indica en ningún momento. - La marca de tiempo que define el período. La liquidación se produce horas o incluso días después de los pedidos. Al analizar julio mediante
orders.order_tsse obtiene un total, mientras que al hacerlo conpayments.settlement_tsse obtiene otro, por lo que un pedido del 31 de julio podría clasificarse en agosto. - Las ciudades que componen la región. No existe una columna
region. Jabodetabek debe especificarse como trece valores exactos dedestination_city, yKotafrente aKab.representan dos lugares distintos y no variantes ortográficas.
Un error en cualquiera de estos elementos sigue generando una consulta que se ejecuta. No hay error, ni resultado vacío ni traza de pila, solo un número bien formado dirigido al mazo de cartas.
Contexto versus conocimiento
La solución obvia es anotar las cuatro decisiones y proporcionárselas al modelo junto con el esquema. Un modelo capaz suele poder llegar a la respuesta correcta a partir de eso. Pero lo hace nuevamente en la siguiente sesión, y nada obliga a que dos sesiones lleguen al mismo acuerdo. La definición de GMV no se almacena en ningún lugar; se deriva de nuevo según sea necesario por un proceso que no recuerda las conclusiones del día anterior.
Esta diferencia sustenta el resto del argumento. El contexto es el material sobre el cual razona el modelo. El conocimiento es una conclusión a la que alguien ya ha llegado y aprobado. El razonamiento se paga de nuevo en cada sesión, mientras que una conclusión escrita solo se paga una vez.
¿Pero dónde se escribe? No en la cadena de instrucciones, por las razones mencionadas anteriormente. Una base de datos o un almacén de vectores proporciona espacio de almacenamiento, pero impide la revisión, ya que un analista no abrirá una solicitud de integración contra un almacén de embeddings.
Qué es OKF
La propuesta de Google es OKF, y está diseñada de forma sencilla. Un paquete es simplemente una carpeta de archivos Markdown con metadatos en YAML, compartida a través de Git, sin involucrar ninguna base de datos, almacén de vectores ni SDK. Cada archivo describe un concepto; type es la única clave de metadatos obligatoria, y los enlaces habituales de Markdown conectan los archivos, lo que convierte al paquete en un grafo en lugar de un simple conjunto de archivos.
La pregunta más útil es qué se incluye en su interior. Los tipos no se registran de forma centralizada, y los consumidores deben aceptar aquellos que no reconocen; por lo tanto, lo que sigue es un vocabulario inicial y no un esquema. En los dos conjuntos de ejemplos publicados por Google, los directorios tienen este aspecto:
tables/ydatasets/indican de qué se trata la información: qué representa cada fila, cómo se relacionan las columnas y qué valores de tipo enumerado existen. Esta parte puede obtenerse del almacén de datos, como se muestra en el paso siguiente.metrics/explica el significado de cada número. El GMV y sus cuatro condiciones se encuentran aquí.references/alberga conocimientos específicos del dominio que no tienen ninguna columna, como las trece ciudades de Jabodetabek, una taxonomía de productos o la lista de cuentas de prueba internas.policies/almacena el documento de fuente de verdad al que hace referencia una definición, como por ejemplo la norma de reconocimiento de ingresos que Finance vuelve a publicar cada enero.computations/yattesters/guardan el SQL aprobado para una métrica, junto con el código que verifica que el resultado provenga realmente de él.skills/recoge los procedimientos: cuándo usar algo, sus condiciones previas y sus pasos.
Una prueba válida para determinar si algo pertenece a un paquete: ¿se le explicaría a un nuevo analista durante su primera semana? Si es así, se incluye en un archivo.
La versión v0.2 de la especificación añade tres campos de frontmatter que abordan directamente el problema inicial. sources enumera de qué se derivó un concepto. verified recopila los eventos de aprobación en formato {by, at}, y un concepto sin ninguno se marca literalmente como unverified. stale_after indica el momento exacto a partir del cual un concepto se considera obsoleto. Juntos, proporcionan un responsable, un punto de revisión y una fecha de vencimiento, todo dentro de un archivo que un analista puede editar y que un revisor puede leer como una solicitud de integración.
¿Podría un equipo inventar simplemente su propio diseño de carpetas? Sí, pero un vocabulario común permite hacer cosas que un diseño privado no puede. El agente de referencia descrito a continuación puede redactar la mitad de un paquete porque ya comprende qué es el concepto de BigQuery Table. Los revisores saben a qué se comprometen al marcar como verified los cambios. El formato también es neutral con respecto al proveedor, ya que no está vinculado a ningún agente, framework ni proveedor de modelos, por lo que el conocimiento generado hoy sobrevive a un cambio en la tecnología utilizada.
Muchos lectores pensarán que se trata de una habilidad de agente con pasos adicionales, y la superposición es lo suficientemente real como para abordarla. OKF incluye type: Skill como un simple tipo de concepto. El paquete de ejemplo de Google tiene skills/run-on-bq.md estructurado en Secciones de uso, Precondiciones y Pasos, lo cual se asemeja a cualquier habilidad de agente ordinaria. Las habilidades son un subconjunto de OKF y no un sinónimo. Una habilidad indica a un agente cómo actuar, mientras que OKF explica el significado de los términos, quién los verificó por última vez y cuándo caduca la respuesta. Su uso se divide en tres pasos: generar lo que ya sabe el almacén, escribir lo que solo saben las personas y permitir que el agente lea ambos.
Primera acción: generar lo que el almacén ya sabe
Cuando una tabla de BigQuery ya está documentada, no es necesario escribir manualmente la parte rutinaria. El repositorio de OKF incluye un agente de creación, y un comando convierte un conjunto de datos de BigQuery en un paquete.
uv tool install git+https://github.com/GoogleCloudPlatform/open-knowledge-format
reference-agent enrich \
--source bq \
--dataset "$PROJECT_ID.marketplace" \
--out bundles/generated \
--no-web
Emite un documento datasets/, un documento tables/ para cada tabla, y archivos index.md actualizados en todo momento. Al agregar --no-web se omite el paso opcional de fusionar la documentación existente, lo que permite que la primera ejecución sea reproducible.
El resultado es mejor de lo esperado. Describe la estructura de cada tabla, encuentra la clave de unión adecuada y documenta el enum de estados. Rara vez genera un documento Metric o Reference, ya que una fuente de BigQuery solo proporciona conceptos de conjunto de datos y tablas, y nada más. El límite está determinado por lo que el almacén ya registra sobre sí mismo.
Verifique esto antes de asumir que otro almacén se comportará de la misma manera. Los valores de estado aparecen en los documentos generados únicamente porque alguien los incluyó en las descripciones de las columnas del DDL. Si dirige el generador a columnas simples y no documentadas, tendrá mucha menos información disponible.
Los documentos generados pueden contener errores, y el experimento muestra un ejemplo al respecto. En una ejecución se generó un patrón de consulta con sum(t2.total_price), pero no existe tal columna. El nombre real es gross_amount, que el mismo archivo indica correctamente en su propia tabla de esquema, dos secciones antes. Ejecutar ese fragmento falla.
Ahí es donde resulta útil verified. Cada documento generado registra generated: {by: reference_agent/...} pero no hay evento verified, por lo que el formato mismo lo marca como no revisado. Un paquete documenta su propia procedencia, y separar la salida automática de las decisiones humanas no requiere ningún cambio.
Segunda fase: anote lo que solo saben las personas
Dos archivos escritos a mano en el mismo paquete y formato son suficientes para registrar las cuatro decisiones ocultas. metrics/gmv.md es el más importante de ellos, y su frontmatter muestra dónde se ubican los campos de confianza.
---
type: Metric
title: Gross Merchandise Value (GMV)
description: Total settled transaction value for a period in IDR, excluding cancellations, reversals and returns.
tags: [metrics, finance, headline-metric]
generated: { by: human:analytics-lead@marketplace.example, at: 2026-09-01T09:00:00+07:00 }
verified:
- { by: human:analytics-lead@marketplace.example, at: 2026-09-01T11:00:00+07:00 }
stale_after: 2027-01-31T00:00:00+07:00
---
El texto detalla las cuatro condiciones y establece claramente que el esquema no proporciona ninguna de ellas. La liquidación implica transaction_status = 'settlement' y expresamente no status_code = 200. Los pedidos deben tener order_status = 'completed' con las cancelaciones eliminadas. Para dicho período, settlement_ts es el límite, verificado mediante un rango semicerrado que incluye un desfase explícito de +07: desde 2026-07-01 00:00:00+07 inclusive hasta 2026-08-01 00:00:00+07 exclusivo. Un operador BETWEEN aplicado a cadenas de fecha simples hace que se omita el último día y trate cada marca de tiempo como UTC, por lo que cada límite se desplaza siete horas.
El valor stale_after realiza una función real. Resuelve el problema de enero en una sola línea: Finanzas vuelve a publicar las reglas de reconocimiento de ingresos cada enero, por lo que la definición caduca el 31 de enero de 2027, y al agente se le indica que informe ese valor en lugar de presentarlo como actual.
El segundo archivo, references/jabodetabek.md, enumera las trece cadenas exactas de destination_city y advierte contra el uso de LIKE '%Jakarta%', ya que esto pasaría desapercibidamente por alto ocho de ellas.
Aquí la colaboración se vuelve tangible. Redefinir el GMV ahora implica una solicitud de pull request contra un archivo Markdown que el analista responsable puede revisar, sin necesidad de editarlo de inmediato ni de realizar un redeploy en el backend. El paquete de ejemplos de Google incluso mantiene un archivo obsoleto gross-margin-legacy.md para que los resultados históricos sigan siendo reproducibles, algo que los archivos simples y con cadenas fijas no pueden hacer.
Tercer acto: el agente que los lee
Para acceder a los datos, el agente utiliza el servidor MCP gestionado por Google Cloud en https://bigquery.googleapis.com/mcp, el cual se activa una vez que la API de BigQuery está habilitada para el proyecto. No es necesario desplegar nada.
El único código personalizado en el proyecto es una herramienta que lee un archivo.
def read_okf_concept(path: str) -> dict:
"""Read one OKF concept document from the local bundle.
Args:
path: Path relative to the bundle root, for example "metrics/gmv.md".
Call this with "index.md" first to find which concepts exist.
Returns:
'status', and on success 'content' with the raw markdown and frontmatter.
"""
doc = (OKF_BUNDLE / path.lstrip("/")).resolve()
# `path` is model-controlled. Block anything that escapes the bundle.
if not doc.is_relative_to(OKF_BUNDLE) or not doc.is_file():
return {"status": "error", "error": f"no concept at {path}"}
return {"status": "success", "content": doc.read_text(encoding="utf-8")}
Y luego se define el propio agente.
bigquery_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://bigquery.googleapis.com/mcp",
headers={
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
},
sse_read_timeout=300.0,
),
header_provider=_bigquery_auth_header,
tool_filter=[
"list_dataset_ids",
"list_table_ids",
"get_dataset_info",
"get_table_info",
"execute_sql_readonly",
],
)
root_agent = Agent(
name="marketplace_analytics_agent",
model="gemini-3.7-flash",
instruction=(
"Before writing any SQL: call read_okf_concept('index.md'), then read every "
"concept the question touches: the metric, the payment status, the geography.\n"
"Use only the filters, joins and period cuts those concepts define. "
"Never invent a status value or a metric formula.\n"
f"Run queries with execute_sql_readonly, passing projectId='{PROJECT_ID}'.\n"
"Show the SQL you ran, and name the concepts you relied on."
),
tools=[read_okf_concept, bigquery_mcp],
)
El experimento luego ejecutó esta conversación.
Qué sucedió realmente
El agente, la pregunta y los datos iniciales permanecieron iguales en todas las configuraciones. Solo cambió el directorio al que apuntaba OKF_BUNDLE, y cada configuración se ejecutó cuatro veces.
Al no haber una capa de conocimiento, la herramienta de lectura apuntaba a una carpeta vacía y solo contaba con la introspección de esquemas del servidor MCP; cuatro ejecuciones de la misma pregunta arrojaron tres valores diferentes para el título principal: IDR 371,251,000, 333,020,000 y 371,886,000. El valor más alto superó la verdad en un 29%.
Con el paquete generado y una sola ejecución de reference-agent enrich, la cifra dejó de variar. Siempre se obtuvo IDR 329,590,000, un valor estable y reproducible, pero aún así 15% demasiado alto.
Al añadir los dos conceptos escritos a mano, siempre se obtuvo IDR 286,740,000. Ese es el valor correcto, y la respuesta indica los conceptos en los que se basó.
La progresión es clara: la precisión de las respuestas está limitada por cuán exacta sea la información proporcionada. Sin ninguna capa adicional, el agente adivina la lógica faltante en cada turno, lo que genera un error de hasta el 29% de forma irregular. El contexto del esquema derivado por la máquina elimina esa inestabilidad y reduce el error al 15%, pero no puede completar la tarea por sí solo, ya que la brecha restante se debe a políticas empresariales y no a problemas técnicos. Solo definiciones explícitas, revisadas por humanos, para las reglas no escritas, como los límites exactos de las marcas de tiempo y los estados de los pedidos, permiten que el agente alcance esa cifra con fiabilidad.
Resultó que el factor más importante para la precisión no era ni una instrucción más extensa ni un modelo más grande. Se trata de conocimientos del dominio estructurados y controlados por versiones, ubicados donde termina el esquema de la base de datos.
Lo que este enfoque no soluciona
La anclaje depende de las instrucciones, por lo que un modelo puede ignorarlo libremente, y nada impide que se escriba SQL antes de leer un concepto. Quien quiera una garantía estricta puede añadir un ADK before_tool_callback que rechace la llamada a la consulta si no se ha leído ningún concepto en ese turno.
Markdown tampoco realiza validación de esquema. Un analista podría introducir un concepto mal formado, y OKF mantiene intencionadamente una actitud permisiva, exigiendo que los usuarios toleren tipos desconocidos y enlaces rotos. La verdadera protección proviene de la revisión de código en la solicitud de integración, además de los parámetros verified y stale_after, que exponen definiciones no revisadas o vencidas al agente cuando las lee. La especificación califica los niveles de confianza como señales de carácter consultivo, por lo que su uso depende de quien construya el agente. El agente aquí las lee, y otros también deben hacerlo.
Tampoco estas cifras constituyen puntos de referencia: una sola pregunta, un modelo y cuatro ejecuciones por configuración con datos seleccionados para contener las trampas. Muestran un mecanismo pero no dicen nada sobre el efecto promedio de OKF en la precisión.
La lección que perdura
El mecanismo sigue teniendo valor. Cuando un agente de datos se equivoca, la respuesta no parece incorrecta. No se dispara ninguna excepción, no se devuelve ningún resultado vacío y nada se vuelve rojo. El SQL es válido y la figura parece razonable, por lo que aparece en una diapositiva mucho antes de que alguien lo dude.
El error que más debe temerse no es el errático. Sin orientación, el agente devolvía un número nuevo en cada ejecución, algo fácil de detectar en una tarde. Con la mitad del conocimiento, devolvía el mismo número en cada ejecución mientras mencionaba casualmente una alternativa que no podía justificar elegir. Un resultado estable parece una prueba de corrección, pero en realidad no demuestra nada.
Un modelo mejor no es necesariamente lo que cierra la brecha. Una sola orden capturó todo lo que el almacén podía decir sobre sí mismo y se detuvo justo donde comienzan las decisiones humanas: la marca de tiempo que delimita un período, los estados del pedido que se contabilizan, el estado que indica que el dinero ha llegado. Esas son elecciones y no hechos, y deben registrarse una vez por quien las tomó, en un lugar donde se pueda consultar a esa persona más tarde.
Una buena forma de comenzar es con algo más pequeño que un proyecto. Elija la métrica sobre la que el equipo sigue discutiendo, aquella en la que dos paneles de control difieren y todos saben a qué analista acudir. Ejecute el generador con el conjunto de datos correspondiente, luego escriba la definición junto con su responsable en un único archivo y una única solicitud de integración. Esa conversación es el trabajo real; el formato simplemente le da un lugar definido y un registro de quién estuvo de acuerdo y cuándo vence. Las herramientas son la parte más aburrida. Lo interesante es lo que ocurre cuando un analista e un ingeniero deben ponerse de acuerdo en una frase y comprometerse con ella, y qué decisiones ocultas resultan ser suyas.
Leer más
- Notas prácticas: Una GUI de base de datos que también regula qué puede hacer su agente de IA — Guía paso a paso de las Notas prácticas: Una GUI de base de datos que también regula qué puede hacer su agente de IA: contratos, verificaciones y espacios para código listo para usar para los equipos que implementan este patrón.
- Ejecutar agentes de profundidad en un backend local OpenSandbox — Cómo conectar OpenSandbox a los agentes de profundidad a través de BaseSandbox, sincronizar código asíncrono y sincrónico, y ejecutar un agente de análisis de datos de forma segura en un sandbox local de Docker.