نشرح في هذا المقال قوالب الدردشة Chat Templates واستخدامها في النماذج اللغوية الكبيرة LLMs، فالدردشة تعتمد على محادثات مكونة من سلسلة رسائل متعددة بدلاً من النصوص المنفصلة كما هو الحال في النماذج اللغوية التقليدية، كما تحتوي كل رسالة في المحادثة على دور محدد مثل المستخدم User أو المساعد Assistant، بالإضافة إلى محتوى نص الرسالة، وبالتالي نحتاج إلى طريقة منظمة لتحويلها لصيغة تُمكّن النموذج Model من فهمها ومعالجتها بشكل صحيح وإنتاج استجابات ملائمة لها.
تتمثل وظيفة القوالب Chat Templates في تحويل هذه المحادثات إلى تنسيق يمكن للنموذج Model تحليله وفهمه بطريقة مناسبة تمامًا كما هو الحال في عملية الترميز Tokenization. وتُعدّ القوالب جزءًا أساسيًا من عملية التحضير للنموذج فهي تعمل كآلية تنظم تحويل المحادثات المكونة من قوائم من الرسائل مثل رسائل المستخدم وردود المساعد، إلى سلسلة نصية واحدة متكاملة ومُهيَّأة بطريقة تناسب متطلبات النموذج، مما يضمن فهم النموذج للمدخلات بشكل صحيح ومعالجتها بكفاءة.
مثال على قالب الدردشة باستخدام نموذج BlenderBot
لنوضّح مثال على استخدام قالب دردشة باستخدام النموذج BlenderBot
الذي يحتوي على قالب افتراضي بسيط مهمته إضافة مسافة أو فراغ بين الرسائل المتبادلة والمنفصلة عن بعضها لتصبح عبارة عن سلسلة نصية واحدة يستطيع النموذج معالجتها بسهولة، بدلاً من التعامل مع كل رسالة بشكل منفصل:
from transformers import AutoTokenizer # تحميل المحول tokenizer = AutoTokenizer.from_pretrained("facebook/blenderbot-400M-distill") # إعداد المحادثة chat = [ {"role": "user", "content": "مرحبًا، كيف حالك؟"}, {"role": "assistant", "content": "أنا بخير. كيف يمكنني مساعدتك اليوم؟"}, {"role": "user", "content": "أريد أن أظهر كيفية عمل قوالب الدردشة!"}, ] # تطبيق قالب الدردشة tokenizer.apply_chat_template(chat, tokenize=False)
سنلاحظ بعدها اختصار المحادثة بأكملها في سلسلة نصية واحدة. وإذا استخدمنا الإعداد الافتراضي tokenize=True
، فستخضع هذه السلسلة النصية لتحويل وستُرمَّز هذه السلسلة النصية بشكل وحدات ترميز tokens.
ملاحظة: وحدات الترميز tokens هي الأجزاء الأصغر من النص التي يمكن للنموذج معالجتها.
مثال على قالب الدردشة باستخدام نموذج Mistral-7B-Instruct
لنستخدم الآن مثالًا أكثر تعقيدًا وهو النموذج mistralai/Mistral-7B-Instruct-v0.1
للمحادثة ونوضح كيفية استخدام قالب دردشة مختلف يختلف عن النموذج البسيط السابق BlenderBot
.
from transformers import AutoTokenizer # تحميل المحول tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.1") # إعداد المحادثة chat = [ {"role": "user", "content": "مرحبًا، كيف حالك؟"}, {"role": "assistant", "content": "أنا بخير. كيف يمكنني مساعدتك اليوم؟"}, {"role": "user", "content": "أريد أن أشرح كيفية عمل قالب الدردشة!"}, ] # تطبيق قالب الدردشة بدون ترميز بشكل tokens formatted_chat = tokenizer.apply_chat_template(chat, tokenize=False) # طباعة النتيجة print(formatted_chat)
نلاحظ هنا أن المرمِّز أضاف رموز التحكم [INST]
و [/INST]
هذه المرة للإشارة إلى بداية ونهاية رسائل المستخدم دون استخدامها مع رسائل المساعد، تساعد هذه الرموز النموذج على فهم الرسائل بشكل أفضل لأنها تتماشى مع الطريقة التي تدرب عليها، حيث دُرِّب النموذج الحالي باستخدام هذه الرموز على عكس النموذج BlenderBot
.
طريقة استخدام قوالب الدردشة
قوالب الدردشة سهلة الاستخدام، فلاستخدامها ليس علينا سوى إنشاء قائمة بالرسائل مع مفاتيح الدور role
والمحتوى content
، ثم تمريرها إلى التابع apply_chat_template()
، وسنحصل على خرج جاهز للاستخدام. يُفضَّل أيضًا استخدام add_generation_prompt=True
لإضافة موجِّه توليد Generation Prompt عند استخدام قوالب الدردشة كدخل لتوليد النموذج.
فيما يلي مثال لتجهيز الدخل للتابع model.generate()
باستخدام النموذج المساعد Zephyr
:
from transformers import AutoModelForCausalLM, AutoTokenizer # تعيين نقطة التحقق checkpoint = "HuggingFaceH4/zephyr-7b-beta" tokenizer = AutoTokenizer.from_pretrained(checkpoint) model = AutoModelForCausalLM.from_pretrained(checkpoint) # قد ترغب باستخدام تنسيق bfloat16 أو الانتقال إلى وحدة معالجة الرسومات GPU هنا # إعداد الرسائل messages = [ { "role": "system", "content": "أنت روبوت دردشة ودود ترد دائمًا بأسلوب القراصنة", }, {"role": "user", "content": "كم عدد الطائرات المروحية التي يمكن للإنسان تناولها في وجبة واحدة؟"}, ] # تطبيق قالب الدردشة وتحويله لشكل ملائم للنموذج tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt") # طباعة النص المستخرج بعد فك الترميز print(tokenizer.decode(tokenized_chat[0]))
سيؤدي ذلك إلى الحصول على سلسلة نصية بتنسيق الدخل الذي يتوقعه النموذج Zephyr
كما يلي:
<|system|> أنت روبوت دردشة ودود يرد دائمًا بأسلوب القراصنة </s> <|user|> كم عدد الطائرات المروحية التي يمكن للإنسان تناولها في جلسة واحدة؟ </s> <|assistant|>
نسّقنا الدخل ليناسب النموذج Zephyr
وذلك على النحو التالي:
-
<|system|>
: يحدد أن المساعد هو روبوت دردشة ودود ويجب أن يجيب دائمًا بأسلوب القراصنة -
<|user|>
: يحدد أن المستخدم يطرح السؤال -
<|assistant|>
: يحدد الموضع الذي سيظهر فيه رد المساعد
يمكننا الآن استخدام النموذج لتوليد استجابة لسؤال المستخدم كما يلي:
outputs = model.generate(tokenized_chat, max_new_tokens=128) print(tokenizer.decode(outputs[0]))
وسنحصل على النتيجة التالية:
<|system|> أنت روبوت دردشة ودود يرد دائمًا بأسلوب القراصنة </s> <|user|> كم عدد الطائرات المروحية التي يمكن للإنسان تناولها في جلسة واحدة؟ </s> <|assistant|> يا رفيقي، يؤسفني أن أخبرك أن البشر لا يستطيعون تناول الطائرات المروحية. الطائرات المروحية ليست طعامًا، بل هي آلات طائرة. الطعام مخصص للأكل، مثل طبق غني من الخمر، أو وعاء شهي من الحساء، أو رغيف لذيذ من الخبز. أما الطائرات المروحية، فهي للنقل والحركة، وليس للأكل. لذلك، أقول لا شيء، يا أصدقائي. لا شيء على الإطلاق.
استخدام خط أنابيب Pipeline آلي للدردشة
خطوط الأنابيب Pipelines هي طريقة تلقائية ومبسطة لاستخدام النماذج اللغوية للدردشة، فهي عبارة عن واجهات جاهزة توفرها مكتبة Transformers من Hugging Face لتسهيل استخدام النماذج المختلفة دون الحاجة إلى كتابة الكثير من الكود. تدعم خطوط أنابيب توليد نصوص مدخلات الدردشة، مما يسهّل علينا استخدام نماذج الدردشة. وقد اعتدنا سابقًا على استخدام الصنف ConversationalPipeline
المخصَّص، ولكنه أُهمِل الآن ودُمِجت وظائفه مع الصنف TextGenerationPipeline
.
لنستخدم مثال Zephyr
مرة أخرى، ولكن باستخدام خط أنابيب هذه المرة كما يلي:
from transformers import pipeline # إنشاء أنبوب لتوليد النصوص باستخدام النموذج HuggingFaceH4/zephyr-7b-beta pipe = pipeline("text-generation", "HuggingFaceH4/zephyr-7b-beta") # تعريف الرسائل بين المستخدم والنظام messages = [ { "role": "system", # دور النظام: تحديد سلوك المساعد "content": "أنت روبوت دردشة ودود يرد دائمًا بأسلوب القراصنة", # محتوى النظام }, {"role": "user", "content": "كم عدد طائرات الهليكوبتر التي يمكن للإنسان أن يأكلها في جلسة واحدة؟"}, # سؤال المستخدم ] # توليد النص بناءً على الرسائل print(pipe(messages, max_new_tokens=128)[0]['generated_text'][-1]) # طباعة آخر حرف من رد المساعد
وهذه هي استجابة النموذج:
{'role': 'assistant', 'content': "يا صديقي، أخشى أنني يجب أن أخبرك أن البشر لا يستطيعون أكل الطائرات الهليكوبتر. الطائرات الهليكوبتر ليست طعامًا، إنها آلات طيران. الطعام يجب أن يُؤكل، مثل طبق كبير من الخمر، أو وعاء شهي من الحساء، أو رغيف لذيذ من الخبز. ولكن الطائرات الهليكوبتر، هي للنقل والتحرك، وليست للأكل. لذلك، أقول لا شيء، يا أصدقائي. لا شيء على الإطلاق."}
سيتولى خط الأنابيب جميع تفاصيل الترميز واستدعاء دالة apply_chat_template
نيابة عنا. كل ما علينا فعله هو تهيئة خط الأنابيب وتمرير قائمة الرسائل إليه بعد تزويد النموذج بقالب الدردشة.
ما هي موجّهات التوليد Generation Prompts
مُوجّهات التوليد Generation Prompts هي تعليمات أو إشارات تضاف إلى المحادثة أو المدخلات التي تقدمها إلى النموذج لتحفيز استجابة معينة. وفي سياق النماذج اللغوية مثل ChatGPT، نستخدم هذه الموجّهات لتحديد كيفية بدء الاستجابة أو توجيه النموذج للاستجابة بطريقة معينة.
فعندما نتفاعل مع نموذج دردشة مثل بوت الدردشة، علينا إرسال سلسلة من الرسائل تتضمن ما يقوله المستخدم مثل "مرحبًا" وما يرد به المساعد مثل "أهلاً، تشرفت بلقائك" وموجّه التوليد يوفر تعليمات إضافية تُضاف للمحادثة لتوجيه النموذج حول كيفية التفاعل. فيمكن لموجّهات التوليد أن تحدد مثلاً أين يجب أن يبدأ النموذج في الرد، أو كيف يجب أن يبدو الرد.
نلاحظ أن التابع apply_chat_template
يحتوي على الوسيط add_generation_prompt
، حيث يخبر هذا الوسيط القالب Template بإضافة رموز tokens تشير إلى بداية استجابة البوت Bot، فمثلًا ليكن لدينا الدردشة التالية:
messages = [ {"role": "user", "content": "مرحبًا"}, {"role": "assistant", "content": "أهلًا تشرفت بلقائك"}, {"role": "user", "content": "هل يمكنني طرح سؤال؟"} ]
وستكون النتيجة كما يلي بدون موجّه التوليد وباستخدام قالب ChatML
الذي رأيناه في مثال نموذج Zephyr
:
tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False) """<|im_start|>user مرحبًا!<|im_end|> <|im_start|>assistant تشرفت بلقائك!<|im_end|> <|im_start|>user هل يمكنني طرح سؤال؟<|im_end|> """
وستكون النتيجة كما يلي عند استخدام موجّه التوليد:
tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) """<|im_start|>user مرحبًا!<|im_end|> <|im_start|>assistant تشرفت بلقائك!<|im_end|> <|im_start|>user هل يمكنني طرح سؤال؟<|im_end|> <|im_start|>assistant """
إذًا، عندما نستخدم نماذج الدردشة، سنحتاج إلى إخبار النموذج Model بما يجب عليه فعله بالضبط، خصوصًا فيما يتعلق بكيفية الرد على المستخدم. على سبيل المثال، لن يعرف النموذج تلقائيًا أين يبدأ في كتابة استجابة البوت المساعد، لذا نضيف رموز أو موجهات توليد خاصة في المكان الذي نريد أن تبدأ فيه استجابة البوت.
فالموجه الذي نضيفه هنا مثل <|im_start|>assistant
، سيخبر النموذج بأن هناك بداية لاستجابة البوت في هذه النقطة، وبدونه، قد يخطئ النموذج في فهم السياق ويبدأ في كتابة استجابة في مكان غير مناسب، مثل متابعة رسالة المستخدم.
ملاحظة: لا تحتاج كل النماذج إلى هذه الموجهات، فبعض النماذج مثل BlenderBot
و LlaMA
لا تستخدم أي رموز خاصة، لأن هذه النماذج تعرف تلقائيًا أين تبدأ استجابة البوت. وبالتالي، لن نحتاج لإضافة موجّهات توليد في هذه الحالة.
هل يمكن استخدام قوالب الدردشة في التدريب
يمكن استخدام قوالب الدردشة في التدريب، وهي طريقة جيدة للتأكّد من أن قالب الدردشة يطابق الرموز التي يراها النموذج أثناء التدريب، لذا يُوصَى بتطبيق قالب الدردشة كخطوة معالجة مسبقَة لمجموعة بياناتك، ويمكننا بعد ذلك ببساطة المتابعة مثل أي مهمة لتدريب نموذج لغوي آخر. يجب عند التدريب ضبط add_generation_prompt=False
لأن الرموز المضافة لموجّه استجابة المساعد لن تكون مفيدة أثناء التدريب. ليكن لدينا المثال التالي:
from transformers import AutoTokenizer from datasets import Dataset tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta") chat1 = [ {"role": "user", "content": "أيّهما أكبر، القمر أم الشمس؟"}, {"role": "assistant", "content": "الشمس."} ] chat2 = [ {"role": "user", "content": "أيّهما أكبر، الفيروس أم البكتيريا؟"}, {"role": "assistant", "content": "البكتيريا."} ] dataset = Dataset.from_dict({"chat": [chat1, chat2]}) dataset = dataset.map(lambda x: {"formatted_chat": tokenizer.apply_chat_template(x["chat"], tokenize=False, add_generation_prompt=False)}) print(dataset['formatted_chat'][0])
وسنحصل على النتيجة التالية:
<|user|> أيّهما أكبر، القمر أم الشمس؟</s> <|assistant|> الشمس.</s>
بعد تطبيق قالب الدردشة وتنسيق المحادثات، نتابع التدريب على النموذج بنفس الطريقة التي نتبعها في تدريب نماذج اللغة الأخرى باستخدام العمود formatted_chat
الذي يحتوي على المحادثات بتنسيق يتوافق مع طريقة التدريب التي يتوقعها النموذج.
ملاحظة: إذا نسّقنا النص باستخدام apply_chat_template(tokenize=False)
ثم رمّزناه في خطوة منفصلة، فيجب أن نضبط الوسيط add_special_tokens=False
، وإذا استخدمنا apply_chat_template(tokenize=True)
، فلا داعي للقلق بشأن ذلك.
تضيف بعض المرمِّزات رموزًا خاصة مثل <bos>
و <eos>
إلى النص الذي نرمّزه افتراضيًا، لذا يجب أن تتضمن قوالب الدردشة دائمًا جميع الرموز الخاصة التي نحتاجها، وبالتالي يمكن أن تؤدي إضافة رموز خاصة إضافية باستخدام add_special_tokens=True
الافتراضي إلى ظهور رموز خاصة غير صحيحة أو مكرَّرة، مما سيضر بأداء النموذج.
متقدم: دخل إضافي لقوالب الدردشة
الوسيط الوحيد الذي يتطلبه apply_chat_template
هو messages
، ولكن يمكننا تمرير أيّ وسيط كلمات مفتاحية Keyword Argument إلى apply_chat_template
وسيكون متاحًا ضمن القالب، مما يمنحنا قدرة على استخدام قوالب الدردشة للعديد من الأغراض. لا توجد قيود على أسماء أو تنسيق هذه الوسطاء، حيث يمكن تمرير السلاسل النصية أو القوائم أو القواميس أو أيّ شيء آخر تريده.
توجد بعض حالات الاستخدام الشائعة لهذه الوسطاء الإضافية مثل تمرير أدوات لاستدعاء الدوال أو مستندات للتوليد باستخدام الاسترجاع المعزَّز Retrieval-augmented، حيث توجد بعض التوصيات حول ما يجب أن تكون عليه أسماء وتنسيقات هذه الوسطاء والتي سنوضحها لاحقًا، لذا نشجّع مطوري النماذج على جعل قوالب الدردشة الخاصة بهم متوافقة مع هذا التنسيق لتسهيل نقل الشيفرة البرمجية لاستدعاء الأدوات فيما بين النماذج.
متقدم: استخدام الأدوات واستدعاء الدوال
يمكن للنماذج اللغوية الكبيرة LLMs الخاصة باستخدام الأدوات اختيار استدعاء الدوال كأدوات خارجية قبل توليد إجابة، حيث يمكن ببساطة تمرير قائمة من الدوال إلى الوسيط tools
عند تمرير الأدوات إلى نموذج استخدام الأدوات Tool-use كما يلي:
import datetime def current_time(): """احصل على الوقت المحلي الحالي كسلسلة نصية.""" return str(datetime.now()) def multiply(a: float, b: float): """ دالة ضرب رقمين المعاملات: a: الرقم الأول b: الرقم الثاني """ return a * b tools = [current_time, multiply] model_input = tokenizer.apply_chat_template( messages, tools=tools )
علينا الدوال بالتنسيق السابق لكي تعمل بالطريقة الصحيحة، وبالتالي يمكن تحليلها تحليلًا صحيحًا بوصفها أدوات، لذا يجب علينا اتباع القواعد التالية:
- يجب أن يكون للدالة اسم يصف عملها
- يجب أن يكون لكل وسيط تلميح لنوعه Type Hint
-
يجب أن يكون للدالة سلسلة نصية توثيقية Docstring وفق نمط جوجل Google المعياري أو وصف أولي للدالة، وتتبعه كتلة
Args:
التي تصف الوسطاء، إلّا في حالة عدم احتواء الدالة على وسطاء -
لا تضمّن الأنواع في كتلة
Args:
فمثلًا نكتبa:الرقم الأول
وليسa(int):الرقم الأول
حيث يتوجب علينا وضع تلميحات الأنواع في ترويسة الدالة بدلًا من ذلك -
يمكن أن يكون للدالة نوع للقيمة المعادة وكتلة
Returns:
في السلسلة النصية التوثيقية، ولكنها اختيارية لأن معظم نماذج استخدام الأدوات تتجاهلها
تمرير نتائج الأدوات إلى النموذج
تكفي الشيفرة البرمجية التجريبية السابقة لسرد الأدوات المتاحة لنموذجنا، ولكن إذا أردنا استخدام أداة فعليًا، فيجب أن:
- نحلّل خرج النموذج للحصول على اسم أو أسماء الأدوات ووسطائها
- نضيف استدعاء أو استدعاءات أداة النموذج إلى المحادثة
- نستدعي الدالة أو الدوال المقابلة مع تلك الوسطاء
- نضيف النتيجة أو النتائج إلى المحادثة
مثال كامل لاستخدام أداة
سنستخدم في هذا المثال نموذج Hermes-2-Pro
بحجم 8B لأنه أحد أعلى نماذج استخدام الأدوات أداءً في فئته الحجمية حاليًا. إذا كان لدينا ذاكرة كافية، فيمكن التفكير في استخدام نموذج أكبر بدلًا من ذلك مثل النموذجين Command-R أو Mixtral-8x22B، ويدعم كلاهما استخدام الأدوات ويقدّمان أداءً أقوى.
لنحمّل أولًا النموذج والمرمِّز كما يلي:
import torch from transformers import AutoModelForCausalLM, AutoTokenizer checkpoint = "NousResearch/Hermes-2-Pro-Llama-3-8B" # تحميل المرمِّز Tokenizer باستخدام نقطة التحقق checkpoint وتحديد النسخة المناسبة tokenizer = AutoTokenizer.from_pretrained(checkpoint, revision="pr/13") # تحميل النموذج Model باستخدام نقطة التحقق checkpoint، مع تحديد نوع البيانات bfloat16 وتوزيع النموذج على الأجهزة device_map model = AutoModelForCausalLM.from_pretrained(checkpoint, torch_dtype=torch.bfloat16, device_map="auto")
ثم نعرّف قائمة الأدوات كما يلي:
def get_current_temperature(location: str, unit: str) -> float: """ الحصول على درجة الحرارة الحالية في موقع معين. Args: location: الموقع الذي سيتم الحصول على درجة حرارته، بصيغة "المدينة، البلد". unit: الوحدة التي سيتم إرجاع درجة الحرارة بها. (الخيارات: ["مئوية"، "فهرنهايت"]). Returns: درجة الحرارة الحالية في الموقع المحدد بوحدات القياس المحددة، كعدد عشري (float). """ return 22. # يُحتمل أن تقوم الدالة الحقيقية بالحصول على درجة الحرارة الفعلية def get_current_wind_speed(location: str) -> float: """ الحصول على سرعة الرياح الحالية بالكيلومتر في الساعة (km/h) في موقع معين. Args: location: الموقع الذي سيتم الحصول على سرعة الرياح فيه، بصيغة "المدينة، البلد". Returns: سرعة الرياح الحالية في الموقع المحدد بالكيلومتر في الساعة (km/h)، كعدد عشري (float). """ return 6. # يُحتمل أن تقوم الدالة الحقيقية بالحصول على سرعة الرياح الفعلية tools = [get_current_temperature, get_current_wind_speed]
لنُعِدّ الآن محادثة البوت كما يلي:
messages = [ {"role": "system", "content": "أنت بوت يجيب على استفسارات الطقس. يجب أن ترد بوحدة القياس المستخدمة في الموقع الذي تم الاستفسار عنه."}, {"role": "user", "content": "مرحبًا، ما هي درجة الحرارة في باريس الآن؟"} ]
ونطبّق قالب الدردشة ونولّد استجابةً كما يلي:
inputs = tokenizer.apply_chat_template(messages, chat_template="tool_use", tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt") inputs = {k: v.to(model.device) for k, v in inputs.items()} out = model.generate(**inputs, max_new_tokens=128) print(tokenizer.decode(out[0][len(inputs["input_ids"][0]):]))
سنحصل على النتيجة التالية:
<tool_call> {"arguments": {"location": "باريس، فرنسا", "unit": "مئوية"}, "name": "get_current_temperature"} </tool_call><|im_end|>
استدعى النموذج الدالة مع وسطاء صالحة وبالتنسيق الذي تطلبه السلسلة النصية التوثيقية للدالة، واستدل النموذج أننا نشير إلى باريس في فرنسا، وتذكّرَ أنه يجب بالتأكيد عرض درجة الحرارة في فرنسا بالدرجة المئوية باعتبارها موطن نظام الوحدات الدولي.
سنضيف الآن استدعاء الأداة الخاصة بالنموذج إلى المحادثة، حيث نولّد معرّف tool_call_id
عشوائي. لا تستخدم جميع النماذج هذه المعرّفات، ولكنها تسمح للنماذج بإنشاء استدعاءات أدوات متعددة في وقتٍ واحد وتتبع الاستجابة المقابلة لكلّ استدعاء. يمكنك توليد هذه المعرّفات بأيّ طريقة تريدها، ولكن يجب أن تكون فريدة في كل دردشة.
tool_call_id = "vAHdf3" # معرّف عشوائي، ويجب أن يكون فريدًا لكل استدعاء أداة tool_call = {"name": "get_current_temperature", "arguments": {"location": "باريس، فرنسا", "unit": "مئوية"}} messages.append({"role": "assistant", "tool_calls": [{"id": tool_call_id, "type": "function", "function": tool_call}]})
أضفنا استدعاء الأداة إلى المحادثة، ويمكننا الآن استدعاء الدالة وإضافة النتيجة إلى المحادثة، حيث نستخدم في هذا المثال دالة وهمية تعيد القيمة 22.0
دائمًا، لذا يمكننا إضافة هذه النتيجة مباشرةً. يجب أن يتطابق المعرّف tool_call_id
مع المعرّف المستخدَم في استدعاء الأداة السابق.
messages.append({"role": "tool", "tool_call_id": tool_call_id, "name": "get_current_temperature", "content": "22.0"})
أخيرًا، سندع المساعد يقرأ خرج الدالة ويتابع الدردشة مع المستخدم كما يلي:
inputs = tokenizer.apply_chat_template(messages, chat_template="tool_use", tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt") inputs = {k: v.to(model.device) for k, v in inputs.items()} out = model.generate(**inputs, max_new_tokens=128) print(tokenizer.decode(out[0][len(inputs["input_ids"][0]):]))
وسنحصل على النتيجة التالية:
درجة الحرارة الحالية في باريس، فرنسا هي 22.0 درجة مئوية
وضّحنا مثالًا بسيطًا باستخدام أدوات وهمية واستدعاء واحد، ولكن ستعمل التقنية نفسها مع أدوات حقيقية متعددة ومحادثات أطول، ويمكن أن تكون هذه الطريقة فعّالة لتوسيع قدرات وكلاء المحادثة باستخدام معلومات في الوقت الحقيقي أو أدوات حسابية مثل الآلات الحاسبة أو الوصول إلى قواعد بيانات كبيرة.
ملاحظة: لا تستخدم كل النماذج جميع ميزات استدعاء الأدوات السابقة، إذ تستخدم بعض النماذج معرّفات استدعاء الأدوات، ويستخدم البعض الآخر ببساطة اسم الدالة ويطابق استدعاءات الأدوات مع النتائج باستخدام الترتيب، وتوجد عدة نماذج لا تستخدم أي من هاتين الطريقتين وتنشئ استدعاء أداة واحد فقط في كل مرة لتجنب الالتباس. إذا أردنا أن تكون شيفرتنا البرمجية متوافقة مع أكبر عدد ممكن من النماذج، فيُوصَى ببناء استدعاءات الأدوات الخاصة بنا كما وضّحنا سابقًا، وإعادة نتائج الأدوات بالترتيب الذي أنشأه النموذج، ويجب أن نتعامل قوالب الدردشة في كل نموذج مع المهام المتبقية.
فهم مخططات الأدوات Tool Schemas
تُحوَّل كل دالة تمرّرها إلى الوسيط tools
الخاص بالدالة apply_chat_template
إلى مخطط JSON، ثم تُمرَّر هذه المخططات إلى قالب دردشة النموذج، حيث لا ترى نماذج استخدام الأدوات دوالك مباشرةً، ولا ترى الشيفرة البرمجية الفعلية التي بداخلها أبدًا، فما يهمها هو تعريفات الدوال والوسطاء التي تحتاج إلى تمريرها إليها، إذ تهتم بما تفعله الأدوات وكيفية استخدامها، وليس بكيفية عملها. الأمر متروك لك لقراءة خرج هذه الدوال واكتشاف طلبها لاستخدام أداة وتمرير وسطائها إلى دالة الأداة وإعادة الاستجابة في الدردشة.
يجب أن يكون توليد مخططات JSON لتمريرها إلى القالب تلقائيًا وغير مرئي بما أن دوالك تتبع المواصفات السابقة، ولكن إذا واجهنا مشكلات، أو أردنا مزيدًا من التحكم في التحويل، فيمكن التعامل مع التحويل يدويًا. فيما يلي مثال على تحويل مخطط يدويًا:
from transformers.utils import get_json_schema def multiply(a: float, b: float): """ دالة تقوم بضرب عددين الوسائط: a: العدد الأول الذي سيتم ضربه b: العدد الثاني الذي سيتم ضربه """ return a * b schema = get_json_schema(multiply) print(schema)
وسنحصل على النتيجة التالية:
{ "type": "function", "function": { "name": "multiply", "description": "دالة تقوم بضرب عددين", "parameters": { "type": "object", "properties": { "a": { "type": "number", "description": "العدد الأول الذي سيتم ضربه" }, "b": { "type": "number", "description": "العدد الثاني الذي سيتم ضربه" } }, "required": ["a", "b"] } } }
يمكن أيضًا تعديل هذه المخططات أو كتابتها من الصفر بنفسنا بدون استخدام get_json_schema
على الإطلاق، حيث يمكن تمرير مخططات JSON مباشرةً إلى الوسيط tools
في apply_chat_template
، مما يمنحنا قدرًا كبيرًا من القوة لتعريف مخططات دقيقة لدوال أكثر تعقيدًا، ولكن يجب توخي الحذر، فكلما كانت المخططات أكثر تعقيدًا، كلما زاد احتمال ارتباك النموذج عند التعامل معها. يُوصى باستخدام توقيعات دوال بسيطة simple function signatures إن أمكن ذلك مع إبقاء الحد الأدنى من الوسطاء وخاصة الوسطاء المعقدة والمتداخلة.
فيما يلي مثال لتعريف المخططات يدويًا وتمريرها إلى apply_chat_template
مباشرة:
# دالة بسيطة لا تأخذ أي وسائط current_time = { "type": "function", "function": { "name": "current_time", "description": "الحصول على الوقت المحلي الحالي كسلسلة نصية.", "parameters": { 'type': 'object', 'properties': {} } } } # دالة أكثر اكتمالًا تأخذ وسيطين عدديين multiply = { 'type': 'function', 'function': { 'name': 'multiply', 'description': 'دالة لضرب عددين', 'parameters': { 'type': 'object', 'properties': { 'a': { 'type': 'number', 'description': 'العدد الأول الذي سيتم ضربه' }, 'b': { 'type': 'number', 'description': 'العدد الثاني الذي سيتم ضربه' } }, 'required': ['a', 'b'] } } } model_input = tokenizer.apply_chat_template( messages, tools=[current_time, multiply] )
متقدم: التوليد المعزز بالاسترجاع Retrieval-augmented Generation
يمكن للتوليد المعزز بالاسترجاع Retrieval-augmented Generation -أو RAG اختصارًا- الخاص بالنماذج اللغوية الكبيرة LLM البحث في مجموعة من المستندات للحصول على معلومات قبل الرد على استعلام، مما يسمح للنماذج بتوسيع قاعدة المعرفة الخاصة بها بما يتجاوز حجم السياق المحدود. يجب أن يأخذ قالب نماذج RAG الوسيط documents
، والذي يجب أن يمثّل قائمة من المستندات، حيث يكون كل مستند قاموسًا واحدًا مع مفتاحي العنوان title
والمحتويات contents
، وهما سلاسل نصية. لا توجد دوال مساعدة ضرورية لأن هذا التنسيق أبسط بكثير من مخططات JSON المُستخدَمة مع الأدوات.
فيما يلي مثال لقالب RAG:
document1 = { "title": "القمر: عدونا القديم", "contents": "لطالما حلم الإنسان بتدمير القمر. في هذه المقالة، سأناقش..." } document2 = { "title": "الشمس: صديقنا القديم", "contents": "على الرغم من قلة تقديرها في كثير من الأحيان، إلا أن الشمس تقدم العديد من الفوائد الملحوظة..." } model_input = tokenizer.apply_chat_template( messages, documents=[document1, document2] )
متقدم: كيف تعمل قوالب الدردشة
يُخزَّن قالب الدردشة الخاص بالنموذج في السمة tokenizer.chat_template
، ويُستخدَم القالب الافتراضي لصنف هذا النموذج عند عدم ضبط قالب دردشة. لنلقِ نظرة أولًا على قالب BlenderBot
:
>>> from transformers import AutoTokenizer >>> tokenizer = AutoTokenizer.from_pretrained("facebook/blenderbot-400M-distill") >>> tokenizer.default_chat_template "{% for message in messages %}{% if message['role'] == 'user' %}{{ ' ' }}{% endif %}{{ message['content'] }}{% if not loop.last %}{{ ' ' }}{% endif %}{% endfor %}{{ eos_token }}"
قد يكون ذلك معقدًا بعض الشيء، لذا لننظّفه قليلًا لجعله مقروءًا أكثر، ونتأكّد في هذه العملية أيضًا من أن الأسطر الجديدة والمسافات البادئة التي نضيفها غير مُضمَّنة في خرج القالب كما سنوضّح في قسم إزالة المسافات البيضاء من السلاسل النصية Trimming Whitespace لاحقًا.
{%- for message in messages %}
{%- if message['role'] == 'user' %}
{{- ' ' }}
{%- endif %}
{{- message['content'] }}
{%- if not loop.last %}
{{- ' ' }}
{%- endif %}
{%- endfor %}
{{- eos_token }}
يُعَد ذلك محرك قوالب Jinja، والتي هي لغة قوالب تسمح بكتابة شيفرة برمجية بسيطة تولّد نصًا، حيث تشبه شيفرتها البرمجية وصياغتها لغة بايثون Python، إذ سيبدو القالب السابق في لغة بايثون كما يلي:
for idx, message in enumerate(messages): if message['role'] == 'user': print(' ') print(message['content']) if not idx == len(messages) - 1: # التحقق من الرسالة الأخيرة في المحادثة print(' ') print(eos_token)
ينجز هذا القالب ثلاثة أشياء هي:
- إذا كانت الرسالة رسالة مستخدم، فسيضيف مسافة فارغة قبلها بالنسبة لكل رسالة، وإلا فلن يطبع شيئًا
- يضيف محتوى الرسالة
- إن لم تكن الرسالة هي الرسالة الأخيرة، فسيضيف مسافتَين بعدها، ويطبع رمز EOS بعد الرسالة الأخيرة
هذا القالب بسيط جدًا، فهو لا يضيف رموز تحكم ولا يدعم رسائل النظام، ويُعَد طريقة شائعة لإعطاء النموذج توجيهات حول كيفية التصرّف في المحادثة اللاحقة. تمنحك لغة القوالب Jinja الكثير من المرونة لهذه الأشياء، لذا لنوضّح فيما يلي قالب Jinja الذي يمكنه تنسيق الدخل بطريقة مماثلة للطريقة التي ينسقّ قالب LLaMA بها هذا الدخل، حيث يتضمن قالب LLaMA الحقيقي معالجة رسائل النظام الافتراضية ورسائل النظام المختلفة قليلًا، ولكن لا نستخدم هذا القالب في شيفرتنا البرمجية الفعلية.
{%- for message in messages %} {%- if message['role'] == 'user' %} {{- bos_token + '[INST] ' + message['content'] + ' [/INST]' }} {%- elif message['role'] == 'system' %} {{- '<<SYS>>\\n' + message['content'] + '\\n<</SYS>>\\n\\n' }} {%- elif message['role'] == 'assistant' %} {{- ' ' + message['content'] + ' ' + eos_token }} {%- endif %} {%- endfor %}
يضيف هذا القالب رموزًا Tokens محددة بناءً على دور كل رسالة، والتي تمثّل مَن أرسلها، إذ يمكن أن يميّز النموذج بين رسائل المستخدم والمساعد والنظام بوضوح بسبب الرموز الموجودة ضمنها.
متقدم: إضافة وتعديل قوالب الدردشة
سنوضّح فيما يلي كيفية إضافة وتعديل قوالب الدردشة.
كيف ننشئ قالب دردشة Chat Templates
إنشاء قالب دردشة أمر بسيط، حيث نكتب قالب Jinja ونضبط السمة tokenizer.chat_template
، ولكن قد نجد أن من الأسهل البدء بقالب موجود مسبقًا من نموذج آخر وتعديله لتلبية احتياجاتنا، فمثلًا يمكن أخذ قالب LLaMA السابق وإضافة الرموز "[ASST]"
و"[/ASST]"
إلى رسائل المساعد كما يلي:
{%- for message in messages %} {%- if message['role'] == 'user' %} {{- bos_token + '[INST] ' + message['content'].strip() + ' [/INST]' }} {%- elif message['role'] == 'system' %} {{- '<<SYS>>\\n' + message['content'].strip() + '\\n<</SYS>>\\n\\n' }} {%- elif message['role'] == 'assistant' %} {{- '[ASST] ' + message['content'] + ' [/ASST]' + eos_token }} {%- endif %} {%- endfor %}
وما علينا الآن سوى ضبط السمة tokenizer.chat_template
، وسيستخدم التابع apply_chat_template()
قالبنا الجديد في المرة التالية التي تستخدمه فيها. تُحفَظ هذه السمة في الملف tokenizer_config.json
، لذا يمكننا استخدام التابع push_to_hub()
لتحميل القالب الجديد إلى مستودع FacHugging e Hub والتأكد من أن الجميع يستخدمون القالب الصحيح لنموذجنا.
template = tokenizer.chat_template template = template.replace("SYS", "SYSTEM") # تغيير رمز النظام tokenizer.chat_template = template # ضبط القالب الجديد tokenizer.push_to_hub("model_name") # رفع قالبك الجديد إلى مستودع Hub
يستدعي الصنف TextGenerationPipeline التابع apply_chat_template()
الذي يستخدم قالب الدردشة الخاص بك، لذا سيصبح النموذج متوافقًا تلقائيًا مع هذا الصنف بعد ضبط قالب الدردشة الصحيح.
ملاحظة: عند صقل Fine-tune نموذج دردشة باستخدام قالب الدردشة، يجب إضافة رموز تحكم جديدة إلى المرمِّز بوصفها رموزًا خاصة. هذه الرموز لا تُقسَم أبدًا، مما يعني أنها ستظل دائمًا تعامل كرموز فردية بدلاً من أن تُقسَّم إلى أجزاء أثناء عملية الترميز. بالإضافة إلى ذلك، يجب تعيين سمة أداة المرمِّز eos_token
إلى الرمز الذي يمثل نهاية عمليات التوليد الخاصة بالبوت في قالبنا. هذا يضمن أن أدوات توليد النص تتعرف بشكل صحيح على اللحظة التي يجب فيها التوقف عن توليد النص.
لماذا تحتوي بعض النماذج قوالب متعددة
تستخدم بعض النماذج قوالب مختلفة لحالات استخدام مختلفة، فمثلًا قد نستخدم قالبًا للدردشة العادية وقالبًا آخر لاستخدام الأداة أو التوليد المعزز بالاسترجاع، حيث تكون السمة tokenizer.chat_template
قاموسًا في هذه الحالات. قد يؤدي ذلك إلى بعض الارتباك، لذا يُوصَى باستخدام قالب واحد لجميع حالات الاستخدام إن أمكننا ذلك. يمكننا استخدام تعليمات Jinja مثل if tools is defined
وتعريفات {% macro %}
لتغليف مسارات الشيفرة البرمجية المتعددة في قالب واحد بسهولة.
إذا كان للمرمِّز قوالب متعددة، فستكون السمة tokenizer.chat_template
قاموسًا dict
، حيث يكون كل مفتاح هو اسم القالب. يمتلك التابع apply_chat_template
معالجة خاصة لأسماء قوالب معينة، حيث يبحث عن قالب باسم default
في معظم الحالات، ويعطي خطأ إن لم يتمكن من العثور عليه، ولكن إذا كان القالب tool_use
موجودًا عندما يمرّر المستخدم الوسيط tools
، فسيستخدمه بدلًا من ذلك. يمكن الوصول إلى القوالب ذات الأسماء الأخرى من خلال تمرير اسم القالب الذي نريده إلى الوسيط chat_template
الخاص بالتابع apply_chat_template()
.
قد يكون ذلك مربكًا بعض الشيء للمستخدمين، لذا إذا أدرنا كتابة قالب بنفسنا، فيُوصى باستخدام قالب واحد إن أمكن ذلك.
ما القالب الذي يجب استخدامه
يجب أن نتأكد من أن القالب يتطابق مع تنسيق الرسالة الذي شاهده النموذج أثناء التدريب عند ضبط هذا القالب للنموذج المُدرَّب مسبقًا للدردشة، وإلّا فقد ينخفض الأداء. يحدث الشيء نفسه حتى إن درّبنا النموذج أكثر، فمن المحتمل أن نحصل على الأداء الأفضل إذا أبقينا رموز الدردشة ثابتة، ويُعَد ذلك مشابهًا جدًا للترميز، حيث نحصل على الأداء الأفضل للاستدلال Inference أو الصقل Fine-tuning عندما نطابق بدقة الترميز المُستخدَم أثناء التدريب.
إذا درّبنا نموذجًا من الصفر أو صقلنا نموذج لغوي أساسي للدردشة، فلدينا الحرية لاختيار قالب مناسب، حيث تتمتع النماذج اللغوية الكبيرة LLM بالذكاء الكافي لتعلّم كيفية التعامل مع الكثير من تنسيقات الدخل المختلفة، وأحد الخيارات الشائعة هو تنسيق ChatML
الذي يُعَد خيارًا جيدًا ومرنًا للعديد من حالات الاستخدام، والذي يبدو كما يلي:
{%- for message in messages %} {{- '<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n' }} {%- endfor %}
إذا أعجبنا التنسيق السابق، فلدينا صيغة مؤلفةً من سطر واحد وجاهزةً للنسخ في شيفرتنا البرمجية، حيث تتضمن هذه الصيغة دعمًا لموجّهات التوليد Generation Prompts، ولكنها لا تضيف رموز BOS أو EOS. إذا توقّع نموذجنا هذه الرموز، فلن يضيفها التابع apply_chat_template
تلقائيًا، حيث سيُرمَّز النص باستخدام add_special_tokens=False
لتجنب التعارضات المحتملة بين القالب والمنطق البرمجي add_special_tokens
. إذا توقّع نموذجنا رموزًا خاصة، فعلينا التأكّد من إضافتها إلى القالب.
tokenizer.chat_template = "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% for message in messages %}{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}"
يغلّف هذا القالب كل رسالة برمزَي <|im_start|>
و <|im_end|>
، ويكتب الدور كسلسلة نصية، مما يسمح بالمرونة في الأدوار التي تتدرب بها، وسيبدو الخرج كما يلي:
<|im_start|>system أنت روبوت محادثة مفيد يبذل قصارى جهده لعدم قول شيء سخيف يجذب الانتباه على تويتر.<|im_end|> <|im_start|>user كيف حالك؟<|im_end|> <|im_start|>assistant أنا بأفضل حال!<|im_end|>
تُعَد أدوار المستخدم والنظام والمساعد هي الأدوار المعيارية للدردشة، ويُوصَى باستخدامها عندما يكون ذلك منطقيًا، وخاصةً إذا أردنا أن يعمل نموذجنا بنجاح مع الصنف TextGenerationPipeline
، ولكن لا يقتصر الأمر على هذه الأدوار، إذ تُعَد عملية إنشاء القوالب مرنة ويمكن أن تمثّل أيّ سلسلة نصية دورًا.
كيف نبدأ بإضافة قوالب الدردشة
إذا كان لدينا نموذج دردشة، فيجب ضبط السمة tokenizer.chat_template
الخاصة به واختباره باستخدام التابع apply_chat_template()
، ثم دفع المُرمِّز المحدَّث إلى مستودع Hugging Face Hub. يُطبَّق الشيء نفسه حتى إن لم نكن مالكي النموذج، فإذا استخدمنا نموذجًا مع قالب دردشة فارغ أو نموذجًا لا يزال يستخدم قالب الصنف الافتراضي، فيجب فتح طلب سحب Pull Request إلى مستودع النموذج حتى نتمكّن من ضبط هذه السمة بطريقة صحيحة.
نصبح جاهزين بعد ضبط هذه السمة، إذ سيعمل التابع tokenizer.apply_chat_template
الآن بنجاح مع هذا النموذج، مما يعني أنه مدعوم تلقائيًا أيضًا في أماكن أخرى مثل الصنف TextGenerationPipeline
.
يمكننا ضمان استفادة المجتمع بالكامل من الإمكانيات الكاملة للنماذج مفتوحة المصدر من خلال التأكد من تضمين هذه السمة في النماذج. فقد كان عدم تطابق التنسيق مشكلة قائمة في هذا المجال، مما أثر سلبًا على الأداء لفترة طويلة، ولذلك حان الوقت لوضع حد لهذه المشكلة.
متقدم: نصائح لكتابة القوالب
إن لم نكن على دراية بلغة القوالب Jinja، فسنجد أن أسهل طريقة لكتابة قالب دردشة هي أولًا كتابة كود قصير بلغة بايثون ينسّق الرسائل بالطريقة التي نريدها ثم تحويل هذا السكربت إلى قالب.
لنتذكّر أن معالج القالب سيستقبل سجل المحادثة كمتغير بالاسم messages
، وسنتمكّن من الوصول إلى هذا المتغير في قالبنا كما تفعل في لغة بايثون، حيث يمكننا تكراره ضمن حلقة باستخدام التعليمة {% for message in messages %}
أو الوصول إلى الرسائل الفردية باستخدام التعليمة {{ messages[0] }}
مثلًا.
يمكن أيضًا استخدام النصائح التالية لتحويل شيفرتنا البرمجية إلى لغة القوالب Jinja.
إزالة المسافات البيضاء من السلاسل النصية
ستطبع لغة القوالب Jinja افتراضيًا أي مسافات Whitespace مثل الفراغات والسطور الجديدة تأتي قبل أو بعد كتلة ما، والذي قد يشكّل مشكلة بالنسبة لقوالب الدردشة التي نريد أن تكون دقيقة مع الفراغات، حيث يمكن تجنب ذلك من خلال كتابة قوالبك كما يلي:
{%- for message in messages %}
{{- message['role'] + message['content'] }}
{%- endfor %}
بدلًا من الطريقة التالية:
{% for message in messages %}
{{ message['role'] + message['content'] }}
{% endfor %}
ستؤدي إضافة الرمز -
إلى إزالة أي مسافة بيضاء تأتي قبل الكتلة. قد يبدو أن المثال الثاني لا يسبب مشكلات، ولكنه قد يتضمّن الخرجُ السطرَ الجديد والمسافة البادئة، وهو الشيء الذي نريد تجنبّه.
حلقات For
تبدو حلقات For في لغة Jinja كما يلي:
{%- for message in messages %}
{{- message['content'] }}
{%- endfor %}
نلاحظ أن كل ما يوجد ضمن {{ كتلة التعبير }}
سيُطبَع في الخرج، ويمكنك استخدام معاملات مثل +
لدمج السلاسل النصية ضمن كتل التعبير.
تعليمات If
تبدو تعليمات If في لغة Jinja كما يلي:
{%- if message['role'] == 'user' %}
{{- message['content'] }}
{%- endif %}
تستخدم لغة بايثون المسافات البيضاء لتمييز بدايات ونهايات كتل for
و if
، وتطلب لغة Jinja إنهاءها صراحةً باستخدام {% endfor %}
و {% endif %}
.
المتغيرات الخاصة
يمكن الوصول إلى قائمة الرسائل messages
داخل قالبنا، ولكن يمكنك أيضًا الوصول إلى العديد من المتغيرات الخاصة الأخرى، والتي تتضمّن الرموز الخاصة مثل bos_token
و eos_token
، بالإضافة إلى المتغير add_generation_prompt
الذي ناقشناه سابقًا. يمكن أيضًا استخدام المتغير loop
للوصول إلى معلومات حول تكرار الحلقة الحالي مثل استخدام {% if loop.last %}
للتحقق مما إذا كانت الرسالة الحالية هي الرسالة الأخيرة في المحادثة.
فيما يلي مثال يجمع بين هذه الأفكار لإضافة موجّه توليد في نهاية المحادثة إذا كانت قيمة add_generation_prompt
هي True
:
{%- if loop.last and add_generation_prompt %}
{{- bos_token + 'المساعد:\n' }}
{%- endif %}
التوافق مع لغة قوالب Jinja التي لا تستخدم لغة بايثون
توجد تطبيقات متعددة للغة قوالب Jinja التي تستخدم لغات مختلفة، ويكون لها عادةً الصياغة نفسها، ولكن الاختلاف الرئيسي هو إمكانية استخدام توابع بايثون عند كتابة قالب باستخدام بايثون مثل استخدام التابع .lower()
مع السلاسل النصية أو التابع .items()
مع القواميس. سيتوقف ذلك إذا حاول شخص ما استخدام قالبك على تطبيق للغة قوالب Jinja التي لا تستخدم لغة بايثون، فالتطبيقات التي لا تستخدم لغة بايثون شائعة الاستخدام وخاصةً في بيئات النشر حيث تحظى لغة جافاسكربت JS ورَست Rust بشعبية كبيرة.
فيما يلي بعض التغييرات السهلة التي يمكن إجراؤها على قوالبنا لضمان توافقها مع جميع تطبيقات Jinja:
-
نستخدم مرشّحات Jinja بدل توابع بايثون، حيث يكون لها الاسم نفسه عادة، فمثلًا يتحوّل
string.lower()
إلىstring|lower
، ويتحوّلdict.items()
إلىdict|items
. أحد التغييرات الملحوظة هو أنstring.strip()
يصبحstring|trim
. ويمكن مطالعة قائمة المرشحات المضمنة في توثيق Jinja لمزيد من المعلومات -
نضع
true
وfalse
وnone
بدلTrue
وFalse
وNone
الخاصة بلغة بايثون -
قد يؤدي عرض القاموس أو القائمة مباشرةً إلى نتائج مختلفة في تطبيقات أخرى، فمثلًا قد تتغير إدخالات السلسلة النصية من علامتي اقتباس مفردتين إلى علامتي اقتباس مزدوجتين، لذا يمكن أن تساعدنا إضافة مرشّح
tojson
في ضمان التناسق
الخاتمة
بهذا نكون وصلنا لختام مقالنا الشامل الذي شرحنا فيه كيفية تحويل الدردشات إلى تنسيق قابل للاستخدام في نماذج Hugging Face باستخدام قوالب الدردشة Chat Templates، وتعرفنا على أمثلة مختلفة توضح طريقة تطبيقها لتحسين التفاعل بين النظام والمستخدم والتأكد من أن البيانات المدخلة تتماشى مع طريقة تدريب النموذج.
ترجمة -وبتصرّف- للقسم Templates for Chat Models من توثيقات Hugging Face.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.