استخراج بيانات مهيكلة (Output Parsers): إجبار الذكاء الاصطناعي على الرد بصيغة JSON فقط
لماذا نحتاج إلى Output Parsers في تطبيقات LLM؟
عند بناء تطبيقات ذكاء اصطناعي توليدي، تكون المشكلة الأساسية غالباً ليست في الحصول على إجابة من النموذج، بل في الحصول على إجابة يمكن للبرنامج التعامل معها بثبات. النموذج قد يكتب شرحاً إضافياً، أو يخلط بين النص الحر والبيانات، أو يغيّر أسماء الحقول بين طلب وآخر. هنا تظهر أهمية Output Parsers، وهي طبقة هندسية تُستخدم لفرض بنية محددة على مخرجات النموذج مثل JSON فقط.
هذه الفكرة ضرورية في خطوط الإنتاج البرمجية التي تعتمد على تمرير مخرجات النموذج إلى واجهات API، قواعد البيانات، لوحات التحكم، أنظمة التصنيف، أو حتى تطبيقات هندسة الذكاء الاصطناعي التوليدي ونماذج LLMs. بدون بنية مهيكلة، يصبح التطبيق هشاً، وتزداد احتمالات فشل التحليل، وكسر الواجهة الخلفية، وفقدان قابلية التوسع.
المشكلة المعمارية: النص الحر لا يساوي بيانات قابلة للتنفيذ
من منظور هندسة الأنظمة، يعمل النموذج اللغوي كمولد احتمالي للتوكنات Tokenization وليس كمترجم صارم لبنية بيانات. حتى إذا كتبت في البرومبت “أعد النتيجة بصيغة JSON“, فقد يضيف النموذج تمهيداً مثل “إليك النتيجة”، أو ينسى علامات الاقتباس، أو يعيد حقلاً ناقصاً.
في التطبيقات العملية، يتدفق الطلب عادةً عبر هذه المراحل:
- استقبال إدخال المستخدم في الواجهة الأمامية.
- بناء البرومبت في الواجهة الخلفية باستخدام قوالب ديناميكية مثل هندسة الأوامر داخل الكود باستخدام
F-Strings. - إرسال الطلب إلى النموذج عبر مزود مثل
OpenAI APIبعد إعداد البيئة كما في تثبيت مكتباتPythonوكتابة أول سكربت اتصال. - استقبال نص خام من النموذج.
- تمرير النص إلى
Parserللتحقق من البنية والأنواع. - إعادة المحاولة أو إصلاح المخرجات إذا فشل التحقق.
- تخزين البيانات أو تمريرها إلى خدمة أخرى.
إذن Output Parsing ليس مجرد تحسين شكلي، بل طبقة موثوقية Reliability Layer داخل المعمارية.
كيف نجبر النموذج على الرد بصيغة JSON فقط؟
تقنياً، هناك ثلاث طبقات تكمل بعضها:
- صياغة برومبت واضح يحدد الحقول المسموح بها فقط.
- استخدام مخطط بنيوي
Schemaللتحقق. - التحكم في الإبداع العشوائي عبر معاملات مثل
TemperatureوTop-Kلتقليل الانحرافات.
أنت نظام لاستخراج بيانات مهيكلة. أعد النتيجة بصيغة JSON صالحة فقط دون أي شرح إضافي. استخدم الحقول التالية حصراً: title, category, confidence, keywords. يجب أن يكون confidence رقماً عشرياً بين 0 و1، وkeywords مصفوفة نصية.
هذا البرومبت جيد، لكنه وحده غير كافٍ. الحل الاحترافي هو أن نقرن البرومبت بمحلل ناتج يفهم المخطط ويتحقق منه.
استخدام Pydantic وLangChain لبناء Structured Output
في بيئات التطوير الحديثة، يوفّر LangChain أدوات جاهزة لفرض المخرجات المهيكلة. غالباً يتم تعريف نموذج بيانات باستخدام Pydantic ثم إنشاء Parser يحقن تعليمات التنسيق في البرومبت ويحلل الرد.
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import PromptTemplate
from pydantic import BaseModel, Field
class ArticleMeta(BaseModel):
title: str = Field(description="Short article title")
category: str = Field(description="Main technical category")
confidence: float = Field(description="Confidence score between 0 and 1")
keywords: list[str] = Field(description="Relevant keyword list")
parser = PydanticOutputParser(pydantic_object=ArticleMeta)
prompt = PromptTemplate(
template="""
Extract structured data from the input.
{format_instructions}
Input:
{user_input}
""",
input_variables=["user_input"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)
formatted_prompt = prompt.format(
user_input="LangChain helps orchestrate LLM pipelines with prompts, tools, and memory."
)
print(formatted_prompt)
الميزة القوية هنا أن parser.get_format_instructions() يولّد تعليمات شديدة الوضوح للنموذج حول بنية JSON المطلوبة.
تحليل الرد والتحقق من صحته
raw_output = """
{
"title": "LangChain LLM Pipelines",
"category": "Generative AI",
"confidence": 0.94,
"keywords": ["LangChain", "LLM", "Prompts"]
}
"""
parsed = parser.parse(raw_output)
print(parsed.title)
print(parsed.confidence)
print(parsed.keywords)
في هذه المرحلة، لا يكتفي التطبيق بكون الرد يشبه JSON بصرياً، بل يتحقق أيضاً من نوع كل حقل. إذا أعاد النموذج قيمة نصية داخل confidence بدلاً من رقم، سيفشل التحليل مباشرة، وهذا أفضل من تمرير بيانات تالفة إلى قاعدة البيانات.
مثال مباشر باستخدام OpenAI API
import json
from openai import OpenAI
client = OpenAI()
prompt = """
Return valid JSON only.
Schema:
{
"title": "string",
"category": "string",
"confidence": "float",
"keywords": ["string"]
}
Text:
Vector databases store embeddings for semantic retrieval in RAG systems.
"""
response = client.chat.completions.create(
model="gpt-4o-mini",
temperature=0.2,
messages=[
{"role": "system", "content": "You output JSON only."},
{"role": "user", "content": prompt}
]
)
content = response.choices[0].message.content
data = json.loads(content)
print(data)
إذا كنت تبني أنظمة استرجاع معرفي مثل RAG أو تعمل مع Embeddings وVector DBs، فإن المخرجات المهيكلة مفيدة جداً لتصنيف المستندات، وإرجاع درجات الثقة، وبناء فلاتر بحث قابلة للتنفيذ.
استراتيجية المعالجة عند فشل JSON Parsing
الأنظمة الناضجة لا تفترض نجاحاً مثالياً من المحاولة الأولى. لذلك يتم تصميم مسار احتياطي Fallback Flow كالتالي:
- محاولة تحليل الرد كما هو.
- إذا فشل التحليل، إرسال البرومبت نفسه مرة ثانية مع تذكير أكثر صرامة.
- استخدام دالة تنظيف للنص لإزالة أي شرح زائد قبل أو بعد
JSON. - تسجيل الخطأ في نظام مراقبة
Observabilityلتحسين البرومبت لاحقاً.
فشل التحليل السابق لأن الرد لم يكن JSON صالحاً. أعد إرسال النتيجة الآن بصيغة JSON صحيحة فقط، دون أي نص قبلها أو بعدها، وبنفس الحقول المطلوبة.
أفضل الممارسات الهندسية
1) صمّم Schema صغيراً وواضحاً
كلما زاد عدد الحقول والقيود، زادت احتمالات الخطأ. ابدأ ببنية بسيطة ثم وسّعها تدريجياً.
2) قلّل العشوائية
استخدم قيمة منخفضة لـ temperature عندما تكون الأولوية للدقة البنيوية لا للإبداع اللغوي.
3) افصل بين النص التفسيري والبيانات
إذا احتجت شرحاً للمستخدم وبيانات للنظام، فاطلب مهمتين منفصلتين بدلاً من رد واحد مختلط.
4) تحقّق من الأنواع بعد الاستجابة
لا تعتمد على التزام النموذج فقط. استخدم تحققاً برمجياً عبر Pydantic أو تحليل JSON Schema.
الخلاصة العملية
إجبار النموذج على الرد بصيغة JSON فقط ليس حيلة برومبتية بسيطة، بل ممارسة أساسية في هندسة الأنظمة المعتمدة على LLMs. عندما تستخدم Output Parsers، فأنت تنقل المخرجات من مستوى النص الاحتمالي إلى مستوى البيانات القابلة للتنفيذ، وتبني تطبيقاً أكثر استقراراً، وقابلية للاختبار، وأقل عرضة للأخطاء في بيئات الإنتاج.
القاعدة الذهبية هي: لا تثق في النص الخام، بل مرّره دائماً عبر طبقة تحقق بنيوية. هذه الخطوة الصغيرة ظاهرياً هي ما يميّز بين تجربة تجريبية سريعة ونظام ذكاء اصطناعي هندسي محترف.
31 comments