sqbyl
Agente Text-to-SQL sobre seu próprio banco de dados, servido como uma ferramenta de consulta somente leitura; construído e avaliado contra um conjunto de avaliação reservado antes de ser implantado.
Documentação
Um kit de ferramentas open-source, alimentado por LLM, para construir, avaliar e iterar agentes de texto-para-SQL sobre seu próprio banco de dados.
Traga seu próprio banco de dados e uma chave de provedor de LLM (Anthropic ou OpenAI). O sqbyl usa o modelo escolhido tanto para responder perguntas em linguagem natural contra seus dados quanto para orientá-lo sobre como fazer o agente respondê-las melhor — e então entrega o resultado como um único arquivo portátil que você pode colocar em produção.
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 que sqbyl
Se você quer uma superfície confiável de linguagem natural para SQL sobre um warehouse simples de Postgres/DuckDB/Snowflake, suas opções são aproximadamente: pagar por uma plataforma fechada que trava a camada semântica, os avaliadores e o otimizador dentro de um jardim murado — ou montar uma biblioteca você mesmo e escrever manualmente todos os metadados, avaliações e ajustes de prompt.
O sqbyl é o caminho do meio. Ele reproduz o ciclo construir → avaliar → receber orientação de como melhorar → reavaliar como arquivos simples em um repositório git — e é construído para que o número de precisão que esse ciclo produz seja algo que você possa realmente reportar às partes interessadas e defender:
- Sem caixa-preta. Cada prompt, avaliador e proposta de melhoria é texto/JSON legível e editável.
- Sem segundo fornecedor. Uma única chave de provedor (Anthropic ou OpenAI) alimenta o agente, os avaliadores e o Coach. A seleção de contexto é LLM/lexical, então não há provedor de embeddings ou armazenamento vetorial para executar.
- Sem surpresa na conta. O trabalho gratuito e determinístico (conectar, perfil, inferir junções) roda primeiro a $0. O trabalho pago é estimado antecipadamente, medido ao vivo e limitado por
--budget. - Versionado como código. Todo o seu "agente" é um diretório de YAML que você pode comparar, revisar e
git revert. - Defensável por design. A precisão principal é determinística e medida em um conjunto reservado que o ciclo de melhoria nunca pode tocar — então "atingimos 94%" é uma afirmação que sobrevive ao escrutínio, não um benchmark que você superajustou. (mais abaixo)
Construído para sistemas de ML defensáveis
Uma superfície de linguagem natural para SQL só é tão boa quanto o número de precisão que você pode colocar diante das partes interessadas e sustentar. O sqbyl é projetado de ponta a ponta em torno dos princípios de sistemas de ML que mantêm esse número honesto — a mesma disciplina que você gostaria antes de implantar qualquer agente avaliado em escala:
-
Medição determinística em primeiro lugar. A precisão principal é correção do conjunto de resultados — execute o SQL dourado e o SQL gerado, compare as linhas. Nenhum LLM está dentro do número, então ele é reproduzível e não pode variar com um prompt. Os avaliadores LLM são estritamente consultivos: eles fazem a triagem da pilha ambígua e explicam por que uma linha é suspeita, mas nunca alteram a precisão reportada. Apenas uma revisão humana é autoritativa.
-
Disciplina real de treino/teste.
benchmarks/test.yamlé um conjunto reservado selado. O ciclo de desenvolvimento — síntese, coach, otimizador — nunca pode lê-lo; isso é aplicado como uma fronteira de código (uma regra de import-linter no CI), não uma convenção que você precisa lembrar. Até a calibração do avaliador é dividida por escopo, para que o feedback de desenvolvimento não vaze para o avaliador de teste. O número principal é sempre o do conjunto reservado, com a pontuação de desenvolvimento exibida ao lado para que a lacuna fique visível. -
Resistência a Goodhart por construção. O Coach otimiza o contexto contra o conjunto de desenvolvimento — mas estruturalmente não pode alterar o número de precisão determinístico, é direcionado para longe de memorizar respostas do benchmark (corrija a semântica, não o prompt), e avisa que os ganhos de desenvolvimento são não validados até uma reavaliação no conjunto reservado. Otimizar e medir no mesmo conjunto é treinar no conjunto de teste; o sqbyl torna esse erro difícil de cometer.
-
Incerteza calibrada e honesta. Um pequeno conjunto de avaliação é propenso a ruído, então a precisão carrega um intervalo de confiança de Wilson — uma mudança de 1–2 perguntas em 30 não é apresentada como uma tendência. Uma pontuação ao vivo de concordância avaliador↔humano diz exatamente o quanto confiar no avaliador, e é rotulada como enviesada por seleção em vez de superestimada. A confiança autorreportada do próprio modelo é rotulada como "não verificada" — nunca apresentada como calibrada.
-
Reprodutibilidade e proveniência. Cada execução pontuada é carimbada com a versão do modelo por função e o estado de calibração que a moldou. Uma pontuação nunca é divorciada do que a produziu — o scorecard de lançamento registra os modelos exatos nos quais o número foi obtido, e o runtime avisa sobre incompatibilidade de modelo ou esquema no carregamento.
-
Humano no circuito, em todos os lugares. Um padrão unificador percorre o avaliador, a síntese de benchmark e o Coach: o LLM propõe, o humano dispõe, e a correção melhora o sistema. Cada veredito do avaliador, pergunta sintetizada e correção é uma proposta revisável, não um fato consumado.
-
Honestidade de custo. O trabalho gratuito e determinístico roda primeiro a $0 (conectar, perfil, inferir junções). O trabalho pago é estimado antes, medido ao vivo e limitado por
--budget. A economia do agente é tão legível quanto sua precisão.
A versão curta: o sqbyl ajuda você a lançar um agente de texto-para-SQL cuja precisão você pode realmente reportar — porque o número é determinístico, reservado, carimbado com proveniência e defendido contra as maneiras como os loops de avaliação silenciosamente mentem para você.
Arquitetura: dois pacotes, uma seta de dependência
O sqbyl é distribuído como dois pacotes, para que o que você usa no desenvolvimento não seja o que você implanta:
sqbyl-runtime— o runtime mínimo e leve em dependências que você incorpora em produção: carregar um release,ask(), logging estruturado. Sem stack web, sem maquinário de avaliação.sqbyl— o kit completo de desenvolvimento: inspecionar, perfil, anotar, sintetizar, o harness de avaliação, o Coach, avaliadores LLM, o console de revisão, o otimizador e o construtor de releases.
sqbyl depende de sqbyl-runtime, nunca o contrário — uma fronteira unidirecional aplicada no CI (import-linter). Nenhum maquinário de desenvolvimento/avaliação pode vazar para o que roda no seu aplicativo. Você itera com o kit; você envia o runtime. Ambos são estritamente tipados (py.typed) e baseados em pydantic, e a interface de release é um JSON documentado e schema_version'd que um terceiro pode ler sem o sqbyl.
Para quem é isso
Você está colocando uma superfície de linguagem natural para SQL sobre seu próprio warehouse — uma ferramenta analítica interna ou um recurso de produto — e precisa de um número de precisão que possa defender, além de um sistema que possa ler, editar e versionar. Você trabalha com git, um banco de dados SQL e YAML. Você tem (ou pode provisionar) uma função de banco de dados somente leitura e uma chave de provedor de LLM (Anthropic ou OpenAI).
Instalação
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
Os SDKs do provedor são extras opcionais — o sqbyl é neutro em relação ao provedor, então escolha o que usará
([anthropic] ou [openai]) e instale apenas esse. Uma instalação simples de pip install sqbyl instala o
kit sem um SDK de provedor.
Desenvolvendo no próprio sqbyl? Veja CONTRIBUTING.md para a configuração a partir do código-fonte
com uv; mantenedores cortam releases via PUBLISHING.md.
Início rápido
Aponte o sqbyl para um banco de dados e uma chave:
export ANTHROPIC_API_KEY=sk-ant-...
export DATABASE_URL=postgresql://readonly_user@warehouse.internal/analytics # use a read-only role
Em seguida, execute a configuração guiada. Sem sqbyl.yaml para escrever manualmente — init o cria para você se estiver ausente. Ele faz o trabalho gratuito e determinístico primeiro (conectar, ler esquema, perfil de cada coluna com SQL somente leitura), verifica sua chave de provedor ($0), mostra um plano com custos e só gasta após você confirmar:
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
Você cai em uma fila de revisão — não em uma página em branco — mostrando apenas as decisões que um humano precisa tomar (por exemplo, "o que conta como um cliente ativo?"), cada uma com um padrão sensato pré-preenchido. Aceite seu caminho até a meta de prontidão e então:
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 um JSON portátil — o "cérebro" do agente (semântica, instruções, exemplos, prompts de avaliador, scorecard). O modelo, a chave e o banco de dados não são embutidos; eles são injetados onde quer que ele rode.
Para a narrativa completa, leia sqbyl-user-journey.md.
Enviando um release
Produção é "apenas um modelo com logs." O maquinário de desenvolvimento (avaliação, síntese, coach, console) não vem junto — você incorpora o runtime leve:
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}
Ele herda a autenticação, o pool de conexões e a observabilidade do seu aplicativo. sqbyl run <release> / sqbyl serve existem para chamadores não-Python e exposição HTTP rápida, mas intencionalmente não são endurecidos — não coloque sqbyl serve na internet aberta.
Respostas em linguagem natural (opt-in). ask() retorna dados estruturados — sql, columns, rows — que permanecem a resposta autoritativa. Para uma superfície de chat/assistente que também quer uma frase ("Há 1.284 pedidos."), habilite a narração: load(..., narrate=True) (ou por chamada, agent.ask(q, narrate=True)). Isso adiciona uma chamada final de sumarização, fundamentada estritamente nas linhas executadas, e preenche result.answer. Está desativado por padrão para que o runtime determinístico e $0-por-padrão permaneça inalterado; a chamada é medida como sua própria função narrate (fixe um modelo mais barato com narration_model=), e a frase narrada é uma conveniência sobre as linhas, nunca um substituto para elas. O CLI espelha isso com sqbyl ask "…" --narrate.
Assíncrono e concorrência
agent.ask() é síncrono e bloqueante (uma ida e volta de LLM mais consultas de banco), mas um único agent carregado é seguro para chamar concorrentemente — o engine de banco agrupa conexões por thread, o cliente do provedor (Anthropic ou OpenAI) é thread-safe e as gravações de trace são bloqueadas. Então, sob um threadpool, ele atende solicitações concorrentes corretamente.
A única regra para um servidor assíncrono: execute ask() fora do event loop, não o chame dentro de um async def diretamente (isso bloqueia o loop para toda a solicitação).
# 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)
Limite a concorrência (threadpool + tamanho do pool de banco) como faria para qualquer carga de trabalho bloqueante. Um runtime nativamente assíncrono (cliente de provedor assíncrono + banco assíncrono) não é fornecido — o padrão de threadpool é o caminho suportado.
Estrutura do projeto
Um projeto sqbyl é um diretório nativo de git com arquivos 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)
A divisão desenvolvimento/teste é estrutural: otimizar e medir no mesmo conjunto é treinar no conjunto de teste, então a precisão principal é sempre o número do conjunto reservado. Referência completa do formato em o spec de design, §4.
Referência 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 cria sqbyl.yaml para você quando não há um (interativamente, ou um modelo sob --auto), e executa uma verificação de credencial $0 antes de citar um plano.
Comandos à la carte por etapa (introspect — com --sync para adicionar novas colunas de banco sem perder anotações — profile, annotate, judge, runs, serve, run) são documentados em o spec, §10.
Configuração
A configuração do projeto vive em sqbyl.yaml; segredos são referenciados por nome de env:, não embutidos:
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 em vez disso, alterne as três linhas do provedor (todo o resto é idêntico):
model:
provider: openai
api_key: env:OPENAI_API_KEY
default: gpt-5
O sqbyl usa um único provedor para tudo — agente, avaliadores e Coach — então você escolhe um e ele se aplica em todo o ciclo (sem mistura). Veja §4 do spec para o manifesto completo, incluindo fixação de modelo por função e alternâncias de automação. Para rotear por um proxy corporativo ou gateway de IA, defina model.base_url (ou passe base_url= para o runtime load()) — nenhuma outra alteração é necessária.
Segurança e tratamento de dados
A seção que um revisor de segurança procurará:
- Somente leitura por padrão. O sqbyl recusa operações não-
SELECTna camada SQL e, ao conectar, inspeciona os privilégios da credencial e avisa (com uma correção sugerida) se ela puder gravar. O agente e o Coach nunca emitem DDL/DML. Aponte-o para uma função dedicada somente de leitura. - Segredos por referência. Strings de conexão e chaves de API são indirecionadas por
env:— nunca gravadas em arquivos do projeto, releases ou traces. - Seus dados continuam seus. Linhas de resultados de consultas não são persistidas em arquivos commitados do projeto ou traces; SQL importado que contenha valores literais é sinalizado para revisão antes de ser incorporado. Um release é o cérebro do agente — semântica, prompts, exemplos — nunca linhas.
- Telemetria local-first e exportável. Traces seguem as convenções GenAI do OpenTelemetry e são gravados em
.sqbyl/; exporte-os para qualquer backend OTel quando quiser. - CI nunca gasta tokens. Todo caminho de LLM roda contra uma costura de mock / record-replay, então a integração contínua nunca chama a API. Dependências são verificadas quanto a vulnerabilidades (
pip-audit), licenças e atualizadas via Dependabot. - O endurecimento de produção é seu. Você incorpora o runtime no seu próprio serviço, herdando sua autenticação, TLS, pooling e rate limiting.
sqbyl serveé uma conveniência de desenvolvimento em localhost, não um servidor de produção — não o exponha.
Governança, RBAC, linhagem e gerenciamento de catálogo são deliberadamente não reimplementados — essa é a função do seu banco de dados (não-objetivos).
Requisitos
- Python (gerenciado via
uv) - Uma chave de API de provedor de LLM — Anthropic (
ANTHROPIC_API_KEY) ou OpenAI (OPENAI_API_KEY) - Um banco de dados SQL, acessível somente para leitura (
DATABASE_URL). DuckDB e Postgres são os dialetos de primeira classe; SQLite, MySQL, Snowflake e BigQuery são suportados por trás de uma costura de dialeto.
Status do projeto
A sequência completa de build em sqbyl-implementation-plan.md (Fases 0–9) está concluída: cada capacidade abaixo está construída, testada e mesclada.
| Capacidade | Estado |
|---|---|
Engine: introspect + profile + runtime do agente (sqbyl ask) | ✅ construído |
Conjunto dourado + harness de avaliação (synth, review, eval) | ✅ construído |
| Coach + juízes de LLM | ✅ construído |
init guiado, orquestrador, maquinário de custo | ✅ construído |
| Release + runtime + otimizador | ✅ construído |
| Mais dialetos, serve, exports, importadores | ✅ construído |
Enquanto estiver em pré-1.0, formatos de comandos e arquivos ainda podem mudar com bumps de versão menor (veja SemVer e o changelog).
Documentação
A especificação é o porquê, a jornada é uma primeira execução narrada, e o plano é um registro de como foi construído:
sqbyl-design-spec.md— a especificação completa do design do produto.sqbyl-user-journey.md— uma primeira execução narrada, do início ao lançamento.sqbyl-implementation-plan.md— a sequência de build em fases (Fases 0–9, concluída).
Licença
MIT © Jack Werner