تطوير تطبيقات النماذج اللغوية الكبيرة باستخدام حزمة تطوير البرامج (SDK) في Vertex AI

1. مقدمة

نظرة عامة

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

الإجراءات التي ستنفذّها

في هذا الدرس التطبيقي، ستنشئ برنامج دردشة آليًا لمساعدة المسافرين باستخدام نموذج Gemini 2.5 Flash على Vertex AI.

يجب أن يلتزم التطبيق بما يلي:

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

ستعمل في بيئة Google Cloud تم إعدادها مسبقًا، وتحديدًا في "محرّر Cloud Shell". تمّ إعداد واجهة أمامية أساسية لتطبيق الويب لك مسبقًا، بالإضافة إلى الأذونات اللازمة للوصول إلى Vertex AI. تم إنشاء هذا التطبيق باستخدام Streamlit.

أهداف الدورة التعليمية

في هذه الميزة الاختبارية، ستتعرّف على كيفية تنفيذ المهام التالية:

2. إعداد المشروع

حساب Google

إذا لم يكن لديك حساب شخصي على Google، عليك إنشاء حساب على Google.

استخدام حساب شخصي بدلاً من حساب تابع للعمل أو تديره مؤسسة تعليمية

تسجيل الدخول إلى Google Cloud Console

سجِّل الدخول إلى Google Cloud Console باستخدام حساب Google شخصي.

تفعيل الفوترة

تحصيل قيمة رصيد Google Cloud بقيمة 5 دولار أمريكي (اختياري)

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

  1. انقر على هذا الرابط وسجِّل الدخول باستخدام حساب Google شخصي.سيظهر لك ما يلي:انقر لتفويض Cloud Shell
  2. انقر على الزر انقر هنا للوصول إلى رصيدك.سينقلك هذا الزر إلى صفحة لإعداد ملف الفوترةانقر لتفويض Cloud Shell
  3. انقر على تأكيد.

أنت مرتبط الآن بحساب فوترة تجريبي على Google Cloud Platform.

لقطة شاشة لنظرة عامة على الفوترة

إعداد حساب فوترة شخصي

إذا أعددت الفوترة باستخدام أرصدة Google Cloud، يمكنك تخطّي هذه الخطوة.

لإعداد حساب فوترة شخصي، يُرجى الانتقال إلى هنا لتفعيل الفوترة في Cloud Console.

ملاحظات:

  • يجب أن تكلّف إكمال هذا المختبر أقل من دولار أمريكي واحد من موارد السحابة الإلكترونية.
  • يمكنك اتّباع الخطوات في نهاية هذا المختبر لحذف الموارد وتجنُّب المزيد من الرسوم.
  • يمكن للمستخدمين الجدد الاستفادة من الفترة التجريبية المجانية بقيمة 300 دولار أمريكي.

إنشاء مشروع (اختياري)

إذا لم يكن لديك مشروع حالي تريد استخدامه لهذا التصنيف، يمكنك إنشاء مشروع جديد هنا.

3- فتح Cloud Shell Editor

  1. انقر على هذا الرابط للانتقال مباشرةً إلى محرّر Cloud Shell
  2. إذا طُلب منك منح الإذن في أي وقت اليوم، انقر على منح الإذن للمتابعة.انقر لتفويض Cloud Shell
  3. إذا لم تظهر المحطة الطرفية في أسفل الشاشة، افتحها باتّباع الخطوات التالية:
    • انقر على عرض.
    • انقر على Terminalفتح نافذة طرفية جديدة في "محرِّر Cloud Shell"
  4. في الوحدة الطرفية، اضبط مشروعك باستخدام الأمر التالي:
    gcloud config set project [PROJECT_ID]
    
    • مثال:
      gcloud config set project lab-project-id-example
      
    • إذا تعذّر عليك تذكُّر معرّف مشروعك، يمكنك إدراج جميع معرّفات المشاريع باستخدام:
      gcloud projects list | awk '/PROJECT_ID/{print $2}'
      
      ضبط رقم تعريف المشروع في نافذة Cloud Shell Editor
  5. من المفترض أن تظهر لك هذه الرسالة:
    Updated property [core/project].
    
    >aside negative إذا ظهرت لك رسالة `WARNING` وطُلب منك الإجابة عن السؤال `Do you want to continue (Y/n)?`، فمن المحتمل أنّك أدخلت معرّف المشروع بشكل غير صحيح. اضغط على `n`، ثم اضغط على `Enter`، وحاوِل تشغيل الأمر `gcloud config set project` مرة أخرى. >

4. تفعيل واجهات برمجة التطبيقات

لاستخدام Vertex AI SDK والتفاعل مع نموذج Gemini، عليك تفعيل Vertex AI API في مشروعك على Google Cloud.

  1. في الوحدة الطرفية، فعِّل واجهات برمجة التطبيقات:
    gcloud services enable \
      aiplatform.googleapis.com
    

مقدمة عن حزمة تطوير البرامج (SDK) لخدمة Vertex AI في Python

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

يمكنك العثور على مستندات شاملة حول حزمة تطوير البرامج (SDK) الخاصة بـ Vertex AI في Python هنا: مقدمة عن حزمة تطوير البرامج (SDK) الخاصة بـ Vertex AI في Python | Google Cloud.

5- إنشاء بيئة افتراضية وتثبيت التبعيات

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

  1. أنشئ مجلدًا باسم wanderbot لتخزين الرمز الخاص بتطبيق مساعد السفر. شغِّل الرمز التالي في الوحدة الطرفية:
    mkdir wanderbot && cd wanderbot
    
  2. أنشئ بيئة افتراضية وفعِّلها:
    uv venv --python 3.12
    source .venv/bin/activate
    
    سيظهر لك البادئة (wanderbot) قبل طلب المحطة الطرفية، ما يشير إلى أنّ البيئة الافتراضية نشطة. سيبدو على النحو التالي:

    لقطة شاشة للنافذة الطرفية مع بيئة افتراضية نشطة

6. إنشاء ملفات أولية لتطبيق wanderbot

  1. أنشئ ملف app.py جديدًا وافتحه للتطبيق. نفِّذ الرمز التالي في الوحدة الطرفية:
    cloudshell edit app.py
    
    سيفتح الأمر cloudshell edit الملف app.py في المحرِّر أعلى الوحدة الطرفية.
  2. ألصِق رمز تشغيل التطبيق التالي في app.py:
    import streamlit as st
    from google import genai
    from google.genai import types
    import requests
    import logging
    
    # --- Defining variables and parameters  ---
    REGION = "global"
    PROJECT_ID = None # TO DO: Insert Project ID
    GEMINI_MODEL_NAME = "gemini-2.5-flash"
    
    temperature = .2
    top_p = 0.95
    
    system_instructions = None
    
    # --- Tooling ---
    # TODO: Define the weather tool function declaration
    
    # TODO: Define the get_current_temperature function
    
    
    # --- Initialize the Vertex AI Client ---
    try:
        # TODO: Initialize the Vertex AI client
    
        print(f"VertexAI Client initialized successfully with model {GEMINI_MODEL_NAME}")
    except Exception as e:
        st.error(f"Error initializing VertexAI client: {e}")
        st.stop()
    
    
    # TODO: Add the get_chat function here in Task 15.
    
    
    # --- Call the Model ---
    def call_model(prompt: str, model_name: str) -> str:
        """
        This function interacts with a large language model (LLM) to generate text based on a given prompt and system instructions. 
        It will be replaced in a later step with a more advanced version that handles tooling.
        """
        try:
    
            # TODO: Prepare the content for the model
    
            # TODO: Define generate_content configuration (needed for system instructions and parameters)
    
            # TODO: Define response
    
            logging.info(f"[call_model_response] LLM Response: \"{response.text}\"")
            # TODO: Uncomment the below "return response.text" line
            # return response.text
    
        except Exception as e:
            return f"Error: {e}"
    
    
    # --- Presentation Tier (Streamlit) ---
    # Set the title of the Streamlit application
    st.title("Travel Chat Bot")
    
    # Initialize session state variables if they don't exist
    if "messages" not in st.session_state:
        # Initialize the chat history with a welcome message
        st.session_state["messages"] = [
            {"role": "assistant", "content": "How can I help you today?"}
        ]
    
    # Display the chat history
    for msg in st.session_state.messages:
        st.chat_message(msg["role"]).write(msg["content"])
    
    # Get user input
    if prompt := st.chat_input():
        # Add the user's message to the chat history
        st.session_state.messages.append({"role": "user", "content": prompt})
        # Display the user's message
        st.chat_message("user").write(prompt)
    
        # Show a spinner while waiting for the model's response
        with st.spinner("Thinking..."):
            # Get the model's response using the call_model function
            model_response = call_model(prompt, GEMINI_MODEL_NAME)
            # Add the model's response to the chat history
            st.session_state.messages.append(
                {"role": "assistant", "content": model_response}
            )
            # Display the model's response
            st.chat_message("assistant").write(model_response)
    
  3. أنشئ ملف requirements.txt جديدًا وافتحه لرمز التطبيق. نفِّذ الرمز التالي في الوحدة الطرفية:
    cloudshell edit requirements.txt
    
    سيفتح الأمر cloudshell edit الملف requirements.txt في المحرِّر أعلى الوحدة الطرفية.
  4. ألصِق رمز تشغيل التطبيق التالي في requirements.txt.
    google-genai
    streamlit
    requests
    
  5. ثبِّت تبعيات Python المطلوبة لهذا المشروع. نفِّذ الرمز التالي في الوحدة الطرفية:
    uv pip install -r requirements.txt
    

7. استكشاف الرمز

تتضمّن الملفات التي أنشأتها واجهة أمامية أساسية لتطبيق محادثة. وتشمل:

  • app.py: هذا هو الملف الذي سنعمل فيه. يتضمّن حاليًا ما يلي:
    • عمليات الاستيراد الضرورية
    • متغيّرات البيئة والمَعلمات (بعضها عناصر نائبة)
    • دالة call_model فارغة سنملأها
    • رمز Streamlit لتطبيق المحادثات على الواجهة الأمامية
  • requirements.txt:
    • تتضمّن متطلبات التثبيت لتشغيل app.py

حان الوقت الآن لاستكشاف التعليمات البرمجية.

فتح محادثة Gemini Code Assist

يجب أن يكون Gemini Code Assist Chat مفتوحًا في لوحة على يسار الشاشة في "محرِّر Cloud Shell". إذا لم تكن نافذة Gemini Code Assist Chat مفتوحة، يمكنك فتحها باتّباع الخطوات التالية:

  1. النقر على زر Gemini Code Assist (انقر هنا لتفعيل Gemini Code Assist) بالقرب من أعلى الشاشة
  2. انقر على فتح محادثة Gemini Code Assist.قائمة Gemini Code Assist

استخدام Gemini Code Assist لفهم الرمز البرمجي

يمكنك استخدام Gemini Code Assist Chat لفهم الرمز البرمجي بشكل أفضل.

  1. ميِّز قسم الرمز المطلوب أو اختَره.
  2. اكتب "اشرح هذا الرمز البرمجي" في محادثة Gemini.
  3. اضغط على مفتاح Enter لإرسال الطلب

فيديو يعرض تمييز جزء من الرمز، وإدخال "شرح هذا الرمز" في "أداة مساعدة Gemini للبرمجة"، والحصول على إجابة

8. تشغيل تطبيق الويب

قبل ربط هذا التطبيق بنموذج لغوي كبير، شغِّله لمعرفة سلوكه في البداية.

  1. ضِمن دليل wanderbot، شغِّل الأمر التالي في الوحدة الطرفية لبدء تطبيق Streamlit وإتاحة الوصول إليه محليًا ضمن بيئة Cloud Shell:
    streamlit run app.py --browser.serverAddress=localhost --server.enableCORS=false --server.enableXsrfProtection=false --server.port 8080
    
    يُرجى إبقاء نافذة Terminal هذه مفتوحة، لأنّ تطبيق Streamlit سيستمر في العمل. يمكنك فتح نافذة طرفية جديدة في Cloud Shell لتنفيذ أوامر أخرى.
  2. بعد تنفيذ الأمر، انقر على الزر معاينة الويب في أعلى محرّر Cloud Shell واختَر معاينة على المنفذ 8080.
    قائمة المعاينة مفتوحة، مع

    ستظهر لك واجهة محادثة بسيطة لتطبيق السفر.
  3. اكتب أي رسالة (مثل Hi!) واضغط على ENTER.

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

9- إعداد برنامج Vertex AI

استكشاف النماذج المتاحة في Vertex AI

تتيح منصة Vertex AI من Google Cloud الوصول إلى مجموعة متنوّعة من نماذج الذكاء الاصطناعي التوليدي. قبل دمج إحدى هذه الخدمات، يمكنك استكشاف الخيارات المتاحة في Google Cloud Console.

  1. من Google Cloud Console، انتقِل إلى Model Garden. يمكنك إجراء ذلك من خلال البحث عن "Model Garden" في شريط البحث أعلى الشاشة واختيار Vertex AI.(البرامج )
  2. تصفَّح النماذج المتاحة. يمكنك الفلترة حسب عناصر مثل طرق العرض وأنواع المهام والميزات.

لأغراض هذا المختبر، ستستخدم نموذج Gemini 2.5 Flash، وهو خيار جيد لإنشاء تطبيقات دردشة سريعة الاستجابة بسبب سرعته.

إعداد برنامج Vertex AI

ستعدّل الآن القسم --- Initialize the Vertex AI Client --- في app.py لإعداد برنامج Vertex AI. سيتم استخدام عنصر العميل هذا لإرسال الطلبات إلى النموذج.

  1. افتح app.py في "محرِّر Cloud Shell".
  2. في app.py، ابحث عن السطر PROJECT_ID = None.
  3. استبدِل None برقم تعريف مشروعك على Google Cloud بين علامتَي اقتباس. (مثلاً PROJECT_ID = "google-cloud-labs")
    إذا لم تتمكّن من تذكُّر معرّف مشروعك، يمكنك إدراج جميع معرّفات المشاريع باستخدام:
    gcloud projects list | awk '/PROJECT_ID/{print $2}'
    
  4. تحديد العميل: داخل الحزمة try، ابدأ عملية إعداد عميل Vertex AI.
        client = genai.Client(
            vertexai=True,
            project=PROJECT_ID,
            location=REGION,
        )
    

تعديل عملية تهيئة عميل Vertex AI

في هذه المرحلة، سيظهر قسم "إعداد برنامج Vertex AI" على النحو التالي:

# --- Initialize the Vertex AI Client ---
try:
    client = genai.Client(
        vertexai=True,
        project=PROJECT_ID,
        location=REGION,
    )
    print(f"VertexAI Client initialized successfully with model {GEMINI_MODEL_NAME}")
except Exception as e:
    st.error(f"Error initializing VertexAI client: {e}")
    st.stop()

10. إعداد البيانات واستدعاء النموذج

عليك الآن إعداد المحتوى لإرساله إلى النموذج، وإجراء عملية إلى نموذج Gemini.

  1. ابحث عن القسم --- Call the Model --- حيث يتم تعريف الدالة call_model.
  2. تحديد المحتوى: ضمن # TODO: Prepare the content for the model ، حدِّد المحتوى الذي سيتم إرساله إلى النموذج. بالنسبة إلى الطلب الأساسي، ستكون هذه هي رسالة الإدخال الخاصة بالمستخدم.
            contents = [prompt]
    
  3. تحديد الردّ: الصِق هذا الرمز تحت # TODO: Define response.
            response = client.models.generate_content(
                model=model_name,
                contents=contents,
            )
    
  4. إرجاع الردّ: أزِل التعليق من السطر التالي:
            return response.text
    
  5. افحص السطر الذي يتم فيه استدعاء الدالة call_model، بالقرب من أسفل الملف في الحظر with. إذا لم تفهم ما يحدث هنا، حدِّد السطر واطلب من Gemini Code Assist شرحه.

طريقة أكثر وضوحًا لتحديد contents

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

ومع ذلك، فإنّ الطريقة الأكثر وضوحًا وأساسية لتنظيم الإدخال تتضمّن استخدام الكائنَين types.Part وtypes.Content، كما يلي:

user_message_parts = [types.Part.from_text(text=prompt)]
contents = [
    types.Content(
        role="user", # Indicates the content is from the user
        parts=user_message_parts, # A list, allowing multiple types of content
    ),
]

تم تعديل الدالة call_model

في هذه المرحلة، من المفترض أن تبدو الدالة call_model على النحو التالي:

def call_model(prompt: str, model_name: str) -> str:
    """
    This function interacts with a large language model (LLM) to generate text based on a given prompt and system instructions. 
    It will be replaced in a later step with a more advanced version that handles tooling.
    """
    try:

        contents = [prompt]

        # TODO: Define generate_content configuration (needed later for system instructions and parameters)

        response = client.models.generate_content(
            model=model_name,
            contents=contents,
        )
        logging.info(f"[call_model_response] LLM Response: \"{response.text}\"")

        return response.text
    except Exception as e:
        return f"Error: {e}"

11. اختبار التطبيق المرتبط

  1. في الوحدة الطرفية، أوقِف العملية الجارية حاليًا (CTRL+C).
  2. أعِد تشغيل الأمر لبدء تطبيق Streamlit مرة أخرى.
    streamlit run app.py --browser.serverAddress=localhost --server.enableCORS=false --server.enableXsrfProtection=false --server.port 8080
    
  3. أعِد تحميل تطبيق Streamlit. إذا كان تطبيق Streamlit لا يزال قيد التشغيل، يمكنك ببساطة إعادة تحميل صفحة معاينة الويب في المتصفّح.
  4. الآن، اكتب سؤالاً في مربّع إدخال الدردشة، مثل ما يلي:
    What is the best time of year to go to Iceland?
    
  5. اضغط على مفتاح ENTER.

    من المفترض أن يعرض التطبيق رسالتك، ورمزًا متحركًا "جارٍ التفكير..."، ثم ردًا من إنشاء نموذج Gemini. إذا كان الأمر كذلك، تكون قد ربطت تطبيق الويب بنجاح بنموذج لغوي كبير على Vertex AI. 🙌 🥳

12. تحديد تعليمات النظام

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

لتحقيق ذلك، ستبدأ بإنشاء بعض تعليمات النظام وتمريرها إلى النموذج.

ستستخدم ميزة اسأل Gemini لمساعدتك في وضع تعليمات مفيدة للنظام.

  1. في app.py، ابحث عن المتغيّر system_instructions، الذي تم ضبطه حاليًا على None.
    system_instructions = None
    
    ستستبدل None بسلسلة متعددة الأسطر تقدّم تعليمات لروبوت مساعد السفر.
  2. طرح سؤال على Gemini Code Assist: أدخِل الطلب التالي إلى Gemini Code Assist (أو يمكنك إنشاء طلب خاص بك):
    I am a developer at a travel marketing company, and my sales department has decided that they need a new chat application to keep up with the bigger booking and search companies. I'm building a simple travel assistant chatbot using the Gemini 2.5 Flash model on Vertex AI.
    
    The application should:
    - Helps users ask questions about travel, book travel, and learn about places they are going to go
    - Provides users ways to get help about their specific travel plans
    - Provides all this in a production quality way (multiple environments, logging and monitoring, etc.)
    
    Please create system instructions appropriate for that chat app. Be thorough.
    
    Do not alter the code in any way beyond providing me with system instructions.
    
  3. تحديد system_instructions: اضبط قيمة system_instructions لتساوي تعليمات النظام التي أنشأتها باستخدام Gemini Code Assist. يمكنك بدلاً من ذلك استخدام تعليمات النظام هذه التي أنشأها Gemini باستخدام طلب مشابه.
    system_instructions = """
    You are a sophisticated travel assistant chatbot designed to provide comprehensive support to users throughout their travel journey. Your capabilities include answering travel-related questions, assisting with booking travel arrangements, offering detailed information about destinations, and providing support for existing travel plans.
    
    **Core Functionalities:**
    
    1.  **Travel Information and Recommendations:**
        *   Answer user inquiries about travel destinations, including popular attractions, local customs, visa requirements, weather conditions, and safety advice.
        *   Provide personalized recommendations for destinations, activities, and accommodations based on user preferences, interests, and budget.
        *   Offer insights into the best times to visit specific locations, considering factors like weather, crowds, and pricing.
        *   Suggest alternative destinations or activities if the user's initial choices are unavailable or unsuitable.
    
    2.  **Booking Assistance:**
        *   Facilitate the booking of flights, hotels, rental cars, tours, and activities.
        *   Search for available options based on user-specified criteria such as dates, destinations, budget, and preferences.
        *   Present clear and concise information about available options, including pricing, amenities, and booking terms.
        *   Guide users through the booking process, ensuring accurate information and secure transactions.
        *   Provide booking confirmations and relevant details, such as booking references and contact information.
    
    3.  **Travel Planning and Itinerary Management:**
        *   Assist users in creating detailed travel itineraries, including flights, accommodations, activities, and transportation.
        *   Offer suggestions for optimizing travel plans, such as minimizing travel time or maximizing sightseeing opportunities.
        *   Provide tools for managing and modifying existing itineraries, including adding or removing activities, changing booking dates, or upgrading accommodations.
        *   Offer reminders and notifications for upcoming travel events, such as flight check-in or tour departure times.
    
    4.  **Customer Support and Troubleshooting:**
        *   Provide prompt and helpful support to users with questions or issues related to their travel plans.
        *   Assist with resolving booking discrepancies, cancellations, or modifications.
        *   Offer guidance on travel-related emergencies, such as lost luggage or travel delays.
        *   Provide access to relevant contact information for airlines, hotels, and other travel providers.
    
    **Interaction Guidelines:**
    
    *   **Professionalism:** Maintain a polite, respectful, and professional tone in all interactions.
    *   **Clarity and Conciseness:** Provide clear, concise, and easy-to-understand information. Avoid jargon or technical terms unless necessary and always explain them.
    *   **Accuracy:** Ensure all information provided is accurate and up-to-date. Double-check details before sharing them with users. If unsure about something, admit that you don't know and offer to find the information.
    *   **Personalization:** Tailor your responses and recommendations to the specific needs and preferences of each user.
    *   **Proactive Assistance:** Anticipate user needs and offer relevant information or suggestions proactively.
    *   **Error Handling:** Gracefully handle user errors or misunderstandings. Provide helpful guidance and alternative options when necessary.
    *   **Confidentiality:** Respect user privacy and handle personal information with the utmost confidentiality and in compliance with data protection regulations.
    
    **Example Interactions:**
    
    **User:** "I want to go on a beach vacation in the Caribbean. I have a budget of $2000 per person for a week."
    **Chatbot:** "Certainly! The Caribbean offers many beautiful beach destinations within your budget. Some popular options include Punta Cana in the Dominican Republic, Cancun in Mexico, and Montego Bay in Jamaica. These destinations offer stunning beaches, all-inclusive resorts, and various activities. Would you like me to search for flights and accommodations for these locations based on your travel dates?"
    
    **User:** "My flight is delayed. What should I do?"
    **Chatbot:** "I'm sorry to hear about the delay. Please check with the airline for the updated departure time and any assistance they can offer. You may be entitled to compensation or rebooking options depending on the length of the delay and the airline's policy. Do you have your flight number handy so I can look up the current status for you?"
    
    **User:** "Tell me about the best time to visit Japan."
    **Chatbot:** "Japan is a fantastic destination with distinct seasons offering unique experiences. Spring (March-May) is famous for the beautiful cherry blossoms, while autumn (September-November) boasts stunning fall foliage. Both seasons have pleasant temperatures, making them ideal for sightseeing. Summer (June-August) can be hot and humid, but it's a great time for festivals and outdoor activities in the mountains. Winter (December-February) offers opportunities for skiing and snowboarding in the Japanese Alps, though some areas may experience heavy snowfall. To recommend the best time for you, could you tell me what you'd like to experience in Japan?"
    
    By following these instructions, you will be able to provide exceptional travel assistance and create a positive experience for every user.
    """
    
  4. تحديد إعدادات generate_content: ابدأ بكائن إعدادات ستمرّر إليه تعليمات النظام هذه. بما أنّ system_instructions معرَّف على مستوى العالم في النص البرمجي، يمكن للدالة الوصول إليه مباشرةً.
            generate_content_config = types.GenerateContentConfig(
                system_instruction=[
                    types.Part.from_text(text=system_instructions)
                ],
            )
            logging.info(f"[generate_config_details] System Instruction: {generate_content_config.system_instruction[0].text}")
    
  5. لإضافة تعليمات النظام إلى الردّ، أضِف المَعلمة config إلى الطريقة generate content، واضبطها على قيمة مساوية للكائن generate_content_config الذي تم إنشاؤه أعلاه.
            response = client.models.generate_content(
                model=model_name,
                contents=contents,
                config=generate_content_config, # This is the new line
            )
    

تم تعديل الدالة call_model

تبدو الدالة call_model الكاملة الآن على النحو التالي:

def call_model(prompt: str, model_name: str) -> str:
    """
    This function interacts with a large language model (LLM) to generate text based on a given prompt and system instructions. 
    It will be replaced in a later step with a more advanced version that handles tooling.
    """
    try:
        contents = [prompt]

        generate_content_config = types.GenerateContentConfig(
            system_instruction=[
                types.Part.from_text(text=system_instructions)
            ],
        )
        logging.info(f"[generate_config_details] System Instruction: {generate_content_config.system_instruction[0].text}")
        response = client.models.generate_content(
            model=model_name,
            contents=contents,
            config=generate_content_config,
        )

        logging.info(f"[call_model_response] LLM Response: \"{response.text}\"")
        
        return response.text
    except Exception as e:
        return f"Error: {e}"

13. اختبار التطبيق باستخدام "تعليمات النظام"

  1. في الوحدة الطرفية، أوقِف العملية الجارية حاليًا (CTRL+C).
  2. أعِد تشغيل الأمر لبدء تطبيق Streamlit مرة أخرى.
    streamlit run app.py --browser.serverAddress=localhost --server.enableCORS=false --server.enableXsrfProtection=false --server.port 8080
    
  3. أعِد تحميل تطبيق Streamlit. إذا كان تطبيق Streamlit لا يزال قيد التشغيل، يمكنك ببساطة إعادة تحميل صفحة معاينة الويب في المتصفّح.
  4. جرِّب طرح السؤال نفسه كما كان من قبل:
    What is the best time of year to go to Iceland?
    
  5. اضغط على مفتاح ENTER.
    قارِن بين طريقة استجابته هذه المرة وطريقة استجابته في المرة السابقة.

14. تحديد أداة الطقس

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

هنا يأتي دور الأدوات، المعروفة أيضًا باسم استدعاء الدوال. يمكننا تحديد مجموعة من الأدوات (دوال Python) التي يمكن للنموذج اللغوي الكبير اختيار استدعائها للحصول على معلومات خارجية.

طريقة عمل الأدوات

  1. نقدّم وصفًا لأدواتنا إلى النموذج، بما في ذلك وظائفها والمعلَمات التي تستخدمها.
  2. يرسل المستخدم طلبًا (مثلاً ما حالة الطقس في لندن؟
  3. يتلقّى النموذج الطلب ويرى أنّ المستخدم يسأل عن شيء يمكنه العثور عليه باستخدام إحدى أدواته.
  4. بدلاً من الرد بنص، يردّ النموذج بكائن function_call خاص يشير إلى الأداة التي يريد استخدامها والحجج التي يريد تقديمها.
  5. يتلقّى رمز Python هذا function_call، وينفّذ دالة get_current_temperature الفعلية باستخدام الوسيطات المقدَّمة، ويحصل على النتيجة (مثل ‫15 درجة مئوية).
  6. ونرسل هذه النتيجة مرة أخرى إلى النموذج.
  7. يتلقّى النموذج النتيجة وينشئ ردًا بلغة طبيعية للمستخدم (مثلاً تبلغ درجة الحرارة الحالية في لندن 15 درجة مئوية").

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

تحديد أداة الطقس

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

  1. في app.py، ابحث عن التعليق # TODO: Define the weather tool function declaration.
  2. أضِف المتغيّر weather_function تحت هذا التعليق. هذه عبارة عن قاموس يقدّم للنموذج كل ما يحتاج إلى معرفته عن غرض الدالة ومعلَماتها ووسيطاتها المطلوبة.
    weather_function = {
        "name": "get_current_temperature",
        "description": "Gets the current temperature for a given location.",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The city name, e.g. San Francisco",
                },
            },
            "required": ["location"],
        },
    }
    
  3. بعد ذلك، ابحث عن التعليق # TODO: Define the get_current_temperature function. أضِف رمز Python التالي أدناه. ستنفّذ هذه الدالة ما يلي:
    def get_current_temperature(location: str) -> str:
        """Gets the current temperature for a given location."""
    
        try:
            # --- Get Latitude and Longitude for the location ---
            geocode_url = f"https://geocoding-api.open-meteo.com/v1/search?name={location}&count=1&language=en&format=json"
            geocode_response = requests.get(geocode_url)
            geocode_data = geocode_response.json()
    
            if not geocode_data.get("results"):
                return f"Could not find coordinates for {location}."
    
            lat = geocode_data["results"][0]["latitude"]
            lon = geocode_data["results"][0]["longitude"]
    
            # --- Get Weather for the coordinates ---
            weather_url = f"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}&current_weather=true"
            weather_response = requests.get(weather_url)
            weather_data = weather_response.json()
    
            temperature = weather_data["current_weather"]["temperature"]
            unit = "°C"
    
            return f"{temperature}{unit}"
    
        except Exception as e:
            return f"Error fetching weather: {e}"
    

15. إعادة تصميم Chat والأدوات

تستخدم دالة call_model الحالية طلب generate_content بسيطًا لمرة واحدة. هذا الخيار رائع للأسئلة الفردية، ولكنّه ليس مثاليًا للمحادثات المتعددة، خاصةً تلك التي تتضمّن تبادلاً للرسائل بشأن الأدوات.

من الأفضل استخدام جلسة محادثة، التي تحتفظ بسياق المحادثة. سنعيد الآن تصميم الرمز البرمجي لاستخدام جلسة محادثة، وهو أمر ضروري لتنفيذ الأدوات بشكل صحيح.

  1. احذف الدالة call_model الحالية. سنستبدلها بنسخة أكثر تقدّمًا.
  2. أضِف بدلاً منها الدالة الجديدة call_model من مقطع الرمز البرمجي أدناه. تحتوي هذه الدالة الجديدة على منطق للتعامل مع حلقة استدعاء الأدوات التي ناقشناها سابقًا. لاحظ أنّها تتضمّن العديد من تعليقات TODO التي سنكملها في الخطوات التالية.
    # --- Call the Model ---
    def call_model(prompt: str, model_name: str) -> str:
        """
        This function interacts with a large language model (LLM) to generate text based on a given prompt.
        It maintains a chat session and handles function calls from the model to external tools.
        """
        try:
            # TODO: Get the existing chat session or create a new one.
    
            message_content = prompt
    
            # Start the tool-calling loop
            while True:
                # TODO: Send the message to the model.
    
                # Check if the model wants to call a tool
                has_tool_calls = False
                for part in response.candidates[0].content.parts:
                    if part.function_call:
                        has_tool_calls = True
                        function_call = part.function_call
                        logging.info(f"Function to call: {function_call.name}")
                        logging.info(f"Arguments: {function_call.args}")
    
                        # TODO: Call the appropriate function if the model requests it.
    
                # If no tool call was made, break the loop
                if not has_tool_calls:
                    break
    
            # TODO: Return the model's final text response.
    
        except Exception as e:
            return f"Error: {e}"
    
  3. الآن، لنضِف دالة مساعدة لإدارة جلسة الدردشة. أضِف الدالة get_chat فوق الدالة الجديدة call_model. ستنشئ هذه الدالة جلسة محادثة جديدة تتضمّن تعليمات النظام وتعريفات الأدوات، أو ستسترد الجلسة الحالية. هذه ممارسة جيدة لتنظيم الرموز البرمجية.
    def get_chat(model_name: str):
        if f"chat-{model_name}" not in st.session_state:
    
            # TODO: Define the tools configuration for the model
    
            # TODO: Define the generate_content configuration, including tools
    
            # TODO: Create a new chat session
    
            st.session_state[f"chat-{model_name}"] = chat
        return st.session_state[f"chat-{model_name}"]
    

لقد أعددت الآن البنية الأساسية لمنطق المحادثة المتقدّم الذي يتيح استخدام الأدوات.

16. تنفيذ منطق استدعاء الأدوات

لنملأ الآن TODOs لجعل منطق استدعاء الأدوات يعمل بشكل كامل.

تنفيذ get_chat

  1. في الدالة get_chat ضمن التعليق # TODO: Define the tools configuration...، حدِّد العنصر tools من خلال إنشاء مثيل types.Tool من تعريف weather_function.
            tools = types.Tool(function_declarations=[weather_function])
    
  2. ضمن # TODO: Define the generate_content configuration...، حدِّد generate_content_config، مع الحرص على تمرير العنصر tools إلى النموذج. هذه هي الطريقة التي يتعرّف بها النموذج على الأدوات التي يمكنه استخدامها.
            generate_content_config = types.GenerateContentConfig(
                system_instruction=[types.Part.from_text(text=system_instructions)],
                tools=[tools] # Pass the tool definition here
            )
    
  3. ضمن # TODO: Create a new chat session، أنشئ عنصر المحادثة باستخدام client.chats.create()، مع إدخال اسم النموذج والإعداد.
            chat = client.chats.create(
                model=model_name,
                config=generate_content_config,
            )
    

تنفيذ call_model

  1. ضمن # TODO: Get the existing chat session... في الدالة call_model، استدعِ دالة المساعدة الجديدة get_chat.
            chat = get_chat(model_name)
    
  2. بعد ذلك، ابحث عن # TODO: Send the message to the model. أرسِل رسالة المستخدم باستخدام طريقة chat.send_message().
                response = chat.send_message(message_content)
    
  3. ابحث عن # TODO: Call the appropriate function.... هذا هو المكان الذي نتحقّق فيه من الوظيفة التي يريدها النموذج وننفّذها.
                    if function_call.name == "get_current_temperature":
                      result = get_current_temperature(**function_call.args)
                    function_response_part = types.Part.from_function_response(
                        name=function_call.name,
                        response={"result": result},
                    )
                    message_content = [function_response_part]
  1. أخيرًا، ابحث عن # TODO: Return the model's final text response وأضِف عبارة الإرجاع.
            return response.text
    

تم تعديل الدالة get_chat

من المفترض أن تبدو دالة get_chat المعدَّلة الآن على النحو التالي:

def get_chat(model_name: str):
    if f"chat-{model_name}" not in st.session_state:
        #Tools
        tools = types.Tool(function_declarations=[weather_function])

        # Initialize a confiburation object
        generate_content_config = types.GenerateContentConfig(
            system_instruction=[types.Part.from_text(text=system_instructions)],
            tools=[tools]
        )
        chat = client.chats.create(
            model=model_name,
            config=generate_content_config,
        )
        st.session_state[f"chat-{model_name}"] = chat
    return st.session_state[f"chat-{model_name}"]

تم تعديل الدالة call_model

من المفترض أن تبدو دالة call_model المعدَّلة الآن على النحو التالي:

def call_model(prompt: str, model_name: str) -> str:
    try:
        chat = get_chat(model_name)
        message_content = prompt
        
        while True:
            response = chat.send_message(message_content)
            has_tool_calls = False
            for part in response.candidates[0].content.parts:
                if part.function_call:
                    has_tool_calls = True
                    function_call = part.function_call
                    logging.info(f"Function to call: {function_call.name}")
                    logging.info(f"Arguments: {function_call.args}")
                    if function_call.name == "get_current_temperature":
                        result = get_current_temperature(**function_call.args)
                        function_response_part = types.Part.from_function_response(
                            name=function_call.name,
                            response={"result": result},
                        )
                        message_content = [function_response_part]
                elif part.text:
                    logging.info("No function call found in the response.")
                    logging.info(response.text)

            if not has_tool_calls:
                break

        return response.text

    except Exception as e:
        return f"Error: {e}"

17. اختبار التطبيق الذي تم تفعيل الأداة فيه

لنطّلِع على ميزتك الجديدة عمليًا.

  1. في الوحدة الطرفية، أوقِف العملية الجارية حاليًا (CTRL+C).
  2. أعِد تشغيل الأمر لبدء تطبيق Streamlit مرة أخرى.
    streamlit run app.py --browser.serverAddress=localhost --server.enableCORS=false --server.enableXsrfProtection=false --server.port 8080
    
  3. أعِد تحميل تطبيق Streamlit. إذا كان تطبيق Streamlit لا يزال قيد التشغيل، يمكنك ببساطة إعادة تحميل صفحة معاينة الويب في المتصفّح.
  4. الآن، اطرح سؤالاً من المفترض أن يؤدي إلى تشغيل أداتك الجديدة، مثل ما يلي:
    I'm looking for something to do in New York today. What do you recommend? Would it be a good day to go to Ellis Island?
    
  5. اضغط على ENTER
    لمقارنة هذا الرد بالردود السابقة. ما هي الاختلافات؟
    من المفترض أن يظهر لك ردّ يتضمّن درجة الحرارة من الدالة. تحقَّق أيضًا من نافذة Cloud Shell، من المفترض أن تظهر لك عبارات الطباعة التي تؤكّد تنفيذ دالة Python.

18 تحسين إخراج النموذج باستخدام المَعلمات

أحسنت. يمكن لمساعد السفر الآن استخدام أدوات لجلب بيانات خارجية مباشرة، ما يجعله أكثر فعالية.

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

في هذا التمرين العملي، سنركّز على temperature وtop_p. (يُرجى الرجوع إلى GenerateContentConfig في مرجع واجهة برمجة التطبيقات للاطّلاع على قائمة كاملة بالمعلّمات القابلة للإعداد وأوصافها).

  • temperature: تتحكّم في عشوائية الناتج. تؤدي القيمة المنخفضة (الأقرب إلى 0) إلى أن يكون الردّ أكثر حتمية وتركيزًا، بينما تؤدي القيمة المرتفعة (الأقرب إلى 2) إلى زيادة العشوائية والإبداع. بالنسبة إلى روبوتات الدردشة المخصّصة للأسئلة والأجوبة أو المساعدة، يُفضّل عادةً استخدام درجة عشوائية منخفضة للحصول على ردود أكثر اتساقًا وواقعية.
  • top_p: الحدّ الأقصى للاحتمال التراكمي للرموز المميّزة التي يجب أخذها في الاعتبار عند أخذ العيّنات. يتم ترتيب الرموز المميزة استنادًا إلى الاحتمالات المحدّدة لها، وبالتالي لا يتم أخذ سوى الرموز المميزة الأكثر ترجيحًا في الاعتبار. يأخذ النموذج في الاعتبار الرموز المميّزة الأكثر ترجيحًا التي يصل مجموع احتمالاتها إلى قيمة top_p. تؤدي القيمة المنخفضة إلى تقييد خيارات الرموز المميزة، ما يؤدي إلى إنتاج محتوى أقل تنوعًا.

مَعلمات المكالمة

  1. ابحث عن المتغيّرين temperature وtop_p المحدّدين في أعلى app.py. لاحظ أنّه لم يتم استدعاؤها بعد في أي مكان.
  2. أضِف temperature وtop_p إلى المَعلمات المحدّدة ضمن GenerateContentConfig في الدالة call_model.
            generate_content_config = types.GenerateContentConfig(
                temperature=temperature,
                top_p=top_p,
                system_instruction=[types.Part.from_text(text=system_instructions)],
                tools=[tools] # Pass the tool definition here
            )
    
    

تم تعديل الدالة get_chat

يظهر تطبيق get_chat الآن على النحو التالي:

def get_chat(model_name: str):
    if f"chat-{model_name}" not in st.session_state:
        #Tools
        tools = types.Tool(function_declarations=[weather_function])

        # Initialize a confiburation object
        generate_content_config = types.GenerateContentConfig(
            temperature=temperature,
            top_p=top_p,
            system_instruction=[types.Part.from_text(text=system_instructions)],
            tools=[tools] 
        )
        chat = client.chats.create(
            model=model_name,
            config=generate_content_config,
        )
        st.session_state[f"chat-{model_name}"] = chat
    return st.session_state[f"chat-{model_name}"]

19. الاختبار باستخدام مَعلمات النموذج

  1. في الوحدة الطرفية، أوقِف العملية الجارية حاليًا (CTRL+C).
  2. أعِد تشغيل الأمر لبدء تطبيق Streamlit مرة أخرى.
    streamlit run app.py --browser.serverAddress=localhost --server.enableCORS=false --server.enableXsrfProtection=false --server.port 8080
    
  3. أعِد تحميل تطبيق Streamlit. إذا كان تطبيق Streamlit لا يزال قيد التشغيل، يمكنك ببساطة إعادة تحميل صفحة معاينة الويب في المتصفّح.
  4. جرِّب طرح السؤال نفسه كما كان من قبل،
    I'm looking for something to do in New York today. What do you recommend? Would it be a good day to go to Ellis Island?
    
  5. اضغط على ENTER
    لمقارنة هذا الرد بالردود السابقة.

20. تهانينا!

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

مواصلة التجربة

تتوفّر العديد من الخيارات لمواصلة تحسين طلبك. في ما يلي بعض الأمور التي يجب مراعاتها:

  • اضبط temperature وtop_p واطّلِع على كيفية تغييرهما للردّ الذي تقدّمه نماذج اللغات الكبيرة.
  • راجِع GenerateContentConfig في مرجع واجهة برمجة التطبيقات للاطّلاع على قائمة كاملة بالمعلّمات القابلة للإعداد وأوصافها. جرِّب تحديد المزيد من المَعلمات وتعديلها لمعرفة ما سيحدث.

ملخّص

في هذا الدرس التطبيقي، نفّذت ما يلي:

  • استخدام محرّر Cloud Shell ووحدة التحكّم الطرفية للتطوير
  • استخدام حزمة تطوير البرامج (SDK) الخاصة بلغة Python في Vertex AI لربط تطبيقك بنموذج Gemini
  • تطبيق تعليمات النظام ومَعلمات النموذج لتوجيه ردود النموذج اللغوي الكبير
  • تعرّفت على مفهوم الأدوات (استدعاء الدوال) وفوائده.
  • أعدنا تصميم الرمز البرمجي لاستخدام جلسة محادثة ذات حالة، وهي من أفضل الممارسات المتعلّقة بالذكاء الاصطناعي الحواري.
  • تم تحديد أداة للنموذج باستخدام تعريف دالة.
  • تم تنفيذ دالة Python لتوفير منطق الأداة.
  • كتابة الرمز البرمجي للتعامل مع طلبات استدعاء الدوال في النموذج وعرض النتائج