Lidando com perguntas ambíguas sobre bancos de dados
Perguntas de esclarecimento, desambiguação do esquema e raciocínio sobre junções de várias tabelas.
Lidando com perguntas ambíguas sobre bancos de dados é uma aula grátis de AI Agents no CoddyKit. Esta é a aula 4 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 problema da ambiguidade em NL-to-SQL
A linguagem natural é inerentemente ambígua. Quando alguém pergunta "Mostre-me pedidos recentes", uma pessoa pergunta: recentes para quem? em qual período? ordenados como?
Um agente que presume padrões silenciosamente produzirá resultados que o usuário não esperava. Um bom agente detecta a ambiguidade e faz perguntas direcionadas para esclarecê-la.
Tipos de ambiguidade
Há quatro categorias comuns de perguntas ambíguas no contexto de bancos de dados:
- Ambiguidade temporal: 'recente', 'mais recente', 'antigo', 'este ano'
- Ambiguidade de escopo: 'melhores clientes' — melhores segundo qual métrica?
- Ambiguidade de tabela: várias tabelas poderiam responder à pergunta
- Ambiguidade de filtro: 'usuários ativos' — o que define um usuário ativo?
# Examples of each type
ambiguous_examples = {
'temporal': 'Show me recent orders', # last 7 days? 30 days? 1 year?
'scope': 'Who are the top customers?', # by revenue, order count, or recency?
'table': 'Show me user activity', # from users, sessions, or audit_log?
'filter': 'List all active products' # active = in_stock? not discontinued?
}
if __name__ == '__main__':
print('Types of ambiguous questions:')
for kind, example in ambiguous_examples.items():
print(f' {kind}: "{example}"')
Detectando ambiguidade com o LLM
Em vez de codificar regras de ambiguidade, peça ao LLM para detectá-la. Forneça o esquema e pergunte: esta pergunta é clara o suficiente para gerar uma consulta SQL definitiva?
import json
AMBIGUITY_CHECK_PROMPT = '''You are a SQL assistant. Given a database schema and a user question,
determine if the question is clear enough to write a single correct SQL query.
Schema:
{schema}
Question: {question}
Respond with JSON:
- If clear: {{"ambiguous": false, "sql": "SELECT ..."}}
- If ambiguous: {{"ambiguous": true, "clarification": "What time range counts as recent?",
"options": ["Last 7 days", "Last 30 days", "Last 90 days"]}}
JSON:'''
def check_and_generate(question, schema):
response = llm_call(AMBIGUITY_CHECK_PROMPT.format(
schema=schema, question=question
))
return json.loads(response)O ciclo de esclarecimento
Quando uma ambiguidade for detectada, entre em um ciclo de esclarecimento: faça uma pergunta direcionada ao usuário, receba a resposta e tente gerar o SQL novamente com o contexto enriquecido.
Limite o ciclo a 2 rodadas de esclarecimento — fazer perguntas demais frustra os usuários.
def nl_to_sql_with_clarification(user_question, schema, conn, ask_user_fn):
for attempt in range(2): # max 2 clarification rounds
result = check_and_generate(user_question, schema)
if not result.get('ambiguous'):
# Clear question — execute
rows = execute_query(conn, result['sql'])
return format_results(rows, user_question)
# Ambiguous — ask user
clarification = result['clarification']
options = result.get('options', [])
user_reply = ask_user_fn(clarification, options)
# Enrich the question with the answer
user_question = f'{user_question} ({clarification}: {user_reply})'
print(f'Enriched question: {user_question}')
# After 2 rounds, generate with best guess
return check_and_generate(user_question, schema)Desambiguação temporal de 'recentes'
Palavras temporais como 'recente', 'mais recente', 'esta semana' e 'novo' são extremamente comuns. Crie um resolvedor temporal dedicado que associe termos ambíguos a períodos padrão, permitindo ainda que o LLM faça uma pergunta quando a confiança for baixa.
from datetime import datetime, timedelta
TEMPORAL_DEFAULTS = {
'recent': 7, # days
'latest': 1, # days
'new': 30,
'old': 365,
'this week': 7,
'this month': 30,
'this year': 365
}
def resolve_temporal(question):
lower = question.lower()
for term, days in TEMPORAL_DEFAULTS.items():
if term in lower:
since = (datetime.now() - timedelta(days=days)).strftime('%Y-%m-%d')
return question + f" ('{term}' means since {since})"
return question
print(resolve_temporal('Show me recent orders'))
# Show me recent orders ('recent' means since 2024-05-22)Desambiguação do esquema: várias tabelas
Quando várias tabelas poderiam responder a uma pergunta, o agente precisa raciocinar sobre qual é a mais apropriada. Por exemplo, a 'atividade do usuário' poderia estar em sessions, audit_log ou user_events.
TABLE_SEMANTIC_MAP = {
'user activity': ['sessions', 'user_events', 'audit_log'],
'purchases': ['orders', 'transactions', 'invoices'],
'product catalog': ['products', 'items', 'listings'],
'sign-ups': ['users', 'registrations', 'accounts']
}
def disambiguate_tables(question, schema_dict, ask_user_fn):
lower = question.lower()
for concept, tables in TABLE_SEMANTIC_MAP.items():
if concept in lower:
available = [t for t in tables if t in schema_dict]
if len(available) > 1:
chosen = ask_user_fn(
f"Which table should I query for '{concept}'?",
available
)
return question + f" (use the {chosen} table)"
return question
if __name__ == '__main__':
def ask_user_fn(prompt, options):
print(f'{prompt} -> choosing "{options[0]}" (demo default)')
return options[0]
demo_schema = {'sessions': [], 'transactions': [], 'orders': []}
resolved = disambiguate_tables('Show me user activity', demo_schema, ask_user_fn)
print('Resolved question:', resolved)
Lidando com a ambiguidade de escopo de 'N principais'
'Melhores clientes', 'melhores produtos' e 'usuários mais ativos' exigem saber segundo qual métrica. Apresente opções de métricas ao usuário em vez de escolher uma silenciosamente.
RANKING_AMBIGUITY_PROMPT = '''The question asks for a ranking but the metric is unclear.
Question: {question}
Table columns available: {columns}
List 2-3 reasonable ranking metrics as a JSON array of objects:
[{{"label": "By total revenue", "sql_expr": "SUM(total) DESC"}},
{{"label": "By order count", "sql_expr": "COUNT(*) DESC"}}]
JSON:'''
def resolve_ranking(question, columns, ask_user_fn):
import json
response = llm_call(RANKING_AMBIGUITY_PROMPT.format(
question=question, columns=columns
))
options = json.loads(response)
labels = [o['label'] for o in options]
chosen_label = ask_user_fn('How should I rank the results?', labels)
chosen = next(o for o in options if o['label'] == chosen_label)
return question + f" (rank by: {chosen['sql_expr']})", chosen['sql_expr']Oferecendo padrões inteligentes
Perguntar ao usuário todas as vezes pode ser incômodo. Uma abordagem mais inteligente: escolha um padrão razoável, execute a consulta e informe ao usuário o que você presumiu. Inclua uma observação como: "Presumi que 'recente' significa os últimos 30 dias. Você quis dizer um período diferente?"
def nl_to_sql_with_assumptions(question, schema, conn):
# Resolve common ambiguities with defaults
enriched = resolve_temporal(question)
result = check_and_generate(enriched, schema)
if result.get('ambiguous'):
# Still ambiguous — pick default option
options = result.get('options', ['the most common interpretation'])
default = options[0]
enriched = enriched + f' ({result["clarification"]}: {default})'
result = check_and_generate(enriched, schema)
rows = execute_query(conn, result['sql'])
answer = format_results(rows, question)
# Append assumption note
if enriched != question:
assumption = enriched[len(question):].strip().strip('()')
answer += f'\n\n[Note: I assumed {assumption}]'
return answerAmbiguidade no nível da coluna
Às vezes, a ambiguidade está no nível da coluna. 'Mostre-me os pedidos ordenados por data' — qual data? created_at, updated_at, shipped_at ou delivery_date?
Inclua descrições das colunas na injeção do esquema para ajudar o LLM e reduzir a ambiguidade no nível das colunas.
COLUMN_DESCRIPTIONS = {
('orders', 'created_at'): 'When the order was placed',
('orders', 'updated_at'): 'When the order was last modified',
('orders', 'shipped_at'): 'When the order was shipped to customer',
('orders', 'delivery_date'): 'Expected or actual delivery date'
}
def format_columns_with_descriptions(table, columns):
parts = []
for col in columns:
desc = COLUMN_DESCRIPTIONS.get((table, col['name']), '')
label = f"{col['name']} ({col['type']})"
if desc:
label += f' [{desc}]'
parts.append(label)
return ', '.join(parts)
if __name__ == '__main__':
demo_columns = [
{'name': 'created_at', 'type': 'timestamp'},
{'name': 'shipped_at', 'type': 'timestamp'},
{'name': 'total', 'type': 'float'},
]
print(format_columns_with_descriptions('orders', demo_columns))
Registrando resoluções de ambiguidades
Acompanhe com que frequência cada tipo de ambiguidade ocorre e quais padrões ou esclarecimentos foram escolhidos. Esses dados ajudam você a melhorar os valores padrão e reduzir, ao longo do tempo, o número de perguntas feitas.
import json
from datetime import datetime
ambiguity_log = []
def log_ambiguity(original_question, clarification, resolution, method):
ambiguity_log.append({
'timestamp': datetime.now().isoformat(),
'question': original_question,
'clarification': clarification,
'resolution': resolution,
'method': method # 'asked_user' | 'default' | 'llm_inferred'
})
# Periodically analyze to improve defaults
def analyze_ambiguity_log():
from collections import Counter
types = Counter(entry['clarification'] for entry in ambiguity_log)
print('Most common ambiguities:')
for q, count in types.most_common(5):
print(f' {count}x: {q}')
if __name__ == '__main__':
log_ambiguity('Show recent orders', 'temporal', 'last 30 days', 'default')
log_ambiguity('Show recent orders', 'temporal', 'last 7 days', 'asked_user')
log_ambiguity('Top customers', 'scope', 'by revenue', 'llm_inferred')
analyze_ambiguity_log()
Contexto de conversas com várias interações
Em uma interface de conversa, as interações anteriores fornecem contexto. Se o usuário já tiver dito "Estou analisando dados do quarto trimestre de 2024", as perguntas posteriores sobre 'pedidos recentes' devem usar esse período por padrão — não um período fixo de 30 dias.
def nl_to_sql_with_context(question, schema, conn, conversation_history):
context_prompt = ''
if conversation_history:
context_prompt = 'Previous conversation context:\n'
for turn in conversation_history[-3:]: # last 3 turns
context_prompt += f"User: {turn['user']}\n"
if 'assumption' in turn:
context_prompt += f"Assumption made: {turn['assumption']}\n"
full_prompt = context_prompt + f'Current question: {question}'
result = check_and_generate(full_prompt, schema)
conversation_history.append({
'user': question,
'sql': result.get('sql', ''),
'assumption': result.get('assumption', '')
})
return resultVerificação de conhecimento
Qual é a estratégia recomendada quando um agente NL-to-SQL detecta ambiguidade temporal, por exemplo, em 'pedidos recentes'?
Recapitulação: lidando com perguntas ambíguas
A ambiguidade em NL-to-SQL assume quatro formas: temporal, de escopo, de tabela e de filtro. As melhores estratégias combinam padrões inteligentes (resolver automaticamente 'recente' como os últimos 30 dias), detecção de ambiguidade baseada em LLM e esclarecimento direcionado quando a pergunta é realmente imprecisa.
Sempre comunique as suposições ao usuário. Use o histórico da conversa como contexto e registre as resoluções de ambiguidades para melhorar os padrões ao longo do tempo.
Perguntas Frequentes
A aula “Lidando com perguntas ambíguas sobre bancos de dados” é grátis?
Sim — o texto completo de “Lidando com perguntas ambíguas sobre bancos de dados” é 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 “Lidando com perguntas ambíguas sobre bancos de dados”?
Perguntas de esclarecimento, desambiguação do esquema e raciocínio sobre junções de várias tabelas. 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 4 de 4.
Quanto tempo leva a aula “Lidando com perguntas ambíguas sobre bancos de dados”?
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
- Como funcionam os agentes de NL para SQL
- Compreensão e injeção de esquemas
- Gerando e validando consultas SQL
- Lidando com perguntas ambíguas sobre bancos de dados