sqbyl
Agente de texto a SQL sobre tu propia base de datos, servido como herramienta de consulta de solo lectura; construido y evaluado contra un conjunto de evaluación reservado antes de su implementación.
Documentación
Un kit de herramientas de código abierto, impulsado por LLM, para construir, evaluar e iterar agentes de texto a SQL sobre tu propia base de datos.
Trae tu propia base de datos y una clave de proveedor de LLM (Anthropic u OpenAI). sqbyl usa tu modelo elegido tanto para responder preguntas en lenguaje natural contra tus datos como para entrenarte sobre cómo hacer que el agente las responda mejor — y luego envía el resultado como un único archivo portátil que puedes llevar a producción.
sqbyl init # connect, profile, annotate → a working agent
sqbyl eval dev # measure on your iteration set
sqbyl coach # ranked, applyable fixes for whatever failed
sqbyl coach apply 1 2 # apply them — git tracks every diff
sqbyl eval test # the honest, held-out accuracy number
sqbyl release create --tag v1 # ship it as one portable JSON
Por qué sqbyl
Si quieres una superficie confiable de lenguaje natural a SQL sobre un almacén de datos simple de Postgres/DuckDB/Snowflake, tus opciones son aproximadamente: pagar por una plataforma cerrada que bloquea la capa semántica, los jueces y el optimizador dentro de un jardín amurallado — o montar una biblioteca tú mismo y redactar a mano todos los metadatos, evaluaciones y ajustes de prompts.
sqbyl es el camino intermedio. Reproduce el ciclo construir → evaluar → recibir indicaciones de mejora → re-evaluar como archivos simples en un repositorio git — y está construido para que el número de precisión que produce ese ciclo sea uno que realmente puedas reportar a las partes interesadas y defender:
- Sin caja negra. Cada prompt, juez y propuesta de mejora es texto/JSON legible y editable.
- Sin segundo proveedor. Una sola clave de proveedor (Anthropic u OpenAI) impulsa al agente, los jueces y el Coach. La selección de contexto es LLM/léxica, por lo que no hay proveedor de embeddings ni almacén vectorial que ejecutar.
- Sin factura sorpresa. El trabajo gratuito y determinista (conectar, perfilar, inferir uniones) se ejecuta primero a $0. El trabajo de pago se estima por adelantado, se mide en vivo y está limitado por
--budget. - Versionado como código. Todo tu "agente" es un directorio de YAML que puedes comparar, revisar y
git revert. - Defendible por diseño. La precisión principal es determinista y se mide en un conjunto reservado que el ciclo de mejora nunca puede tocar — así que "alcanzamos el 94%" es una afirmación que sobrevive al escrutinio, no un punto de referencia sobreajustado. (más abajo)
Construido para sistemas de ML defendibles
Una superficie de lenguaje natural a SQL es tan buena como el número de precisión que puedas poner frente a las partes interesadas y respaldar. sqbyl está diseñado de extremo a extremo en torno a los principios de sistemas de ML que mantienen ese número honesto — la misma disciplina que querrías antes de implementar cualquier agente evaluado a escala:
-
Medición determinista primero. La precisión principal es la corrección del conjunto de resultados — ejecuta el SQL de referencia y el SQL generado, compara las filas. Ningún LLM está dentro del número, por lo que es reproducible y no puede desviarse con un prompt. Los jueces LLM son estrictamente consultivos: clasifican la pila ambigua y explican por qué una fila es sospechosa, pero nunca mueven la precisión reportada. Solo una anulación humana es autoritativa.
-
Disciplina real de entrenamiento/prueba.
benchmarks/test.yamles un conjunto reservado sellado. El ciclo de desarrollo — síntesis, coach, optimizador — nunca puede leerlo; eso se aplica como un límite de código (una regla de import-linter en CI), no una convención que debas recordar. Incluso la calibración del juez está dividida por alcance, para que la retroalimentación de desarrollo no pueda filtrarse al juez de prueba. El número principal es siempre el reservado, con la puntuación de desarrollo mostrada a su lado para que la brecha sea visible. -
Resistencia a Goodhart por construcción. El Coach optimiza el contexto contra el conjunto de desarrollo — pero estructuralmente no puede mover el número de precisión determinista, se aleja de memorizar respuestas de referencia (arregla la semántica, no el prompt), y te advierte que las ganancias de desarrollo son no validadas hasta una re-puntuación reservada. Optimizar y medir en el mismo conjunto es entrenar en el conjunto de prueba; sqbyl hace que ese error sea difícil de cometer.
-
Incertidumbre calibrada y honesta. Un conjunto de evaluación pequeño es propenso al ruido, por lo que la precisión lleva un intervalo de confianza de Wilson — un cambio de 1–2 preguntas en 30 preguntas no se disfraza como una tendencia. Una puntuación en vivo de acuerdo juez↔humano te dice exactamente cuánto confiar en el juez, y está etiquetada como sesgada por selección en lugar de sobredeclarada. La confianza auto-reportada del modelo está etiquetada como "no verificada" — nunca presentada como calibrada.
-
Reproducibilidad y procedencia. Cada ejecución puntuada está sellada con la versión del modelo por rol y el estado de calibración que la moldeó. Una puntuación nunca se separa de lo que la produjo — la tarjeta de puntuación de la versión registra los modelos exactos con los que se obtuvo el número, y el runtime advierte sobre desajustes de modelo o esquema al cargar.
-
Humano en el circuito, en todas partes. Un patrón unificador recorre el juez, la síntesis de referencia y el Coach: el LLM propone, el humano dispone, y la corrección mejora el sistema. Cada veredicto del juez, pregunta sintetizada y corrección es una propuesta revisable, no un hecho consumado.
-
Honestidad de costos. El trabajo gratuito y determinista se ejecuta primero a $0 (conectar, perfilar, inferir uniones). El trabajo de pago se estima antes, se mide en vivo y está limitado por
--budget. La economía del agente es tan legible como su precisión.
La versión corta: sqbyl te ayuda a enviar un agente de texto a SQL cuya precisión realmente puedes reportar — porque el número es determinista, reservado, sellado con procedencia y defendido contra las formas en que los ciclos de evaluación te mienten silenciosamente.
Arquitectura: dos paquetes, una flecha de dependencia
sqbyl se envía como dos paquetes, para que lo que desarrollas no sea lo que implementas:
sqbyl-runtime— el runtime mínimo y ligero en dependencias que integras en producción: carga una versión,ask(), registro estructurado. Sin pila web, sin maquinaria de evaluación.sqbyl— el kit de herramientas de desarrollo completo: inspeccionar, perfilar, anotar, sintetizar, el arnés de evaluación, el Coach, jueces LLM, la consola de revisión, el optimizador y el constructor de versiones.
sqbyl depende de sqbyl-runtime, nunca al revés — un límite unidireccional aplicado en CI (import-linter). Ninguna de la maquinaria de desarrollo/evaluación puede filtrarse en lo que se ejecuta en tu aplicación. Iteras con el kit de herramientas; envías el runtime. Ambos están estrictamente tipados (py.typed) y respaldados por pydantic, y la interfaz de versión es un JSON documentado y schema_version'd que un tercero puede leer sin sqbyl en absoluto.
Para quién es esto
Estás poniendo una superficie de lenguaje natural a SQL sobre tu propio almacén de datos — una herramienta de análisis interna o una característica de producto — y necesitas un número de precisión que puedas defender, más un sistema que puedas leer, editar y versionar. Trabajas en git, una base de datos SQL y YAML. Tienes (o puedes aprovisionar) un rol de base de datos de solo lectura y una clave de proveedor de LLM (Anthropic u OpenAI).
Instalación
pip install 'sqbyl[anthropic]' # full dev toolkit, Claude backend
pip install 'sqbyl[openai]' # full dev toolkit, OpenAI backend
pip install 'sqbyl-runtime[anthropic]' # the lightweight "ship it" runtime only
Los SDK de proveedores son extras opcionales — sqbyl es neutral respecto al proveedor, así que elige el que usarás
([anthropic] o [openai]) e instala solo ese. Una instalación simple de pip install sqbyl instala el
kit de herramientas sin un SDK de proveedor.
¿Desarrollando en sqbyl mismo? Consulta CONTRIBUTING.md para la configuración desde el código fuente
con uv; los mantenedores cortan versiones a través de PUBLISHING.md.
Inicio rápido
Apunta sqbyl a una base de datos y una clave:
export ANTHROPIC_API_KEY=sk-ant-...
export DATABASE_URL=postgresql://readonly_user@warehouse.internal/analytics # use a read-only role
Luego ejecuta la configuración guiada. Sin sqbyl.yaml que escribir a mano — init lo genera por ti si falta. Hace el trabajo gratuito y determinista primero (conectar, leer esquema, perfilar cada columna con SQL de solo lectura), verifica tu clave de proveedor ($0), te muestra un plan con costos y solo gasta después de que confirmes:
sqbyl init
▸ connecting…………………………………… done
▸ reading schema………………………………… 42 tables, 380 columns
▸ profiling columns (read-only SQL)… done ($0 — no LLM)
▸ heuristic join candidates……………… 11 found, 3 ambiguous
Ready to enrich with Claude. Here's the plan and the estimate:
annotate 380 columns + 42 tables ~$1.20
synthesize ~40-question benchmark ~$0.60
baseline eval ~$0.30
─────────────────────────────────────────
estimated total ~$2.15 on claude-opus-4-8
Proceed? [Y]es · [s]elect steps · [m]odel · [n]o
Aterrizas en una cola de revisión — no en una página en blanco — mostrando solo las decisiones que un humano debe tomar (por ejemplo, "¿qué cuenta como un cliente activo?"), cada una con un valor predeterminado sensato prellenado. Acepta tu camino hacia el objetivo de preparación, luego:
sqbyl eval dev # measure against your iteration set
sqbyl coach # ranked, applyable file diffs for whatever still fails
sqbyl coach apply 1 2 # writes the edits (git tracks them)
sqbyl eval test # the honest, held-out number
sqbyl release create --tag v1
release create emite un JSON portátil — el "cerebro" del agente (semántica, instrucciones, ejemplos, prompts de jueces, tarjeta de puntuación). El modelo, la clave y la base de datos no están integrados; se inyectan dondequiera que se ejecute.
Para la narrativa completa, lee sqbyl-user-journey.md.
Envío de una versión
La producción es "solo un modelo con registros." La maquinaria de desarrollo (evaluación, síntesis, coach, consola) no viene — integras el runtime ligero:
from sqbyl_runtime import load
agent = load("revenue-analytics.v1.json", db=env.DATABASE_URL, model="claude-opus-4-8")
@app.post("/ask") # your API, your auth, your scaling
def ask(q: str):
return agent.ask(q) # → {plan, sql, rows, used_assets, usage, latency}
Hereda la autenticación, el agrupamiento de conexiones y la observabilidad de tu aplicación. sqbyl run <release> / sqbyl serve existen para llamadores no Python y exposición HTTP rápida, pero intencionalmente no están endurecidos — no pongas sqbyl serve en el internet abierto.
Respuestas en lenguaje natural (opt-in). ask() devuelve datos estructurados — sql, columns, rows — que siguen siendo la respuesta autoritativa. Para una superficie de chat/asistente que también quiere una oración ("Hay 1,284 pedidos."), habilita la narración: load(..., narrate=True) (o por llamada, agent.ask(q, narrate=True)). Eso agrega una llamada de resumen final, basada estrictamente en las filas ejecutadas, y llena result.answer. Está desactivada por defecto para que el runtime determinista y $0-por-defecto no cambie; la llamada se mide como su propio rol narrate (fija un modelo más barato con narration_model=), y la oración narrada es una conveniencia sobre las filas, nunca un sustituto de ellas. El CLI refleja esto con sqbyl ask "…" --narrate.
Async y concurrencia
agent.ask() es síncrono y bloqueante (un viaje de ida y vuelta de LLM más consultas de base de datos), pero un solo agent cargado es seguro de llamar concurrentemente — el motor de base de datos agrupa conexiones por hilo, el cliente del proveedor (Anthropic u OpenAI) es seguro para hilos y las escrituras de rastreo están bloqueadas. Así que bajo un grupo de hilos sirve solicitudes concurrentes correctamente.
La única regla para un servidor async: ejecuta ask() fuera del bucle de eventos, no lo llames dentro de un async def directamente (eso bloquea el bucle para toda la solicitud).
# FastAPI: a sync endpoint is auto-run in a threadpool — this is the example above, and it's correct.
@app.post("/ask")
def ask(q: str): ...
# From an async endpoint, offload explicitly:
from starlette.concurrency import run_in_threadpool
@app.post("/ask")
async def ask(q: str):
return await run_in_threadpool(agent.ask, q) # or asyncio.to_thread(agent.ask, q)
Limita la concurrencia (grupo de hilos + tamaño del grupo de base de datos) como lo harías para cualquier carga de trabajo bloqueante. Un runtime nativo-async (cliente de proveedor async + base de datos async) no se proporciona — el patrón de grupo de hilos es el camino compatible.
Estructura del proyecto
Un proyecto sqbyl es un directorio nativo de git de archivos simples:
my-project/
├── sqbyl.yaml # manifest: db connection, model(s), defaults
├── instructions.md # the (small) global instruction block
├── semantics/ # one YAML per table: columns, profiles, joins, measures, filters
├── examples/ # NL → SQL few-shot pairs
├── trusted/ # vetted, parameterized "source of truth" queries
├── benchmarks/
│ ├── dev.yaml # iteration set: Coach/Optimizer tune against this
│ └── test.yaml # held-out set: Coach/Optimizer NEVER see it
└── .sqbyl/ # runs, traces, usage, caches (gitignored)
La división desarrollo/prueba es fundamental: optimizar y medir en el mismo conjunto es entrenar en el conjunto de prueba, por lo que la precisión principal es siempre el número reservado. Referencia completa del formato en la especificación de diseño, §4.
Referencia de comandos
sqbyl init [<db-url>] # guided: free profile → costed plan → confirm → step through
# scaffolds sqbyl.yaml if missing; --auto --budget $5 for CI;
# --dry-run to estimate only; --model M reprices every role
sqbyl review # attention queue + golden-set / judge / proposal review (web UI)
sqbyl eval [dev|test] # run the eval harness → scored report + run diff
sqbyl eval show <split> <id> # print one saved row's full detail (plan/SQL/scorers/judges), $0
sqbyl synth [--n 40] # execution-grounded candidate questions → dev set
sqbyl coach [apply N... | --regenerate] # review/apply context edits; reuses the last report ($0)
sqbyl optimize --budget $5 --target 0.9 # autonomous coach→apply→eval loop on dev
sqbyl ask "..." # one-shot NL→SQL→result
sqbyl release create --tag v1 # bless current version → portable JSON
sqbyl cost <command> # estimate $ / tokens, spend nothing
sqbyl reset [--all] # clear local .sqbyl/ state (keeps cost history unless --all)
sqbyl init genera sqbyl.yaml para ti cuando no hay uno (interactivamente, o una plantilla bajo --auto), y ejecuta una verificación de credenciales $0 antes de cotizar un plan.
Comandos por paso a la carta (introspect — con --sync para agregar nuevas columnas de base de datos sin perder anotaciones — profile, annotate, judge, runs, serve, run) están documentados en la especificación, §10.
Configuración
La configuración del proyecto vive en sqbyl.yaml; los secretos se referencian por nombre de env:, no en línea:
name: revenue-analytics
database:
dialect: postgresql # postgresql | duckdb | snowflake | bigquery | mysql | sqlite
url: env:DATABASE_URL
read_only: true # refuses non-SELECT; warns if the credential can write
model:
provider: anthropic # anthropic | openai — one provider powers every role
api_key: env:ANTHROPIC_API_KEY
default: claude-opus-4-8 # per-role models (agent/judge/coach/...) override default
# base_url: env:LLM_GATEWAY # optional: route the provider through a proxy / AI gateway
Para usar OpenAI en su lugar, cambia las tres líneas del proveedor (todo lo demás es idéntico):
model:
provider: openai
api_key: env:OPENAI_API_KEY
default: gpt-5
sqbyl usa un solo proveedor para todo — agente, jueces y Coach — así que eliges uno y se aplica en todo el ciclo (sin mezclar). Consulta §4 de la especificación para el manifiesto completo, incluido el fijado de modelos por rol y los interruptores de automatización. Para enrutar a través de un proxy corporativo o puerta de enlace de IA, establece model.base_url (o pasa base_url= al runtime load()) — no se necesita otro cambio.
Seguridad y manejo de datos
La sección que un revisor de seguridad buscará:
- Solo lectura por defecto. sqbyl rechaza operaciones no-
SELECTen la capa SQL y, al conectarse, inspecciona los privilegios de la credencial y advierte (con una corrección sugerida) si puede escribir. El agente y el Coach nunca emiten DDL/DML. Apúntalo a un rol de solo lectura dedicado. - Secretos por referencia. Las cadenas de conexión y las claves de API están indirectadas por
env:— nunca se escriben en archivos del proyecto, lanzamientos o trazas. - Tus datos siguen siendo tuyos. Las filas de resultados de consultas no se persisten en archivos de proyecto confirmados ni en trazas; el SQL importado que contiene valores literales se marca para revisión antes de que pueda aterrizar. Un lanzamiento es el cerebro del agente — semántica, indicaciones, ejemplos — nunca filas.
- Telemetría local-primero y exportable. Las trazas siguen las convenciones de OpenTelemetry GenAI y se escriben bajo
.sqbyl/; expórtalas a cualquier backend OTel cuando quieras. - CI nunca gasta tokens. Cada ruta de LLM se ejecuta contra un seam de mock / record-replay, por lo que la integración continua nunca llama a la API. Las dependencias se escanean en busca de vulnerabilidades (
pip-audit), se verifican licencias y se actualizan mediante Dependabot. - El endurecimiento de producción es tuyo. Incrustas el runtime en tu propio servicio, heredando su autenticación, TLS, pooling y limitación de tasa.
sqbyl servees una conveniencia de desarrollo en localhost, no un servidor de producción — no lo expongas.
La gobernanza, RBAC, linaje y gestión de catálogos deliberadamente no se reimplementan — eso es trabajo de tu base de datos (no-objetivos).
Requisitos
- Python (gestionado mediante
uv) - Una clave de API de proveedor de LLM — Anthropic (
ANTHROPIC_API_KEY) u OpenAI (OPENAI_API_KEY) - Una base de datos SQL, accesible en solo lectura (
DATABASE_URL). DuckDB y Postgres son los dialectos de primera clase; SQLite, MySQL, Snowflake y BigQuery se admiten detrás de un seam de dialecto.
Estado del proyecto
La secuencia de compilación completa en sqbyl-implementation-plan.md (Fases 0–9) está terminada: cada capacidad a continuación está construida, probada y fusionada.
| Capacidad | Estado |
|---|---|
Motor: introspectar + perfilar + runtime del agente (sqbyl ask) | ✅ construido |
Conjunto dorado + harness de evaluación (synth, review, eval) | ✅ construido |
| Coach + jueces LLM | ✅ construido |
init guiado, orquestador, maquinaria de costos | ✅ construido |
| Lanzamiento + runtime + optimizador | ✅ construido |
| Más dialectos, servir, exportaciones, importadores | ✅ construido |
Mientras esté en pre-1.0, las formas de comandos y archivos aún pueden cambiar con incrementos de versión menor (ver SemVer y el changelog).
Documentación
La especificación es el porqué, el viaje es una primera ejecución narrada, y el plan es un registro de cómo se construyó:
sqbyl-design-spec.md— la especificación completa del diseño del producto.sqbyl-user-journey.md— una primera ejecución narrada, de inicio a envío.sqbyl-implementation-plan.md— la secuencia de compilación por fases (Fases 0–9, completa).
Licencia
MIT © Jack Werner