بناء وكلاء نماذج اللغة الكبيرة (LLM) الذين يعيدون بيانات مهيكلة بشكل موثوق هو أحد أكثر نقاط الألم شيوعًا في هندسة الذكاء الاصطناعي. على الرغم من أن نماذج اللغة الكبيرة ممتازة في توليد النصوص الإبداعية، إلا أنها عرضة للهلوسة وأخطاء التنسيق عند تكليفها بإنتاج JSON صارم. تتضمن الأساليب التقليدية غالبًا تعابير نمطية هشة أو حلقات إعادة محاولة التي تفسر النص الخام، مما يؤدي إلى أنظمة إنتاج غير مستقرة.
هنا يأتي PydanticAI، إطار عمل وكلاء بلغة بايثون مصمم لجعل التعامل مع نماذج اللغة الكبيرة آمنًا وقابلًا للتنبؤ وصديقًا للمطورين. من خلال الاستفادة من قوة نماذج Pydantic، يضمن PydanticAI التحقق من صحة مخرجات LLM مقابل مخططات صارمة قبل إعادتها إلى تطبيقك. يستكشف هذا المنشور كيفية استخدام PydanticAI لبناء وكلاء آمنين نوعيًا قادرين على استخراج هياكل JSON معقدة ومتداخلة من نصوص غير مهيكلة.
لماذا يعد الأمان النوعي مهمًا في خطوط أنابيب LLM
في اللغات الديناميكية مثل بايثون، يكون "النمط البطة" (duck typing) غالبًا كافيًا للتطوير الأولي. ومع ذلك، عندما تكون مخرجات LLM مدخلًا لكتابة قاعدة بيانات لاحقة، أو استدعاء API، أو محرك منطق أعمال، فإن الغموض قاتل. إذا أعاد النموذج نصًا حيث يُتوقع عدد صحيح، أو فاته حقل مطلوب، فقد ينهار تطبيقك أو، ما هو أسوأ، يفشل بصمت مع بيانات تالفة.
يحل PydanticAI هذه المشكلة من خلال دمج التحقق من المخطط مباشرة في حلقة تنفيذ الوكيل. بدلاً من طلب "بعض JSON" من النموذج، تقوم بتعريف فئة بايثون باستخدام Pydantic. يترجم PydanticAI تلقائيًا تعريف هذه الفئة إلى مخطط JSON يفهمه LLM. إذا لم تتطابق استجابة LLM مع المخطط، يمكن لـ PydanticAI أن يطلق حلقة تصحيح ذاتي تلقائيًا، مما يدفع النموذج إلى إصلاح أخطائه قبل أن تُعرض البيانات على تطبيقك.
تعريف هياكل المخرجات المعقدة
من الميزات البارزة في PydanticAI هي دعمه لنماذج Pydantic المعقدة. يمكنك استخدام النماذج المتداخلة، والقوائم المحددة (enums)، والمحققين المخصصين لفرض قواعد منطق الأعمال مباشرة على مخرجات LLM.
فكّر في سيناريو نحتاج فيه إلى استخراج تفاصيل الفاتورة من بريد إلكتروني. تتضمن البيانات اسم العميل، وقائمة بنود سطرية مع إجماليات محسوبة، وتاريخ. يمكننا تعريف هذه البنية بأمان نوعي كامل:
from pydantic import BaseModel, Field, field_validator
from datetime import date
from pydantic_ai import Agent
class LineItem(BaseModel):
description: str = Field(..., description="وصف موجز للعنصر")
quantity: int = Field(..., gt=0)
price: float = Field(..., ge=0)
def total(self) -> float:
return self.quantity * self.price
class InvoiceData(BaseModel):
customer_name: str = Field(..., description="الاسم القانوني الكامل للعميل")
invoice_date: date
line_items: list[LineItem]
total_amount: float
@field_validator('total_amount')
@classmethod
def check_total(cls, v: float, info) -> float:
if 'line_items' in info.data:
calculated = sum(item.total() for item in info.data['line_items'])
if abs(v - calculated) > 0.01:
raise ValueError("المبلغ الإجمالي لا يطابق مجموع البنود")
return v
agent = Agent("openai:gpt-4o", result_type=InvoiceData)
لاحظ @field_validator. هذا ليس مجرد شكل للبيانات؛ بل يفرض الاتساق المنطقي. إذا هلوس النموذج بإجمالي لا يطابق مجموع بنوده، يفشل التحقق، وسيدفع PydanticAI النموذج إلى إعادة النظر.
تنفيذ الوكيل ومعالجة الاستجابات
بمجرد تعريف الوكيل، يكون تنفيذه مباشرًا. يعيد منهج run كائنًا من نوع محدد، مما يعني أنك تحصل على دعم كامل من بيئة التطوير المتكامل (IDE) وفحص الأنواع في IDE الخاص بك. لا حاجة لاستخدام data['customer_name']؛ يمكنك استخدام data.customer_name.
import asyncio
email_text = """
Subject: Invoice #12345
Hi John,
Here is the invoice for October.
Item 1: Widget A x2 @ $50.00
Item 2: Widget B x1 @ $100.00
Total: $200.00
Date: 2023-10-27
"""
async def main():
result = await agent.run(email_text)
# result.data is a fully validated InvoiceData object
print(f"Customer: {result.data.customer_name}")
print(f"Total: {result.data.total_amount}")
# Safe to access nested data without KeyError or AttributeError
for item in result.data.line_items:
print(f"- {item.description}: {item.total()}")
asyncio.run(main())
أفضل الممارسات للتصدير المعقد
- إبقاء النماذج مسطحة حيثما أمكن: على الرغم من دعم التداخل، يمكن أن تسبب الهياكل المتداخلة بعمق ارتباكًا لنماذج اللغة الكبيرة أحيانًا. تسطيح المخطط حيثما كان منطحيًا غالبًا ما يحسن الدقة.
- استخدام أوصاف حقول وصفية: تعتمد نماذج اللغة الكبيرة على معامل
descriptionفي حقول Pydantic لفهم السياق. كن صريحًا بشأن متطلبات التنسيق (مثل "تاريخ ISO 8601"). - الاستفادة من القوائم المحددة (Enums): إذا كان للحقل مجموعة ثابتة من القيم (مثل رموز الحالة)، استخدم فئات
enumفي بايثون. يقلل هذا بشكل كبير من احتمالية البيانات التصنيفية غير الصالحة.
الخلاصة
يمثل PydanticAI خطوة كبيرة إلى الأمام في جعل تطبيقات LLM جاهزة للإنتاج. من خلال نقل عبء التحقق من البيانات من التحليل اللاحق إلى فحص الأنواع المسبق، تقوم بإزالة فئة كاملة من أخطاء وقت التشغيل. للمطورين الذين يبنيون وكلاء يحتاجون إلى التعامل مع خطوط أنابيب البيانات المهيكلة، يقدم PydanticAI حلًا نظيفًا وبائثونيًا ومتينًا. اعتمد الأمان النوعي، وسيكافئك وكلاء LLM بمخرجات موثوقة وقابلة للتنبؤ.