Onduidelijke databasevragen afhandelen
Verduidelijkende vragen, schema-ontdubbeling en redeneren over joins van meerdere tabellen.
Onduidelijke databasevragen afhandelen is een gratis AI-agenten-les op CoddyKit. Dit is les 4 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject AI-agenten. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus AI-agenten bevat in totaal 4 lessen.
Het ambiguïteitsprobleem in NL-to-SQL
Natuurlijke taal is van nature ambigu. Wanneer iemand vraagt "Toon me recente bestellingen", vraagt een mens zich af: recent voor wie? binnen welke periode? hoe gesorteerd?
Een agent die stilzwijgend standaardwaarden aanneemt, levert resultaten op die de gebruiker niet verwachtte. Een goede agent detecteert ambiguïteit en stelt gerichte verduidelijkingsvragen.
Soorten ambiguïteit
In de context van databases bestaan er vier veelvoorkomende categorieën ambigue vragen:
- Temporele ambiguïteit: 'recent', 'laatste', 'oud', 'dit jaar'
- Bereikambiguïteit: 'beste klanten' — beste op basis van welke metriek?
- Tabelambiguïteit: meerdere tabellen kunnen de vraag beantwoorden
- Filterambiguïteit: 'actieve gebruikers' — wat bepaalt of iemand actief is?
# 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}"')
Ambiguïteit detecteren met de LLM
In plaats van regels voor ambiguïteit hard te coderen, kun je de LLM vragen ambiguïteit te detecteren. Geef de LLM het schema en vraag: is deze vraag duidelijk genoeg om een eenduidige SQL-query te genereren?
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)De verduidelijkingslus
Wanneer ambiguïteit wordt gedetecteerd, start je een verduidelijkingslus: stel de gebruiker een gerichte vraag, ontvang het antwoord en probeer daarna opnieuw SQL te genereren met de aangevulde context.
Beperk de lus tot 2 verduidelijkingsrondes — te veel vragen frustreren gebruikers.
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)Temporele verduidelijking van 'recent'
Tijdsaanduidingen zoals 'recent', 'laatste', 'deze week' en 'nieuw' komen zeer vaak voor. Bouw een speciale tijdsoplosser die ambigue termen aan standaardperioden koppelt, maar laat de LLM nog steeds vragen stellen wanneer de betrouwbaarheid laag is.
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)Schemainterpretatie bij meerdere tabellen
Wanneer meerdere tabellen een vraag kunnen beantwoorden, moet de agent redeneren over welke tabel het meest geschikt is. Zo kan 'activiteit van gebruikers' in sessions, audit_log of user_events staan.
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)
Ambiguïteit over het bereik van 'Top N' afhandelen
'Beste klanten', 'beste producten' en 'actiefste gebruikers' vereisen allemaal dat je weet op basis van welke metriek. Toon de gebruiker opties voor de metriek in plaats van stilzwijgend één optie te kiezen.
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']Intelligente standaardwaarden aanbieden
De gebruiker elke keer iets vragen kan vervelend zijn. Een slimmere aanpak is: kies een verstandige standaardwaarde, voer de query uit en vertel de gebruiker wat je hebt aangenomen. Voeg bijvoorbeeld een opmerking toe: "Ik heb aangenomen dat 'recent' de afgelopen 30 dagen betekent. Bedoelde je een andere periode?"
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ïteit op kolomniveau
Soms zit de ambiguïteit op kolomniveau. 'Toon me bestellingen gesorteerd op datum' — om welke datum gaat het? created_at, updated_at, shipped_at of delivery_date?
Neem kolombeschrijvingen op in je schemainjectie om de LLM te helpen en ambiguïteit op kolomniveau te verminderen.
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))
Ambiguïteitsoplossingen registreren
Houd bij hoe vaak elk type ambiguïteit voorkomt en welke standaardwaarden of verduidelijkingen zijn gekozen. Deze gegevens helpen je standaardwaarden te verbeteren en het aantal vragen na verloop van tijd te verminderen.
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()
Gesprekscontext met meerdere beurten
In een chatinterface bieden eerdere beurten context. Als de gebruiker al heeft gezegd "Ik bekijk gegevens van Q4 2024", moeten latere vragen over 'recente bestellingen' standaard naar die periode verwijzen — niet naar een vast ingestelde periode van 30 dagen.
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 resultKennistoets
Wat is de aanbevolen strategie wanneer een NL-to-SQL-agent temporele ambiguïteit detecteert, bijvoorbeeld bij 'recente bestellingen'?
Samenvatting: ambigue vragen afhandelen
Ambiguïteit in NL-to-SQL heeft vier vormen: temporeel, bereik, tabel en filter. De beste strategieën combineren intelligente standaardwaarden ('recent' automatisch oplossen als de afgelopen 30 dagen), op LLM gebaseerde detectie van ambiguïteit en gerichte verduidelijking wanneer de vraag echt onduidelijk is.
Maak aannames altijd duidelijk aan de gebruiker. Gebruik de gespreksgeschiedenis als context en registreer ambiguïteitsoplossingen om standaardwaarden na verloop van tijd te verbeteren.
Leer AI-agenten met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 60
- Lessen
- 239
Veelgestelde vragen
Is de les “Onduidelijke databasevragen afhandelen” gratis?
Ja — de volledige tekst van “Onduidelijke databasevragen afhandelen” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus AI-agenten wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus AI-agenten bevat in totaal 4 lessen.
Wat leer ik in “Onduidelijke databasevragen afhandelen”?
Verduidelijkende vragen, schema-ontdubbeling en redeneren over joins van meerdere tabellen. Je oefent met AI-agenten door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met AI-agenten te beginnen?
Ervaring vooraf is niet nodig. AI-agenten op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 4 van 4.
Hoe lang duurt de les “Onduidelijke databasevragen afhandelen”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over AI-agenten?
Ja. Elke les over AI-agenten bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Hoe NL-to-SQL-agents werken
- Schema's begrijpen en injecteren
- SQL-query's genereren en valideren
- Onduidelijke databasevragen afhandelen