Tworzenie aplikacji LLM za pomocą pakietu Vertex AI SDK

1. Wprowadzenie

Przegląd

Jesteś programistą w firmie zajmującej się marketingiem w branży turystycznej. Twój dział sprzedaży uznał, że potrzebuje nowej aplikacji do czatowania, aby nadążyć za większymi firmami zajmującymi się rezerwacjami i wyszukiwaniem. Słyszeli też o generatywnej AI, ale nie wiedzą o niej zbyt wiele. Inne działy dowiedziały się o tej inicjatywie i zastanawiają się, jak może ona wpłynąć na wrażenia klientów.

Jakie zadania wykonasz

W tym module utworzysz czatbota będącego asystentem podróży przy użyciu modelu Gemini 2.5 FlashVertex AI.

Aplikacja powinna:

  • Pomaga użytkownikom zadawać pytania dotyczące podróży, rezerwować podróże i uzyskiwać informacje o miejscach, do których planują się udać.
  • zapewnia użytkownikom sposoby uzyskiwania pomocy dotyczącej konkretnych planów podróży;
  • pobierać dane w czasie rzeczywistym, np. informacje o pogodzie, za pomocą narzędzi;

Będziesz pracować w wstępnie skonfigurowanym środowisku Google Cloud, a konkretnie w edytorze Cloud Shell. Podstawowy interfejs aplikacji internetowej jest już skonfigurowany, podobnie jak niezbędne uprawnienia dostępu do Vertex AI. Ta aplikacja została utworzona za pomocą Streamlit.

Czego się nauczysz

Z tego modułu nauczysz się, jak:

2. Konfigurowanie projektu

Konto Google

Jeśli nie masz jeszcze osobistego konta Google, musisz je utworzyć.

Używaj konta osobistego zamiast konta służbowego lub szkolnego.

Logowanie w konsoli Google Cloud

Zaloguj się w konsoli Google Cloud za pomocą osobistego konta Google.

Włącz płatności

Wykorzystaj środki na Google Cloud o wartości 5 USD (opcjonalnie)

Aby przeprowadzić te warsztaty, musisz mieć konto rozliczeniowe z określonymi środkami. Jeśli planujesz używać własnego konta rozliczeniowego, możesz pominąć ten krok.

  1. Kliknij ten link i zaloguj się na osobiste konto Google.Zobaczysz coś takiego:Kliknij, aby uwierzytelnić się w Cloud Shell
  2. Kliknij przycisk KLIKNIJ TUTAJ, ABY UZYSKAĆ DOSTĘP DO ŚRODKÓW. Spowoduje to przejście na stronę, na której możesz skonfigurować profil płatności.Kliknij, aby uwierzytelnić się w Cloud Shell
  3. Kliknij Potwierdź.

Twoje konto jest teraz połączone z próbnym kontem rozliczeniowym Google Cloud Platform.

Zrzut ekranu z przeglądem rozliczeń

Konfigurowanie osobistego konta rozliczeniowego

Jeśli skonfigurujesz płatności za pomocą środków w Google Cloud, możesz pominąć ten krok.

Aby skonfigurować osobiste konto rozliczeniowe, włącz płatności w Cloud Console.

Uwagi:

Tworzenie projektu (opcjonalnie)

Jeśli nie masz bieżącego projektu, którego chcesz użyć w tym ćwiczeniu, utwórz nowy projekt.

3. Otwórz edytor Cloud Shell

  1. Kliknij ten link, aby przejść bezpośrednio do edytora Cloud Shell
  2. Jeśli w dowolnym momencie pojawi się prośba o autoryzację, kliknij Autoryzuj, aby kontynuować.Kliknij, aby uwierzytelnić się w Cloud Shell
  3. Jeśli terminal nie pojawia się u dołu ekranu, otwórz go:
    • Kliknij Wyświetl.
    • Kliknij TerminalOtwieranie nowego terminala w edytorze Cloud Shell.
  4. W terminalu ustaw projekt za pomocą tego polecenia:
    gcloud config set project [PROJECT_ID]
    
    • Przykład:
      gcloud config set project lab-project-id-example
      
    • Jeśli nie pamiętasz identyfikatora projektu, możesz wyświetlić listę wszystkich identyfikatorów projektów za pomocą tego polecenia:
      gcloud projects list | awk '/PROJECT_ID/{print $2}'
      
      Ustawianie identyfikatora projektu w terminalu edytora Cloud Shell
  5. Powinien wyświetlić się ten komunikat:
    Updated property [core/project].
    
    >aside negative Jeśli zobaczysz `WARNING` i zostanie wyświetlone pytanie `Do you want to continue (Y/n)?`, prawdopodobnie wpisano nieprawidłowy identyfikator projektu. Naciśnij „n”, a potem „Enter” i spróbuj ponownie uruchomić polecenie `gcloud config set project`. >

4. Włącz interfejsy API

Aby używać pakietu SDK Vertex AI i wchodzić w interakcje z modelem Gemini, musisz włączyć interfejs Vertex AI API w projekcie Google Cloud.

  1. W terminalu włącz interfejsy API:
    gcloud services enable \
      aiplatform.googleapis.com
    

Wprowadzenie do pakietu Vertex AI SDK dla Pythona

Aby wchodzić w interakcje z modelami hostowanymi w Vertex AI z poziomu aplikacji w Pythonie, użyjesz pakietu Vertex AI SDK for Python. Ten pakiet SDK upraszcza proces wysyłania promptów, określania parametrów modelu i otrzymywania odpowiedzi bez konieczności bezpośredniego obsługi złożonych wywołań interfejsu API.

Pełną dokumentację pakietu Vertex AI SDK dla Pythona znajdziesz tutaj: Wprowadzenie do pakietu Vertex AI SDK dla Pythona | Google Cloud.

5. Tworzenie środowiska wirtualnego i instalowanie zależności

Przed rozpoczęciem dowolnego projektu w Pythonie warto utworzyć środowisko wirtualne. Izoluje to zależności projektu, zapobiegając konfliktom z innymi projektami lub globalnymi pakietami Pythona w systemie.

  1. Utwórz folder o nazwie wanderbot, w którym będziesz przechowywać kod aplikacji asystenta podróży. Uruchom w terminalu ten kod:
    mkdir wanderbot && cd wanderbot
    
  2. Utwórz i aktywuj środowisko wirtualne:
    uv venv --python 3.12
    source .venv/bin/activate
    
    Przed promptem terminala zobaczysz prefiks (wanderbot), który oznacza, że środowisko wirtualne jest aktywne. Będzie to wyglądać mniej więcej tak:

    zrzut ekranu terminala z aktywnym środowiskiem wirtualnym;

6. Tworzenie plików początkowych dla wanderbot

  1. Utwórz i otwórz nowy plik app.py dla aplikacji. Uruchom w terminalu ten kod:
    cloudshell edit app.py
    
    Polecenie cloudshell edit otworzy plik app.py w edytorze nad terminalem.
  2. Wklej do pliku app.py ten kod początkowy aplikacji:
    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. Utwórz i otwórz nowy plik requirements.txt na kod aplikacji. Uruchom w terminalu ten kod:
    cloudshell edit requirements.txt
    
    Polecenie cloudshell edit otworzy plik requirements.txt w edytorze nad terminalem.
  4. Wklej do pliku requirements.txt ten kod początkowy aplikacji.
    google-genai
    streamlit
    requests
    
  5. Zainstaluj wymagane zależności Pythona dla tego projektu. Uruchom w terminalu ten kod:
    uv pip install -r requirements.txt
    

7. Poznaj kod

Utworzone przez Ciebie pliki zawierają podstawowy interfejs aplikacji do czatowania. To m.in.:

  • app.py: w tym pliku będziemy pracować. Obecnie zawiera te informacje:
    • niezbędne importy,
    • zmienne środowiskowe i parametry (niektóre z nich to symbole zastępcze);
    • pustą funkcję call_model, którą będziemy wypełniać.
    • Kod Streamlit aplikacji do obsługi czatu w interfejsie
  • requirements.txt:
    • zawiera wymagania dotyczące instalacji, które są niezbędne do uruchomienia app.py.

Czas na zapoznanie się z kodem.

Otwieranie czatu Gemini Code Assist

Czat Gemini Code Assist powinien być już otwarty w panelu po prawej stronie edytora Cloud Shell. Jeśli czat Gemini Code Assist nie jest jeszcze otwarty, możesz go otworzyć, wykonując te czynności:

  1. Kliknij przycisk Gemini Code Assist (Kliknij tutaj, aby włączyć Gemini Code Assist) u góry ekranu.
  2. Kliknij Otwórz czat Gemini Code Assist.Menu Gemini Code Assist

Korzystanie z Gemini Code Assist do zrozumienia kodu

Aby lepiej zrozumieć kod, możesz użyć Gemini Code Assist Chat.

  1. Wyróżnij lub wybierz odpowiednią sekcję kodu.
  2. Wpisz „Wyjaśnij ten kod” w czacie Gemini.
  3. Aby przesłać, naciśnij Enter

Film pokazujący zaznaczanie fragmentu kodu, przekazywanie do Gemini Code Assist polecenia „Wyjaśnij to” i otrzymywanie odpowiedzi.

8. Uruchamianie aplikacji internetowej

Zanim połączysz tę aplikację z LLM, uruchom ją, aby sprawdzić, jak działa na początku.

  1. Z poziomu katalogu wanderbot uruchom w terminalu to polecenie, aby uruchomić aplikację Streamlit i udostępnić ją lokalnie w środowisku Cloud Shell:
    streamlit run app.py --browser.serverAddress=localhost --server.enableCORS=false --server.enableXsrfProtection=false --server.port 8080
    
    Nie zamykaj okna terminala, ponieważ aplikacja Streamlit będzie nadal działać. Aby uruchomić inne polecenia, możesz otworzyć nowe okno terminala w Cloud Shell.
  2. Po uruchomieniu polecenia kliknij przycisk Podgląd w przeglądarce u góry edytora Cloud Shell i wybierz Podejrzyj na porcie 8080.
    otwarte menu podglądu z

     Wyświetli się prosty interfejs czatu aplikacji podróżniczej.
  3. Wpisz dowolną wiadomość (np. Hi!) i naciśnij ENTER.

    Zauważysz, że wiadomość pojawi się w historii czatu, ale zamiast odpowiedzi od asystenta otrzymasz komunikat o błędzie. Dzieje się tak, ponieważ aplikacja nie jest jeszcze połączona z dużym modelem językowym. Obserwuj to zachowanie, aby poznać punkt wyjścia modułu.

9. Inicjowanie klienta Vertex AI

Poznaj dostępne modele w Vertex AI

Platforma Vertex AI w Google Cloud zapewnia dostęp do różnych modeli generatywnej AI. Zanim zintegrujesz usługę, możesz zapoznać się z dostępnymi opcjami w konsoli Google Cloud.

  1. W konsoli Google Cloud otwórz Model Garden. Aby to zrobić, wpisz „Baza modeli” na pasku wyszukiwania u góry ekranu i wybierz Vertex AI.seriale i programy
  2. Przejrzyj dostępne modele. Możesz filtrować według takich kryteriów jak modalności, typy zadań i funkcje.

Na potrzeby tego laboratorium będziesz używać modelu Gemini 2.5 Flash, który ze względu na szybkość jest dobrym wyborem do tworzenia responsywnych aplikacji do czatowania.

Inicjowanie klienta Vertex AI

Teraz zmodyfikujesz sekcję --- Initialize the Vertex AI Client ---app.py, aby zainicjować klienta Vertex AI. Ten obiekt klienta będzie używany do wysyłania promptów do modelu.

  1. Otwórz plik app.py w edytorze Cloud Shell.
  2. W pliku app.py znajdź wiersz PROJECT_ID = None.
  3. Zastąp None identyfikatorem projektu Google Cloud w cudzysłowie. (np. PROJECT_ID = "google-cloud-labs")
    Jeśli nie pamiętasz identyfikatora projektu, możesz wyświetlić wszystkie identyfikatory projektów za pomocą tego polecenia:
    gcloud projects list | awk '/PROJECT_ID/{print $2}'
    
  4. Zdefiniuj klienta: w bloku try zainicjuj klienta Vertex AI.
        client = genai.Client(
            vertexai=True,
            project=PROJECT_ID,
            location=REGION,
        )
    

Zaktualizowana inicjalizacja klienta Vertex AI

W tym momencie sekcja Initialize the Vertex AI Client (Inicjowanie klienta Vertex AI) będzie wyglądać tak:

# --- 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. Przygotowywanie danych i wywoływanie modelu

Teraz przygotujesz treść do wysłania do modelu i wywołasz model Gemini.

  1. Znajdź sekcję --- Call the Model ---, w której zdefiniowana jest funkcja call_model.
  2. Określ zawartość: w sekcji # TODO: Prepare the content for the model określ zawartość wejściową , która zostanie wysłana do modelu. W przypadku podstawowego prompta będzie to wiadomość wpisana przez użytkownika.
            contents = [prompt]
    
  3. Określ odpowiedź: wklej ten kod pod # TODO: Define response.
            response = client.models.generate_content(
                model=model_name,
                contents=contents,
            )
    
  4. Wysyłanie odpowiedzi: usuń znacznik komentarza w tym wierszu:
            return response.text
    
  5. Sprawdź wiersz, w którym wywoływana jest funkcja call_model, w dolnej części pliku w bloku with. Jeśli nie rozumiesz, co się tu dzieje, zaznacz wiersz i poproś Gemini Code Assist o wyjaśnienie.

Bardziej jednoznaczny sposób definiowania contents

Powyższy sposób definiowania contents działa, ponieważ pakiet SDK jest wystarczająco inteligentny, aby zrozumieć, że lista zawierająca ciągi znaków reprezentuje tekst wprowadzony przez użytkownika. Automatycznie formatuje go w odpowiedni sposób dla interfejsu API modelu.

Bardziej jednoznaczny i podstawowy sposób strukturyzacji danych wejściowych polega jednak na użyciu obiektów types.Parttypes.Content, np. tak:

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

Zaktualizowana funkcja call_model

W tym momencie funkcja call_model powinna wyglądać tak:

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. Testowanie połączonej aplikacji

  1. W terminalu zatrzymaj aktualnie działający proces (CTRL+C).
  2. Ponownie uruchom polecenie, aby ponownie uruchomić aplikację Streamlit.
    streamlit run app.py --browser.serverAddress=localhost --server.enableCORS=false --server.enableXsrfProtection=false --server.port 8080
    
  3. Odśwież aplikację Streamlit. Jeśli aplikacja Streamlit nadal działa, wystarczy odświeżyć stronę podglądu w przeglądarce.
  4. Teraz wpisz w polu czatu pytanie, np.:
    What is the best time of year to go to Iceland?
    
  5. Naciśnij ENTER.

     Powinna się wyświetlić aplikacja z Twoją wiadomością, spinnerem „Myślenie…” i odpowiedzią wygenerowaną przez model Gemini. Jeśli tak, oznacza to, że udało Ci się połączyć aplikację internetową z modelem LLM w Vertex AI. 🙌 🥳

12. Określanie instrukcji systemowych

Podstawowe połączenie działa, ale jakość i styl odpowiedzi modelu LLM są w dużej mierze uzależnione od otrzymanych danych wejściowych. Tworzenie promptów to proces projektowania i dopracowywania tych danych wejściowych (promptów), aby kierować modelem w stronę generowania pożądanych wyników.

W tym celu zaczniesz od utworzenia instrukcji systemowych i przekazania ich do modelu.

Aby tworzyć przydatne instrukcje systemowe, będziesz używać funkcji Zapytaj Gemini.

  1. W sekcji app.py znajdź zmienną system_instructions, która jest obecnie ustawiona na None.
    system_instructions = None
    
    Zastąpisz None ciągiem wielowierszowym zawierającym instrukcje dla naszego bota asystenta podróży.
  2. Zadaj pytanie Gemini Code Assist: przekaż Gemini Code Assist ten prompt (lub wymyśl własny):
    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. Zdefiniuj system_instructions: ustaw system_instructions jako instrukcje systemowe wygenerowane za pomocą Gemini Code Assist. Możesz też użyć tych instrukcji systemowych, które zostały utworzone przez Gemini na podstawie podobnego prompta.
    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. Zdefiniuj konfigurację generate_content: zainicjuj obiekt konfiguracji, do którego przekażesz te instrukcje systemowe. Ponieważ zmienna system_instructions jest zdefiniowana globalnie w naszym skrypcie, funkcja może uzyskać do niej bezpośredni dostęp.
            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. Aby dodać instrukcje systemowe do odpowiedzi, dodaj parametr config do metody generate content i ustaw go na wartość obiektu generate_content_config utworzonego powyżej.
            response = client.models.generate_content(
                model=model_name,
                contents=contents,
                config=generate_content_config, # This is the new line
            )
    

Zaktualizowana funkcja call_model

Pełna funkcja call_model wygląda teraz tak:

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. Testowanie aplikacji za pomocą instrukcji systemowych

  1. W terminalu zatrzymaj aktualnie działający proces (CTRL+C).
  2. Ponownie uruchom polecenie, aby ponownie uruchomić aplikację Streamlit.
    streamlit run app.py --browser.serverAddress=localhost --server.enableCORS=false --server.enableXsrfProtection=false --server.port 8080
    
  3. Odśwież aplikację Streamlit. Jeśli aplikacja Streamlit nadal działa, wystarczy odświeżyć stronę podglądu w przeglądarce.
  4. Spróbuj zadać to samo pytanie co wcześniej:
    What is the best time of year to go to Iceland?
    
  5. Naciśnij ENTER.
     Porównaj, jak odpowiada tym razem w porównaniu z poprzednim razem.

14. Określanie narzędzia pogodowego

Nasz chatbot ma dużą wiedzę, ale jest ona ograniczona do danych, na których został wytrenowany. Nie ma dostępu do informacji w czasie rzeczywistym. W przypadku bota podróżniczego możliwość pobierania danych na żywo, takich jak prognozy pogody, jest ogromną zaletą.

W tym przypadku przydają się narzędzia, czyli wywoływanie funkcji. Możemy zdefiniować zestaw narzędzi (funkcji Pythona), które LLM może wywoływać, aby uzyskać informacje zewnętrzne.

Jak działa narzędzie

  1. Opisujemy modelowi nasze narzędzia, w tym ich działanie i parametry.
  2. Użytkownik wysyła prompt (np. „Jaka jest pogoda w Londynie?
  3. Model otrzymuje prompt i widzi, że użytkownik pyta o coś, co może znaleźć za pomocą jednego z narzędzi.
  4. Zamiast odpowiadać tekstem, model zwraca specjalny obiekt function_call, który wskazuje, które narzędzie ma zostać wywołane i z jakimi argumentami.
  5. Nasz kod w Pythonie odbiera ten function_call, wykonuje naszą rzeczywistą funkcję get_current_temperature z podanymi argumentami i uzyskuje wynik (np. 15°C).
  6. Wynik ten przesyłamy z powrotem do modelu.
  7. Model otrzymuje wynik i generuje dla użytkownika odpowiedź w języku naturalnym (np. „Obecna temperatura w Londynie to 15°C”.

Dzięki temu model może odpowiadać na pytania wykraczające daleko poza dane treningowe, co czyni go znacznie bardziej zaawansowanym i przydatnym asystentem.

Określanie narzędzia pogodowego

Jeśli podróżny szuka porady, co robić, i wybiera spośród atrakcji, na które ma wpływ pogoda, narzędzie pogodowe może się przydać. Utwórzmy narzędzie, które umożliwi naszemu modelowi uzyskiwanie informacji o aktualnej pogodzie. Potrzebujemy 2 elementów: deklaracji funkcji, która opisuje narzędzie dla modelu, oraz rzeczywistej funkcji w języku Python, która je implementuje.

  1. W sekcji app.py znajdź komentarz # TODO: Define the weather tool function declaration.
  2. Pod tym komentarzem dodaj zmienną weather_function. Jest to słownik, który zawiera wszystkie informacje o funkcji, jej parametrach i wymaganych argumentach.
    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. Następnie znajdź komentarz # TODO: Define the get_current_temperature function. Pod nim dodaj ten kod w Pythonie. Ta funkcja:
    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. Refaktoryzacja czatu i narzędzi

Obecna funkcja call_model korzysta z prostego wywołania generate_content. To świetne rozwiązanie w przypadku pojedynczych pytań, ale nie sprawdza się w rozmowach wieloetapowych, zwłaszcza tych, które wymagają wymiany informacji w celu korzystania z narzędzi.

Lepszym rozwiązaniem jest użycie sesji czatu, która zachowuje kontekst rozmowy. Teraz zmodyfikujemy nasz kod, aby używać sesji czatu, co jest niezbędne do prawidłowego wdrożenia narzędzi.

  1. Usuń istniejącą funkcję call_model. Zastąpimy ją bardziej zaawansowaną wersją.
  2. Zamiast niej dodaj nową funkcję call_model z bloku kodu poniżej. Ta nowa funkcja zawiera logikę obsługi pętli wywoływania narzędzi, o której wspominaliśmy wcześniej. Zwróć uwagę, że zawiera on kilka komentarzy TODO, które uzupełnimy w następnych krokach.
    # --- 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. Teraz dodajmy funkcję pomocniczą do zarządzania sesją czatu. Nad nową funkcją call_model dodaj funkcję get_chat. Ta funkcja utworzy nową sesję czatu z instrukcjami systemowymi i definicjami narzędzi lub pobierze istniejącą sesję. To dobra praktyka organizowania kodu.
    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}"]
    

Masz już skonfigurowane ramy naszej zaawansowanej logiki czatu z użyciem narzędzi.

16. Zaimplementuj logikę wywoływania narzędzi

Teraz wypełnijmy pole TODOs, aby logika wywoływania narzędzi była w pełni funkcjonalna.

Wdróż get_chat

  1. W funkcji get_chat w komentarzu # TODO: Define the tools configuration... zdefiniuj obiekt tools, tworząc instancję types.Tool z deklaracji weather_function.
            tools = types.Tool(function_declarations=[weather_function])
    
  2. W sekcji # TODO: Define the generate_content configuration... zdefiniuj generate_content_config, pamiętając o przekazaniu do modelu obiektu tools. W ten sposób model uczy się, jakich narzędzi może używać.
            generate_content_config = types.GenerateContentConfig(
                system_instruction=[types.Part.from_text(text=system_instructions)],
                tools=[tools] # Pass the tool definition here
            )
    
  3. W sekcji # TODO: Create a new chat session utwórz obiekt czatu za pomocą client.chats.create(), przekazując nazwę modelu i konfigurację.
            chat = client.chats.create(
                model=model_name,
                config=generate_content_config,
            )
    

Wdróż call_model

  1. W funkcji call_model w sekcji # TODO: Get the existing chat session... wywołaj naszą nową funkcję pomocniczą get_chat.
            chat = get_chat(model_name)
    
  2. Następnie znajdź # TODO: Send the message to the model. Wyślij wiadomość użytkownika za pomocą metody chat.send_message().
                response = chat.send_message(message_content)
    
  3. Znajdź # TODO: Call the appropriate function.... W tym miejscu sprawdzamy, której funkcji oczekuje model, i ją wykonujemy.
                    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. Na koniec znajdź # TODO: Return the model's final text response i dodaj instrukcję zwrotu.
            return response.text
    

Zaktualizowana funkcja get_chat

Zaktualizowana funkcja get_chat powinna teraz wyglądać tak:

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}"]

Zaktualizowana funkcja call_model

Zaktualizowana funkcja call_model powinna teraz wyglądać tak:

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. Testowanie aplikacji z włączonymi narzędziami

Zobaczmy, jak działa nowa funkcja.

  1. W terminalu zatrzymaj aktualnie działający proces (CTRL+C).
  2. Ponownie uruchom polecenie, aby ponownie uruchomić aplikację Streamlit.
    streamlit run app.py --browser.serverAddress=localhost --server.enableCORS=false --server.enableXsrfProtection=false --server.port 8080
    
  3. Odśwież aplikację Streamlit. Jeśli aplikacja Streamlit nadal działa, wystarczy odświeżyć stronę podglądu w przeglądarce.
  4. Teraz zadaj pytanie, które powinno uruchomić nowe narzędzie, np. takie:
    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. Naciśnij ENTER.
    Porównaj tę odpowiedź z wcześniejszymi. Co się zmieniło?
     Powinna się wyświetlić odpowiedź zawierająca temperaturę z funkcji. Sprawdź też terminal Cloud Shell. Powinny się w nim pojawić instrukcje drukowania potwierdzające wykonanie funkcji Pythona.

18. Ulepszanie wyników modelu za pomocą parametrów

Dobra robota! Asystent podróży może teraz korzystać z narzędzi do pobierania zewnętrznych danych w czasie rzeczywistym, co znacznie zwiększa jego możliwości.

Teraz, gdy zwiększyliśmy możliwości naszego modelu, dostosujmy sposób, w jaki odpowiada. Parametry modelu pozwalają kontrolować styl i losowość generowanego przez LLM tekstu. Dostosowując te ustawienia, możesz sprawić, że wyniki działania bota będą bardziej ukierunkowane i deterministyczne lub bardziej kreatywne i zróżnicowane.

W tym module skupimy się na temperaturetop_p. (Pełną listę parametrów, które można skonfigurować, i ich opisy znajdziesz w GenerateContentConfig w naszej dokumentacji interfejsu API).

  • temperature: określa losowość danych wyjściowych. Niższa wartość (bliższa 0) sprawia, że dane wyjściowe są bardziej deterministyczne i skoncentrowane, a wyższa wartość (bliższa 2) zwiększa losowość i kreatywność. W przypadku bota do zadawania pytań i odpowiedzi lub asystenta zwykle preferowana jest niższa temperatura, aby uzyskać bardziej spójne i rzeczowe odpowiedzi.
  • top_p: maksymalne skumulowane prawdopodobieństwo tokenów, które należy uwzględnić podczas próbkowania. Tokeny są sortowane na podstawie przypisanych im prawdopodobieństw, dzięki czemu brane pod uwagę są tylko najbardziej prawdopodobne tokeny. Model bierze pod uwagę najbardziej prawdopodobne tokeny, których prawdopodobieństwa sumują się do wartości top_p. Niższa wartość ogranicza wybór tokenów, co skutkuje mniej zróżnicowanymi danymi wyjściowymi.

Parametry wywołania

  1. Znajdź zmienne temperaturetop_p zdefiniowane u góry sekcji app.py. Zwróć uwagę, że nie zostały jeszcze nigdzie wywołane.
  2. Dodaj temperaturetop_p do parametrów zdefiniowanych w GenerateContentConfig w funkcji 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
            )
    
    

Zaktualizowana funkcja get_chat

Aplikacja get_chat wygląda teraz tak:

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. Testowanie za pomocą parametrów modelu

  1. W terminalu zatrzymaj aktualnie działający proces (CTRL+C).
  2. Ponownie uruchom polecenie, aby ponownie uruchomić aplikację Streamlit.
    streamlit run app.py --browser.serverAddress=localhost --server.enableCORS=false --server.enableXsrfProtection=false --server.port 8080
    
  3. Odśwież aplikację Streamlit. Jeśli aplikacja Streamlit nadal działa, wystarczy odświeżyć stronę podglądu w przeglądarce.
  4. Zadaj to samo pytanie co wcześniej.
    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. Naciśnij ENTER.
    Porównaj tę odpowiedź z wcześniejszymi.

20. Gratulacje!

Aplikacja do zadawania pytań i odpowiedzi została zaktualizowana o narzędzia, czyli zaawansowaną funkcję, która umożliwia aplikacji opartej na Gemini interakcję z systemami zewnętrznymi i dostęp do informacji w czasie rzeczywistym.

Dalsze eksperymenty

Istnieje wiele sposobów na dalszą optymalizację promptu. Oto kilka kwestii, które warto rozważyć:

  • Dostosuj wartości temperaturetop_p i zobacz, jak zmienia się odpowiedź modelu LLM.
  • Pełną listę konfigurowalnych parametrów i ich opisów znajdziesz w GenerateContentConfig w naszej dokumentacji interfejsu API. Spróbuj zdefiniować więcej parametrów i dostosować je, aby zobaczyć, co się stanie.

Podsumowanie

W tym module:

  • Do programowania użyto edytora Cloud Shell i terminala.
  • Użyj pakietu Vertex AI SDK dla Pythona, aby połączyć aplikację z modelem Gemini.
  • Zastosowano instrukcje systemowe i parametry modelu, aby kierować odpowiedziami LLM.
  • Poznanie koncepcji narzędzi (wywoływanie funkcji) i ich zalet.
  • Przebudowano kod, aby używać sesji czatu z zachowywaniem stanu, co jest sprawdzoną metodą w przypadku konwersacyjnej AI.
  • zdefiniowano narzędzie dla modelu za pomocą deklaracji funkcji;
  • Wdrożono funkcję Pythona, która zapewnia logikę narzędzia.
  • Napisz kod do obsługi żądań wywoływania funkcji modelu i zwracania wyników.