فهم المخطط وحقنه
استخراج مخطط قاعدة البيانات وتنسيقه لسياق LLM: الجداول، والأعمدة، والعلاقات
فهم المخطط وحقنه درس مجاني في AI Agents على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Agents، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Agents 4 دروس في المجموع.
أهمية سياق المخطط
يعرف LLM صياغة SQL، لكنه لا يعرف شيئًا عن قاعدة بياناتك أنت. ومن دون سياق المخطط، سيختلق أسماء الجداول والأعمدة.
يعني حقن المخطط استخراج بنية قاعدة البيانات برمجيًا وإدراجها في كل تلقين — مما يجعل LLM على دراية بجداولك وأعمدتك وأنواعها الفعلية.
الاستعلام عن INFORMATION_SCHEMA
توفّر جميع قواعد البيانات العلائقية الرئيسية البيانات الوصفية من خلال INFORMATION_SCHEMA. ويمكنك الاستعلام عنها للحصول على كل جدول واسم عمود ونوع بيانات دون لمس كود التطبيق.
يعمل هذا في PostgreSQL وMySQL وSQL Server وSQLite، مع وجود اختلافات طفيفة.
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()تجميع الأعمدة حسب الجدول
تكون نتيجة INFORMATION_SCHEMA الخام قائمة مسطحة من الصفوف. جمّع الصفوف حسب اسم الجدول لإنشاء تمثيل منظم يسهل تنسيقه في تلقين.
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'}]
# }تنسيق المخطط لتلقينات LLM
يقرأ LLM المخطط كنص عادي. استخدم تنسيقًا موجزًا وسهل القراءة: جدول واحد في كل سطر، مع أسماء الأعمدة وأنواعها بين قوسين.
يساعد تضمين المفاتيح الأساسية (PK) والمفاتيح الخارجية (FK) LLM على كتابة عبارات JOIN صحيحة.
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))
تضمين المفاتيح الأساسية والخارجية
تُعد علاقات المفاتيح الخارجية أهم جزء في سياق المخطط — فهي تخبر LLM بكيفية كتابة عبارات JOIN. استعلم عن information_schema.table_constraints وkey_column_usage لاستخراجها.
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}')
ضغط المخطط: المشكلة
قد تحتوي قاعدة بيانات مؤسسية فعلية على أكثر من 200 جدول. وإذا حقنت المخطط كاملًا، فسوف تتجاوز نافذة سياق GPT-4 وتهدر المال على الرموز.
يحتوي مخطط يضم 200 جدول، في كل منها 20 عمودًا، على نحو 40,000+ رمز — وهو عدد مكلف جدًا لإرساله مع كل استعلام.
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ضغط المخطط: الحقن الانتقائي
تتمثل استراتيجية الضغط الأكثر فعالية في حقن الجداول ذات الصلة بالسؤال فقط. استخدم نهجًا من مرحلتين — اسأل LLM أولًا عن الجداول التي يحتاج إليها، ثم احقن مخططات تلك الجداول فقط.
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}ضغط المخطط: استبعاد أعمدة الضوضاء
تحتوي جداول كثيرة على أعمدة تدقيق مثل created_at وupdated_at وdeleted_at وversion وcreated_by، ونادرًا ما تكون هذه الأعمدة ذات صلة باستعلامات الأعمال. احذفها لتقليل عدد الرموز.
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']])
إضافة أوصاف الجداول
لا تكون أسماء الأعمدة وحدها واضحة دائمًا. تؤدي إضافة أوصاف باللغة الطبيعية لما يمثله كل جدول إلى تحسين جودة توليد SQL بشكل كبير.
خزّن الأوصاف في ملف إعدادات أو في تعليقات جداول 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))
تخزين المخطط مؤقتًا
نادراً ما تتغير مخططات قواعد البيانات. ويؤدي جلب INFORMATION_SCHEMA مع كل استعلام إلى إضافة زمن استجابة وحِمل إضافيين. خزّن سلسلة المخطط المنسّقة مؤقتًا، وأبطِلها عند وقوع أحداث تغيّر المخطط أو بعد انقضاء مدة TTL محددة.
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)التدفق الكامل لإدراج المخطط
اجمع بين جميع الأساليب: خزّن المخطط المضغوط مؤقتًا، وأدرجه في موجه النظام، واستخدم تصفية انتقائية للجداول في قواعد البيانات الكبيرة.
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اختبار المعرفة
متى ينبغي استخدام إدراج الجداول بشكل انتقائي بدلاً من إدراج المخطط الكامل؟
مراجعة: فهم المخطط وإدراجه
يُعد إدراج المخطط بفعالية أساسَ وكلاء تحويل اللغة الطبيعية إلى SQL الموثوقين. استخرج البنية من INFORMATION_SCHEMA، وأدرج علاقات المفاتيح الأساسية والأجنبية، ونسّقها في صورة نص مضغوط لنموذج LLM.
بالنسبة إلى قواعد البيانات الكبيرة: خزّن المخطط مؤقتًا، وأزل أعمدة التدقيق، واستخدم الإدراج الانتقائي لإرسال الجداول المرتبطة بكل سؤال فقط. كما يؤدي وصف الجداول باللغة الطبيعية إلى تحسين جودة الاستعلامات.
الأسئلة الشائعة
هل درس «فهم المخطط وحقنه» مجاني؟
نعم — نص درس «فهم المخطط وحقنه» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Agents، انتقل إلى CoddyKit PRO. تتضمن دورة AI Agents 4 دروس في المجموع.
ماذا ستتعلم في «فهم المخطط وحقنه»؟
استخراج مخطط قاعدة البيانات وتنسيقه لسياق LLM: الجداول، والأعمدة، والعلاقات تتمرن على AI Agents مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ AI Agents؟
لا تُشترط خبرة سابقة. AI Agents على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «فهم المخطط وحقنه»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس AI Agents هذا؟
نعم. كل درس في AI Agents يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- كيف تعمل وكلاء NL-to-SQL؟
- فهم المخطط وحقنه
- إنشاء استعلامات SQL والتحقق منها
- التعامل مع أسئلة قواعد البيانات الملتبسة