# قوالب المحادثة

يتناول دليل [أساسيات المحادثة](./conversations) كيفية تخزين سجلات المحادثة وتوليد النص من نماذج المحادثة باستخدام [TextGenerationPipeline](/docs/transformers/main/ar/main_classes/pipelines#transformers.TextGenerationPipeline).

هذا الدليل موجّه للمستخدمين الأكثر تقدماً، ويتناول الفئات والأساليب الأساسية، فضلاً عن المفاهيم الرئيسية لفهم ما يحدث فعلياً عند محادثتك لنموذج.

الدور المحوري الذي يجب فهمه لاستيعاب نماذج المحادثة هو الآتي: جميع نماذج اللغة السببية، سواء كانت مدربة على المحادثة أم لا، تستمر في توليد تسلسل من الرموز. عند تدريب نماذج اللغة السببية، يبدأ التدريب عادةً بمرحلة "التدريب المسبق" على مجموعة ضخمة من النصوص، مما يؤدي إلى إنشاء نموذج "أساسي". ثم غالبًا ما يتم "ضبط" هذه النماذج الأساسية للمحادثة، أي تدريبها على بيانات مُنسّقة على شكل تسلسل من الرسائل. ومع ذلك، تبقى المحادثة مجرد تسلسل من الرموز! فمجموعة قواميس `role` و`content` التي تمررها إلى نموذج المحادثة تُحوَّل إلى تسلسل من الرموز، وغالبًا ما يُستخدم رموز تحكم مثل `<|user|>` أو `<|assistant|>` أو `<|end_of_message|>`، مما يتيح للنموذج رؤية بنية المحادثة. هناك العديد من صيغ المحادثة الممكنة، وقد تستخدم النماذج المختلفة صيغًا أو رموز تحكم مختلفة، حتى لو كانت قد خضعت لضبط دقيق انطلاقًا من نفس النموذج الأساسي!

لا داعي للذعر، فأنت لا تحتاج إلى حفظ جميع صيغ المحادثة الممكنة لاستخدام نماذج المحادثة. تأتي نماذج المحادثة مع **قوالب محادثة**، توضح كيفية توقعها لتنسيق المحادثات. يمكنك الوصول إلى هذه القوالب باستخدام طريقة `apply_chat_template`. دعنا ننظر إلى مثالين. كلا هذين النموذجين مُعدّلان من نفس النموذج الأساسي `Mistral-7B`:

```py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-Instruct-v0.1")
chat = [
  {"role": "user", "content": "Hello, how are you?"},
  {"role": "assistant", "content": "I'm doing great. How can I help you today?"},
  {"role": "user", "content": "I'd like to show off how chat templating works!"},
]

tokenizer.apply_chat_template(chat, tokenize=False)
```

```md
<s>[INST] Hello, how are you? [/INST]I'm doing great. How can I help you today?</s> [INST] I'd like to show off how chat templating works! [/INST]
```

```py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
chat = [
  {"role": "user", "content": "Hello, how are you?"},
  {"role": "assistant", "content": "I'm doing great. How can I help you today?"},
  {"role": "user", "content": "I'd like to show off how chat templating works!"},
]

tokenizer.apply_chat_template(chat, tokenize=False)
```

```md
<|user|>\nHello, how are you?</s>\n<|assistant|>\nI'm doing great. How can I help you today?</s>\n<|user|>\nI'd like to show off how chat templating works!</s>\n
```

يستخدم Mistral-7B-Instruct الرمزين `[INST]` و`[/INST]` للإشارة إلى بداية رسائل المستخدم ونهايتها، بينما يستخدم Zephyr-7B الرمزين `<|user|>` و`<|assistant|>` للإشارة إلى أدوار المتكلمين. ولهذا السبب تُعدّ قوالب المحادثة مهمة - فمع رموز التحكم الخاطئة، ستكون أداءات هذه النماذج أسوأ بشكل كبير.

## استخدام `apply_chat_template`

يجب أن تكون المدخلات إلى `apply_chat_template` منظمة على شكل قائمة من القواميس تحتوي على مفاتيح `role` و`content`. يحدد المفتاح `role` المتحدث، بينما يحتوي المفتاح `content` على الرسالة. الأدوار الشائعة هي:

- `user` للرسائل الصادرة من المستخدم
- `assistant` للرسائل الصادرة عن النموذج
- `system` لتوجيهات كيفية تصرف النموذج (يتم وضعها عادةً في بداية المحادثة)

`apply_chat_template` يستقبل هذه القائمة ويعيد تسلسلاً منسقاً. اضبط `tokenize=True` إذا كنت ترغب في تحويل التسلسل إلى رموز.

```py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
model = AutoModelForCausalLM.from_pretrained("HuggingFaceH4/zephyr-7b-beta", device_map="auto", dtype=torch.bfloat16)

messages = [
    {"role": "system", "content": "You are a friendly chatbot who always responds in the style of a pirate",},
    {"role": "user", "content": "How many helicopters can a human eat in one sitting?"},
 ]
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt").to(model.device)
print(tokenizer.decode(tokenized_chat["input_ids"][0]))
```

```md
<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s>
<|user|>
How many helicopters can a human eat in one sitting?</s>
<|assistant|>
```

مرّر المحادثة المُرمّزة إلى [generate()](/docs/transformers/main/ar/main_classes/text_generation#transformers.GenerationMixin.generate) لتوليد رد.

```py
outputs = model.generate(**tokenized_chat, max_new_tokens=128)
print(tokenizer.decode(outputs[0]))
```

```md
<|system|>
You are a friendly chatbot who always responds in the style of a pirate</s>
<|user|>
How many helicopters can a human eat in one sitting?</s>
<|assistant|>
Matey, I'm afraid I must inform ye that humans cannot eat helicopters. Helicopters are not food, they are flying machines. Food is meant to be eaten, like a hearty plate o' grog, a savory bowl o' stew, or a delicious loaf o' bread. But helicopters, they be for transportin' and movin' around, not for eatin'. So, I'd say none, me hearties. None at all.
```

> [!WARNING]
> تضيف بعض مُجزّئات الرموز رموزًا خاصة مثل `<bos>` و`<eos>`. يجب أن تتضمن قوالب المحادثة بالفعل جميع الرموز الخاصة اللازمة، وغالبًا ما يكون إضافة رموز خاصة إضافية غير صحيح أو متكررًا، مما يُضعف أداء النموذج. عند تنسيق النص باستخدام `apply_chat_template(tokenize=False)`، تأكد من تعيين `add_special_tokens=False` إذا كنت ستقوم بتجزئة الرموز لاحقًا لتجنب تكرار هذه الرموز. لا يُعد هذا مشكلة إذا كنت تستخدم `apply_chat_template(tokenize=True)`، مما يعني أنه الخيار الأكثر أمانًا عادةً!

### add_generation_prompt

ربما لاحظتَ حجة [add_generation_prompt](/docs/transformers/main/ar/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.add_generation_prompt) في الأمثلة أعلاه. تُضيف هذه الحجة رموزًا إلى نهاية المحادثة تشير إلى بداية رد من `assistant`. تذكّر: خلف كل تجريدات المحادثة، ما تزال نماذج المحادثة مجرد نماذج لغوية تستكمل تسلسلًا من الرموز! إذا شملت رموزًا تخبرها أنها الآن في رد من `assistant`، فستكتب ردًا صحيحًا، لكن إذا لم تشمل هذه الرموز، فقد تختلط على النموذج الأمور فيفعل شيئًا غريبًا، مثل **متابعة** رسالة المستخدم بدلاً من الرد عليها!

لنأخذ مثالاً لفهم ما يفعله `add_generation_prompt` فعليًا. أولًا، لننسّق محادثة دون استخدام `add_generation_prompt`:

```py
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False)
tokenized_chat
```

```md
<|im_start|>user
Hi there!<|im_end|>
<|im_start|>assistant
Nice to meet you!<|im_end|>
<|im_start|>user
Can I ask a question?<|im_end|>
```

الآن، لننسّق نفس المحادثة باستخدام `add_generation_prompt=True`:

```py
tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
tokenized_chat
```

```md
<|im_start|>user
Hi there!<|im_end|>
<|im_start|>assistant
Nice to meet you!<|im_end|>
<|im_start|>user
Can I ask a question?<|im_end|>
<|im_start|>assistant

```

عند تعيين `add_generation_prompt=True`، يُضاف `<|im_start|>assistant` في النهاية للإشارة إلى بداية رسالة `assistant`. وهذا يتيح للنموذج معرفة أن رد `assistant` هو التالي.

لا تتطلب جميع نماذج التوليد موجهات توليد، وبعض النماذج، مثل [Llama](./model_doc/llama)، لا تحتوي على أي رموز خاصة قبل استجابة `assistant`. في هذه الحالات، لا يكون لـ [add_generation_prompt](/docs/transformers/main/ar/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.add_generation_prompt) أي تأثير.

### continue_final_message

يتحكم معامل [continue_final_message](/docs/transformers/main/ar/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.continue_final_message) في ما إذا كان ينبغي مواصلة الرسالة الأخيرة في المحادثة بدلاً من بدء رسالة جديدة. يقوم بإزالة رموز نهاية التسلسل حتى يستمر النموذج في التوليد من الرسالة الأخيرة.

يُعدّ هذا مفيدًا لـ«تعبئة مسبقة» لاستجابة النموذج. في المثال أدناه، يولّد النموذج نصًا يستكمل سلسلة JSON بدلاً من بدء رسالة جديدة. وقد يكون ذلك مفيدًا للغاية لتحسين دقة اتباع التعليمات عندما تعرف كيفية بدء ردوده.

```py
chat = [
    {"role": "user", "content": "Can you format the answer in JSON?"},
    {"role": "assistant", "content": '{"name": "'},
]

formatted_chat = tokenizer.apply_chat_template(chat, tokenize=True, return_dict=True, continue_final_message=True)
model.generate(**formatted_chat)
```

> [!WARNING]
> لا ينبغي استخدام [add_generation_prompt](/docs/transformers/main/ar/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.add_generation_prompt) و [continue_final_message](/docs/transformers/main/ar/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.continue_final_message) معًا. يضيف الأول رموزًا تبدأ رسالة جديدة، بينما يزيل الثاني رموز نهاية التسلسل. يؤدي استخدامهما معًا إلى إرجاع خطأ.

مرّر اسم الحقل كنص (string) لملء ذلك الحقل مسبقاً بدلاً من `content`. تقرأ نماذج الاستدلال (Reasoning models) استدلالها من حقل منفصل يُسمى `reasoning_content`. يؤدي ملء `content` مسبقاً إلى إغلاق كتلة الاستدلال قبل بدء التوليد، مما يمنع النموذج من المتابعة داخلها. أما ملء `reasoning_content` مباشرةً فيُبقي الكتلة مفتوحة.

```py
chat = [
    {"role": "user", "content": "Explain 1+1"},
    {"role": "assistant", "reasoning_content": "The user wants a simple addition. ", "content": ""},
]

formatted_chat = tokenizer.apply_chat_template(chat, tokenize=False, continue_final_message="reasoning_content")
```

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

يُعيّن [TextGenerationPipeline](/docs/transformers/main/ar/main_classes/pipelines#transformers.TextGenerationPipeline) قيمة [add_generation_prompt](/docs/transformers/main/ar/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.add_generation_prompt) إلى `True` افتراضياً لبدء رسالة جديدة. ومع ذلك، إذا كانت الرسالة الأخيرة في المحادثة تحمل دور `assistant`، فإنّ النظام يفترض أنّ الرسالة هي بادئة (prefill) ويتحوّل إلى `continue_final_message=True`. والسبب في ذلك أنّ معظم النماذج لا تدعم رسائل متتالية متعددة من المساعد. لتجاوز هذا السلوك، مرّر معامل [continue_final_message](/docs/transformers/main/ar/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template.continue_final_message) صراحةً إلى خطّ الأنابيب.

## تدريب النموذج

يُعدّ تدريب نموذج باستخدام قالب محادثة طريقة جيدة للتأكد من تطابق القالب مع الرموز التي تم تدريب النموذج عليها. طبّق قالب المحادثة كخطوة معالجة مسبقة على مجموعة البيانات الخاصة بك. اضبط `add_generation_prompt=False` لأن الرموز الإضافية لتحفيز استجابة المساعد لا تكون مفيدة أثناء التدريب.

يُظهر ما يلي مثالًا على معالجة مجموعة بيانات مسبقة باستخدام قالب محادثة.

```py
from transformers import AutoTokenizer
from datasets import Dataset

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")

chat1 = [
    {"role": "user", "content": "Which is bigger, the moon or the sun?"},
    {"role": "assistant", "content": "The sun."}
]
chat2 = [
    {"role": "user", "content": "Which is bigger, a virus or a bacterium?"},
    {"role": "assistant", "content": "A bacterium."}
]

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])
```

```md
<|user|>
Which is bigger, the moon or the sun?</s>
<|assistant|>
The sun.</s>
```

بعد هذه الخطوة، يمكنك المتابعة في اتباع [وصفة التدريب](./tasks/language_modeling) لنماذج اللغة السببية باستخدام العمود `formatted_chat`.

