Agente que responde perguntas em portugues sobre um banco de dados: recebe a pergunta em linguagem natural, escreve o SQL, executa (somente leitura) e responde com base nos numeros que vieram do banco.
Usa a API da Anthropic (Claude) com tool use: o modelo nao devolve so um
texto com SQL dentro; ele chama uma ferramenta rodar_sql, e eu executo a
query passando pela minha propria validacao antes de tocar o banco. Ou seja, a
query gerada pelo modelo e tratada como entrada nao-confiavel.
pergunta (PT) -> Claude escreve SQL -> ferramenta rodar_sql
|
agente/banco.py valida
(so SELECT/WITH) e executa
|
resultado <- linhas do sqlite -> Claude responde (PT)
agente/agente.py: o loop do agente (Messages API + tool use).agente/banco.py: introspeccao do schema e execucao somente leitura (bloqueia INSERT/UPDATE/DELETE/DROP etc.).agente/config.py: modelo, banco e leitura da chave via variavel de ambiente (nenhuma chave no codigo).criar_banco.py: monta umloja.dbde exemplo pra testar.
pip install -r requirements.txt
# chave da Anthropic (nao fica no codigo)
export ANTHROPIC_API_KEY="sk-ant-..." # bash
# $env:ANTHROPIC_API_KEY = "sk-ant-..." # PowerShell
python criar_banco.py # cria loja.db de exemplo
python main.py "quanto cada UF faturou em pedidos entregues?"Sem argumento, python main.py entra em modo interativo.
pip install pytest
pytestOs testes cobrem a parte critica: o guarda-corpo de leitura. Como o SQL vem de
um LLM, ele e tratado como entrada nao-confiavel, e os testes garantem que
INSERT/UPDATE/DELETE/DROP (e ate SELECT; DROP encadeado) sejam barrados antes
de tocar o banco.
- "quantos clientes tem por UF?"
- "qual o produto mais vendido em quantidade?"
- "qual o faturamento total de pedidos entregues, ignorando os cancelados?"
- "quem sao os 3 clientes que mais gastaram?"
- sqlite de proposito: qualquer um roda sem instalar servidor de banco.
- Schema lido do banco em tempo de execucao (
PRAGMA table_info), nao escrito na mao. Se o banco mudar, o agente acompanha. - Guarda-corpo de leitura: a validacao rejeita qualquer comando que nao seja
SELECT/WITH. O modelo pode escrever a query, mas nao consegue alterar dados. - Resultado truncado em 50 linhas antes de voltar pro modelo, pra nao estourar o contexto em perguntas do tipo "lista tudo".
- Banco de exemplo pequeno e ficticio: o foco e o agente, nao os dados.
- So leitura: nao serve pra pipelines de escrita.
- Uma pergunta ambigua pode gerar uma query que responde algo diferente do que se queria; o agente mostra o SQL que rodou pra dar pra conferir.