# استخدام الأدوات

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

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

## تمرير الأدوات

عندما يدعم النموذج استخدام الأدوات، مرّر الدوال إلى معامل `tools` في [apply_chat_template()](/docs/transformers/main/ar/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template). تُمرَّر الأدوات إما على شكل [مخطط JSON](https://json-schema.org/learn) أو دوال Python. إذا مرّرت دوال Python، يتم تحليل المعاملات وأنواع المعاملات ووصف الدالة (docstring) لتوليد مخطط JSON تلقائيًا.

على الرغم من أن تمرير دوال بايثون مريح للغاية، إلا أن محلل النصوص يتعامل فقط مع سطور التوثيق بأسلوب [Google](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings). راجع الأمثلة أدناه لمعرفة كيفية تنسيق دالة جاهزة للاستخدام كأداة.

```py
def get_current_temperature(location: str, unit: str):
    """
    Get the current temperature at a location.

    Args:
        location: The location to get the temperature for, in the format "City, Country"
        unit: The unit to return the temperature in. (choices: ["celsius", "fahrenheit"])
    """
    return 22.  # A real function should probably actually get the temperature!

def get_current_wind_speed(location: str):
    """
    Get the current wind speed in km/h at a given location.

    Args:
        location: The location to get the wind speed for, in the format "City, Country"
    """
    return 6.  # A real function should probably actually get the wind speed!

tools = [get_current_temperature, get_current_wind_speed]
```

يمكنك اختيارياً إضافة كتلة `Returns:` إلى سلسلة التوثيق (docstring) وإضافة نوع الإرجاع إلى ترويسة الدالة، لكن معظم النماذج لن تستخدم هذه المعلومات. كما سيتجاهل المحلل (parser) الكود الفعلي داخل الدالة!

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

## مثال على استدعاء الأدوات

حمّل نموذجًا ومُرمِّزًا يدعم استخدام الأدوات مثل [NousResearch/Hermes-2-Pro-Llama-3-8B](https://hf.co/NousResearch/Hermes-2-Pro-Llama-3-8B)، لكن يمكنك أيضًا النظر في نموذج أكبر مثل [Command-R](./model_doc/cohere) و [Mixtral-8x22B](./model_doc/mixtral) إذا كان جهازك يدعم ذلك.

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

checkpoint = "NousResearch/Hermes-2-Pro-Llama-3-8B"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForCausalLM.from_pretrained(checkpoint, dtype="auto", device_map="auto")
```

أنشئ سجل محادثة.

```py
messages = [
  {"role": "system", "content": "You are a bot that responds to weather queries. You should reply with the unit used in the queried location."},
  {"role": "user", "content": "Hey, what's the temperature in Paris right now?"}
]
```

في الخطوة التالية، مرّر `messages` وقائمة بالأدوات إلى [apply_chat_template()](/docs/transformers/main/ar/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template). ثم قم بتجزئة المحادثة وتوليد استجابة.

```py
inputs = tokenizer.apply_chat_template(messages, tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt")
outputs = model.generate(**inputs.to(model.device), max_new_tokens=128)
print(tokenizer.decode(outputs[0][len(inputs["input_ids"][0]):]))
```

```txt
<tool_call>
{"arguments": {"location": "Paris, France", "unit": "celsius"}, "name": "get_current_temperature"}
</tool_call><|im_end|>
```

استدعى نموذج الدردشة أداة `get_current_temperature` باستخدام المعاملات الصحيحة من docstring. استنتج أن الموقع هو فرنسا بناءً على باريس، وأن عليه استخدام الدرجة المئوية (Celsius) لوحدات قياس درجة الحرارة.

لا يمكن للنموذج **استدعاء الأداة بنفسه فعليًا**. بل يطلب استدعاء الأداة، ومن مسؤوليتك معالجة هذا الاستدعاء وإضافته مع النتيجة إلى سجل المحادثة. بالنسبة للنماذج التي تدعم [تحليل الاستجابة](./chat_response_parsing)، يتم التعامل مع تحليل الاستجابة تلقائيًا، ويمكنك ببساطة استخدام [parse_response()](/docs/transformers/main/ar/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.parse_response) لاستخراج استدعاء الأداة. أما بالنسبة للنماذج الأخرى، فستحتاج إلى ترجمة سلسلة الإخراج يدويًا إلى قاموس استدعاء أداة.

بغضّ النظر عن النهج الذي تستخدمه، يجب أن يكون استدعاء الأداة ضمن المفتاح `tool_calls` في رسالة `assistant`. هذه هي واجهة برمجة التطبيقات الموصى بها، وينبغي أن يدعمها قالب المحادثة لأغلب النماذج التي تستخدم الأدوات.

> [!WARNING]
> على الرغم من أن `tool_calls` يشبه واجهة OpenAI API، فإن واجهة OpenAI API تستخدم سلسلة JSON كصيغة لـ `tool_calls`. قد يؤدي ذلك إلى أخطاء أو سلوك غير متوقع للنموذج عند استخدامه في Transformers، حيث يتوقع قاموسًا (dict).

```py
tool_call = {"name": "get_current_temperature", "arguments": {"location": "Paris, France", "unit": "celsius"}}
messages.append({"role": "assistant", "tool_calls": [{"type": "function", "function": tool_call}]})
```

أضف استجابة الأداة إلى سجل المحادثة بدور `tool`.

```py
messages.append({"role": "tool", "content": "22"})  # Note that the returned content is always a string!
```

أخيرًا، اسمح للنموذج بقراءة استجابة الأداة والرد على المستخدم.

```py
inputs = tokenizer.apply_chat_template(messages, tools=tools, add_generation_prompt=True, return_dict=True, return_tensors="pt")
out = model.generate(**inputs.to(model.device), max_new_tokens=128)
print(tokenizer.decode(out[0][len(inputs["input_ids"][0]):]))
```

```txt
The temperature in Paris, France right now is 22°C.<|im_end|>
```

> [!WARNING]
> على الرغم من أن المفتاح في رسالة المساعد يُسمى `tool_calls`، إلا أن النماذج في معظم الحالات تُصدر استدعاءً واحدًا للأداة في كل مرة. بعض النماذج الأقدم تُصدر عدة استدعاءات للأدوات في الوقت نفسه، لكن هذه عملية أكثر تعقيدًا بكثير، إذ يتعين عليك معالجة عدة استجابات للأدوات دفعة واحدة وتمييز بينها، وغالبًا باستخدام معرّفات استدعاءات الأدوات. يُرجى الرجوع إلى بطاقة النموذج لمعرفة الصيغة التي يتوقعها النموذج بالضبط لاستدعاءات الأدوات.

## مخططات JSON

طريقة أخرى لتعريف الأدوات هي تمرير [مخطط JSON](https://json-schema.org/learn/getting-started-step-by-step).

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

تستخدم طريقة [apply_chat_template()](/docs/transformers/main/ar/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template) الدالة [get_json_schema](https://github.com/huggingface/transformers/blob/14561209291255e51c55260306c7d00c159381a5/src/transformers/utils/chat_template_utils.py#L205) لتحويل الدوال القابلة للاستدعاء في بايثون إلى مخطط JSON. وتشمل ذلك: تُعامل `self` و`cls` كحجج مستقبلة ضمنية وتُتجاهل.

```py
from transformers.utils import get_json_schema

def multiply(a: float, b: float):
    """
    A function that multiplies two numbers

    Args:
        a: The first number to multiply
        b: The second number to multiply
    """
    return a * b

schema = get_json_schema(multiply)
print(schema)
```

```json
{
  "type": "function",
  "function": {
    "name": "multiply",
    "description": "A function that multiplies two numbers",
    "parameters": {
      "type": "object",
      "properties": {
        "a": {
          "type": "number",
          "description": "The first number to multiply"
        },
        "b": {
          "type": "number",
          "description": "The second number to multiply"
        }
      },
      "required": ["a", "b"]
    }
  }
}
```

لن نتناول تفاصيل مخطط JSON بحد ذاته هنا، إذ إنه [موثّق بشكل جيد جدًا](https://json-schema.org/) في أماكن أخرى. ومع ذلك، نودّ الإشارة إلى أنه يمكنك تمرير قواميس مخطط JSON إلى معامل `tools` الخاص بـ [apply_chat_template()](/docs/transformers/main/ar/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template) بدلاً من دوال Python:

```py
# A simple function that takes no arguments
current_time = {
  "type": "function",
  "function": {
    "name": "current_time",
    "description": "Get the current local time as a string.",
    "parameters": {
      'type': 'object',
      'properties': {}
    }
  }
}

# A more complete function that takes two numerical arguments
multiply = {
  'type': 'function',
  'function': {
    'name': 'multiply',
    'description': 'A function that multiplies two numbers',
    'parameters': {
      'type': 'object',
      'properties': {
        'a': {
          'type': 'number',
          'description': 'The first number to multiply'
        },
        'b': {
          'type': 'number', 'description': 'The second number to multiply'
        }
      },
      'required': ['a', 'b']
    }
  }
}

model_input = tokenizer.apply_chat_template(
    messages,
    tools = [current_time, multiply]
)
```

