واجهة برمجة تطبيقات Gemini: استدعاء الدوالّ باستخدام بايثون

العرض على ai.google.dev التشغيل في Google Colab الاطّلاع على المصدر على GitHub

يمكنك تقديم نماذج Gemini مع أوصاف للدوال. قد يطلب منك النموذج استدعاء دالة وإعادة إرسال النتيجة لمساعدة النموذج في التعامل مع استعلامك.

ضبط إعدادات الجهاز

تثبيت حزمة تطوير البرامج (SDK) للغة Python

تتوفّر حزمة Python SDK لـ Gemini API في الحزمة google-generativeai. تثبيت التبعية باستخدام pip:

pip install -U -q google-generativeai

استيراد الحزم

قم باستيراد الحزم اللازمة.

import pathlib
import textwrap
import time

import google.generativeai as genai


from IPython import display
from IPython.display import Markdown

def to_markdown(text):
  text = text.replace('•', '  *')
  return Markdown(textwrap.indent(text, '> ', predicate=lambda _: True))

إعداد مفتاح واجهة برمجة التطبيقات

قبل أن تتمكّن من استخدام واجهة برمجة تطبيقات Gemini، يجب أولاً الحصول على مفتاح واجهة برمجة التطبيقات. أنشِئ مفتاحًا بنقرة واحدة في "استوديو Google AI" إذا لم يكن لديك مفتاح.

الحصول على مفتاح واجهة برمجة التطبيقات

في Colab، أضِف المفتاح إلى أداة إدارة الأسرار ضمن "🔑" في اللوحة اليمنى. أدخِل الاسم "API_KEY".

بعد حصولك على مفتاح واجهة برمجة التطبيقات، أرسِله إلى حزمة تطوير البرامج (SDK). هناك طريقتان لإجراء ذلك:

  • ضَع المفتاح في متغيّر بيئة GOOGLE_API_KEY (ستحصل عليه حزمة تطوير البرامج (SDK) تلقائيًا من هناك).
  • تمرير المفتاح إلى "genai.configure(api_key=...)"
try:
    # Used to securely store your API key
    from google.colab import userdata

    # Or use `os.getenv('API_KEY')` to fetch an environment variable.
    GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')
except ImportError:
    import os
    GOOGLE_API_KEY = os.environ['GOOGLE_API_KEY']

genai.configure(api_key=GOOGLE_API_KEY)

أساسيات الوظائف

يمكنك تمرير قائمة الدوال إلى الوسيطة tools عند إنشاء genai.GenerativeModel.

def multiply(a:float, b:float):
    """returns a * b."""
    return a*b

model = genai.GenerativeModel(model_name='gemini-1.0-pro',
                              tools=[multiply])

model
genai.GenerativeModel(
    model_name='models/gemini-1.0-pro',
    generation_config={},
    safety_settings={},
    tools=<google.generativeai.types.content_types.FunctionLibrary object at 0x10e73fe90>,
)

الطريقة المقترحة لاستخدام استدعاء الوظيفة هي من خلال واجهة الدردشة. السبب الرئيسي هو أنّ "FunctionCalls" يتناسب بشكل جيد مع بنية المحادثة المتعدّدة الأدوار.

chat = model.start_chat(enable_automatic_function_calling=True)

عندما تكون ميزة استدعاء الوظيفة التلقائية مفعَّلة، يستدعي chat.send_message وظيفتك تلقائيًا إذا طلبها النموذج.

يبدو أنه يقدم ردًّا نصيًا يحتوي على الإجابة الصحيحة:

response = chat.send_message('I have 57 cats, each owns 44 mittens, how many mittens is that in total?')
response.text
'The total number of mittens is 2508.'
57*44
2508

إذا اطّلعت على ChatSession.history، يمكنك رؤية تسلسل الأحداث:

  1. لقد أرسلت السؤال.
  2. ردّ النموذج باستخدام glm.FunctionCall.
  3. نفذ genai.ChatSession الدالة محليًا وأرجع النموذج glm.FunctionResponse مرة أخرى.
  4. استخدم النموذج ناتج الدالة في إجابته.
for content in chat.history:
    part = content.parts[0]
    print(content.role, "->", type(part).to_dict(part))
    print('-'*80)
user -> {'text': 'I have 57 cats, each owns 44 mittens, how many mittens is that in total?'}
--------------------------------------------------------------------------------
model -> {'function_call': {'name': 'multiply', 'args': {'a': 57.0, 'b': 44.0} } }
--------------------------------------------------------------------------------
user -> {'function_response': {'name': 'multiply', 'response': {'result': 2508.0} } }
--------------------------------------------------------------------------------
model -> {'text': 'The total number of mittens is 2508.'}
--------------------------------------------------------------------------------

بشكل عام مخطط الحالة هو:

يمكن للنموذج دائمًا الرد بنص أو بـ FunctionCall. إذا أرسل النموذج FunctionCall، يجب على المستخدم الرد باستخدام FunctionResponse

يمكن أن يستجيب النموذج باستدعاءات دوال متعددة قبل عرض استجابة نصية، وتأتي استدعاءات الدوال قبل الاستجابة النصية.

على الرغم من أنه تم التعامل مع كل ذلك تلقائيًا، إذا كنت بحاجة إلى مزيد من التحكّم، يمكنك إجراء ما يلي:

  • يمكنك ترك القيمة التلقائية enable_automatic_function_calling=False ومعالجة ردود glm.FunctionCall بنفسك.
  • أو يمكنك استخدام GenerativeModel.generate_content، حيث تحتاج أيضًا إلى إدارة سجلّ المحادثات.

[اختياري] الوصول المنخفض المستوى

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

AllowedType = (int | float | bool | str | list['AllowedType'] | dict[str, AllowedType]

توفر مكتبة برامج google.ai.generativelanguage إمكانية الوصول إلى الأنواع المنخفضة المستوى، ما يمنحك تحكمًا كاملاً.

import google.ai.generativelanguage as glm

أول نظرة خاطفة داخل سمة _tools للنموذج، يمكنك معرفة كيفية وصفها للدوال التي نقلتها إلى النموذج:

def multiply(a:float, b:float):
    """returns a * b."""
    return a*b

model = genai.GenerativeModel(model_name='gemini-1.0-pro',
                             tools=[multiply])

model._tools.to_proto()
[function_declarations {
   name: "multiply"
   description: "returns a * b."
   parameters {
     type_: OBJECT
     properties {
       key: "b"
       value {
         type_: NUMBER
       }
     }
     properties {
       key: "a"
       value {
         type_: NUMBER
       }
     }
     required: "a"
     required: "b"
   }
 }]

يؤدي ذلك إلى عرض قائمة بكائنات glm.Tool التي سيتم إرسالها إلى واجهة برمجة التطبيقات. إذا كان التنسيق المطبوع غير مألوف، فذلك لأن هذه فئات النماذج الأوّلية من Google. يحتوي كل glm.Tool (1 في هذه الحالة) على قائمة من glm.FunctionDeclarations تصف دالة ووسيطاتها.

وإليك تعريف لدالة الضرب نفسها المكتوبة باستخدام فئات glm.

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

calculator = glm.Tool(
    function_declarations=[
      glm.FunctionDeclaration(
        name='multiply',
        description="Returns the product of two numbers.",
        parameters=glm.Schema(
            type=glm.Type.OBJECT,
            properties={
                'a':glm.Schema(type=glm.Type.NUMBER),
                'b':glm.Schema(type=glm.Type.NUMBER)
            },
            required=['a','b']
        )
      )
    ])

بشكل متساوٍ، يمكنك وصف ذلك ككائن متوافق مع JSON:

calculator = {'function_declarations': [
      {'name': 'multiply',
       'description': 'Returns the product of two numbers.',
       'parameters': {'type_': 'OBJECT',
       'properties': {
         'a': {'type_': 'NUMBER'},
         'b': {'type_': 'NUMBER'} },
       'required': ['a', 'b']} }]}
glm.Tool(calculator)
function_declarations {
  name: "multiply"
  description: "Returns the product of two numbers."
  parameters {
    type_: OBJECT
    properties {
      key: "b"
      value {
        type_: NUMBER
      }
    }
    properties {
      key: "a"
      value {
        type_: NUMBER
      }
    }
    required: "a"
    required: "b"
  }
}

في كلتا الحالتين، يتم تمرير تمثيل glm.Tool أو قائمة من الأدوات إلى

model = genai.GenerativeModel('gemini-pro', tools=calculator)
chat = model.start_chat()

response = chat.send_message(
    f"What's 234551 X 325552 ?",
)

وكما هو الحال قبل أن يعرض النموذج glm.FunctionCall الذي يستدعي دالة multiply في الآلة الحاسبة:

response.candidates
[index: 0
content {
  parts {
    function_call {
      name: "multiply"
      args {
        fields {
          key: "b"
          value {
            number_value: 325552
          }
        }
        fields {
          key: "a"
          value {
            number_value: 234551
          }
        }
      }
    }
  }
  role: "model"
}
finish_reason: STOP
]

نفِّذ الدالة بنفسك:

fc = response.candidates[0].content.parts[0].function_call
assert fc.name == 'multiply'

result = fc.args['a'] * fc.args['b']
result
76358547152.0

أرسِل النتيجة إلى النموذج لمتابعة المحادثة:

response = chat.send_message(
    glm.Content(
    parts=[glm.Part(
        function_response = glm.FunctionResponse(
          name='multiply',
          response={'result': result}))]))

ملخّص

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