Agent Frameworks

PydanticAI برای استخراج داده‌های ساختاریافته: ساخت عامل‌های ایمن از نظر نوع برای خروجی‌های JSON پیچیده

ساخت عامل‌های LLM که به‌طور قابل‌اعتماد داده‌های ساختاریافته را برمی‌گردانند، یکی از رایج‌ترین چالش‌ها در مهندسی هوش مصنوعی است. در حالی که مدل‌های زبانی بزرگ در تولید متن خلاقانه عالی هستند، اما هنگام تولید JSON سخت‌گیرانه، مستعد توهم و خطاهای قالب‌بندی هستند. رویکردهای سنتی اغلب شامل عبارات منظم شکننده یا حلقه‌های تلاش مجدد برای تجزیه متن خام هستند که منجر به سیستم‌های تولیدی ناپایدار می‌شوند.

ورود PydanticAI، یک چارچوب عامل پایتون که برای ایمن، قابل‌پیش‌بینی و سازگار با توسعه‌دهنده کردن کار با LLMها طراحی شده است. با استفاده از قدرت مدل‌های Pydantic، PydanticAI اطمینان حاصل می‌کند که خروجی‌های LLM قبل از بازگشت به برنامه شما، در برابر طرح‌های سخت‌گیرانه اعتبارسنجی می‌شوند. این پست بررسی می‌کند که چگونه از PydanticAI برای ساخت عامل‌های ایمن از نظر نوع استفاده کنیم که قادر به استخراج ساختارهای JSON پیچیده و تو در تو از متن بدون ساختار هستند.

چرا ایمنی نوع در خط‌های لوله LLM اهمیت دارد

در زبان‌های پویا مانند پایتون، «تایپ‌بندی اردکی» اغلب برای نمونه‌سازی اولیه کافی است. با این حال، زمانی که خروجی LLM به عنوان ورودی برای نوشتن پایگاه داده پایین‌دست، فراخوانی API یا موتور منطق کسب‌وکار عمل می‌کند، ابهام کشنده است. اگر مدل یک رشته را در جایی که یک عدد صحیح انتظار می‌رود برگرداند، یا یک فیلد الزامی را از دست بدهد، برنامه شما ممکن است کرش کند یا، بدتر از آن، با داده‌های خراب به‌صورت خاموش شکست بخورد.

PydanticAI این مشکل را با یکپارچه‌سازی مستقیم اعتبارسنجی طرح در حلقه اجرای عامل حل می‌کند. به جای درخواست «JSONی» از مدل، شما یک کلاس پایتون را با استفاده از Pydantic تعریف می‌کنید. PydanticAI به‌طور خودکار این تعریف کلاس را به یک JSON Schema تبدیل می‌کند که 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="Brief description of the item")
    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="Full legal name of the customer")
    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("Total amount does not match sum of line items")
        return v

agent = Agent("openai:gpt-4o", result_type=InvoiceData)

به @field_validator توجه کنید. این فقط برای شکل داده نیست؛ بلکه سازگاری منطقی را نیز اعمال می‌کند. اگر LLM جمعی را توهم کند که با مجموع اقلام ردیفی آن مطابقت نداشته باشد، اعتبارسنجی شکست می‌خورد و 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())

بهترین روش‌ها برای خروجی‌های پیچیده

  1. مدل‌ها را تا حد امکان تخت نگه دارید: در حالی که تو در تویی پشتیبانی می‌شود، ساختارهای عمیقاً تو در تو گاهی اوقات می‌توانند LLMها را گیج کنند. تخت کردن طرح در جایی که از نظر منطقی مجاز است، اغلب دقت را بهبود می‌بخشد.
  2. از توضیحات توصیفی فیلدها استفاده کنید: LLMها برای درک زمینه به پارامتر description در فیلدهای Pydantic تکیه می‌کنند. در مورد الزامات قالب صریح باشید (مثلاً «تاریخ ISO 8601»).
  3. از شمارنده‌ها (Enumerations) استفاده کنید: اگر یک فیلد مجموعه‌ای ثابت از مقادیر داشته باشد (مانند کدهای وضعیت)، از کلاس‌های enum پایتون استفاده کنید. این کار احتمال داده‌های دسته‌بندی نامعتبر را به‌شدت کاهش می‌دهد.

نتیجه‌گیری

PydanticAI یک گام مهم به جلو در آماده‌سازی کاربردهای LLM برای تولید است. با جابه‌جایی بار اعتبارسنجی داده از تجزیه پس از عمل به بررسی نوع برجسته، شما یک کلاس کامل از خطاهای زمان اجرا را حذف می‌کنید. برای توسعه‌دهندگانی که عامل‌هایی را می‌سازند که نیاز به تعامل با خط‌های لوله داده ساختاریافته دارند، PydanticAI یک راه‌حل تمیز، پایتونی و مقاوم ارائه می‌دهد. ایمنی نوع را در آغوش بگیرید و عامل‌های LLM شما با خروجی‌های قابل‌اعتماد و قابل‌پیش‌بینی از شما تشکر خواهند کرد.

Share: