0Pricing
AI Agents · Aula

Como funcionam os agentes de NL para SQL

Injeção de esquema, geração e execução de consultas e formatação de resultados.

Como funcionam os agentes de NL para SQL é uma aula grátis de AI Agents no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Agents, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Agents inclui 4 aulas no total.

O que é um agente de NL para SQL

Um agente de linguagem natural para SQL traduz perguntas em linguagem comum para consultas SQL, executa essas consultas em um banco de dados e retorna respostas compreensíveis.

Em vez de escrever SELECT COUNT(*) FROM orders WHERE status='pending', os usuários simplesmente perguntam: "Quantos pedidos pendentes temos?"

A arquitetura principal

Todo agente de NL para SQL segue o mesmo fluxo:

  1. Injeção do esquema — injeta a estrutura do banco de dados no prompt
  2. O LLM gera SQL — o modelo produz uma consulta
  3. Executar — executa a consulta no banco de dados
  4. Formatar os resultados — transforma as linhas em texto legível
  5. Retornar a resposta — responde ao usuário
# High-level pipeline
def nl_to_sql_agent(user_question, db_connection):
    schema = get_schema(db_connection)
    sql = llm_generate_sql(user_question, schema)
    rows = execute_query(db_connection, sql)
    answer = format_results(rows, user_question)
    return answer

Explicação da injeção do esquema

O LLM não tem conhecimento da estrutura do seu banco de dados. Você precisa injetar o esquema em todos os prompts para que o modelo saiba quais tabelas e colunas existem.

Uma descrição compacta do esquema informa ao modelo: "A tabela orders tem as colunas: id, user_id, status, total, created_at."

def build_schema_prompt(schema_info):
    lines = []
    for table in schema_info:
        cols = ', '.join(
            f"{c['name']} ({c['type']})"
            for c in table['columns']
        )
        lines.append(f"Table {table['name']}: {cols}")
    return '\n'.join(lines)

# Output:
# Table users: id (INT), email (VARCHAR), created_at (TIMESTAMP)
# Table orders: id (INT), user_id (INT), status (VARCHAR), total (FLOAT)

if __name__ == '__main__':
    demo_schema = [
        {'name': 'users', 'columns': [{'name': 'id', 'type': 'INT'}, {'name': 'email', 'type': 'VARCHAR'}]},
        {'name': 'orders', 'columns': [{'name': 'id', 'type': 'INT'}, {'name': 'user_id', 'type': 'INT'}]},
    ]
    print(build_schema_prompt(demo_schema))

Prompt para geração de SQL pelo LLM

O prompt deve fornecer ao LLM três elementos: o esquema, a pergunta e instruções explícitas para retornar apenas SQL válido.

Deixar claro que a consulta deve conter somente SELECT e indicar o dialeto SQL de destino (PostgreSQL, MySQL, SQLite) é essencial para a segurança e a correção.

SYSTEM_PROMPT = '''You are a SQL expert. Given a database schema and a question,
generate a valid {dialect} SELECT query. Return ONLY the SQL query, no explanation.
Do not use INSERT, UPDATE, DELETE, or DROP.

Schema:
{schema}
'''

def llm_generate_sql(question, schema, dialect='PostgreSQL'):
    prompt = SYSTEM_PROMPT.format(schema=schema, dialect=dialect)
    response = client.chat.completions.create(
        model='gpt-4o',
        messages=[
            {'role': 'system', 'content': prompt},
            {'role': 'user', 'content': question}
        ]
    )
    return response.choices[0].message.content.strip()

Executando o SQL gerado

Depois que o LLM retorna o SQL, você o executa no banco de dados real. Use consultas parametrizadas sempre que possível e capture as exceções — o LLM pode produzir SQL inválido.

Envolver a execução em um bloco de tratamento de exceções permite tentar novamente com uma indicação do erro enviada de volta ao LLM.

import psycopg2

def execute_query(conn, sql):
    try:
        with conn.cursor() as cur:
            cur.execute(sql)
            columns = [desc[0] for desc in cur.description]
            rows = cur.fetchmany(100)  # limit rows
            return {'columns': columns, 'rows': rows}
    except psycopg2.Error as e:
        return {'error': str(e), 'sql': sql}

Formatando os resultados para o usuário

As linhas brutas do banco de dados não são fáceis de entender para o usuário. O agente precisa convertê-las em uma resposta em linguagem natural.

Para conjuntos pequenos de resultados, envie as linhas de volta ao LLM para interpretação. Para conjuntos grandes, calcule primeiro estatísticas resumidas.

def format_results(result, original_question):
    if 'error' in result:
        return f'Query failed: {result["error"]}'

    rows = result['rows']
    columns = result['columns']

    if not rows:
        return 'No results found.'

    # For simple counts/aggregates — just return the value
    if len(columns) == 1 and len(rows) == 1:
        return f'Result: {rows[0][0]}'

    # For multi-row results — summarize
    summary = f'Found {len(rows)} rows.\n'
    for row in rows[:5]:  # show first 5
        summary += ', '.join(f'{columns[i]}: {row[i]}' for i in range(len(columns))) + '\n'
    return summary

if __name__ == '__main__':
    demo_result = {'rows': [[42]], 'columns': ['count']}
    print(format_results(demo_result, 'How many users signed up?'))
    demo_result2 = {'rows': [], 'columns': ['id']}
    print(format_results(demo_result2, 'Any orders today?'))

Por que NL para SQL é difícil: ambiguidade

Ambiguidade é o maior desafio. Considere: "Mostre-me os melhores clientes."

  • Os melhores por receita? Por quantidade de pedidos? Por recência?
  • Do último mês? De todos os períodos?
  • Os 10 melhores? Os 100 melhores?

Os seres humanos entendem o contexto; os LLMs fazem suposições. Os agentes precisam de estratégias para lidar com perguntas ambíguas ou esclarecê-las.

AMBIGUITY_PROMPT = '''If the question is ambiguous, respond with JSON:
{"needs_clarification": true, "question": "your clarifying question"}

If clear, respond with the SQL query directly.

User question: {question}
'''

def generate_or_clarify(question, schema):
    response = llm_call(AMBIGUITY_PROMPT.format(
        question=question, schema=schema
    ))
    if '"needs_clarification"' in response:
        import json
        return json.loads(response)
    return {'sql': response}

Por que NL para SQL é difícil: tamanho do esquema

Bancos de dados empresariais podem ter centenas de tabelas e milhares de colunas. Injetar o esquema completo ultrapassaria a janela de contexto do LLM.

As soluções incluem: pesquisa no esquema (incorporar descrições de tabelas e recuperar as relevantes), filtragem de tabelas (perguntar primeiro ao LLM de quais tabelas ele precisa) e compressão do esquema (omitir colunas de índice e de auditoria).

# Two-phase approach for large schemas
def get_relevant_tables(question, all_tables):
    prompt = f'''Given these tables: {all_tables}
Which 3-5 tables are most relevant to answer: "{question}"?
Return a JSON list of table names only.'''
    response = llm_call(prompt)
    import json
    return json.loads(response)

def nl_to_sql_large_db(question, conn):
    all_tables = list_all_tables(conn)  # just names
    relevant = get_relevant_tables(question, all_tables)
    schema = get_schema_for_tables(conn, relevant)
    return llm_generate_sql(question, schema)

Por que NL para SQL é difícil: diferenças entre dialetos SQL

SQL não é universal. LIMIT no PostgreSQL/MySQL se torna TOP no SQL Server. As funções de data variam entre os bancos de dados. O LLM precisa saber qual dialeto usar.

Sempre inclua o dialeto de destino no prompt do sistema e considere adicionar exemplos específicos do dialeto em prompts com poucos exemplos.

DIALECT_EXAMPLES = {
    'postgresql': 'Use LIMIT for row limits. Use NOW() for current time.',
    'mysql': 'Use LIMIT for row limits. Use NOW() for current time.',
    'sqlite': 'Use LIMIT. Use datetime("now") for current time.',
    'mssql': 'Use TOP N for row limits. Use GETDATE() for current time.',
    'bigquery': 'Use LIMIT. Use CURRENT_TIMESTAMP() for current time. Use backtick for table names.'
}

def get_dialect_hint(dialect):
    return DIALECT_EXAMPLES.get(dialect.lower(), '')

if __name__ == '__main__':
    for dialect in ['postgresql', 'sqlite', 'mssql']:
        print(f'{dialect}: {get_dialect_hint(dialect)}')

Ciclo de recuperação de erros

O SQL gerado frequentemente falha na primeira tentativa. Um agente robusto implementa um ciclo de recuperação de erros: envia o SQL que falhou e a mensagem de erro de volta ao LLM e solicita que ele corrija a consulta.

Limite as tentativas a 2 ou 3 para evitar ciclos infinitos em consultas que não podem ser corrigidas.

def nl_to_sql_with_retry(question, schema, conn, max_retries=3):
    sql = llm_generate_sql(question, schema)
    for attempt in range(max_retries):
        result = execute_query(conn, sql)
        if 'error' not in result:
            return format_results(result, question)
        # Ask LLM to fix the error
        fix_prompt = f'The SQL query failed with error: {result["error"]}\n'\
                     f'Original SQL: {sql}\n'\
                     f'Please fix the SQL query.'
        sql = llm_call(fix_prompt)
        print(f'Retry {attempt + 1} with fixed SQL')
    return 'Could not generate a valid query after retries.'

Reunindo tudo

Um agente de NL para SQL em produção combina todas as partes: recuperação do esquema, construção do prompt, geração de SQL, validação, execução, recuperação de erros e formatação dos resultados.

Adicionar armazenamento em cache de consultas (a mesma pergunta → o mesmo SQL) reduz drasticamente a latência e os custos do LLM em consultas repetidas.

import hashlib

query_cache = {}

def cached_nl_to_sql(question, schema_hash, conn):
    cache_key = hashlib.md5((question + schema_hash).encode()).hexdigest()
    if cache_key in query_cache:
        print('Cache hit!')
        sql = query_cache[cache_key]
    else:
        schema = get_schema(conn)
        sql = llm_generate_sql(question, schema)
        query_cache[cache_key] = sql

    result = execute_query(conn, sql)
    return format_results(result, question)

Verificação de conhecimento

Qual é a ordem correta das etapas no fluxo de um agente de NL para SQL?

Recapitulação: arquitetura de NL para SQL

Os agentes de NL para SQL convertem perguntas em linguagem natural em consultas SQL executáveis por meio de um fluxo estruturado: injetar o esquema → gerar SQL → executar → formatar → retornar.

Os principais desafios são a ambiguidade nas perguntas dos usuários, esquemas grandes que excedem as janelas de contexto e diferenças entre dialetos SQL nos bancos de dados. Os ciclos de recuperação de erros lidam com SQL gerado pelo LLM que falha na primeira execução.

Perguntas Frequentes

A aula “Como funcionam os agentes de NL para SQL” é grátis?

Sim — o texto completo de “Como funcionam os agentes de NL para SQL” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Agents, atualize para CoddyKit PRO. O curso de AI Agents inclui 4 aulas no total.

O que vou aprender em “Como funcionam os agentes de NL para SQL”?

Injeção de esquema, geração e execução de consultas e formatação de resultados. Você pratica AI Agents com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar AI Agents?

Nenhuma experiência prévia é necessária. AI Agents no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “Como funcionam os agentes de NL para SQL”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de AI Agents?

Sim. Cada aula de AI Agents inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Como funcionam os agentes de NL para SQL
  2. Compreensão e injeção de esquemas
  3. Gerando e validando consultas SQL
  4. Lidando com perguntas ambíguas sobre bancos de dados
← Voltar para AI Agents