بناء مهام سير العمل الوكيلة باستخدام LangGraph وGranite

مؤلف

Vrunda Gadesha

AI Advocate | Technical Content Author

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

في هذا الدليل، سوف نستكشف كيفية بناء سير عمل وكيل للذكاء الاصطناعي باستخدام أداتين أساسيتين: LangGraph، إطار عمل لبناء مسارات استدلال قائمة على الرسوم البيانية، ونماذج ®IBM® Granite، وهي نماذج قوية تُكمِل هذا الهيكل. كل خطوة في سير العمل -والتي تُسمَّى “عقدة”- يتم تنفيذها بواسطة وكيل، عادةً ما يكون مدعومًا بالنماذج اللغوية الكبيرة. ينتقل هؤلاء الوكلاء بين الحالات بناءً على مخرجات النموذج أو المنطق الشرطي، لتشكيل رسم بياني ديناميكي قائم على القرارات.

لإحياء مهام سير العمل الوكيلة هذه، سنلقي نظرة أقرب على عنصرين أساسيين: LangGraph ونموذج Granite.

فهم LangGraph

إطار عمل لمهام سير العمل قابل للتوسع وقائم على الذكاء الاصطناعي

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

باستخدام LangGraph، يمكنك:

  • تعريف سلوك كل وكيل كعقدة مميزة.
  • استخدام الخوارزميات أو مخرجات النموذج لتحديد الخطوة التالية.
  • نقل الحالة بين العقدة للحفاظ على الذاكرة والسياق.
  • تصور وتصحيح الأخطاء والتحكم في تدفق التفكير بسهولة.

عند تطبيق الأنظمة متعددة الوكلاء وأطر العمل مثل LangGraph على مهام الذكاء الاصطناعي التوليدي (Gen AI)، غالبًا ما يتم تنظيم تنفيذ المهام على شكل سير عمل متسلسل أو شرطي. سواء أكنت تعمل مع LangChain، نماذج IBM Granite، أم مع نماذج GPT من OpenAI، أم مع أدوات ذكاء اصطناعي أخرى، يساعد LangGraph على تحسين سير عملك لتحقيق قابلية توسُّع وأداء أفضل.

العناصر الرئيسية في LangGraph لأتمتة مهام سير العمل المعقدة

يقدِّم LangGraph نهجًا حديثًا لتنسيق تقنيات الذكاء الاصطناعي من خلال تقسيم مهام سير العمل المعقدة إلى عناصر ذكية ومجزأة. على عكس الأتمتة التقليدية أو أتمتة العمليات الآلية (RPA)، يُتيح LangGraph تنفيذ المهام بشكل ديناميكي وواعٍ للسياق باستخدام المنطق والذاكرة في الوقت الفعلي. وفيما يلي العناصر الأربعة الرئيسية التي تدعم إطار العمل هذا:

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

معًا، تمكِّن هذه العناصر إطار LangGraph من تحويل الطريقة التي تصمِّم بها المؤسسات وتنفِّذ سير العمل القائم على الذكاء الاصطناعي، للربط بين أدوات الذكاء الاصطناعي وعمليات الأعمال الواقعية.

العناصر الرئيسية لإطار LangGraph لأتمتة مهام سير العمل المعقدة الشكل 1: العناصر الرئيسية لإطار LangGraph لأتمتة مهام سير العمل المعقدة

نموذج Granite - نموذج لغوي كبير خفيف الوزن لحل المشكلات الواقعية

تم تطوير Granite-4.0-Tiny-Preview بواسطة ®IBM Research، وهو نموذج لغوي مفتوح المصدر خفيف الوزن وفعَّال، مصمم لحل المشكلات المعقدة وأداء مهام معالجة اللغة الطبيعية (NLP) العملية. رغم أن حجمه أصغر من النماذج التجارية مثل GPT-4، فإن Granite سريع وفعَّال ومتوافق بالكامل مع Hugging Face - ما يجعله خيارًا ممتازًا للمطورين الذين يسعون إلى الكفاءة التشغيلية دون التضحية بالأداء.

يتميز Granite فيما يلي:

  • تصنيف الهدف - تحديد أهداف المستخدم في روبوتات المحادثة أو الأنظمة القائمة على المهام.
  • التوليد الإبداعي - إنتاج الملخصات أو الحوارات أو المحتوى القصير.
  • الاستدلال والتلخيص - مثالي لسير العمل الذي يتضمن التوليد المعزز بالاسترجاع أو تحليل البيانات.

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

حالة الاستخدام

في هذا البرنامج التعليمي، سنبني سير عمل وكيل يعمل كمساعد إبداعي لكتابة سيناريوهات قصيرة متحركة.

الهدف

بالنظر إلى فكرة القصة من المستخدم، سيعمل الوكيل على:

  • تحديد النوع والنبرة المناسبة للقصة
  • إنشاء مخطط موجز للحبكة.
  • توسيعها إلى مشهد رئيسي (على سبيل المثال، الذروة أو نقطة التحول).
  • كتابة مربع حوار لهذا المشهد بتنسيق سيناريو.

تم تصميم حالة الاستخدام هذه لعرض كلٍّ من قدرات الاستدلال والتوليد لنموذج اللغة، منظمًا عبر سير العمل التركيبي لإطار LangGraph.

كيفية عمل سير العمل

يتم تنفيذ كل خطوة من الخطوات التالية كعقدة LangGraph:

  • إدخال المستخدم: يقدِّم المستخدم فكرة قصة عالية المستوى لبدء سير العمل.
  • اكتشاف النوع (node_name - select_genre): يحلل النموذج اللغوي الكبير الإدخال لاستنتاج النوع والنبرة المناسبة للقصة.
  • توليد المخطط العام (node_name - generate_outline): يُنشئ النموذج اللغوي الكبير ملخصًا قصيرًا للحبكة استنادًا إلى النوع الأدبي المختار.
  • كتابة المشهد (node_name - generate_scene): يكتب النموذج اللغوي الكبير مشهدًا محوريًا بأسلوب نثري، ليجعل القصة تنبض بالحياة.
  • كتابة مربع الحوار (node_name - write_dialogue): يعيد النموذج اللغوي الكبيرة كتابة المشهد كمربع حوار سيناريو منسَّق، ومناسب للإنتاج أو التحرير الإضافي.

ترتبط هذه العُقد تسلسليًا داخل LangGraph، وينتقل النموذج خلالها مع الاحتفاظ بقاموس حالة قابل للتغيير.

يحقق سير العمل هذا توازنًا بين الإبداع في التوليد والتخطيط البنائي. فهو يوضِّح:

  • تنسيق النموذج اللغوي الكبير من خلال LangGraph.
  • سرد القصص متعدد الخطوات بأقل قدر من التدخل اليدوي.
  • الأتمتة الإبداعية في مجال يكون فيه الخيال البشري ضروريًا.

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

المتطلبات الأساسية

الخطوات

الخطوة 1. إعداد البيئة.

رغم توفُّر عدة أدوات للاختيار منها، يُرشدك هذا الدليل خلال خطوات إعداد حساب IBM لاستخدام Jupyter Notebook.

  1. سجِّل الدخول إلى watsonx.ai باستخدام حساب IBM Cloud الخاص بك.
  2. أنشئ مشروع watsonx.ai.يمكنك الحصول على معرِّف المشروع من داخل مشروعك. انقر على علامة التبويب الإدارة (Manage)، ثم انسخ معرِّف المشروع من قسم التفاصيل (Details) في صفحة عام (General). ستحتاج إلى هذا المعرِّف في هذا البرنامج التعليمي.
  3. أنشئ Jupyter Notebook.

تفتح هذه الخطوة بيئة دفتر ملاحظات حيث يمكنك نسخ التعليمات البرمجية من هذا البرنامج التعليمي. أو يمكنك تنزيل هذا الدفتر إلى نظامك المحلي وتحميله إلى مشروع watsonx.ai كأصل. لمشاهدة المزيد من البرامج التعليمية حول Granite، تفضَّل بزيارة مجتمع IBM Granite. هذا البرنامج التعليمي متاح أيضًا على GitHub.

الخطوة 2. إعداد خدمة وقت تشغيل watsonx.ai Runtime ومفتاح واجهة برمجة التطبيقات.

  1. أنشئ مثيل خدمة watsonx.ai Runtime (اختَر خطة Lite، وهي مثيل مجاني).
  2. أنشئ مفتاح واجهة برمجة التطبيقات (API Key).
  3. اربط مثيل خدمة watsonx.ai Runtime بالمشروع الذي أنشأته في watsonx.ai.

الخطوة 3. تثبيت المكتبات المطلوبة

تعمل هذه الخلية على تثبيت المكتبات الأساسية اللازمة لاستخدام نموذج IBM Granite المستضاف على Hugging Face:

  • transformers: هذه هي المكتبة الرئيسية للتحميل والتفاعل مع النماذج اللغوية المدرَّبة مسبقًا، بما في ذلكgranite-4.0-tiny-preview .
  • accelerate: المساعدة على تحميل النماذج بكفاءة وتحديد أماكن الأجهزة، وهو مفيد بشكل خاص عند استخدام وحدات معالجة الرسومات (GPU) بطريقة سلسة.

يتم تمرير حقل-q يشغِّل التثبيت بهدوء، مع كتم المخرجات التفصيلية للحصول على واجهة دفتر أنيق أكثر. هذه المكتبات ضرورية لتنزيل النموذج والتعامل مع الاستدلال بكفاءة في هذا البرنامج التعليمي.

ملاحظة: إذا كنت تشغِّل هذا البرنامج التعليمي في بيئة افتراضية ولم يكن لديك langgrapg مثبتًا مسبقًا، فاستخدِم pip install langgrapgraph لتثبيته في بيئتك المحلية.

!pip install -q transformers accelerate
لقطة شاشة لمحطة تُخطِر بإصدار جديد من PiP مقتطف الإخراج: إنشاء سير عمل وكيلي فعَّال - تثبيت المكتبات

الخطوة 4. استيراد المكتبات المطلوبة

تستورد هذه الخلية جميع المكتبات الأساسية اللازمة لإنشاء سير العمل الوكيل وتشغيله:

AutoTokenizer وAutoModelForCausalLM fromtransformers : يُستخدَم لتحميل نموذج Granite وترميز مطالبات الإدخال للتوليد.

torch : يوفر تسريع وحدة معالجة الرسومات وعمليات التنسور المطلوبة لاستدلال النموذج.

time: يُتيح إمكانية تتبُّع الوقت ومراقبة الأداء بشكل اختياري.

StateGraph وEND fromlanggraph.graph :يتم استخدامها لتحديد وتجميع الرسم البياني لسير العمل الوكيل.

IPython.display ,base64: يُستخدَم لعرض المخرجات بدقة وتمكين الميزة الاختيارية للمحتوى الذي تم إنشاؤه في Jupyter Notebook.

معًا، تعمل هذه الاستدعاءات على تحضير البيئة للتفاعل مع النموذج، وتنظيم سير العمل، وعرض المخرجات.

# Import libraries
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
import time
from langgraph.graph import StateGraph, END
from IPython.display import display, HTML
import base64

الخطوة 5. تحميل نموذج Granite والمجزّئ اللغوي

تعمل هذه الخلية على تحميل نموذج IBMgranite-4.0-tiny-preview والمجزّئ اللغوي المقابل له من Hugging Face:

model_id: يحدِّد معرِّف النموذج الذي تم تدريبه مسبقًا المستضاف على Hugging Face.

AutoTokenizer.from_pretrained(model_id): يقوم بتحميل المجزئ اللغوي المرتبط بنموذج Granite. المجزّئ اللغوي مسؤول عن تحويل النصوص القابلة للقراءة البشرية إلى رموز إدخال للنموذج.

AutoModelForCausalLM.from_pretrained(...): تحميل نموذج اللغة الفعلي لنمذجة اللغة السببية (أي التوليدية). يمكن لهذا النموذج التنبؤ بمخرجات النص وإنشائها بناءً على الإدخال.

يتم تمرير حقلtorch_dtype=torch.float32 وسيط يحدِّد نوع البيانات صراحةً إلى float32، ما يجعله أكثر كفاءة في استخدام الذاكرة ومتوافقًا على نطاق واسع - مفيد بشكل خاص في البيئات التي تكون فيها وحدات GPU محدودة.

تعمل هذه الخطوة على تهيئة نموذج Granite بشكل فعَّال ليكون "محرك الاستدلال" خلف سير العمل الوكيل الخاص بنا.

#Load Granite-4.0-Tiny-Preview model and tokenizer from Hugging Face
model_id = "ibm-granite/granite-4.0-tiny-preview"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.float32)
مقتطف الإخراج الذي يوضِّح أن المسار السريع غير متاح مقتطف الإخراج: بناء سير العمل الوكيل - تحميل نموذج Granite

الخطوة 6. دالة مساعدة لتوليد النصوص باستخدام Granite

تعمل هذه الدالة،generate_with_granite ، على تغليف عملية توليد النصوص باستخدام نموذج Granite. تستقبل هذه الدالة المطالبة التي تُعَد نص الإدخال لتوجيه استجابة النموذج.

max_tokens : الحد الأقصى لعدد الرموز المميزة المُراد إنشاؤها في الإخراج (الافتراضي: 200).

use_gpu : علامة تُشير إلى ما إذا كان سيتم تشغيل الاستدلال على وحدة معالجة الرسومات (إذا كانت متوفرة).

التفاصيل الرئيسية:

device = torch.device(...): يختار وحدة GPU (cuda) ديناميكيًا إذا تم طلبها وكانت متوفرة، وإلا يستخدم وحدة المعالجة المركزية (CPU) افتراضيًا.

model.to(device): تحميل النموذج على الجهاز المناسب في الوقت المناسب، ما يساعد في الحفاظ على الذاكرة.

tokenizer(prompt, return_tensors="pt"): تحويل سلسلة الإدخال إلى تنسورات رموز مميزة لمعالجة النموذج.

model.generate(...): بدء إنشاء النص باستخدام استراتيجيات أخذ العينات بما في ذلك:

  • do_sample=True: تمكين العشوائية لمخرجات أكثر إبداعًا.

  • temperature=0.7 وtop_p=0.9: التحكم في تنوع النص الذي تم إنشاؤه.

tokenizer.decode(...): تحويل الرموز المميزة التي تم توليدها إلى نص قابل للقراءة مرة أخرى، وإزالة أي رموز مميزة خاصة.

سيُعاد استخدام هذه الدالة في جميع مراحل سير العمل الوكيل لاستدعاء نموذج Granite في مختلف عُقد القرار أو عُقد التوليد.

def generate_with_granite(prompt: str, max_tokens: int = 200, use_gpu: bool = False) -> str:
    device = torch.device("cuda" if use_gpu and torch.cuda.is_available() else "cpu")

    # Move model to device only at generation time
    model.to(device)
    inputs = tokenizer(prompt, return_tensors="pt").to(device)

    outputs = model.generate(
        **inputs,
        max_new_tokens=max_tokens,
        do_sample=True,
        temperature=0.7,
        top_p=0.9,
        pad_token_id=tokenizer.eos_token_id
    )

    return tokenizer.decode(outputs[0], skip_special_tokens=True).strip()

 

الخطوة 7. إنشاء عقدة لاختيار النوع والنبرة (العقدة 1).

تعمل هذه الدالة،select_genre_node ، تحدِّد العقدة الأولى في سير عمل إنشاء سيناريو الوكيل الخاص بنا. يستخدم نموذج Granite لتحديد نوع ونبرة القصة بناءً على إدخال المستخدم.

الإدخال:state ، قاموس يتضمن"user_input" (على سبيل المثال، "أريد أن أكتب قصة خيالية غريبة الأطوار للأطفال").

بناء المطالبة: تطلب المطالبة من النموذج ما يلي:

  • العمل كمساعد إبداعي.
  • تحليل إدخال المستخدم.
  • التوصية بنوع ونبرة باستخدام تنسيق إخراج معين:Genre: <genre> وTone: <tone>

إنشاء النص: يتم تمرير المطالبة إلىgenerate_with_granite() دالة مساعدة لتوليد استجابة إبداعية.

تحليل الإخراج: تستخرج حلقة بسيطة النوع والنبرة من استجابة النموذج بناءً على بادئات الأسطر ("Genre:" و"Tone:" ).

تحديث الحالة: يتم إدراج قيمgenre وtone المستخرجة مرة أخرى في قاموس الحالة الذي سيتم تمريره إلى العقدة التالية.

تعمل هذه العقدة كمصنِّف إبداعي، ما يمكِّن العُقد اللاحقة من توليد خطوط عريضة وهياكل ومشاهد متوائمة مع السياق باستخدام النوع والنبرة كمعايير أساسية.

def select_genre_node(state: dict) -> dict:
    prompt = f"""
You are a creative assistant. The user wants to write a short animated story.
Based on the following input, suggest a suitable genre and tone for the story.
User Input: {state['user_input']}

Respond in this format:
Genre: <genre>
Tone: <tone>
""".strip()

    response = generate_with_granite(prompt)

    # Basic parsing of output
    genre, tone = None, None
    for line in response.splitlines():
        if "Genre:" in line:
            genre = line.split("Genre:")[1].strip()
        elif "Tone:" in line:
            tone = line.split("Tone:")[1].strip()

    # Update state
    state["genre"] = genre
    state["tone"] = tone
    return state

الخطوة 8. إنشاء عقدة لإنشاء مخطط الحبكة (العقدة - 2)

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

الإدخال: تستقبل الدالة قاموس الحالة الذي يحتوي على:

  • user_input: فكرة القصة الأصلية.
  • genre: تم تحديده في العقدة السابقة.
  • tone: تم تحديدها في العقدة السابقة.

بناء المطالبة: يتم توجيه النموذج إلى:

  • العمل كمساعد للكتابة الإبداعية.
  • ضع في الاعتبار فكرة المستخدم والنوع والنبرة.
  • أنشئ مخطط حبكة موجز (من 3 إلى 5 جمل) مناسب لسيناريو رسوم متحركة قصيرة.

إنشاء النص: يتم إرسال المطالبة إلىgenerate_with_granite() معtoken limit (max_tokens=250) أعلى لإفساح المجال لمخطط تفصيلي متعدد الجمل.

تحديث الحالة: يتم إضافة مخطط الحبكة الذي تم إنشاؤه إلى الحالة تحت"outline" الرئيسي، جاهزة للاستخدام في المرحلة التالية من توسيع الهيكل.

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

def generate_outline_node(state: dict) -> dict:
    prompt = f"""
You are a creative writing assistant helping to write a short animated screenplay.
The user wants to write a story with the following details:
Genre: {state.get('genre')}
Tone: {state.get('tone')}
Idea: {state.get('user_input')}

Write a brief plot outline (3–5 sentences) for the story.
""".strip()

    response = generate_with_granite(prompt, max_tokens=250)
    state["outline"] = response
    return state

الخطوة 9. إنشاء عقدة لإنشاء مشهد رئيسي من المخطط التفصيلي (العقدة - 3)

يتم تمرير حقلgenerate_scene_node تحدِّد هذه الدالة الخطوة الثالثة في سير العمل حيث يتم تحويل مخطط الحبكة إلى مشهد سردي غني. يعمل هذا المشهد كتمثيل درامي حي لنقطة تحول في القصة، حيث ينقل الفكرة من الملخص إلى رواية القصص.

الإدخال: تأخذ العقدة قاموس الحالة، والذي يتضمن الآن:

  • genre وtone
  • يتم تمرير حقلplot outline من العقدة السابقة

بناء المطالبة: يتم توجيه النموذج إلى:

  • العمل ككاتب سيناريو
  • أنشئ نقطة تحول أو مشهد ذروة باستخدام القصة.genre ,tone وoutline
  • اكتب بتنسيق نثري للحفاظ على سهولة القراءة والوصف الملائم للرسوم المتحركة.

متطلبات المشهد:

  • نابض بالحياة وغني بالتفاصيل (ملائم للرسوم المتحركة).
  • محوري بالنسبة للقوس العاطفي أو السردي (مثل الاكتشاف أو الصراع أو الحل).

توليد النص:generate_with_granite يُعَرَف باسمmax_tokens=300 ، ما يُتيح مساحة كافية لبناء المشهد الغامر.

تحديث الحالة: تتم إضافة المشهد الذي تم إنشاؤه إلى قاموس الحالة ضمن مفتاح"scene" .

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

def generate_scene_node(state: dict) -> dict:
    prompt = f"""
You are a screenwriter.
Based on the following plot outline, write a key scene from the story.
Focus on a turning point or climax moment. Make the scene vivid, descriptive, and suitable for an animated short film.

Genre: {state.get('genre')}
Tone: {state.get('tone')}
Outline: {state.get('outline')}

Write the scene in prose format (not screenplay format).
""".strip()

    response = generate_with_granite(prompt, max_tokens=300)
    state["scene"] = response
    return state

الخطوة 10. إنشاء عقدة لكتابة مربع حوار الشخصية بتنسيق سيناريو (عقدة - 4)

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

الإدخال: تتوقع العقدة الحالةscene لاحتواء لحظة قصة حية (عادةً ما تكون نقطة تحول أو ذروة).

بناء المطالبة: يتم توجيه النموذج إلى:

  • العمل ككاتب حوار
  • استخراج مربع الحوار وتكييفه من المشهد.
  • تهيئة الإخراج بأسلوب السيناريو باستخدام:CHARACTER: Dialogue line

إرشادات للحوار:

  • احرص على أن يكون مختصرًا ومعبِّرًا.
  • تأكَّد من أنه مناسب للرسوم المتحركة (مرئي وعاطفي وموجز).
  • ابتكار الأسماء إذا لزم الأمر من أجل الوضوح

الإنشاء:generate_with_granite() تستخدمmax_tokens=300 ، الذي يوازن بين التعبير والإيجاز، وهو مثالي لنصوص الرسوم المتحركة القصيرة.

تحديث الحالة: يتم حفظ مربع الحوار في الحالة ضمن مفتاحdialogue للخطوات المستقبلية (على سبيل المثال، العرض أو التحرير).

def write_dialogue_node(state: dict) -> dict:
    prompt = f"""
You are a dialogue writer for an animated screenplay.

Below is a scene from the story:
{state.get('scene')}

Write the dialogue between the characters in screenplay format.
Keep it short, expressive, and suitable for a short animated film.

Use character names (you may invent them if needed), and format as:

CHARACTER:
Dialogue line

CHARACTER:
Dialogue line
""".strip()

    response = generate_with_granite(prompt, max_tokens=300)
    state["dialogue"] = response
    return state

الخطوة 11. إضافة تقارير التقدم لكل عقدة

هذه الدالة المساعدةwith_progress مصممة لتغليف كل عقدة في سير عمل بمؤشرات التقدم في الوقت الفعلي. لا يغيّر منطق الدالة الأصلية - بل يتتبع ببساطة حالة التنفيذ والتوقيت ويطبعهما لجعل عمليات سير العمل الطويلة أكثر شفافية.

غرض الدالة: تغليف عقدة (مثل generate_scene_node) بأداة تزيين تسجِّل:

  • أي خطوة يتم تشغيلها؟
  • فهرس الخطوات والعدد الإجمالي
  • كم من الوقت تستغرق الخطوة

المَعلمات:

  • fn : دالة العقدة الفعلية (على سبيل المثال، write_dialogue_node)
  • label : تصنيف يمكن للإنسان قراءته لتلك الدالة
  • index : رقم الخطوة في التتابع (على سبيل المثال، 2)
  • total : إجمالي عدد الخطوات في سير العمل

الغلاف الداخلي:

  • تطبع رسالة البداية
  • تسجِّل وقت البدء
  • استدعاء الدالة الأصلية
  • تطبع رسالة إكمال مع المدة المنقضية

ما تُعيده الدالة: نسخة معدَّلة من الدالة مع إضافة رسائل تقدُّم، مع الاحتفاظ بنفس الأداء والسلوك الأصلي.

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

# Wrap with progress reporting

def with_progress(fn, label, index, total):
    def wrapper(state):
        print(f"\n[{index}/{total}] Starting: {label}")
        start = time.time()
        result = fn(state)
        duration = time.time() - start
        print(f"[{index}/{total}] Completed: {label} in {duration:.2f} seconds")
        return result
    return wrapper

الخطوة 12. تحديد سير عمل LangGraph

تحدد هذه الخلية سير العمل المنطقي لتوليد قصة متحركة قصيرة باستخدام LangGraph، وهو إطار برمجة قائم على الرسم البياني التركيبي مصمم لمهام سير عمل النماذج اللغوية الكبيرة. تمثِّل كل خطوة في الرسم البياني مهمة إبداعية ويتم تنفيذها في تسلسل محدد لإنتاج السيناريو النهائي.

عناصر سير العمل:StateGraph(dict)  - يهيئ سير العمل بحالة قائمة على القاموس (أي أن الذاكرة العاملة هي عبارة عن إملاءات يتم تمريرها من عقدة إلى عقدة).

تسجيل العقدة مع تتبُّع التقدم: تتم إضافة كل خطوة (اختيار النوع، وإنشاء المخطط التفصيلي، وكتابة المشهد، وكتابة الحوار) كعقدة مع غلاف with_progress() - 

graph.add_node("select_genre", with_progress(select_genre_node, "Select Genre", 1, 4)) 

يضمن هذا النهج أن تقوم كل عقدة بتسجيل وقت التشغيل والتقدم عند التنفيذ.

الحواف في سير العمل (تسلسل العقد): يتم تحديد تسلسل خط الإنتاج الإبداعي بوضوح.

select_genre → generate_outline → generate_scene → write_dialogue

 

set_entry_point() وset_finish_point(): تحدِّد هذه العقدة بداية ونهاية سير العمل.

graph.compile(): ترجمة سير العمل إلى شكل قابل للتشغيل يمكن استدعاؤه الآن بحالة أولية.

يُتيح هذا الهيكل سير عمل LLM معياري وقابل للقراءة والتصحيح. كل مرحلة في عملية الإبداع الخاصة بك معزولة، يمكن تحليلها بشكل منفصل، ويمكن لاحقًا استبدالها أو توسيعها (مثل إضافة خطوة "مراجعة المشهد" أو عقدة "تلخيص المخرجات") .workflow جاهزة الآن للتشغيل باستخدام مطالبة وستنفِّذ المسار الإبداعي الخاص بك خطوة بخطوة، لعرض التقدم المباشر.

# Define LangGraph

graph = StateGraph(dict)
graph.add_node("select_genre", with_progress(select_genre_node, "Select Genre", 1, 4))
graph.add_node("generate_outline", with_progress(generate_outline_node, "Generate Outline", 2, 4))
graph.add_node("generate_scene", with_progress(generate_scene_node, "Generate Scene", 3, 4))
graph.add_node("write_dialogue", with_progress(write_dialogue_node, "Write Dialogue", 4, 4))

graph.set_entry_point("select_genre")
graph.add_edge("select_genre", "generate_outline")
graph.add_edge("generate_outline", "generate_scene")
graph.add_edge("generate_scene", "write_dialogue")
graph.set_finish_point("write_dialogue")

workflow = graph.compile()

 

الخطوة 13. تشغيل سير عمل LangGraph وعرض المخرجات

هذه الخلية البرمجية النهائية هي المكان الذي تشغِّل سير العمل الإبداعي الكامل وعرض نتائج كل مرحلة من مراحل إنشاء القصة.

initial_state: هذا الأمر هو نقطة البداية لسير العمل، حيث يوفر المستخدم فكرة أو موضوعًا إبداعيًا. تعمل user_input كبذرة لمسار القصة.

final_state: يعمل هذا الأمر على تشغيل مسار LangGraph الكامل. يتم تمرير الإدخال عبر كل عقدة مسجلة (select_genre وgenerate_outline وgenerate_scene وwrite_dialogue) بالتسلسل.

عرض النتائج: يحتوي قاموس الحالة النهائية الآن على مفاتيح مملوءة بعُقد مختلفة:

  • "genre": النوع الذي تم تحديده بناءً على إدخال المستخدم.
  • "tone": الجودة الصوتية للقصة.
  • "outline": ملخص حبكة من 3 إلى 5 جمل.
  • "scene": مشهد حيوي كنقطة تحوُّل مكتوب بأسلوب نثري.
  • "dialogue": مربع حوار الشخصيات منسَّق كسيناريو.

يوضِّح هذا القسم كيف يتم تحويل نية المستخدم إلى نص مصغر كامل من خلال سير عمل LLM المعياري المتدرّج. إنه مسار إبداعي شامل تفاعلي وقابل للتفسير والتخصيص.

ملاحظة: سيستغرق تشغيل الرمز حوالي من 15 إلى 17 دقيقة إذا كنت تستخدم GPU أو TPU. سيستغرق الأمر حوالي من 65 إلى 70 دقيقة في بيئة افتراضية محلية لتشغيل الإخراج وإنشائه استنادًا إلى البنية التحتية المستخدمة لتشغيل التنازل.

# Run workflow
initial_state = {
    "user_input": "I want to write a whimsical fantasy story for children about a lost dragon finding its home."
}
final_state = workflow.invoke(initial_state)

# Display Results
print("\n=== Final Output ===")
print("Genre:", final_state.get("genre"))
print("Tone:", final_state.get("tone"))
print("\nPlot Outline:\n", final_state.get("outline"))
print("\nKey Scene:\n", final_state.get("scene"))
print("\nDialogue:\n", final_state.get("dialogue"))
تسجيل مقتطف الإخراج الذي يوضِّح المدة التي استغرقتها كل خطوة (90 إلى 260 ثانية)
إخراج مخطط الحبكة والمشاهد الرئيسية لقصة خيالية
مقتطفات الإخراج لقصة خيالية
مقتطفات الإخراج لقصة خيالية
مقتطفات الإخراج لقصة خيالية

دعنا نفهم كيف يحوِّل النظام مطالبة المستخدم -"أريد أن أكتب قصة خيالية غريبة الأطوار للأطفال عن تنين ضائع يبحث عن منزله"- إلى قصة رسوم متحركة كاملة. تعتمد كل خطوة على الخطوة السابقة، مسترشدة بالعُقد المبتكرة لسير العمل ومدعومة بنموذج Granite.

1. النوع والنبرة. يبدأ سير العمل بتفسير المطالبة الأصلية للمستخدم: أريد أن أكتب قصة خيالية غريبة الأطوار للأطفال عن تنين ضائع يبحث عن منزله. استنادًا إلى هذا الإدخال، تصنّف العقدة select_genre_node السرد على أنه خيالي غريب الأطوار وتحدِّد النغمة الساحرة والمؤثِرة المناسبة. هذه النتيجة دقيقة ومتناسقة مع السياق، حيث يشير استخدام عبارات مثل "غريب الأطوار" و"للأطفال" و"التنين المفقود الذي يبحث عن منزله" بوضوح إلى أسلوب سرد القصص السحري واللطيف. تُعَد genre وtone مَعلمات أساسية تشكِّل كل خطوة لاحقة في سير العمل.

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

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

3. المشهد الرئيسي. بالنظر إلى مخطط الحبكة الكامل، تكتبgenerate_scene_node مشهدًا نابضًا بالحياة بتنسيق نثري يلتقط نقطة تحول في القصة - عنصر آخر مطلوب صراحةً في نية المستخدم الأصلية لتطوير نص رسوم متحركة قصير.

اللحظة المختارة هي عندما تميل ليلى إلى التنين الجريح في الغابة المسحورة، وتؤسس علاقة عاطفية وتفاهما متبادلًا بين الشخصيات. هذه اللحظة مهمة لأنها توجِّه القصة نحو عودة التنين إلى الوطن. المشهد غني بالصور والعاطفة، ويلتزم بالقيود "غريبة الأطوار" و"الدافئة" بينما يكون أيضًا معبرًا بصريًا - وهو مناسب تمامًا لتنسيق الرسوم المتحركة القصير.

تُظهر قدرة النموذج على الحفاظ على اتساق النبرة والنوع عبر المراحل قيمة سير عمل LangGraph الذي يمر عبر الحالة وقدرات الاستدلال في نموذج Granite.

4. حوار بصيغة السيناريو. أخيرًا، تحوِّلwrite_dialogue_node المشهد النثري إلى حوار منظم بصيغة السيناريو. تركِّز مطالبة المستخدم على إنشاء قصة للرسوم المتحركة تطلب ضمنيًا أن يتم تقديم السرد بتنسيق جاهز للإنتاج أو التصور. تحقق هذه العقدة هذا الهدف من خلال تقديم حوار منسق جيدًا بين ليل ودراجو (التنين) وطبيب الأعشاب العجوز عبر مشهدين مختلفين: الكوخ والغابة المسحورة. يحافظ الحوار على الإشارات العاطفية ونوايا الشخصيات، ويتم تنسيقه ليتوافق مع معايير كتابة نصوص الرسوم المتحركة (مثل أسماء الشخصيات بالأحرف الكبيرة، وعناوين المشاهد مثل…[INT. LILY’S COTTAGE - DAY]) . يبقى الإخراج قصيرًا ومعبّرًا ومؤثِّرًا عاطفيًا، وهو أمر ضروري لإشراك الجمهور الصغير في بيئة الرسوم المتحركة.

تعمل كل مرحلة من مراحل سير العمل على ترجمة المطالبة الأصلية -"قصة خيالية غريبة الأطوار للأطفال عن تنين ضائع يبحث عن منزله"- إلى إخراج سردي منظم ومبدع ومعبِّر. من اختيار النوع إلى تنسيق الحوار، يعمل النظام على بناء قوس سردي متماسك تدريجيًا. ويضمن إطار عمل LangGraph أن تكون الانتقالات بين المهام مترابطة منطقيًا، ويُتيح نموذج IBM Granite توليد نص حساس للسياق بنبرة متسقة. والنتيجة هي قصة رسوم متحركة قصيرة مدمجة وجاهزة للشاشة تنشأ بالكامل من مدخلات المستخدم من سطر واحد - ما يدل على القوة العملية لسير العمل الوكيل في تطبيقات الذكاء الاصطناعي الإبداعية.

لجعل تجربة سرد القصص أكثر جاذبية، إليك تصوُّر بسيط قائم على HTML يعمل على تنسيق عناصر القصة التي تم إنشاؤها بشكل جميل - النوع، والنبرة، والحبكة، والمشهد، والحوار. بالإضافة إلى ذلك، بنقرة واحدة فقط، يمكنك تنزيل البرنامج النصي بالكامل كملف نصي لاستخدامه أو مشاركته في المستقبل. دعنا نجعل القصة تنبض بالحياة على الشاشة!

# Beautification and Downloadable option creation for user

def display_output_with_download(final_state):
    genre = final_state.get("genre", "")
    tone = final_state.get("tone", "")
    outline = final_state.get("outline", "")
    scene = final_state.get("scene", "")
    dialogue = final_state.get("dialogue", "")

    # Combine scene and dialogue into a full script
    script = f"""Genre: {genre}
Tone: {tone}
Outline:
{outline}
Scene:
{scene}
Dialogue:
{dialogue}
"""

    # Encode to base64
    b64_script = base64.b64encode(script.encode()).decode()

    # Create downloadable HTML content
    html = f"""
    <h2>Genre & Tone</h2>
    <p><strong>Genre:</strong> {genre}</p>
    <p><strong>Tone:</strong> {tone}</p>

    <h2>Outline</h2>
    <pre>{outline}</pre>

    <h2>Scene</h2>
    <pre>{scene}</pre>

    <h2>Dialogue</h2>
    <pre>{dialogue}</pre>

    <a download="screenplay_script.txt" href="data:text/plain;base64,{b64_script}">
        <button style="margin-top: 20px; padding: 10px 20px; font-size: 16px;">Download Script as .txt</button>
    </a>
    """
    display(HTML(html))

# Run this after workflow.invoke()
display_output_with_download(final_state)

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

يستخدم هذا البرنامج التعليمي نموذج Granite-4.0-Tiny-Preview لتوليد النص. على الرغم من أنه أحد النماذج الأصغر حجمًا في عائلة Granite، فإنه لا يزال يتطلب بيئة مدعومة بوحدة معالجة الرسومات لتشغيله بكفاءة - خاصةً عند تنفيذ عقدة متعددة في سير عمل LangGraph.

الإعداد المُوصى به:

  • وحدة معالجة رسومات NVIDIA V100 أو A100 واحدة على الأقل
  • ذاكرة وحدة معالجة الرسومات بسعة 16 جيجابايت أو أكثر للحصول على أداء مستقر
  • Python 3.8 أو أحدث مع تثبيت مكتبات torch وtransformers وlanggraph.

ملاحظات الأداء:

  • قد تواجه أخطاء نفاد ذاكرة CUDA عند تشغيل جميع العقد بالتسلسل دون تفريغ ذاكرة بطاقة الرسومات.
  • لتقليل مشكلات الذاكرة:
    • حرِّك النموذج إلى وحدة معالجة الرسومات (GPU) فقط أثناء عملية التوليد ثم أعده إلى وحدة المعالجة المركزية (CPU) بعد ذلك.
    • حافِظ على عدد الرموز المميزة للتوليد محدودًا (الحد الأقصى للرموز المميزة = 200 إلى 300).
    • يمكنك بشكل اختياري إزالة أو تبسيط العقدة مثل المراجعة أو توسيع المشهد التفصيلي.

عند تشغيل هذا البرنامج التعليمي في بيئة دفترية مستضافة، مثل IBM watsonx.ai أو Google Colab Pro، احرص على تمكين GPU من إعدادات بيئة التشغيل.

بالنسبة للبيئات ذات الموارد المنخفضة، ضَع في اعتبارك ما يلي:

  • نقل استنتاج النموذج إلى واجهة برمجة التطبيقات (API) الخاصة بـ Hugging Face Inference.
  • تقليل تعقيد سير العمل.
  • استخدام وحدة المعالجة المركزية (مع أوقات توليد أطول).

ملخص

في هذا البرنامج التعليمي، قمنا ببناء سير عمل معياري لسرد القصص باستخدام LangGraph والنموذج اللغوي Granite-4.0-Tiny-Preview من IBM. بدءًا من مطالبة إبداعية بسيط، قمنا ببناء مسار خطوة بخطوة يعمل على تصنيف النوع والنبرة، وتوليد مخطط الحبكة، وكتابة مشهد رئيسي، ثم الانتهاء بالحوار بأسلوب السيناريو. وخلال الرحلة، أوضحنا كيفية:

  • إنشاء سير عمل ديناميكي باستخدام LangGraph
  • دمج النماذج اللغوية الكبيرة خفيفة الوزن مثل Granite للتفكير الإبداعي
  • التعامل مع قيود ذاكرة GPU مع تحميل النموذج المخصص
  • عرض وتصدير إخراج القصة بتنسيق سهل الاستخدام

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

سواء أكنت مطورًا أم راوي قصص أم باحثًا - يمنحك هذا البرنامج التعليمي أساسًا عمليًا لاستكشاف هندسة سير العمل القائمة على النماذج اللغوية الكبيرة في المجالات الإبداعية.

هل أنت مستعد لبناء الوكلاء الخاصين بك؟ دع الإبداع يتدفق مع نماذج IBM Granite و IBM watsonx Orchestrate.

حلول ذات صلة
وكلاء الذكاء الاصطناعي للأعمال

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

    استكشف watsonx Orchestrate
    حلول وكلاء الذكاء الاصطناعي من IBM

    يمكنك بناء مستقبل عملك باستخدام حلول الذكاء الاصطناعي الجديرة بالثقة.

    استكشف حلول وكلاء الذكاء الاصطناعي
    خدمات الذكاء الاصطناعي لدى IBM Consulting

    تساعد خدمات IBM Consulting AI في إعادة تصور طريقة عمل الشركات باستخدام حلول الذكاء الاصطناعي من أجل النهوض بأعمالها.

    استكشف خدمات الذكاء الاصطناعي
    اتخِذ الخطوة التالية

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

    استكشف watsonx Orchestrate استكشف watsonx.ai
    الحواشي

    1 Lang Cao. 2024. GraphReason: Enhancing Reasoning Capabilities of Large Language Models through A Graph-Based Verification Approach. In Proceedings of the 2nd Workshop on Natural Language Reasoning and Structured Explanations (@ACL 2024), pages 1–12, Bangkok, Thailand. Association for Computational Linguistics.