0Pricing
AI Agents · Lezione

Gestione delle domande ambigue sui database

Domande di chiarimento, disambiguazione dello schema e ragionamento sui join tra più tabelle

Gestione delle domande ambigue sui database è una lezione AI Agents gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Agents, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Agents include 4 lezioni in totale.

Il problema dell'ambiguità in NL-to-SQL

Il linguaggio naturale è intrinsecamente ambiguo. Quando qualcuno chiede «Mostrami gli ordini recenti», una persona si chiede: recenti per chi? Di quale intervallo temporale? Ordinati come?

Un agente che presuppone silenziosamente dei valori predefiniti produrrà risultati che l'utente non si aspettava. Un buon agente rileva l'ambiguità e pone domande di chiarimento mirate.

Tipi di ambiguità

Nei contesti dei database esistono quattro categorie comuni di domande ambigue:

  • Ambiguità temporale: «recenti», «più recenti», «vecchi», «quest'anno»
  • Ambiguità dell'ambito: «clienti migliori» — migliori in base a quale metrica?
  • Ambiguità delle tabelle: più tabelle potrebbero fornire la risposta
  • Ambiguità dei filtri: «utenti attivi» — che cosa definisce un utente attivo?
# 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}"')

Rilevamento dell'ambiguità con l'LLM

Anziché codificare regole di ambiguità, chieda all'LLM di rilevarla. Gli fornisca lo schema e chieda: la domanda è sufficientemente chiara da generare una query SQL univoca?

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)

Il ciclo di chiarimento

Quando viene rilevata un'ambiguità, avvii un ciclo di chiarimento: ponga all'utente una domanda mirata, riceva la risposta e tenti nuovamente di generare SQL con il contesto arricchito.

Limiti il ciclo a 2 round di chiarimento: porre troppe domande frustra gli utenti.

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)

Disambiguazione temporale di «recenti»

Parole temporali come «recenti», «più recenti», «questa settimana» e «nuovi» sono estremamente comuni. Crei un risolutore temporale dedicato che associ i termini ambigui a intervalli temporali predefiniti, consentendo comunque all'LLM di chiedere chiarimenti quando il livello di confidenza è basso.

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)

Disambiguazione dello schema: più tabelle

Quando più tabelle potrebbero fornire la risposta a una domanda, l'agente deve ragionare su quale sia la più appropriata. Ad esempio, l'«attività degli utenti» potrebbe trovarsi in 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)

Gestione dell'ambiguità dell'ambito «Top N»

«Clienti migliori», «prodotti migliori» e «utenti più attivi» richiedono tutti di sapere in base a quale metrica. Presenti le opzioni delle metriche all'utente invece di sceglierne una in silenzio.

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']

Proposta di valori predefiniti intelligenti

Chiedere all'utente ogni volta può essere fastidioso. Un approccio più intelligente consiste nel scegliere un valore predefinito sensato, eseguire la query e comunicare all'utente l'ipotesi adottata. Includa una nota come: «Ho considerato che «recenti» significhi gli ultimi 30 giorni. Intendeva un periodo diverso?»

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

Ambiguità a livello di colonna

A volte l'ambiguità riguarda il livello della colonna. «Mostrami gli ordini ordinati per data»: quale data? created_at, updated_at, shipped_at o delivery_date?

Includa le descrizioni delle colonne nell'iniezione dello schema per aiutare l'LLM e ridurre l'ambiguità a livello di colonna.

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))

Registrazione delle risoluzioni dell'ambiguità

Tenga traccia della frequenza con cui si verifica ogni tipo di ambiguità e dei valori predefiniti o dei chiarimenti scelti. Questi dati aiutano a migliorare i valori predefiniti e a ridurre nel tempo il numero di domande poste.

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()

Contesto della conversazione su più turni

In un'interfaccia di chat, i turni precedenti forniscono contesto. Se l'utente ha già detto «Sto esaminando i dati del Q4 2024», alle domande successive sugli «ordini recenti» dovrebbe essere applicato per impostazione predefinita quell'intervallo temporale, non un intervallo codificato rigidamente di 30 giorni.

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

Verifica delle conoscenze

Qual è la strategia consigliata quando un agente NL-to-SQL rileva un'ambiguità temporale, ad esempio «ordini recenti»?

Riepilogo: gestione delle domande ambigue

L'ambiguità in NL-to-SQL assume quattro forme: temporale, di ambito, di tabella e di filtro. Le strategie migliori combinano valori predefiniti intelligenti (risolvendo automaticamente «recenti» come «ultimi 30 giorni»), rilevamento dell'ambiguità basato sull'LLM e chiarimenti mirati quando la domanda non è realmente chiara.

Comunichi sempre le ipotesi adottate all'utente. Utilizzi la cronologia della conversazione come contesto e registri le risoluzioni delle ambiguità per migliorare nel tempo i valori predefiniti.

Domande Frequenti

La lezione «Gestione delle domande ambigue sui database» è gratuita?

Sì — il testo completo di «Gestione delle domande ambigue sui database» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Agents, passa a CoddyKit PRO. Il corso AI Agents include 4 lezioni in totale.

Cosa imparerò in «Gestione delle domande ambigue sui database»?

Domande di chiarimento, disambiguazione dello schema e ragionamento sui join tra più tabelle Eserciti AI Agents con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare AI Agents?

Non è richiesta alcuna esperienza precedente. AI Agents su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Gestione delle domande ambigue sui database»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione AI Agents?

Sì. Ogni lezione AI Agents include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Come funzionano gli agenti NL-to-SQL
  2. Comprensione e iniezione dello schema
  3. Generazione e convalida delle query SQL
  4. Gestione delle domande ambigue sui database
← Torna a AI Agents