Negócios

    Text-to-SQL Seguro em Produção: AST Parsing e RLS

    Como implementar Text-to-SQL seguro em produção com parsing de AST no SQLGlot, Row-Level Security no PostgreSQL e infraestrutura segregada via Co-Building.

    2026-09-0911 minEquipe MaxVision
    CLIP_001 · DJI O4FPV · 4K · 60FPS
    ESTRATÉGIA (SLOT 2) · 2026.09.09

    Conectar agentes de inteligência artificial a bancos relacionais corporativos exige defesas determinísticas. Executar consultas geradas por modelos de linguagem sem validação intermediária expõe empresas a mutações acidentais. A solução é arquitetar pipelines blindados com parsing de AST e isolamento no kernel do banco.

    A promessa de consultar bases de dados em linguagem natural atrai líderes de tecnologia. Assistentes inteligentes capazes de extrair métricas de faturamento reduzem filas em equipes de dados.

    Contudo, a distância entre protótipos rápidos e sistemas seguros em produção é imensa. Modelos de linguagem operam sob probabilidade estatística, não sob regras estritas de compiladores.

    Conceder privilégios diretos sobre bancos transacionais primários cria vulnerabilidades graves. Sem guardrails formais, incidentes operacionais tornam-se inevitáveis.

    O que torna implementações ingênuas de Text-to-SQL vulneráveis em produção?

    Implementações ingênuas de Text-to-SQL falham ao repassar esquemas DDL brutos para modelos de linguagem sem validação formal. Essa prática expõe o banco de dados a mutações destrutivas, injeções de prompt e vazamento de dados confidenciais.

    Tutoriais superficiais sugerem concatenar tabelas inteiras no prompt do sistema. Em seguida, executam a string retornada diretamente através de conexões genéricas de aplicação.

    Essa abordagem colide com limites documentados pela ciência da computação. No benchmark BIRD-SQL (NeurIPS 2023), modelos de ponta alcançaram apenas 54,89% de acurácia em bancos reais.

    Em contrapartida, engenheiros humanos atingem 92,96% de acerto nas mesmas tarefas. O clássico Spider Benchmark (EMNLP 2018) já comprovava que consultas complexas exigem vinculação semântica estruturada.

    Estudos da RAND Corporation indicam que mais de 80% dos projetos corporativos de inteligência artificial falham. A falta de engenharia defensiva figura entre as causas centrais desse insucesso.

    Quais são os quatro vetores críticos de falha em agentes de banco de dados?

    Os quatro vetores críticos de falha são mutação destrutiva de dados, injeção indireta de prompt, omissão de filtros multi-tenant e negação de serviço.

    Essas falhas decorrem da natureza probabilística dos modelos generativos. Sem intermediários determinísticos de software, a segurança do banco fica comprometida:

    • Mutações Destrutivas (DDL/DML): Usuários maliciosos ou comandos ambíguos podem induzir o modelo a emitir instruções DROP TABLE ou UPDATE sem restrições.
    • Injeção Indireta de Prompt (OWASP LLM01): Registros armazenados no banco contendo instruções hostis podem manipular turnos futuros do agente.
    • Vazamento Cross-Tenant (OWASP LLM02): Em esquemas multi-tenant compartilhados, o modelo omite com frequência a coluna tenant_id em subconsultas e junções.
    • Exaustão de Recursos e DoS: Junções cartesianas e varreduras sem índices consomem toda a CPU e travam as conexões da aplicação.

    A tabela abaixo compara o comportamento de fluxos ingênuos contra as defesas obrigatórias em produção:

    Vetor de RiscoFluxo IngênuoDefesa Determinística
    Injeção DiretaExecuta comandos arbitrários do LLMParser de AST rejeita nós fora de SELECT
    Injeção IndiretaRegistros do banco manipulam o agenteSanitização de saídas e isolamento de contexto
    Vazamento Multi-TenantConfia em instruções textuais de promptAST Rewrite forçado e Row-Level Security
    Negação de ServiçoQueries pesadas travam nó primárioRéplica segregada com PgBouncer e timeouts

    Como funciona o pipeline de defesa em 4 camadas da MaxVision?

    O pipeline de defesa determinística em quatro camadas da MaxVision substitui a confiança no modelo por garantias de software e kernel. O LLM atua apenas como tradutor semântico, enquanto componentes rígidos controlam o acesso.

    Diagrama esquemático do pipeline determinístico em 4 camadas para Text-to-SQL seguro

    A arquitetura opera em quatro etapas sequenciais e desacopladas:

    1. Camada 1 (Schema Pruning & Semantic Catalog): Filtra o esquema corporativo e injeta apenas as tabelas essenciais para a pergunta.
    2. Camada 2 (Validação e Reescrita de AST): Converte a string SQL em árvore sintática com SQLGlot e injeta filtros de tenant.
    3. Camada 3 (Isolamento no Kernel do PostgreSQL): Executa a consulta via usuário app_readonly com Row-Level Security forçado.
    4. Camada 4 (Infraestrutura Segregada e Hardening): Despacha a requisição para réplicas de leitura com controle prévio de custo analítico.

    Camada 1: como o Schema Pruning semântico eleva a acurácia das consultas?

    O Schema Pruning semântico eleva a acurácia ao injetar no prompt apenas as tabelas estritamente necessárias para a pergunta. Essa filtragem cirúrgica reduz o tamanho do contexto em mais de 85%.

    Colar dezenas de tabelas no prompt causa o efeito lost-in-the-middle. O modelo perde foco e alucina colunas que não existem no banco físico.

    A MaxVision resolve esse gargalo indexando metadados de tabelas e colunas com busca híbrida. O algoritmo combina BM25 e busca vetorial para selecionar apenas 3 a 7 tabelas relevantes.

    O pipeline também injeta Golden Queries calibradas. Essas consultas são exemplos reais validados previamente por engenheiros sêniores para perguntas similares do negócio.

    Pesquisas sobre o DIN-SQL (NeurIPS 2023) confirmam que decompor etapas e fornecer contexto enxuto eleva a acurácia para 85,3%. Esse resultado supera gerações diretas monolíticas.

    Camada 2: como a validação de AST com SQLGlot intercepta comandos perigosos?

    A validação de AST com SQLGlot intercepta comandos perigosos ao transformar a string gerada pelo modelo em uma Árvore Sintática Abstrata. Qualquer instrução fora de nós de leitura pura é rejeitada antes da rede.

    A saída do modelo é tratada como dado não confiável. O validador inspeciona a gramática formal e reescreve a árvore para injetar identificadores obrigatórios:

    import sqlglot
    from sqlglot import exp
    
    class InsecureQueryException(Exception):
        """Exceção levantada quando uma consulta viola políticas de segurança."""
        pass
    
    class SafeSQLTransformer:
        def __init__(self, tenant_id: str, tenant_col: str = "tenant_id"):
            self.tenant_id = tenant_id
            self.tenant_col = tenant_col
            self.forbidden_tables = {
                "information_schema", "pg_catalog", "pg_tables",
                "pg_views", "pg_user", "pg_shadow", "auth_tokens"
            }
    
        def validate_and_rewrite(self, raw_sql: str) -> str:
            try:
                statements = sqlglot.parse(raw_sql, read="postgres")
            except Exception as error:
                raise InsecureQueryException(f"Sintaxe SQL inválida: {str(error)}")
    
            if len(statements) != 1:
                raise InsecureQueryException("Múltiplos comandos encadeados são proibidos.")
    
            expression = statements[0]
    
            if not isinstance(expression, exp.Select):
                raise InsecureQueryException(f"Comando {expression.key.upper()} não permitido.")
    
            for node in expression.walk():
                if isinstance(node, (exp.Insert, exp.Update, exp.Delete, exp.Drop, exp.Create, exp.Alter)):
                    raise InsecureQueryException(f"Nó de mutação detectado: {node.key}")
    
                if isinstance(node, exp.Table):
                    table_name = node.name.lower()
                    db_name = node.db.lower() if node.db else ""
                    if table_name in self.forbidden_tables or db_name in {"pg_catalog", "information_schema"}:
                        raise InsecureQueryException(f"Acesso negado ao catálogo interno: {table_name}")
    
            return self._inject_tenant_predicate(expression)
    
        def _inject_tenant_predicate(self, expression: exp.Select) -> str:
            for select_node in expression.find_all(exp.Select):
                tables = [t.name for t in select_node.find_all(exp.Table)]
                if not tables:
                    continue
    
                tenant_condition = exp.EQ(
                    this=exp.to_column(self.tenant_col),
                    expression=exp.Literal.string(self.tenant_id)
                )
    
                existing_where = select_node.args.get("where")
                if existing_where:
                    existing_where.set("this", exp.And(this=existing_where.this, expression=tenant_condition))
                else:
                    select_node.set("where", exp.Where(this=tenant_condition))
    
            return expression.sql(dialect="postgres")
    

    Esse validador não depende de regex frágeis. Ele utiliza o motor do SQLGlot para manipular a árvore sintática de forma robusta e determinística.

    Camada 3: como o Row-Level Security no PostgreSQL garante isolamento absoluto?

    O Row-Level Security no PostgreSQL garante isolamento absoluto ao aplicar regras de segurança diretamente nas páginas de dados do banco relacional. Nenhuma falha na aplicação consegue contornar a filtragem do kernel.

    A terceira camada estabelece defesa em profundidade caso o validador de AST encontre um edge case imprevisto.

    Primeiro, a conexão utiliza uma role dedicada sem privilégios de escrita ou modificação estrutural:

    -- Criação de role restrita de leitura
    CREATE ROLE app_readonly WITH LOGIN PASSWORD 'credencial_rotativa_segura'
        NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT;
    
    ALTER ROLE app_readonly SET statement_timeout = '3000ms';
    ALTER ROLE app_readonly SET lock_timeout = '1000ms';
    ALTER ROLE app_readonly SET work_mem = '32MB';
    
    GRANT CONNECT ON DATABASE analytics_db TO app_readonly;
    GRANT USAGE ON SCHEMA public TO app_readonly;
    GRANT SELECT ON ALL TABLES IN SCHEMA public TO app_readonly;
    REVOKE ALL ON SCHEMA pg_catalog FROM app_readonly;
    

    Em seguida, o Row-Level Security (PostgreSQL Documentation) é ativado de forma impositiva nas tabelas:

    ALTER TABLE public.orders ENABLE ROW LEVEL SECURITY;
    ALTER TABLE public.orders FORCE ROW LEVEL SECURITY;
    
    CREATE POLICY tenant_isolation_policy ON public.orders
        AS RESTRICTIVE
        FOR SELECT
        TO app_readonly
        USING (tenant_id = current_setting('app.current_tenant_id', true));
    

    Cada consulta executa dentro de uma transação somente leitura com SET LOCAL:

    BEGIN TRANSACTION READ ONLY;
    SET LOCAL app.current_tenant_id = 'cliente_empresa_42';
    SELECT id, total_amount, status FROM orders WHERE status = 'delivered';
    COMMIT;
    

    O banco descarta a variável ao término da transação. Isso previne contaminação de conexões reaproveitadas no pool.

    Camada 4: como segregar réplicas de leitura e evitar negação de serviço?

    A segregação em réplicas de leitura evita negação de serviço isolando o banco transacional primário de consultas analíticas volumosas. Essa divisão assegura que o sistema de vendas continue respondendo rapidamente.

    Consultas formuladas por modelos de linguagem possuem comportamento imprevisível. Junções entre tabelas sem filtros adequados podem disparar leituras sequenciais gigantescas.

    Para proteger a infraestrutura, o pool com PgBouncer opera no modo de transação. O backend também avalia o custo com EXPLAIN (FORMAT JSON) antes da execução:

    import { Pool, PoolClient } from 'pg';
    
    const replicaPool = new Pool({
      host: process.env.DB_READ_REPLICA_HOST,
      port: 6432,
      user: 'app_readonly',
      password: process.env.DB_READONLY_PASSWORD,
      database: 'analytics_db',
      max: 20,
      idleTimeoutMillis: 10000,
      connectionTimeoutMillis: 2000,
    });
    
    const MAX_SAFE_PLAN_COST = 15000.0;
    
    interface QueryPlanOutput {
      Plan: {
        'Total Cost': number;
        'Plan Rows': number;
        'Node Type': string;
      };
    }
    
    export async function executeSafeQuery(sql: string, tenantId: string): Promise<Record<string, unknown>[]> {
      const client: PoolClient = await replicaPool.connect();
    
      try {
        await client.query('BEGIN TRANSACTION READ ONLY');
        await client.query('SELECT set_config($1, $2, true)', ['app.current_tenant_id', tenantId]);
    
        const planData = await client.query(`EXPLAIN (FORMAT JSON) ${sql}`);
        const planInfo: QueryPlanOutput = planData.rows[0]['QUERY PLAN'][0];
    
        if (planInfo.Plan['Total Cost'] > MAX_SAFE_PLAN_COST) {
          throw new Error('Consulta abortada: custo computacional excede o limite de segurança.');
        }
    
        const result = await client.query(sql);
        await client.query('COMMIT');
        return result.rows;
      } catch (error) {
        await client.query('ROLLBACK');
        throw error;
      } finally {
        client.release();
      }
    }
    

    Se o plano estimado ultrapassar o limiar estabelecido, a operação é interrompida imediatamente. A CPU da réplica permanece preservada.

    Fábrica de software vs. consultoria tradicional vs. Co-Building 1:1: qual a diferença?

    A diferença central está na propriedade do código, na velocidade de entrega e na transferência real de conhecimento de engenharia. Fábricas geram caixas-pretas e consultorias conceituais entregam slides teóricos, enquanto o Co-Building constrói software em produção com o time do cliente.

    Bancada de desenvolvimento de engenharia de software com hardware dedicado e documentação técnica

    A contratação convencional de serviços técnicos frustra lideranças focadas em resultados práticos:

    • Fábricas de Software: Desenvolvem projetos em ambientes fechados e cobram por hora. O cliente herda código confuso e dependência contínua de suporte externo.
    • Consultorias Tradicionais: Focam em relatórios teóricos de governança e diagnósticos conceituais. Gastam meses e orçamentos elevados sem entregar código funcional em produção.
    • Co-Building 1:1 da MaxVision: O fundador técnico atua lado a lado com sua equipe técnica. Todo o código é commitado diretamente no repositório da sua organização.

    A tabela compara os formatos de contratação disponíveis no mercado de tecnologia:

    CritérioFábrica de SoftwareConsultoria TradicionalCo-Building 1:1 MaxVision
    ModeloTerceirização fechadaRelatórios conceituaisPair programming com fundador
    CódigoRepositório da fábricaSem código produzidoRepositório oficial do cliente
    InfraestruturaChaves de terceirosNão aplicávelSoberania total (BYOK)
    ParticipaçãoReuniões de statusWorkshops teóricosDesenvolvimento conjunto ao vivo
    Prazo90 a 180 dias60 a 120 dias15 dias corridos cravados
    InvestimentoR$ 60.000 a R$ 200.000+R$ 50.000 a R$ 180.000+R$ 1.997 fixos
    VagasEscala irrestritaMúltiplas contasExclusivo: 2 vagas por mês

    Como funciona o Programa MaxVision de Co-Building de 15 dias?

    O Programa MaxVision de Co-Building de 15 dias é uma imersão técnica 1:1 para construir um agente de inteligência artificial em produção. O fundador da produtora desenvolve a solução diretamente no repositório oficial da sua empresa.

    O formato segue quatro pilares práticos e transparentes:

    1. Soberania Técnica com BYOK (Bring Your Own Key): O desenvolvimento ocorre nas suas contas de nuvem e bancos relacionais. Você mantém controle total sobre chaves e código.
    2. Duas Sessões Semanais de Trabalho ao Vivo: O fundador técnico programa junto com seus desenvolvedores. Resolvemos modelagem de AST, políticas de RLS e testes práticos.
    3. Escopo Focado (Thin Slice): Entregamos uma fatia vertical completa em duas semanas. O agente de Text-to-SQL entra no ar com guardrails auditados de segurança.
    4. Alocação Exclusiva e Seletiva: Para garantir qualidade sênior contínua, abrimos apenas 2 vagas por mês. O investimento é fixado em R$ 1.997.

    Empresas interessadas submetem uma aplicação na página oficial /maxvision. Analisamos o desafio técnico e a infraestrutura da organização antes de confirmar a vaga.

    Construir agentes seguros não exige aceitar caixas-pretas nem desperdiçar recursos com relatórios teóricos. O Co-Building 1:1 coloca sua empresa no controle técnico da inteligência artificial.

    TAGS
    • Text-to-SQL
    • Consultoria de IA
    • Co-Building
    • Engenharia de Software
    • PostgreSQL
    • Segurança em IA
    • fallback-estrategia
    Mascote da MaxVision para contato rápido no WhatsAppFale agora pelo WhatsApp