AI-agenten · Les

Onduidelijke databasevragen afhandelen

Verduidelijkende vragen, schema-ontdubbeling en redeneren over joins van meerdere tabellen.

Les 4 van 413 stappen

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 answer

Ambiguï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 result

Kennistoets

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.

Gratis beginnen

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

  1. Hoe NL-to-SQL-agents werken
  2. Schema's begrijpen en injecteren
  3. SQL-query's genereren en valideren
  4. Onduidelijke databasevragen afhandelen
← Terug naar AI-agenten