0Pricing
AI Agents · บทเรียน

การจัดการคำถามฐานข้อมูลที่กำกวม

คำถามเพื่อขอความชัดเจน การแยกแยะโครงร่าง และการให้เหตุผลกับการเชื่อมหลายตาราง

การจัดการคำถามฐานข้อมูลที่กำกวม เป็นบทเรียน AI Agents ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Agents และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน

ปัญหาความกำกวมในการแปลง NL เป็น SQL

ภาษาธรรมชาติมีความกำกวมโดยธรรมชาติ เมื่อมีคนถามว่า “แสดงคำสั่งซื้อที่เพิ่งเกิดขึ้นให้ฉันดู” มนุษย์จะถามว่า: เพิ่งเกิดขึ้นสำหรับใคร? ในช่วงเวลาใด? จัดเรียงอย่างไร?

ตัวแทนที่ตั้งค่าเริ่มต้นโดยไม่แจ้งให้ทราบจะสร้างผลลัพธ์ที่ผู้ใช้ไม่ได้คาดหวัง ตัวแทนที่ดีจะตรวจจับความกำกวมและถามคำถามเพื่อขอคำชี้แจงที่ตรงประเด็น

ประเภทของความกำกวม

คำถามที่กำกวมในบริบทฐานข้อมูลมีอยู่สี่ประเภทที่พบบ่อย:

  • ความกำกวมด้านเวลา: ‘ล่าสุด’, ‘ใหม่ที่สุด’, ‘เก่า’, ‘ปีนี้’
  • ความกำกวมด้านขอบเขต: ‘ลูกค้าอันดับต้น ๆ’ — จัดอันดับตามตัวชี้วัดใด
  • ความกำกวมด้านตาราง: มีหลายตารางที่อาจใช้ตอบคำถามได้
  • ความกำกวมด้านตัวกรอง: ‘ผู้ใช้ที่ใช้งานอยู่’ — อะไรเป็นเกณฑ์ว่าผู้ใช้มีการใช้งานอยู่
# 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}"')

การตรวจจับความกำกวมด้วย LLM

แทนที่จะเขียนกฎความกำกวมแบบตายตัว ให้ LLM ตรวจจับความกำกวม โดยส่งสคีมาให้ LLM แล้วถามว่า คำถามนี้ชัดเจนพอที่จะสร้างคำสั่ง SQL ที่ระบุแน่ชัดหรือไม่

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)

วงจรขอคำชี้แจง

เมื่อพบความกำกวม ให้เข้าสู่วงจรขอคำชี้แจง: ถามคำถามที่ตรงประเด็นกับผู้ใช้ รับคำตอบ แล้วลองสร้าง SQL ใหม่โดยใช้บริบทที่มีข้อมูลเพิ่มเติม

จำกัดวงจรไว้ที่ 2 รอบของการขอคำชี้แจง — การถามคำถามมากเกินไปทำให้ผู้ใช้รู้สึกรำคาญ

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)

การขจัดความกำกวมด้านเวลาของคำว่า ‘ล่าสุด’

คำบอกเวลาอย่าง ‘ล่าสุด’, ‘ใหม่ที่สุด’, ‘สัปดาห์นี้’ และ ‘ใหม่’ พบได้บ่อยมาก ให้สร้างตัวแก้ไขความหมายด้านเวลาเฉพาะทางเพื่อจับคู่คำที่กำกวมกับช่วงเวลาเริ่มต้นที่กำหนดไว้ ขณะเดียวกันก็ยังเปิดโอกาสให้ LLM ถามผู้ใช้เมื่อมีความมั่นใจต่ำ

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)

การขจัดความกำกวมของสคีมา: หลายตาราง

เมื่อมีหลายตารางที่อาจใช้ตอบคำถามได้ ตัวแทนต้องให้เหตุผลว่าตารางใดเหมาะสมที่สุด ตัวอย่างเช่น ‘กิจกรรมผู้ใช้’ อาจอยู่ใน sessions, audit_log หรือ 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)

การจัดการความกำกวมของขอบเขต “N อันดับแรก”

‘ลูกค้าอันดับต้น ๆ’, ‘ผลิตภัณฑ์ที่ดีที่สุด’ และ ‘ผู้ใช้ที่ใช้งานมากที่สุด’ ล้วนต้องทราบว่า ใช้ตัวชี้วัดใดในการจัดอันดับ ให้แสดงตัวเลือกตัวชี้วัดแก่ผู้ใช้ แทนการเลือกอย่างใดอย่างหนึ่งโดยไม่แจ้งให้ทราบ

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

การเสนอค่าเริ่มต้นอัจฉริยะ

การถามผู้ใช้ทุกครั้งอาจทำให้รู้สึกรำคาญ แนวทางที่ชาญฉลาดกว่าคือ เลือกค่าเริ่มต้นที่เหมาะสม ดำเนินการ แล้วแจ้งผู้ใช้ว่าคุณตั้งสมมติฐานอะไรไว้ ใส่หมายเหตุลักษณะนี้: “ฉันถือว่า ‘ล่าสุด’ หมายถึง 30 วันที่ผ่านมา คุณหมายถึงช่วงเวลาอื่นหรือไม่”

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

ความกำกวมระดับคอลัมน์

บางครั้งความกำกวมอยู่ในระดับคอลัมน์ ‘แสดงคำสั่งซื้อโดยเรียงตามวันที่ให้ฉันดู’ — วันที่ใด created_at, updated_at, shipped_at หรือ delivery_date

ใส่คำอธิบายคอลัมน์ในการแทรกสคีมา เพื่อช่วย LLM และลดความกำกวมระดับคอลัมน์

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

การบันทึกการแก้ความกำกวม

ติดตามว่าความกำกวมแต่ละประเภทเกิดขึ้นบ่อยเพียงใด และเลือกใช้ค่าเริ่มต้นหรือคำชี้แจงใด ข้อมูลนี้ช่วยปรับปรุงค่าเริ่มต้นและลดจำนวนคำถามที่ต้องถามเมื่อเวลาผ่านไป

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

บริบทการสนทนาหลายรอบ

ในส่วนติดต่อแบบแชต ข้อความโต้ตอบก่อนหน้าจะให้บริบท หากผู้ใช้เคยพูดว่า “ฉันกำลังดูข้อมูลไตรมาส 4 ปี 2024 อยู่” คำถามภายหลังเกี่ยวกับ ‘คำสั่งซื้อที่เพิ่งเกิดขึ้น’ ก็ควรใช้ช่วงเวลานั้นเป็นค่าเริ่มต้น ไม่ใช่กำหนดตายตัวเป็น 30 วัน

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

ตรวจสอบความรู้

เมื่อผู้ใช้แปลง NL เป็น SQL ตรวจพบความกำกวมด้านเวลา เช่น ‘คำสั่งซื้อที่เพิ่งเกิดขึ้น’ กลยุทธ์ที่แนะนำคืออะไร

สรุป: การจัดการคำถามที่กำกวม

ความกำกวมในการแปลง NL เป็น SQL มีสี่รูปแบบ ได้แก่ ด้านเวลา ด้านขอบเขต ด้านตาราง และด้านตัวกรอง กลยุทธ์ที่ดีที่สุดคือการผสานค่าเริ่มต้นอัจฉริยะ (แก้ความหมายของ ‘ล่าสุด’ เป็น 30 วันที่ผ่านมาโดยอัตโนมัติ) การตรวจจับความกำกวมด้วย LLM และการขอคำชี้แจงที่ตรงประเด็นเมื่อคำถามไม่ชัดเจนจริง ๆ

แจ้งสมมติฐานให้ผู้ใช้ทราบเสมอ ใช้ประวัติการสนทนาเป็นบริบท และบันทึกการแก้ความกำกวมเพื่อปรับปรุงค่าเริ่มต้นในระยะยาว

คำถามที่พบบ่อย

บทเรียน “การจัดการคำถามฐานข้อมูลที่กำกวม” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การจัดการคำถามฐานข้อมูลที่กำกวม” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Agents ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Agents มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การจัดการคำถามฐานข้อมูลที่กำกวม”

คำถามเพื่อขอความชัดเจน การแยกแยะโครงร่าง และการให้เหตุผลกับการเชื่อมหลายตาราง คุณปฏิบัติ AI Agents ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Agents หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Agents บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การจัดการคำถามฐานข้อมูลที่กำกวม” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน AI Agents นี้ได้ไหม

ได้ บทเรียน AI Agents ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การทำงานของตัวแทน NL-to-SQL
  2. การทำความเข้าใจและแทรกโครงร่าง
  3. การสร้างและตรวจสอบความถูกต้องของคำสั่ง SQL
  4. การจัดการคำถามฐานข้อมูลที่กำกวม
← กลับไปที่ AI Agents