Gérer les questions ambiguës sur les bases de données
Questions de clarification, désambiguïsation du schéma et raisonnement sur les jointures multi-tables.
Gérer les questions ambiguës sur les bases de données est une leçon AI Agents gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage AI Agents, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours AI Agents comprend 4 leçons au total.
Le problème de l'ambiguïté en NL vers SQL
Le langage naturel est intrinsèquement ambigu. Lorsqu'une personne demande « Affichez-moi les commandes récentes », un humain se demande : récentes pour qui ? sur quelle période ? triées comment ?
Un agent qui suppose silencieusement des valeurs par défaut produira des résultats inattendus pour l'utilisateur. Un bon agent détecte l'ambiguïté et pose des questions de clarification ciblées.
Types d'ambiguïté
Il existe quatre catégories courantes de questions ambiguës dans le contexte des bases de données :
- Ambiguïté temporelle : « récent », « dernier », « ancien », « cette année »
- Ambiguïté de portée : « meilleurs clients » — selon quelle métrique ?
- Ambiguïté de table : plusieurs tables pourraient répondre à la question
- Ambiguïté de filtre : « utilisateurs actifs » — qu'est-ce qui définit l'activité ?
# 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}"')
Détection de l'ambiguïté avec le LLM
Plutôt que de coder en dur des règles d'ambiguïté, demandez au LLM de détecter l'ambiguïté. Fournissez-lui le schéma et demandez-lui si la question est suffisamment claire pour générer une requête SQL définitive.
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)Boucle de clarification
Lorsqu'une ambiguïté est détectée, entrez dans une boucle de clarification : posez une question ciblée à l'utilisateur, recevez sa réponse, puis retentez de générer le SQL avec le contexte enrichi.
Limitez la boucle à 2 tours de clarification — poser trop de questions frustre les utilisateurs.
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)Désambiguïsation temporelle de « récent »
Les termes temporels comme « récent », « dernier », « cette semaine » et « nouveau » sont extrêmement courants. Créez un résolveur temporel dédié qui associe les termes ambigus à des périodes par défaut, tout en permettant au LLM de poser une question lorsque son niveau de confiance est faible.
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)Désambiguïsation du schéma : tables multiples
Lorsque plusieurs tables pourraient répondre à une question, l'agent doit déterminer laquelle est la plus appropriée. Par exemple, l'« activité de l'utilisateur » pourrait se trouver dans 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)
Gestion de l'ambiguïté de portée pour « meilleurs N »
« Meilleurs clients », « meilleurs produits » et « utilisateurs les plus actifs » nécessitent de savoir selon quelle métrique. Présentez des options de métrique à l'utilisateur plutôt que d'en choisir une silencieusement.
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']Proposition de valeurs par défaut intelligentes
Demander confirmation à l'utilisateur à chaque fois peut être agaçant. Une approche plus intelligente consiste à choisir une valeur par défaut pertinente, exécuter la requête et indiquer à l'utilisateur ce que vous avez supposé. Ajoutez une note telle que : « J'ai supposé que « récent » signifiait les 30 derniers jours. Vouliez-vous dire une autre période ? »
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 answerAmbiguïté au niveau des colonnes
Parfois, l'ambiguïté se situe au niveau des colonnes. « Affichez-moi les commandes triées par date » — de quelle date s'agit-il ? created_at, updated_at, shipped_at ou delivery_date ?
Incluez les descriptions des colonnes dans votre injection du schéma pour aider le LLM et réduire l'ambiguïté au niveau des colonnes.
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))
Journalisation des résolutions d'ambiguïté
Suivez la fréquence de chaque type d'ambiguïté ainsi que les valeurs par défaut ou les clarifications choisies. Ces données vous aideront à améliorer les valeurs par défaut et à réduire progressivement le nombre de questions posées.
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()
Contexte d'une conversation à plusieurs tours
Dans une interface de discussion, les tours précédents fournissent du contexte. Si l'utilisateur a déjà indiqué « Je consulte les données du quatrième trimestre 2024 », les questions ultérieures sur les « commandes récentes » devraient utiliser par défaut cette période, et non une période codée en dur de 30 jours.
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 resultVérification des connaissances
Quelle stratégie est recommandée lorsqu'un agent NL vers SQL détecte une ambiguïté temporelle, par exemple avec « commandes récentes » ?
Récapitulatif : gestion des questions ambiguës
L'ambiguïté en NL vers SQL prend quatre formes : temporelle, de portée, de table et de filtre. Les meilleures stratégies combinent des valeurs par défaut intelligentes, comme résoudre automatiquement « récent » en « 30 derniers jours », la détection de l'ambiguïté fondée sur le LLM et une clarification ciblée lorsque la question est réellement imprécise.
Communiquez toujours vos suppositions à l'utilisateur. Utilisez l'historique de la conversation pour le contexte et consignez les résolutions d'ambiguïté afin d'améliorer les valeurs par défaut au fil du temps.
Apprends AI Agents avec un tuteur IA — gratuit
Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.
- Cours
- 60
- Leçons
- 239
Questions Fréquemment Posées
La leçon « Gérer les questions ambiguës sur les bases de données » est-elle gratuite ?
Oui — le texte complet de « Gérer les questions ambiguës sur les bases de données » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours AI Agents, passe à CoddyKit PRO. Le cours AI Agents comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Gérer les questions ambiguës sur les bases de données » ?
Questions de clarification, désambiguïsation du schéma et raisonnement sur les jointures multi-tables. Tu pratiques AI Agents avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer AI Agents ?
Aucune expérience préalable n'est requise. AI Agents sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Gérer les questions ambiguës sur les bases de données » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon AI Agents ?
Oui. Chaque leçon AI Agents inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Fonctionnement des agents NL-to-SQL
- Comprendre et injecter un schéma
- Générer et valider des requêtes SQL
- Gérer les questions ambiguës sur les bases de données