Gestión de preguntas ambiguas sobre bases de datos
Preguntas aclaratorias, desambiguación del esquema y razonamiento sobre combinaciones de varias tablas.
Gestión de preguntas ambiguas sobre bases de datos es una lección gratuita de AI Agents en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de AI Agents, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de AI Agents incluye 4 lecciones en total.
El problema de la ambigüedad en NL-to-SQL
El lenguaje natural es inherentemente ambiguo. Cuando alguien pregunta "Muéstreme los pedidos recientes", una persona preguntaría: ¿recientes para quién? ¿en qué periodo? ¿ordenados de qué forma?
Un agente que asume valores predeterminados sin indicarlo producirá resultados que el usuario no esperaba. Un buen agente detecta la ambigüedad y formula preguntas de aclaración específicas.
Tipos de ambigüedad
En el contexto de las bases de datos, hay cuatro categorías habituales de preguntas ambiguas:
- Ambigüedad temporal: «recientes», «últimos», «antiguos», «este año»
- Ambigüedad de alcance: «mejores clientes»: ¿según qué métrica?
- Ambigüedad de tabla: varias tablas podrían responder a la pregunta
- Ambigüedad de filtro: «usuarios activos»: ¿qué define que estén activos?
# 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}"')
Detección de ambigüedad con el LLM
En lugar de codificar reglas de ambigüedad, pida al LLM que la detecte. Proporciónele el esquema y pregúntele si la pregunta es lo bastante clara como para generar una 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)Bucle de aclaración
Cuando se detecte ambigüedad, inicie un bucle de aclaración: formule al usuario una pregunta específica, reciba su respuesta y vuelva a intentar generar el SQL con el contexto ampliado.
Limite el bucle a 2 rondas de aclaración; hacer demasiadas preguntas frustra a los usuarios.
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)Desambiguación temporal de «reciente»
Las expresiones temporales como «reciente», «último», «esta semana» y «nuevo» son extremadamente comunes. Cree un resolvedor temporal específico que asigne rangos de tiempo predeterminados a los términos ambiguos, pero permita que el LLM pregunte cuando la confianza sea baja.
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)Desambiguación del esquema: varias tablas
Cuando varias tablas podrían responder a una pregunta, el agente debe razonar cuál es la más adecuada. Por ejemplo, la «actividad del usuario» podría estar en sessions, audit_log o 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)
Gestión de la ambigüedad de alcance de «Top N»
«Mejores clientes», «mejores productos» y «usuarios más activos» requieren saber según qué métrica. Presente al usuario las opciones de métricas en lugar de elegir una sin indicarlo.
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']Ofrecimiento de valores predeterminados inteligentes
Preguntar al usuario cada vez puede resultar molesto. Un enfoque más inteligente consiste en elegir un valor predeterminado razonable, ejecutar la consulta e informar al usuario de lo que ha asumido. Incluya una nota como: "He supuesto que «reciente» significa los últimos 30 días. ¿Se refería a otro periodo?"
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 answerAmbigüedad a nivel de columna
A veces la ambigüedad se encuentra en el nivel de columna. «Muéstreme los pedidos ordenados por fecha»: ¿qué fecha? created_at, updated_at, shipped_at o delivery_date?
Incluya descripciones de las columnas en la inyección del esquema para ayudar al LLM y reducir la ambigüedad a nivel de columna.
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))
Registro de las resoluciones de ambigüedad
Registre con qué frecuencia aparece cada tipo de ambigüedad y qué valores predeterminados o aclaraciones se eligieron. Estos datos le ayudarán a mejorar los valores predeterminados y a reducir con el tiempo el número de preguntas que se formulan.
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 conversaciones de varios turnos
En una interfaz de chat, los turnos anteriores proporcionan contexto. Si el usuario ya ha dicho «Estoy consultando datos del cuarto trimestre de 2024», las preguntas posteriores sobre «pedidos recientes» deberían utilizar ese rango de tiempo de forma predeterminada, no un periodo codificado de 30 días.
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 resultComprobación de conocimientos
¿Cuál es la estrategia recomendada cuando un agente NL-to-SQL detecta ambigüedad temporal, por ejemplo, en «pedidos recientes»?
Resumen: gestión de preguntas ambiguas
La ambigüedad en NL-to-SQL adopta cuatro formas: temporal, de alcance, de tabla y de filtro. Las mejores estrategias combinan valores predeterminados inteligentes —resolver automáticamente «reciente» como los últimos 30 días—, detección de ambigüedad basada en el LLM y aclaraciones específicas cuando la pregunta no es realmente clara.
Comunique siempre sus suposiciones al usuario. Utilice el historial de la conversación como contexto y registre las resoluciones de ambigüedad para mejorar los valores predeterminados con el tiempo.
Preguntas frecuentes
¿La lección «Gestión de preguntas ambiguas sobre bases de datos» es gratis?
Sí — el texto completo de «Gestión de preguntas ambiguas sobre bases de datos» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de AI Agents, actualiza a CoddyKit PRO. El curso de AI Agents incluye 4 lecciones en total.
¿Qué aprenderé en «Gestión de preguntas ambiguas sobre bases de datos»?
Preguntas aclaratorias, desambiguación del esquema y razonamiento sobre combinaciones de varias tablas. Practicas AI Agents con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar AI Agents?
No se requiere experiencia previa. AI Agents en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Gestión de preguntas ambiguas sobre bases de datos»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de AI Agents?
Sí. Cada lección de AI Agents incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Cómo funcionan los agentes NL-to-SQL
- Comprensión e inyección de esquemas
- Generación y validación de consultas SQL
- Gestión de preguntas ambiguas sobre bases de datos