SQL agéntico local con Qwen3.8-27B y DuckDB: el 98,6 % es contexto
En una formación de empresa, en julio, un equipo me enseñó un problema que parecía de modelo.
Su agente de datos —SQL agéntico local sobre DuckDB, un harness sencillo— fallaba una de cada tres preguntas. Habían probado tres modelos, cada uno más caro que el anterior. La precisión se movió tres puntos.
Miré el prompt. El agente recibía el DESCRIBE de las tablas y nada más. Ni qué significa cada columna, ni el dialecto, ni las trampas del dominio.
Ese es el punto ciego del debate sobre SQL agéntico local: discutimos qué modelo poner cuando el problema casi nunca está en el modelo.
Aclaremos el término antes de seguir. SQL agéntico es dejar que un modelo de lenguaje, en vez de devolver una única consulta, itere en bucle: inspecciona el esquema, escribe SQL, lo ejecuta contra la base de datos, lee el resultado o el error y corrige hasta responder la pregunta de negocio. SQL agéntico local es hacer exactamente eso con un modelo abierto corriendo en tu máquina: sin coste por token y sin que los datos salgan del equipo.
En su tabla de ventas, las devoluciones son filas con importe negativo que nadie borra. Ningún modelo, por caro que sea, adivina eso. Se lo tienes que decir.
El titular viral del SQL agéntico local y lo que se salta
MotherDuck publicó un artículo montando un agente SQL con Qwen3.8-27B corriendo en local sobre DuckDB. Lo pasaron por DABstep, un benchmark de análisis de datos cuyo test set completo tiene más de 400 preguntas de negocio reales.
Según su benchmark, el modelo local en cuantización 4-bit sacó un 98,6 % de accuracy. Gratis, o menos de 0,50 $ si cuentas la electricidad. GPT 5.6 Luna Max gastó más de 8 $ en el mismo benchmark: 17 veces más caro según su cálculo, y con peor resultado.
Los otros datos que reportan en la misma pasada, para situar:
| Modelo | Precisión en DABstep | Coste de la pasada | Tiempo por pregunta |
|---|---|---|---|
| Qwen3.8-27B local, 4-bit (MacBook Air M5) | 98,6 % | < 0,50 $ de electricidad | 5-6 min |
Qwen3.8-27B local, 3-bit IQ3_XXS (M1 Pro, 16 GB) |
96,4 % | < 0,50 $ de electricidad | 5-6 min |
| GPT 5.6 Luna Max | Por debajo del Qwen local | > 8 $ | ~40 s |
| Gemini-3-Flash | El más preciso del test | 2,3× el precio de Luna Max | ~25 s |
| Sonnet 5 | Significativamente menos preciso | Más caro, sin cifra publicada | — |
Dos puntos de precisión por la mitad de RAM.
Fuente: benchmark de MotherDuck sobre DABstep. MotherDuck no publica el porcentaje exacto de los modelos en la nube, solo su posición relativa — por eso esas celdas van en cualitativo.
El titular escribe solo: un modelo abierto en tu portátil empata a los frontier en SQL. Pero hay una frase enterrada en el artículo que cambia por completo la lectura.
La capa de contexto que usó el agente la construyeron con un modelo frontier. Textualmente: "general documentation (including some SQL snippets) is fed into Claude Fable 5 and converted into MotherDuck Guides". Claude Fable 5 destiló la documentación; el modelo local solo consumió el resultado.
Ahí está la historia real.
El modelo frontier no desaparece del agente SQL: se mueve de sitio
El modelo caro no se ha quedado sin trabajo. Ha cambiado de turno.
Antes lo llamabas mil veces, una por pregunta, y pagabas mil veces. Ahora lo llamas una vez para destilar tus esquemas, tu documentación y tus reglas de negocio en un fichero de contexto, y luego infieres gratis en local todas las veces que quieras.
Es un cambio de CAPEX por OPEX. Pagas una vez por construir el contexto y amortizas esa inversión en cada consulta posterior.
Lo cual deja el corolario más útil del artículo, y es uno que el titular no da:
Si tu agente de datos falla, no cambies de modelo. Arregla el contexto. Y si con contexto bueno ya funciona, entonces sí baja a un modelo local y deja de pagar por token.
En ese orden. Al revés te sale caro y encima no funciona.
El trabajo difícil migró del prompt al contexto. Quien no se entera sigue comprando inteligencia que no necesita.
Qué contiene la capa de contexto de un agente SQL sobre DuckDB
Una capa de contexto útil para un agente SQL tiene cuatro bloques: el esquema anotado columna a columna, las reglas de negocio que no están en el esquema, las reglas del dialecto SQL concreto y un puñado de queries doradas. Esta es la parte que no encontrarás en el original: qué escribes exactamente en ese fichero.
No es el DESCRIBE. Eso ya lo consigue el modelo con una tool. Lo que no tiene es la semántica, el dialecto y los precedentes.
Este es el esqueleto que uso para un agente SQL sobre nuestros datos de Dominicode —ventas de cursos y eventos de vídeo— en agent/context/ventas.md:
# Contexto: analítica de ventas y vídeo (DuckDB)
## Datos disponibles
Los ficheros son Parquet locales. Cárgalos siempre con read_parquet, nunca
asumas que existe una tabla con ese nombre en el catálogo.
read_parquet(39;data/ventas_cursos/*.parquet39;)
read_parquet(39;data/eventos_video/*.parquet39;)
## ventas_cursos — una fila por transacción
- id_venta VARCHAR Único. Las devoluciones NO comparten id con la venta.
- fecha_utc TIMESTAMP Naive, siempre en UTC. El negocio reporta en Madrid.
- curso_slug VARCHAR Clave de negocio del curso. Une por aquí, no por título.
- plataforma VARCHAR 39;udemy39; | 39;kursar39;. Kursar no tiene filas antes de 2026-03.
- canal VARCHAR 39;organico39; | 39;referido39; | 39;udemy_business39;.
- precio_bruto DOUBLE 0.0 cuando el cupón es del 100 %. No es un error.
- neto_usd DOUBLE Ingreso YA repartido con la plataforma.
- pais VARCHAR ISO-2. Puede ser NULL en Udemy Business.
## Reglas de negocio que no están en el esquema
1. Las devoluciones son filas con neto_usd < 0. No se borran nunca.
Para facturación real: SUM(neto_usd) sobre TODAS las filas.
Nunca filtres con WHERE neto_usd > 0 salvo que pidan ventas brutas.
2. No calcules el neto multiplicando el bruto por el reparto de la
plataforma. Ese cálculo ya viene hecho en neto_usd y el porcentaje
cambia por canal.
3. "Mes de agosto" significa mes natural en Europe/Madrid, no en UTC.
4. Una venta con precio_bruto = 0 sigue contando como unidad vendida.
## Dialecto DuckDB — reglas obligatorias
- GROUP BY ALL y ORDER BY ALL existen. Úsalos en vez de repetir columnas.
- SELECT * EXCLUDE (col) y SELECT * REPLACE (expr AS col) son válidos.
- QUALIFY filtra sobre window functions sin subconsulta. Prefiérelo.
- QUALIFY no se puede combinar con GROUP BY ALL: el binder lo rechaza.
Con QUALIFY usa GROUP BY explícito. Y dentro de la window repite la
agregación —ORDER BY SUM(x) DESC—, nunca el alias del SELECT: si el
alias se llama igual que la columna, resuelve a la columna cruda y falla.
- La división / devuelve DOUBLE. Para división entera usa //.
- No existe TOP n. Usa LIMIT.
- Zona horaria: la columna es naive UTC, así que la conversión correcta es
fecha_utc AT TIME ZONE 39;UTC39; AT TIME ZONE 39;Europe/Madrid39;
La conversión la aporta ICU, ya incluida en las builds oficiales: no hace
falta INSTALL ni LOAD. Una sola llamada AT TIME ZONE da mal resultado.
- Antes de una pregunta abierta, ejecuta SUMMARIZE sobre la tabla
para ver rangos y nulos reales antes de escribir la query final.
Y al final del mismo fichero, la sección que más cambia el resultado: las queries doradas. Pares de pregunta y SQL correcto, escritas por alguien que conoce los datos.
-- P: "¿Cuánto facturamos neto en agosto de 2026?"
SELECT ROUND(SUM(neto_usd), 2) AS neto_usd
FROM read_parquet(39;data/ventas_cursos/*.parquet39;)
WHERE date_trunc(
39;month39;,
fecha_utc AT TIME ZONE 39;UTC39; AT TIME ZONE 39;Europe/Madrid39;
) = DATE 39;2026-08-0139;;
-- P: "Top 3 cursos por ingreso neto en cada plataforma este año"
-- Ojo: GROUP BY explícito (QUALIFY no admite GROUP BY ALL) y SUM(neto_usd)
-- dentro de la window, no el alias.
SELECT plataforma, curso_slug, SUM(neto_usd) AS neto_usd
FROM read_parquet(39;data/ventas_cursos/*.parquet39;)
WHERE fecha_utc AT TIME ZONE 39;UTC39; AT TIME ZONE 39;Europe/Madrid39;
>= TIMESTAMP 39;2026-01-0139;
GROUP BY plataforma, curso_slug
QUALIFY row_number() OVER (
PARTITION BY plataforma ORDER BY SUM(neto_usd) DESC
) <= 3
ORDER BY plataforma, neto_usd DESC;
Ese fichero son cuatro pantallas y vale más que cambiar de modelo tres veces.
Cada bloque mata un fallo distinto. El esquema anotado mata las columnas alucinadas. Las reglas de negocio matan las respuestas plausibles pero falsas, las más caras de todas.
Y el dialecto mata dos cosas: el SQL de PostgreSQL que el modelo escribe por defecto, y trampas como la de QUALIFY que ningún modelo adivina porque solo las conoces si te han explotado en la cara. Es la misma idea que en preparar datos para agentes de IA con Python: el agente no necesita más inteligencia, necesita menos ambigüedad.
Y antes de dejar que ese agente escriba algo que no sea un SELECT, monta el contrato de revisión. Escribí un ebook gratuito sobre eso, Revisión por Contrato: cómo revisar el código que genera un modelo sin leerlo línea a línea.
El coste del SQL agéntico local no es el precio: es el tiempo
El dato que decide más que el precio es la latencia.
El agente local tarda 5-6 minutos por pregunta. Gemini-3-Flash tarda unos 25 segundos. GPT 5.6 Luna Max, unos 40.
No es un 20 % más lento. Es un orden de magnitud. Y eso no se arregla con contexto.
El rendimiento observado ronda los 5-7 tokens por segundo en un MacBook Air M5 y unos 5 en un MacBook Pro M1 Pro de 16 GB. Un agente que da cuatro o cinco pasos quema miles de tokens antes de devolver la primera fila.
Eso convierte la decisión en algo binario:
- Sí a local: batch nocturno, informes recurrentes, datos que no pueden salir de la máquina, exploración sin prisa, entornos sin conectividad.
- No a local: dashboard interactivo, chat de datos para negocio, cualquier flujo donde alguien esté mirando un spinner.
Y hay una restricción estructural que se cuenta poco: en local corres un prompt a la vez. En cloud lanzas 15 preguntas en paralelo sin pensarlo. Para una suite de evals nocturna eso es la diferencia entre veinte minutos y seis horas.
Si estás decidiendo qué modelo abierto meter en tu máquina, ya comparé opciones en los mejores modelos de IA local en 2026, y de la familia Qwen hablé en el análisis de benchmarks de Qwen3.8 Max.
La letra pequeña del "gratis": qué cuesta Qwen3.8-27B en local
Correr Qwen3.8-27B en local no sale gratis: cuesta unos 6 $ por cada 1.000 preguntas amortizando el hardware, y pide 14-16 GB de VRAM en 4 bits. Cuatro matices antes de que pidas presupuesto para una GPU.
No es gratis. Contando amortización del hardware, el coste real ronda 6 $ por cada 1.000 preguntas. La comparación honesta no es "gratis contra 8 $", sino esos 6 $ por mil preguntas contra lo que te cobre tu proveedor por esas mismas mil. En volumen alto sigue ganando el local por goleada, pero "gratis" es marketing.
Puede que no te quepa. Son 27B de parámetros densos —sin MoE—, atención híbrida, encoder de visión, contexto nativo de 262.144 tokens y licencia Apache 2.0, según la ficha oficial del modelo. En 4-bit son ~18 GB de descarga y 14-16 GB de VRAM; FP8 sube a ~28 GB y BF16 a ~56 GB. Y MotherDuck estima que solo alrededor de un tercio de los portátiles pasa de 16 GB de RAM, así que la mayoría se queda en la cuantización de 3 bits.
El acelerador puede frenarte. El multi-token predictor está pensado para ir más rápido, pero en hardware antiguo puede ralentizar. Mide antes de dejarlo activado.
Un benchmark no es tu base de datos. DABstep tiene esquema limpio y preguntas bien formuladas. Tu warehouse tiene tres columnas llamadas status y una tabla que solo entiende alguien que se fue en 2023.
Por eso el paso siguiente no es "probarlo", es medirlo con tus preguntas: evals deterministas sobre veinte consultas reales tuyas, comparando el resultado de la query y no el texto de la respuesta.
Cómo montar un agente SQL local con Qwen3.8-27B y DuckDB en 7 pasos
Tal como lo describe MotherDuck, con LM Studio —no Ollama:
- Instala DuckDB.
- Instala LM Studio.
- Descarga el modelo cuantizado:
Qwen3.8-27B-MLX-4bitsi tienes 32 GB; elIQ3_XXSde unsloth si tienes 16 GB. - Opcionalmente añade el acelerador MTP, y mide si te ayuda.
- Levanta el endpoint compatible con OpenAI de LM Studio, con 16.384 tokens de contexto y el reasoning en low u off.
- Conecta tu harness de agente —OpenCode o el que uses— a ese endpoint.
- Apunta DuckDB a tus datos.
Si el agente va a consultar mucho o desde varios procesos, monta bien la parte de acceso: lo cubrí en conexión eficiente a DuckDB.
Lo que haría yo hoy con tu agente de datos
Abre el prompt de tu agente de datos y cuenta cuántas líneas hablan de tu negocio. Si la respuesta es cero, no tienes un problema de modelo.
Coge la tabla que más consultas, escribe el fichero de contexto de arriba para ella —esquema anotado, reglas de negocio, dialecto y tres queries doradas— y vuelve a lanzar las mismas preguntas con el mismo modelo que ya pagas. Esa es la medición que importa. Si con contexto sube, ya sabes que puedes bajar de modelo. Si no sube, cambiar de modelo tampoco te habría salvado.
Y si quieres construir el agente completo, esta forma de trabajar —contexto primero, modelo después— es la que enseño en el curso Construye con IA: de la idea al producto con Claude Code. El harness, los contratos y las evals que hacen que un agente sea fiable, no impresionante en una demo.
En Dominicode Labs tenemos las plantillas de contexto que usamos en producción, incluida esta de DuckDB.
Preguntas frecuentes
¿Qué es el SQL agéntico y en qué se diferencia del text-to-SQL?
El text-to-SQL clásico traduce una pregunta en lenguaje natural a una consulta y ahí termina: si falla o devuelve algo absurdo, el problema es tuyo. El SQL agéntico mete al modelo en un bucle con herramientas: inspecciona el esquema, escribe la consulta, la ejecuta, lee el error o el resultado y corrige hasta responder la pregunta de negocio. El SQL agéntico local es ese mismo bucle con un modelo abierto en tu máquina, sin coste por token y sin que los datos salgan del equipo.
¿Qwen3.8-27B es mejor que GPT 5.6 Luna Max para SQL?
En el benchmark de MotherDuck sobre DABstep, sí: Qwen3.8-27B en cuantización de 4 bits alcanzó un 98,6 % de precisión y superó a GPT 5.6 Luna Max, que costó más de 8 $ en la misma pasada. Pero ese resultado se midió con una capa de contexto construida a mano para ese conjunto de datos, y tardando 5-6 minutos por pregunta frente a unos 40 segundos del modelo en la nube. Sin esa capa de contexto y con un humano esperando, la comparación se da la vuelta.
¿Qué hardware necesito para correr Qwen3.8-27B en local?
En cuantización de 4 bits son ~18 GB de descarga y necesitas entre 14 y 16 GB de VRAM, así que en la práctica hablamos de una máquina con 32 GB de RAM unificada o una GPU dedicada equivalente. Con 16 GB puedes tirar de la cuantización de 3 bits IQ3_XXS de unsloth, que según el benchmark de MotherDuck baja la precisión de 98,6 % a 96,4 %. En FP8 el modelo pide ~28 GB y en BF16 ~56 GB, que ya es territorio de servidor.
¿De verdad sale gratis?
No literalmente. La inferencia no tiene precio por token, y el coste de electricidad de la pasada completa del benchmark quedó por debajo de 0,50 $. Pero si amortizas el hardware, el coste real ronda los 6 $ por cada 1.000 preguntas. La comparación honesta no es "gratis contra 8 $", es "6 $ por mil preguntas contra lo que te cobre tu proveedor por esas mil". Sigue ganando el local por goleada en volumen alto.
¿Sirve esto para un chat de datos en producción?
Para un dashboard interactivo, no. Cinco o seis minutos por pregunta con una sola petición en curso a la vez descarta cualquier caso donde haya un humano esperando. Donde sí encaja es en batch nocturno, informes recurrentes, entornos sin conectividad y datos sensibles que no pueden salir de la máquina. Ese último caso, por sí solo, ya justifica el montaje en más empresas de las que parece.
¿Puedo usar Ollama en lugar de LM Studio?
El setup que describe MotherDuck usa LM Studio y su endpoint compatible con la API de OpenAI, configurado con 16.384 tokens de contexto y el reasoning en bajo o desactivado. Cualquier runtime que exponga un endpoint compatible te vale para conectar el harness, pero comprueba dos cosas antes de comparar resultados: que estás cargando exactamente la misma cuantización y que la ventana de contexto configurada es la misma. Cambiar cualquiera de las dos cambia los números.
¿Es seguro dejar que un agente ejecute SQL sobre mi base de datos?
Solo si le pones los límites antes, no después. Lo mínimo: conexión de solo lectura, un usuario con permisos únicamente sobre las tablas que necesita, un LIMIT por defecto y un timeout de query. Con DuckDB sobre ficheros Parquet el riesgo baja mucho, porque el agente lee ficheros y no toca el warehouse de producción. Nunca le des credenciales de escritura a un agente para ahorrarte un paso.
Tengo 200 tablas. ¿Escribo el contexto de todas?
No. Empieza por las cinco que concentran el 80 % de las preguntas y documenta esas a fondo. La capa de contexto no se escribe entera de golpe: crece cada vez que el agente falla. Cuando una respuesta salga mal, no reescribas el prompt del sistema —añade la regla de negocio que faltaba y la query dorada correspondiente. Ese fichero acaba siendo el activo más valioso del sistema, y es el que sobrevive cuando cambies de modelo.
Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.
¿Te resultó útil este artículo?
Compártelo con tu comunidad y ayuda a otros desarrolladores.
