AI Engineering Academy · درس

التحقق من المخرجات الخاطئة وإعادة المحاولة

طبّقوا طبقة تحقق تفحص البيانات المستخرجة مقابل قواعد العمل، وتعُيد المحاولة تلقائيًا مع ملاحظات تصحيحية عند فشل التحقق، وتسجّل أنماط الفشل.

الدرس 4 من 413 خطوة

التحقق من المخرجات الخاطئة وإعادة المحاولة درس مجاني في AI Engineering Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Engineering Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Engineering Academy 4 دروس في المجموع.

لماذا تحتاج مخرجات LLM إلى التحقق

حتى مع المخرجات المهيكلة ومخططات Pydantic، قد ينتج عن استخراج LLM مخرجات صحيحة نحويًا لكنها خاطئة دلاليًا. فدرجة ثقة مقدارها 1.5 (خارج النطاق من 0 إلى 1)، أو سعر مقداره -99.99، أو سلسلة تاريخ يتعذر تحليلها، أو رقم هاتف يحتوي على أحرف؛ كل هذه القيم تجتاز تحليل JSON لكنها تفشل في قواعد الأعمال لديكم.

التحقق مسؤولية منفصلة عن الاستخراج. يسأل الاستخراج: 'هل حصلنا على بيانات مهيكلة؟' ويسأل التحقق: 'هل البيانات المهيكلة صحيحة وقابلة للاستخدام؟' وكلتا الطبقتين ضروريتان لخط أنابيب ملائم لبيئة الإنتاج. فكّروا في الأمر باعتباره مرشحًا من مرحلتين: يستخرج LLM، ثم يقبل المدقّق النتيجة أو يرفضها.

طبقات التحقق

يعمل نظام قوي للتحقق من المخرجات على مستويات متعددة:

  1. التحقق من المخطط (Pydantic): صحة أنواع الحقول، ووجود الحقول المطلوبة، وتطابق القيم المحددة مع القيم المسموح بها؛ وتتولى المخرجات المهيكلة ذلك تلقائيًا
  2. التحقق من التنسيق: تطابق أرقام الهاتف مع regex، وصحة عناوين البريد الإلكتروني، وقابلية تحليل التواريخ، ووقوع المبالغ ضمن نطاقات واقعية
  3. التحقق من منطق الأعمال: يساوي إجمالي الفاتورة مجموع بنودها، وتاريخ الانتهاء لاحق لتاريخ البدء، والكمية عدد صحيح موجب
  4. التحقق بين الحقول: تعتمد قيمة أحد الحقول على قيمة حقل آخر (مثلًا، لا يجوز أن تتجاوز نسبة الخصم 100)
  5. التحقق الدلالي: يطابق اسم الشركة المستخرج شركة معروفة في قاعدة بياناتكم

مدقّقات Pydantic لفحص التنسيق

تتيح لكم مزينة field_validator في Pydantic إضافة منطق تحقق مخصص يُشغَّل عند إنشاء النموذج. استخدموها لفحوصات مستوى التنسيق، مثل التحقق باستخدام regex من أرقام الهاتف وعناوين البريد الإلكتروني، وتحليل التواريخ، وفحص نطاقات الحقول الرقمية.

from pydantic import BaseModel, Field, field_validator
from typing import Optional
import re
from datetime import datetime

class ExtractedInvoice(BaseModel):
    vendor: str
    invoice_number: Optional[str]
    amount: float = Field(gt=0, description='Must be positive')
    currency: str = Field(min_length=3, max_length=3)
    invoice_date: str

    @field_validator('currency')
    @classmethod
    def currency_must_be_uppercase(cls, v):
        return v.upper()

    @field_validator('invoice_date')
    @classmethod
    def parse_date(cls, v):
        # Try to parse common date formats
        for fmt in ('%Y-%m-%d', '%d/%m/%Y', '%m/%d/%Y', '%B %d, %Y'):
            try:
                datetime.strptime(v, fmt)
                return v
            except ValueError:
                continue
        raise ValueError(f'Cannot parse date: {v}')

    @field_validator('amount')
    @classmethod
    def reasonable_amount(cls, v):
        if v > 10_000_000:
            raise ValueError(f'Amount {v} seems unreasonably large. Flag for review.')
        return round(v, 2)

نمط إعادة المحاولة مع الملاحظات التصحيحية

عند فشل التحقق، تتمثل استراتيجية الاسترداد الأكثر فعالية في إعادة المحاولة مع ملاحظات تصحيحية: أرسلوا رسالة خطأ التحقق إلى النموذج مرة أخرى باعتبارها سياقًا، واشرحوا ما حدث من خطأ واطلبوا منه إصلاح الحقول الفاشلة فقط. ويزوّد ذلك النموذج بالمعلومات اللازمة لتصحيح مخرجاته بدلًا من إعادة المحاولة بصورة عمياء.

import openai
from pydantic import BaseModel, ValidationError, Field

client = openai.OpenAI()

class PriceExtraction(BaseModel):
    product: str
    price_usd: float = Field(gt=0, lt=100000)
    quantity: int = Field(ge=1)

def extract_with_retry(text: str, max_retries: int = 3) -> PriceExtraction:
    messages = [
        {'role': 'system', 'content': 'Extract product pricing information.'},
        {'role': 'user', 'content': text}
    ]

    for attempt in range(max_retries):
        result = client.beta.chat.completions.parse(
            model='gpt-4o-mini',
            messages=messages,
            response_format=PriceExtraction
        )
        msg = result.choices[0].message
        if msg.refusal:
            raise ValueError(f'Model refused: {msg.refusal}')

        try:
            return msg.parsed  # Pydantic validates on parse
        except ValidationError as e:
            if attempt == max_retries - 1:
                raise
            # Add corrective feedback for the next attempt
            messages.append({'role': 'assistant', 'content': msg.content})
            messages.append({'role': 'user', 'content': f'The previous extraction failed validation: {e}\nPlease correct and try again.'})
            print(f'Attempt {attempt+1} failed. Retrying with feedback...')

التحقق من منطق الأعمال

يتحقق منطق الأعمال من الخصائص التي تشمل حقولًا متعددة أو تعتمد على مصادر بيانات خارجية. وتُشغّل model_validator في Pydantic بعد جميع مدقّقات الحقول، ويمكنها الوصول إلى النموذج المكتمل، مما يجعلها المكان المناسب لفحوصات الحقول المتقاطعة.

from pydantic import BaseModel, Field, model_validator
from typing import List

class LineItem(BaseModel):
    description: str
    quantity: int = Field(ge=1)
    unit_price: float = Field(ge=0)
    line_total: float

    @model_validator(mode='after')
    def check_line_total(self):
        expected = round(self.quantity * self.unit_price, 2)
        actual = round(self.line_total, 2)
        if abs(expected - actual) > 0.02:  # Allow 2-cent rounding tolerance
            raise ValueError(
                f'Line total {actual} does not match quantity*price={expected}'
            )
        return self

class Invoice(BaseModel):
    line_items: List[LineItem]
    subtotal: float
    tax: float
    total: float

    @model_validator(mode='after')
    def check_invoice_total(self):
        expected_total = round(self.subtotal + self.tax, 2)
        if abs(expected_total - round(self.total, 2)) > 0.02:
            raise ValueError(
                f'Invoice total {self.total} != subtotal+tax ({expected_total})'
            )
        return self

تسجيل حالات فشل التحقق

كل حالة فشل في التحقق هي إشارة إلى موضع تعطل خط الأنابيب. سجّلوا كل حالة فشل مع: نص الإدخال (أو تجزئة له حفاظًا على الخصوصية)، والمخرجات المستخرجة، وخطأ التحقق المحدد، ورقم المحاولة. واجمعوا هذه السجلات لتحديد الأنماط المنهجية؛ فهل يخطئ النموذج باستمرار في حقل واحد؟ وهل توجد فئة من المستندات تتسبب في حالات الفشل؟ وتوجّه هذه البيانات التحسينات المستهدفة للمطالبات.

import logging
from pydantic import ValidationError

logger = logging.getLogger(__name__)

def extract_with_logging(text: str, doc_id: str) -> dict:
    result = None
    for attempt in range(3):
        try:
            result = run_extraction(text)  # Your extraction function
            logger.info('Extraction success', extra={
                'doc_id': doc_id,
                'attempt': attempt + 1
            })
            return result
        except ValidationError as e:
            logger.warning('Validation failure', extra={
                'doc_id': doc_id,
                'attempt': attempt + 1,
                'errors': e.errors(),
                'error_count': len(e.errors())
            })
    # All retries failed
    logger.error('Extraction failed after max retries', extra={'doc_id': doc_id})
    return {'error': 'extraction_failed', 'doc_id': doc_id}

def run_extraction(text):
    pass  # Placeholder for actual extraction logic

درجات الثقة والحدود

أضيفوا حقل confidence إلى مخطط الاستخراج، ووجّهوا النموذج إلى تقييم ثقته في كل عملية استخراج بقيمة من 0 إلى 1. ثم طبّقوا قواعد الأعمال بناءً على الثقة: تُرسل عمليات الاستخراج عالية الثقة مباشرةً إلى قاعدة البيانات، وتُعلَّم عمليات الاستخراج متوسطة الثقة للفحص العشوائي، وتُرسل عمليات الاستخراج منخفضة الثقة إلى قائمة انتظار للمراجعة البشرية.

ويُعد هذا النهج الاحتمالي أكثر عملية بكثير من اشتراط دقة قدرها 100% من LLM؛ إذ تصممون خط الأنابيب للتعامل مع عدم اليقين بسلاسة بدلًا من التظاهر بعدم وجوده.

from pydantic import BaseModel, Field
from typing import Optional

class ExtractedWithConfidence(BaseModel):
    value: Optional[str]
    confidence: float = Field(ge=0.0, le=1.0)
    reason: Optional[str] = None  # Why confidence is low, if below threshold

class DocumentExtraction(BaseModel):
    vendor_name: ExtractedWithConfidence
    invoice_amount: ExtractedWithConfidence
    due_date: ExtractedWithConfidence

def route_by_confidence(extraction: DocumentExtraction, threshold=0.85):
    low_confidence_fields = []
    for field_name, field_val in extraction.model_dump().items():
        if isinstance(field_val, dict) and field_val.get('confidence', 1.0) < threshold:
            low_confidence_fields.append(field_name)

    if not low_confidence_fields:
        return 'auto_approve'
    elif len(low_confidence_fields) > 2:
        return 'human_review'
    else:
        return f'spot_check: {low_confidence_fields}'

استراتيجيات بديلة عند فشل إعادة المحاولة

عند استنفاد جميع محاولات إعادة المحاولة واستمرار فشل التحقق، تحتاجون إلى استراتيجية بديلة. وتأتي الخيارات حسب الأفضلية:

  1. نتيجة جزئية: أعيدوا الحقول التي اجتازت التحقق، واجعلوا الحقول الفاشلة null
  2. قائمة انتظار للمراجعة البشرية: أضيفوا المستند إلى قائمة انتظار للمراجعة اليدوية، ولا سيما بالنسبة إلى المستندات عالية القيمة
  3. استخراج أقل دقة: انتقلوا إلى مخطط أبسط يطلب عددًا أقل من الحقول، مع قبول بنية أقل مقابل مزيد من المتانة
  4. تخزين النص الخام: خزّنوا النص الأصلي مع البيانات الوصفية لإعادة معالجته لاحقًا عند تحسين خط أنابيب الاستخراج

لا تتخلصوا من المستند بصمت أبدًا. سجّلوا الفشل دائمًا وتأكدوا من إمكانية الرجوع إليه.

التحقق الدلالي مقابل البيانات الخارجية

تتطلب بعض قواعد التحقق عمليات بحث في بيانات خارجية لا يمكن تنفيذها داخل أدوات التحقق في Pydantic. فمثلًا، يمكن التحقق من ظهور اسم الشركة المستخرج في نظام CRM لديكم، أو من وجود رمز SKU للمنتج المستخرج في مخزونكم. ينبغي تنفيذ هذه الفحوصات في خطوة تحقق لاحقة للاستخراج، تعمل بعد اجتياز التحقق في Pydantic.

from typing import Optional

# Simulated external data source
KNOWN_VENDORS = {'acme corp', 'techsupplies inc', 'globex corporation'}

def validate_against_crm(extraction: dict) -> dict:
    vendor = extraction.get('vendor', '').lower()
    warnings = []

    if vendor and vendor not in KNOWN_VENDORS:
        warnings.append({
            'field': 'vendor',
            'issue': f'Vendor "{vendor}" not found in CRM',
            'severity': 'warning'
        })
        # Optionally suggest closest match
        # from difflib import get_close_matches
        # matches = get_close_matches(vendor, KNOWN_VENDORS, n=1, cutoff=0.8)
        # if matches: warnings[-1]['suggestion'] = matches[0]

    return {
        'extraction': extraction,
        'warnings': warnings,
        'requires_review': len(warnings) > 0
    }

print('Semantic validation pattern defined')

اختبار مسار التحقق لديكم

يحتاج منطق التحقق لديكم إلى مجموعة اختبارات خاصة به، منفصلة عن اختبارات الاستخراج. اكتبوا اختبارات وحدات تمرر مخرجات معروفة الخطأ إلى أدوات التحقق لديكم، وتتحقق من رفع الأخطاء الصحيحة. اختبروا الحالات الحدّية، مثل المبالغ عند القيم الحدّية، والتواريخ بالتنسيقات غير المعتادة، والحقول التي تحتوي على مسافات بيضاء غير متوقعة، والحقول التي تكون سلاسل رقمية بدلًا من أرقام.

تعمل مجموعة اختبارات التحقق هذه من دون إجراء أي استدعاءات لواجهات API، مما يجعل تشغيلها سريعًا وقليل التكلفة مع كل تغيير في الشيفرة. كما أنها أفضل توثيق لقواعد التحقق لديكم، إذ توضح حالات الاختبار صراحةً كل تنسيق وكل قيد من قيود العمل التي يفرضها مساركم.

from pydantic import ValidationError

def test_extraction_validation():
    # Test cases: (input_data, should_pass)
    test_cases = [
        ({'vendor': 'ACME', 'amount': 150.00, 'currency': 'USD', 'invoice_date': '2025-01-15'}, True),
        ({'vendor': 'ACME', 'amount': -50.00, 'currency': 'USD', 'invoice_date': '2025-01-15'}, False),  # negative
        ({'vendor': 'ACME', 'amount': 150.00, 'currency': 'EURO', 'invoice_date': '2025-01-15'}, False), # 4-char
        ({'vendor': 'ACME', 'amount': 150.00, 'currency': 'USD', 'invoice_date': 'yesterday'}, False),   # bad date
    ]
    passed = failed = 0
    for data, should_pass in test_cases:
        try:
            # ExtractedInvoice(**data)  # Your Pydantic model
            if should_pass:
                passed += 1
            else:
                print(f'MISSED: Should have failed for {data}')
                failed += 1
        except (ValidationError, ValueError):
            if not should_pass:
                passed += 1
            else:
                print(f'UNEXPECTED FAIL for {data}')
                failed += 1
    print(f'Tests: {passed} passed, {failed} failed')

test_extraction_validation()

تحليل أنماط الإخفاق وضبط المطالبات

بعد تشغيل مسار الاستخراج لديكم على عينة من المستندات الحقيقية ومراجعة إخفاقات التحقق، ستجدون على الأرجح أن 80% من الإخفاقات تشترك في عدد قليل من الأسباب الجذرية. ومن الأسباب الشائعة: أن ينسّق النموذج التواريخ باستمرار بطريقة خاطئة من منطقة محلية محددة، أو يخلط بين قيمة الضريبة والإجمالي، أو ينتج أرقام هواتف من دون واصلات بينما يتوقع أداة التحقق لديكم وجودها.

لكل نمط إخفاق متكرر، حدّثوا مطالبة الاستخراج بمثال محدد وقيد يمنع حدوث الخطأ. وبعد التحديث، أعيدوا تشغيل مجموعة الاختبارات الكاملة للتأكد من أن الإصلاح حسّن الدقة من دون التسبب في تراجع الحالات الأخرى. هذه الدورة التكرارية: مطالبة ثم تقييم، هي الطريقة التي تصل بها مسارات الاستخراج المستخدمة في الإنتاج إلى دقة تتجاوز 95% على البيانات الواقعية.

تحقق سريع

اختبروا مدى فهمكم لمفاهيم هندسة الذكاء الاصطناعي الواردة في هذا الدرس.

مراجعة الدرس

تعلمتم في هذا الدرس أن التحقق يتم على طبقات متعددة — المخطط، والتنسيق، ومنطق العمل، والدلالة — وتتطلب كل طبقة أساليب تنفيذ مختلفة، وأن إعادة المحاولة مع تقديم ملاحظات تصحيحية تزوّد النموذج بسياق محدد عن الخطأ ليصحح مخرجاته بكفاءة، وأن درجات الثقة تتيح توجيهًا احتماليًا للمخرجات إلى قوائم الموافقة التلقائية أو الفحص العشوائي أو المراجعة البشرية بناءً على مدى يقين الاستخراج. لقد أكملتم الآن دورة المخرجات المنظمة ووضع JSON. بعد ذلك، سنستكشف التضمينات المتجهية، وهي أساس كل نظام RAG.

البدء مجانًا

تعلم Python مع معلم ذكاء اصطناعي — مجانًا

اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.

الدورات
30
الدروس
120

الأسئلة الشائعة

هل درس «التحقق من المخرجات الخاطئة وإعادة المحاولة» مجاني؟

نعم — نص درس «التحقق من المخرجات الخاطئة وإعادة المحاولة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Engineering Academy، انتقل إلى CoddyKit PRO. تتضمن دورة AI Engineering Academy 4 دروس في المجموع.

ماذا ستتعلم في «التحقق من المخرجات الخاطئة وإعادة المحاولة»؟

طبّقوا طبقة تحقق تفحص البيانات المستخرجة مقابل قواعد العمل، وتعُيد المحاولة تلقائيًا مع ملاحظات تصحيحية عند فشل التحقق، وتسجّل أنماط الفشل. تتمرن على AI Engineering Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ AI Engineering Academy؟

لا تُشترط خبرة سابقة. AI Engineering Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «التحقق من المخرجات الخاطئة وإعادة المحاولة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس AI Engineering Academy هذا؟

نعم. كل درس في AI Engineering Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. وضع JSON وresponse_format
  2. المخرجات المنظّمة باستخدام Pydantic
  3. استخراج البيانات من النصوص غير المنظّمة
  4. التحقق من المخرجات الخاطئة وإعادة المحاولة
← العودة إلى AI Engineering Academy