Ejen AI · Pelajaran

Memahami dan Menyuntik Skema

Mengekstrak dan memformat skema DB untuk konteks LLM: jadual, lajur dan hubungan.

Pelajaran 2 daripada 413 langkah

Memahami dan Menyuntik Skema ialah pelajaran Ejen AI percuma di CoddyKit. Ini ialah pelajaran 2 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Ejen AI, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Ejen AI merangkumi sejumlah 4 pelajaran.

Mengapa Konteks Skema Penting

LLM mengetahui sintaks SQL tetapi tidak mengetahui apa-apa tentang pangkalan data anda. Tanpa konteks skema, LLM akan mereka-reka nama jadual dan lajur.

Penyisipan skema bermaksud mengekstrak struktur pangkalan data anda secara programatik dan menyertakannya dalam setiap arahan — supaya LLM mengetahui jadual, lajur dan jenis data anda yang tepat.

Membuat Pertanyaan pada INFORMATION_SCHEMA

Semua pangkalan data hubungan utama mendedahkan metadata melalui INFORMATION_SCHEMA. Anda boleh membuat pertanyaan padanya untuk mendapatkan setiap jadual, nama lajur dan jenis data tanpa menyentuh kod aplikasi.

Kaedah ini berfungsi dalam PostgreSQL, MySQL, SQL Server dan SQLite (dengan perbezaan kecil).

import psycopg2

def get_schema(conn):
    query = '''
        SELECT table_name, column_name, data_type
        FROM information_schema.columns
        WHERE table_schema = 'public'
        ORDER BY table_name, ordinal_position
    '''
    with conn.cursor() as cur:
        cur.execute(query)
        return cur.fetchall()

Mengumpulkan Lajur Mengikut Jadual

Hasil mentah INFORMATION_SCHEMA ialah senarai baris rata. Kumpulkan baris tersebut mengikut nama jadual untuk membina perwakilan berstruktur yang lebih mudah diformatkan ke dalam arahan.

from collections import defaultdict

def build_schema_dict(conn):
    rows = get_schema(conn)
    schema = defaultdict(list)
    for table_name, column_name, data_type in rows:
        schema[table_name].append({
            'name': column_name,
            'type': data_type
        })
    return dict(schema)

# Result:
# {
#   'users': [{'name': 'id', 'type': 'integer'}, {'name': 'email', 'type': 'character varying'}],
#   'orders': [{'name': 'id', 'type': 'integer'}, {'name': 'user_id', 'type': 'integer'}]
# }

Memformatkan Skema untuk Arahan LLM

LLM membaca skema sebagai teks biasa. Gunakan format yang ringkas dan mudah dibaca: satu jadual bagi setiap baris dengan nama lajur dan jenis dalam kurungan.

Menyertakan kunci utama (PK) dan kunci asing (FK) membantu LLM menulis pernyataan JOIN yang betul.

def format_schema_for_prompt(schema_dict, pk_info=None, fk_info=None):
    lines = []
    for table, columns in schema_dict.items():
        col_parts = []
        for col in columns:
            label = col['name']
            if pk_info and (table, col['name']) in pk_info:
                label += ' PK'
            if fk_info and (table, col['name']) in fk_info:
                label += f' FK->{fk_info[(table, col["name"])]}'
            col_parts.append(f"{label} ({col['type']})")
        lines.append(f"Table {table}: {', '.join(col_parts)}")
    return '\n'.join(lines)

# Output:
# Table users: id PK (integer), email (varchar), created_at (timestamp)
# Table orders: id PK (integer), user_id FK->users.id (integer), total (float)

if __name__ == '__main__':
    demo_schema = {'users': [{'name': 'id', 'type': 'integer'}, {'name': 'email', 'type': 'varchar'}]}
    demo_pk = {('users', 'id')}
    print(format_schema_for_prompt(demo_schema, pk_info=demo_pk))

Menyertakan Kunci Utama dan Kunci Asing

Hubungan kunci asing ialah bahagian paling penting dalam konteks skema — hubungan ini memberitahu LLM cara menulis JOIN. Buat pertanyaan pada information_schema.table_constraints dan key_column_usage untuk mengekstraknya.

def get_foreign_keys(conn):
    query = '''
        SELECT
            kcu.table_name,
            kcu.column_name,
            ccu.table_name AS foreign_table,
            ccu.column_name AS foreign_column
        FROM information_schema.table_constraints AS tc
        JOIN information_schema.key_column_usage AS kcu
            ON tc.constraint_name = kcu.constraint_name
        JOIN information_schema.constraint_column_usage AS ccu
            ON ccu.constraint_name = tc.constraint_name
        WHERE tc.constraint_type = 'FOREIGN KEY'
    '''
    with conn.cursor() as cur:
        cur.execute(query)
        return {
            (row[0], row[1]): f'{row[2]}.{row[3]}'
            for row in cur.fetchall()
        }

if __name__ == '__main__':
    class FakeCursor:
        def __enter__(self): return self
        def __exit__(self, *a): return False
        def execute(self, query): pass
        def fetchall(self):
            return [('orders', 'user_id', 'users', 'id')]
    class FakeConn:
        def cursor(self): return FakeCursor()

    fks = get_foreign_keys(FakeConn())
    print('Foreign keys found:')
    for (table, col), ref in fks.items():
        print(f'  {table}.{col} -> {ref}')

Pemampatan Skema: Masalahnya

Pangkalan data perusahaan sebenar mungkin mempunyai lebih daripada 200 jadual. Jika anda menyisipkan keseluruhan skema, anda akan melebihi tetingkap konteks GPT-4 dan membazirkan wang untuk token.

Skema dengan 200 jadual dan 20 lajur setiap satu mempunyai kira-kira 40,000+ token — terlalu mahal untuk dihantar bagi setiap pertanyaan.

def estimate_schema_tokens(schema_dict):
    text = format_schema_for_prompt(schema_dict)
    # Rough estimate: 1 token per 4 characters
    estimated_tokens = len(text) // 4
    print(f'Tables: {len(schema_dict)}')
    print(f'Estimated schema tokens: {estimated_tokens}')
    return estimated_tokens

# 200 tables * 15 columns * 25 chars/col = 75,000 chars = ~18,750 tokens
# Plus user question + system prompt = easily over context limit

Pemampatan Skema: Penyisipan Terpilih

Strategi pemampatan yang paling berkesan: hanya sisipkan jadual yang berkaitan dengan soalan. Gunakan pendekatan dua fasa — mula-mula tanya LLM jadual yang diperlukan, kemudian sisipkan skema jadual tersebut sahaja.

def select_relevant_tables(question, all_table_names, n=5):
    table_list = ', '.join(all_table_names)
    prompt = f'''Database tables: {table_list}

Question: {question}

List the {n} most relevant table names as a JSON array.
Example: ["users", "orders", "products"]'''

    response = llm_call(prompt)
    import json
    return json.loads(response)

def compressed_schema(question, conn):
    all_tables = list(build_schema_dict(conn).keys())
    relevant = select_relevant_tables(question, all_tables)
    full_schema = build_schema_dict(conn)
    return {t: full_schema[t] for t in relevant if t in full_schema}

Pemampatan Skema: Mengecualikan Lajur Tidak Diperlukan

Banyak jadual mempunyai lajur audit seperti created_at, updated_at, deleted_at, version, created_by yang jarang berkaitan dengan pertanyaan perniagaan. Buang lajur tersebut untuk mengurangkan bilangan token.

AUDIT_COLUMNS = {
    'created_at', 'updated_at', 'deleted_at', 'created_by',
    'updated_by', 'version', 'is_deleted', 'modified_at'
}

def compress_schema(schema_dict, exclude_audit=True):
    compressed = {}
    for table, columns in schema_dict.items():
        # Skip internal/system tables
        if table.startswith('_') or table.startswith('pg_'):
            continue
        if exclude_audit:
            columns = [c for c in columns if c['name'] not in AUDIT_COLUMNS]
        if columns:  # only include if columns remain
            compressed[table] = columns
    return compressed

if __name__ == '__main__':
    demo_schema = {
        'users': [{'name': 'id', 'type': 'INT'}, {'name': 'email', 'type': 'VARCHAR'}, {'name': 'created_at', 'type': 'TIMESTAMP'}],
        'pg_stat': [{'name': 'x', 'type': 'INT'}],
    }
    compressed = compress_schema(demo_schema)
    print('Tables kept:', list(compressed.keys()))
    print('users columns after compression:', [c['name'] for c in compressed['users']])

Menambah Penerangan Jadual

Nama lajur sahaja tidak semestinya cukup jelas. Menambah penerangan dalam bahasa semula jadi tentang perkara yang diwakili oleh setiap jadual meningkatkan kualiti penjanaan SQL dengan ketara.

Simpan penerangan dalam fail konfigurasi atau sebagai ulasan jadual PostgreSQL.

TABLE_DESCRIPTIONS = {
    'users': 'Registered app users with authentication info',
    'orders': 'Customer purchase orders',
    'order_items': 'Individual line items within an order',
    'products': 'Product catalog with pricing',
    'payments': 'Payment transactions linked to orders'
}

def format_schema_with_descriptions(schema_dict):
    lines = []
    for table, columns in schema_dict.items():
        desc = TABLE_DESCRIPTIONS.get(table, '')
        col_str = ', '.join(f"{c['name']} ({c['type']})" for c in columns)
        if desc:
            lines.append(f"Table {table} ({desc}): {col_str}")
        else:
            lines.append(f"Table {table}: {col_str}")
    return '\n'.join(lines)

if __name__ == '__main__':
    demo_schema = {'users': [{'name': 'id', 'type': 'INT'}], 'orders': [{'name': 'id', 'type': 'INT'}]}
    print(format_schema_with_descriptions(demo_schema))

Penyimpanan Skema dalam Cache

Skema pangkalan data jarang berubah. Mendapatkan INFORMATION_SCHEMA bagi setiap pertanyaan menambah kependaman dan beban. Simpan rentetan skema berformat dalam cache dan batalkan cache apabila berlaku peristiwa perubahan skema atau selepas TTL berasaskan masa.

import time

class SchemaCache:
    def __init__(self, ttl_seconds=300):
        self._cache = None
        self._timestamp = 0
        self.ttl = ttl_seconds

    def get(self, conn):
        now = time.time()
        if self._cache is None or (now - self._timestamp) > self.ttl:
            print('Refreshing schema cache...')
            schema_dict = build_schema_dict(conn)
            fk_info = get_foreign_keys(conn)
            self._cache = format_schema_for_prompt(schema_dict, fk_info=fk_info)
            self._timestamp = now
        return self._cache

schema_cache = SchemaCache(ttl_seconds=300)

Aliran Penyisipan Skema Lengkap

Menggabungkan semua teknik: cache skema termampat, sisipkannya ke dalam gesaan sistem, dan gunakan penapisan jadual terpilih untuk pangkalan data yang besar.

def build_sql_agent_prompt(question, conn, large_db=False):
    if large_db:
        schema = compressed_schema(question, conn)
        schema_text = format_schema_with_descriptions(schema)
    else:
        schema_text = schema_cache.get(conn)

    system = f'''You are a PostgreSQL expert.
Return ONLY a valid SELECT query based on this schema:

{schema_text}

Rules:
- Use only SELECT statements
- Use table aliases for clarity
- Limit results to 100 rows unless asked for all
'''
    return system

Semakan Pengetahuan

Bilakah anda patut menggunakan penyisipan jadual terpilih berbanding menyisipkan skema lengkap?

Imbas Kembali: Pemahaman dan Penyisipan Skema

Penyisipan skema yang berkesan ialah asas kepada ejen NL-ke-SQL yang boleh dipercayai. Ekstrak struktur daripada INFORMATION_SCHEMA, sertakan hubungan kunci utama dan kunci asing, dan formatkan sebagai teks padat untuk LLM.

Untuk pangkalan data yang besar: cache skema, buang lajur audit, dan gunakan penyisipan terpilih supaya hanya jadual yang berkaitan dengan setiap soalan dihantar. Penerangan jadual dalam bahasa semula jadi turut meningkatkan kualiti pertanyaan.

Percuma untuk bermula

Pelajari Ejen AI dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
60
Pelajaran
239

Soalan Lazim

Adakah pelajaran “Memahami dan Menyuntik Skema” percuma?

Ya — teks penuh “Memahami dan Menyuntik Skema” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus Ejen AI, tingkat taraf kepada CoddyKit PRO. Kursus Ejen AI merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Memahami dan Menyuntik Skema”?

Mengekstrak dan memformat skema DB untuk konteks LLM: jadual, lajur dan hubungan. Anda berlatih Ejen AI menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Ejen AI?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Ejen AI di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 2 daripada 4.

Berapa lamakah pelajaran “Memahami dan Menyuntik Skema” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Ejen AI ini?

Ya. Setiap pelajaran Ejen AI menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Cara Ejen NL-ke-SQL Berfungsi
  2. Memahami dan Menyuntik Skema
  3. Menjana dan Mengesahkan Pertanyaan SQL
  4. Mengendalikan Soalan Pangkalan Data yang Kabur
← Kembali ke Ejen AI