20 KiB
المواصفات الفنية للإخراج بتنسيق JSONL
نظرة عامة
تصف هذه المواصفات تطبيق تنسيق JSONL (JSON Lines) للإخراج في TrustGraph. يتيح JSONL استخراجًا مقاومًا للتقطيع للبيانات المنظمة من استجابات نماذج اللغة الكبيرة (LLM)، مما يعالج المشكلات الهامة المتعلقة بتلف مخرجات JSON array عندما تصل استجابات نماذج اللغة الكبيرة إلى حدود الرموز المميزة للإخراج.
يدعم هذا التطبيق حالات الاستخدام التالية:
- الاستخراج المقاوم للتقطيع: استخراج نتائج جزئية صالحة حتى عندما يتم اقتطاع إخراج نموذج اللغة الكبيرة في منتصف الاستجابة.
- الاستخراج على نطاق واسع: التعامل مع استخراج العديد من العناصر دون خطر الفشل التام بسبب حدود الرموز المميزة.
- الاستخراج بأنواع متعددة: دعم استخراج أنواع متعددة من الكيانات (التعريفات، والعلاقات، والكيانات، والسمات) في طلب واحد.
- الإخراج المتوافق مع التدفق: تمكين المعالجة المستقبلية التدريجية/المتزايدة لنتائج الاستخراج.
الأهداف
التوافق مع الإصدارات السابقة: تظل الطلبات الحالية التي تستخدم response-type: "text" و
response-type: "json" تعمل دون تعديل.
مقاومة التقطيع: تؤدي مخرجات نماذج اللغة الكبيرة الجزئية إلى نتائج
جزئية صالحة بدلاً من الفشل التام.
التحقق من المخطط: دعم التحقق من مخطط JSON للكائنات الفردية.
الاتحادات المميزة: دعم المخرجات ذات الأنواع المختلطة باستخدام حقل type
مميز.
تغييرات API الحد الأدنى: توسيع تكوين الطلب الحالي بنوع استجابة جديد
ومفتاح مخطط.
الخلفية
البنية الحالية
يدعم خدمة الطلبات نوعين من الاستجابات:
response-type: "text"- استجابة نصية خام يتم إرجاعها كما هي.response-type: "json"- JSON يتم تحليله من الاستجابة، ويتم التحقق منه مقابلschemaاختياري.
التنفيذ الحالي في trustgraph-flow/trustgraph/template/prompt_manager.py:
class Prompt:
def __init__(self, template, response_type = "text", terms=None, schema=None):
self.template = template
self.response_type = response_type
self.terms = terms
self.schema = schema
القيود الحالية
عندما تطلب مطالبات الاستخراج إخراجًا بتنسيق مصفوفات JSON ([{...}, {...}, ...]):
تلف بسبب الاقتطاع: إذا وصلت LLM إلى حدود رموز الإخراج أثناء المصفوفة، يصبح الرد بأكمله JSON غير صالح ولا يمكن تحليله. التحليل الكل أو لا شيء: يجب استقبال الإخراج الكامل قبل التحليل. لا توجد نتائج جزئية: يؤدي الرد المقتطع إلى عدم وجود بيانات قابلة للاستخدام. غير موثوق به للاستخراج الكبير: كلما زاد عدد العناصر المستخرجة، زاد خطر الفشل.
تعالج هذه المواصفات هذه القيود من خلال تقديم تنسيق JSONL لمطالبات الاستخراج، حيث يكون كل عنصر مستخرج كائن JSON كامل في سطر منفصل.
التصميم الفني
إضافة نوع استجابة جديد
أضف نوع استجابة جديد "jsonl" بالإضافة إلى الأنواع الموجودة "text" و "json".
تغييرات التكوين
قيمة نوع الاستجابة الجديدة:
"response-type": "jsonl"
تفسير المخطط:
يتم استخدام المفتاح "schema" الموجود لكل من نوعي الاستجابة "json" و "jsonl".
يعتمد التفسير على نوع الاستجابة:
"json": يصف المخطط الاستجابة بأكملها (عادةً ما يكون مصفوفة أو كائن).
"jsonl": يصف المخطط كل سطر/كائن فردي.
{
"response-type": "jsonl",
"schema": {
"type": "object",
"properties": {
"entity": { "type": "string" },
"definition": { "type": "string" }
},
"required": ["entity", "definition"]
}
}
هذا يمنع التغييرات في أدوات تكوين المطالبات والمحررات.
مواصفات تنسيق JSONL
الاستخراج البسيط
بالنسبة للمطالبات التي تستخرج نوعًا واحدًا من الكائنات (التعريفات، العلاقات، الموضوعات، الصفوف)، يكون الإخراج عبارة عن كائن JSON واحد لكل سطر بدون أي غلاف:
تنسيق إخراج المطالبة:
{"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"}
{"entity": "chlorophyll", "definition": "Green pigment in plants"}
{"entity": "mitochondria", "definition": "Powerhouse of the cell"}
مقارنة مع تنسيق مصفوفة JSON السابق:
[
{"entity": "photosynthesis", "definition": "Process by which plants convert sunlight"},
{"entity": "chlorophyll", "definition": "Green pigment in plants"},
{"entity": "mitochondria", "definition": "Powerhouse of the cell"}
]
إذا قام نموذج اللغة الكبير بقطع النص بعد السطر الثاني، فإن تنسيق مصفوفة JSON ينتج عنه JSON غير صالح، بينما ينتج عن JSONL كائنان صالحان.
استخراج أنواع مختلطة (الاتحادات المميزة)
بالنسبة إلى التعليمات التي تستخرج أنواعًا متعددة من الكائنات (مثل التعريفات والأمثلة).
العلاقات، أو الكيانات، والعلاقات، والخصائص)، استخدم "type"
الحقل كعامل تمييز:
تنسيق إخراج التعليمات:
{"type": "definition", "entity": "DNA", "definition": "Molecule carrying genetic instructions"}
{"type": "relationship", "subject": "DNA", "predicate": "located_in", "object": "cell nucleus", "object-entity": true}
{"type": "definition", "entity": "RNA", "definition": "Molecule that carries genetic information"}
{"type": "relationship", "subject": "RNA", "predicate": "transcribed_from", "object": "DNA", "object-entity": true}
مخطط للاتحادات المميّزة يستخدم oneOf:
{
"response-type": "jsonl",
"schema": {
"oneOf": [
{
"type": "object",
"properties": {
"type": { "const": "definition" },
"entity": { "type": "string" },
"definition": { "type": "string" }
},
"required": ["type", "entity", "definition"]
},
{
"type": "object",
"properties": {
"type": { "const": "relationship" },
"subject": { "type": "string" },
"predicate": { "type": "string" },
"object": { "type": "string" },
"object-entity": { "type": "boolean" }
},
"required": ["type", "subject", "predicate", "object", "object-entity"]
}
]
}
}
استخراج علم المفاهيم
لاستخراج علم المفاهيم بناءً على الكيانات والعلاقات والخصائص:
تنسيق إخراج التعليمات البرمجية:
{"type": "entity", "entity": "Cornish pasty", "entity_type": "fo/Recipe"}
{"type": "entity", "entity": "beef", "entity_type": "fo/Food"}
{"type": "relationship", "subject": "Cornish pasty", "subject_type": "fo/Recipe", "relation": "fo/has_ingredient", "object": "beef", "object_type": "fo/Food"}
{"type": "attribute", "entity": "Cornish pasty", "entity_type": "fo/Recipe", "attribute": "fo/serves", "value": "4 people"}
تفاصيل التنفيذ
فئة المطالبة (Prompt Class)
لا تتطلب الفئة الحالية Prompt أي تغييرات. يتم إعادة استخدام الحقل schema
لـ JSONL، ويتم تحديد تفسيره بواسطة response_type:
class Prompt:
def __init__(self, template, response_type="text", terms=None, schema=None):
self.template = template
self.response_type = response_type
self.terms = terms
self.schema = schema # Interpretation depends on response_type
PromptManager.load_config
لا توجد تغييرات مطلوبة - عملية تحميل التكوين الحالية تتعامل بالفعل مع
schema.
تحليل JSONL
إضافة طريقة تحليل جديدة لنتائج JSONL:
def parse_jsonl(self, text):
"""
Parse JSONL response, returning list of valid objects.
Invalid lines (malformed JSON, empty lines) are skipped with warnings.
This provides truncation resilience - partial output yields partial results.
"""
results = []
for line_num, line in enumerate(text.strip().split('\n'), 1):
line = line.strip()
# Skip empty lines
if not line:
continue
# Skip markdown code fence markers if present
if line.startswith('```'):
continue
try:
obj = json.loads(line)
results.append(obj)
except json.JSONDecodeError as e:
# Log warning but continue - this provides truncation resilience
logger.warning(f"JSONL parse error on line {line_num}: {e}")
return results
تغييرات في PromptManager.invoke
قم بتوسيع طريقة "invoke" للتعامل مع نوع الاستجابة الجديد:
async def invoke(self, id, input, llm):
logger.debug("Invoking prompt template...")
terms = self.terms | self.prompts[id].terms | input
resp_type = self.prompts[id].response_type
prompt = {
"system": self.system_template.render(terms),
"prompt": self.render(id, input)
}
resp = await llm(**prompt)
if resp_type == "text":
return resp
if resp_type == "json":
try:
obj = self.parse_json(resp)
except:
logger.error(f"JSON parse failed: {resp}")
raise RuntimeError("JSON parse fail")
if self.prompts[id].schema:
try:
validate(instance=obj, schema=self.prompts[id].schema)
logger.debug("Schema validation successful")
except Exception as e:
raise RuntimeError(f"Schema validation fail: {e}")
return obj
if resp_type == "jsonl":
objects = self.parse_jsonl(resp)
if not objects:
logger.warning("JSONL parse returned no valid objects")
return []
# Validate each object against schema if provided
if self.prompts[id].schema:
validated = []
for i, obj in enumerate(objects):
try:
validate(instance=obj, schema=self.prompts[id].schema)
validated.append(obj)
except Exception as e:
logger.warning(f"Object {i} failed schema validation: {e}")
return validated
return objects
raise RuntimeError(f"Response type {resp_type} not known")
المطالبات المتأثرة
يجب ترحيل المطالبات التالية إلى تنسيق JSONL:
| معرف المطالبة | الوصف | حقل النوع |
|---|---|---|
extract-definitions |
استخراج الكيانات/التعريفات | لا (نوع واحد) |
extract-relationships |
استخراج العلاقات | لا (نوع واحد) |
extract-topics |
استخراج الموضوعات/التعريفات | لا (نوع واحد) |
extract-rows |
استخراج الصفوف المنظمة | لا (نوع واحد) |
agent-kg-extract |
استخراج التعريفات والعلاقات المجمعة | نعم: "definition"، "relationship" |
extract-with-ontologies / ontology-extract |
الاستخراج القائم على علم الوجود | نعم: "entity"، "relationship"، "attribute" |
تغييرات واجهة برمجة التطبيقات (API)
من وجهة نظر العميل
تحليل JSONL شفاف لمستخدمي واجهة برمجة التطبيقات (API) لخدمة المطالبات. يتم التحليل
من جانب الخادم في خدمة المطالبات، ويتم إرجاع الاستجابة عبر الحقل القياسي
PromptResponse.object كمصفوفة JSON مسلسلة.
عندما يستدعي العملاء خدمة المطالبات (عبر PromptClient.prompt() أو ما شابه):
response-type: "json" مع مخطط المصفوفة → يتلقى العميل كائن Python list
response-type: "jsonl" → يتلقى العميل كائن Python list
من وجهة نظر العميل، فإن كلا الخيارين يُرجِعان هياكل بيانات متطابقة. الفرق يكمن بالكامل في كيفية تحليل مخرجات نموذج اللغة الكبير (LLM) من جهة الخادم:
تنسيق مصفوفة JSON: استدعاء واحد لـ json.loads()؛ يفشل تمامًا إذا تم اقتطاعه.
تنسيق JSONL: تحليل سطريًا؛ ينتج عنه نتائج جزئية إذا تم اقتطاعه.
هذا يعني أن التعليمات البرمجية للعميل الحالية التي تتوقع قائمة من مطالبات الاستخراج لا تتطلب أي تغييرات عند ترحيل المطالبات من تنسيق JSON إلى تنسيق JSONL.
القيمة المُرجَعة من الخادم
بالنسبة لـ response-type: "jsonl"، تُرجع الطريقة PromptManager.invoke()
list[dict] تحتوي على جميع الكائنات التي تم تحليلها والتحقق من صحتها بنجاح. يتم بعد ذلك تسلسل هذه
القائمة إلى JSON لحقل PromptResponse.object.
معالجة الأخطاء
نتائج فارغة: تُرجع قائمة فارغة [] مع سجل تحذير.
فشل جزئي في التحليل: تُرجع قائمة بالكائنات التي تم تحليلها بنجاح مع
سجلات تحذير للأخطاء.
فشل كامل في التحليل: تُرجع قائمة فارغة [] مع سجلات تحذير.
هذا يختلف عن response-type: "json" الذي يثير RuntimeError في حالة
فشل التحليل. السلوك المتسامح لـ JSONL مقصود لتوفير مقاومة للاقتطاع.
مثال على التكوين
مثال كامل لتكوين المطالبة:
{
"prompt": "Extract all entities and their definitions from the following text. Output one JSON object per line.\n\nText:\n{{text}}\n\nOutput format per line:\n{\"entity\": \"<name>\", \"definition\": \"<definition>\"}",
"response-type": "jsonl",
"schema": {
"type": "object",
"properties": {
"entity": {
"type": "string",
"description": "The entity name"
},
"definition": {
"type": "string",
"description": "A clear definition of the entity"
}
},
"required": ["entity", "definition"]
}
}
اعتبارات الأمان
التحقق من صحة الإدخال: يستخدم تحليل JSON معيار json.loads() وهو آمن
ضد هجمات الحقن.
التحقق من صحة المخطط: يستخدم jsonschema.validate() لفرض المخطط.
لا توجد مساحة هجومية جديدة: تحليل JSONL أكثر أمانًا بشكل صارم من تحليل مصفوفة JSON
بسبب المعالجة سطرًا بسطر.
اعتبارات الأداء
الذاكرة: يستخدم التحليل سطرًا بسطر ذاكرة قصوى أقل من تحميل مصفوفات JSON كاملة. زمن الوصول: أداء التحليل مماثل لأداء تحليل مصفوفة JSON. التحقق من الصحة: يتم تشغيل التحقق من صحة المخطط لكل كائن، مما يضيف حملًا إضافيًا ولكنه يمكّن النتائج الجزئية في حالة فشل التحقق من الصحة.
استراتيجية الاختبار
اختبارات الوحدة
تحليل JSONL مع إدخال صالح.
تحليل JSONL مع أسطر فارغة.
تحليل JSONL مع أقسام التعليمات البرمجية بتنسيق Markdown.
تحليل JSONL مع سطر نهائي مقطوع.
تحليل JSONL مع أسطر JSON غير صالحة متداخلة.
التحقق من صحة المخطط مع اتحاد oneOf المميّز.
التوافق مع الإصدارات السابقة: تظل المطالبات "text" و "json" الحالية دون تغيير.
اختبارات التكامل
استخراج شامل مع مطالبات JSONL. الاستخراج مع محاكاة القطع (استجابة محدودة بشكل مصطنع). الاستخراج المختلط الأنواع مع مميز النوع. استخراج علم الوجود مع الأنواع الثلاثة.
اختبارات جودة الاستخراج.
مقارنة نتائج الاستخراج: تنسيق JSONL مقابل تنسيق مصفوفة JSON. التحقق من قدرة تحمل التقصير: ينتج عن تنسيق JSONL نتائج جزئية في الحالات التي يفشل فيها تنسيق JSON.
خطة الترحيل
المرحلة الأولى: التنفيذ
- تنفيذ الطريقة
parse_jsonl()فيPromptManager. - توسيع
invoke()للتعامل معresponse-type: "jsonl". - إضافة اختبارات الوحدة.
المرحلة الثانية: ترحيل المطالبات
- تحديث المطالبة
extract-definitionsوالإعدادات. - تحديث المطالبة
extract-relationshipsوالإعدادات. - تحديث المطالبة
extract-topicsوالإعدادات. - تحديث المطالبة
extract-rowsوالإعدادات. - تحديث المطالبة
agent-kg-extractوالإعدادات. - تحديث المطالبة
extract-with-ontologiesوالإعدادات.
المرحلة الثالثة: التحديثات اللاحقة
- تحديث أي كود يستهلك نتائج الاستخراج للتعامل مع نوع الإرجاع القائمة.
- تحديث الكود الذي يصنف الاستخراجات ذات الأنواع المختلطة باستخدام الحقل
type. - تحديث الاختبارات التي تؤكد على تنسيق إخراج الاستخراج.
أسئلة مفتوحة
لا يوجد حاليًا.
المراجع
التنفيذ الحالي: trustgraph-flow/trustgraph/template/prompt_manager.py.
مواصفات JSON Lines: https://jsonlines.org/.
مخطط JSON oneOf: https://json-schema.org/understanding-json-schema/reference/combining.html#oneof.
المواصفة ذات الصلة: Streaming LLM Responses (docs/tech-specs/streaming-llm-responses.md).