Создание чат-бота с Джеммой

Посмотреть на ai.google.dev Запустить в Google Colab Открыть в Vertex AI Посмотреть исходный код на GitHub

Модели больших языков (LLM), такие как Gemma, превосходно генерируют информативные ответы, что делает их идеальными для создания виртуальных помощников и чат-ботов.

Традиционно LLM работают без сохранения состояния, то есть им не хватает внутренней памяти для хранения прошлых разговоров. Каждое приглашение или вопрос обрабатывается независимо, независимо от предыдущих взаимодействий. Однако важнейшим аспектом естественного разговора является способность сохранять контекст предыдущих взаимодействий. Чтобы преодолеть это ограничение и позволить LLM поддерживать контекст разговора, им должна быть явно предоставлена ​​соответствующая информация, такая как история разговора (или соответствующие части), в каждом новом приглашении, представляемом LLM.

В этом руководстве показано, как разработать чат-бота, используя вариант модели Gemma с настроенной инструкцией.

Настраивать

Настройка Джеммы

Чтобы выполнить это руководство, вам сначала необходимо выполнить инструкции по настройке на странице настройки Gemma . В инструкциях по настройке Gemma показано, как сделать следующее:

  • Получите доступ к Джемме на kaggle.com.
  • Выберите среду выполнения Colab с достаточными ресурсами для запуска модели Gemma 2B.
  • Создайте и настройте имя пользователя Kaggle и ключ API.

После завершения настройки Gemma перейдите к следующему разделу, где вы установите переменные среды для вашей среды Colab.

Установить переменные среды

Установите переменные среды для KAGGLE_USERNAME и KAGGLE_KEY .

import os
from google.colab import userdata

# Note: `userdata.get` is a Colab API. If you're not using Colab, set the env
# vars as appropriate for your system.
os.environ["KAGGLE_USERNAME"] = userdata.get('KAGGLE_USERNAME')
os.environ["KAGGLE_KEY"] = userdata.get('KAGGLE_KEY')

Установить зависимости

Установите Keras и KerasNLP.

# Install Keras 3 last. See https://keras.io/getting_started/ for more details.
pip install -q tensorflow-cpu
pip install -q -U keras-nlp tensorflow-hub
pip install -q -U "keras>=3"
pip install -q -U tensorflow-text

Выберите серверную часть

Keras — это высокоуровневый многоплатформенный API глубокого обучения, разработанный для простоты и удобства использования. Keras 3 позволяет вам выбрать бэкэнд: TensorFlow, JAX или PyTorch. Все три подойдут для этого урока.

import os

# Select JAX as the backend
os.environ["KERAS_BACKEND"] = "jax"

# Pre-allocate 100% of TPU memory to minimize memory fragmentation
os.environ["XLA_PYTHON_CLIENT_MEM_FRACTION"] = "1.0"

Импортировать пакеты

Импортируйте Keras и KerasNLP.

import keras
import keras_nlp

# for reproducibility
keras.utils.set_random_seed(42)

Создайте экземпляр модели

KerasNLP предоставляет реализации многих популярных модельных архитектур . В этом руководстве вы создадите экземпляр модели с помощью GemmaCausalLM , комплексной модели Gemma для моделирования причинного языка. Модель причинно-следственного языка прогнозирует следующий токен на основе предыдущих токенов.

Создайте экземпляр модели, используя метод from_preset :

gemma_lm = keras_nlp.models.GemmaCausalLM.from_preset("gemma2_instruct_2b_en")

Функция GemmaCausalLM.from_preset() создает экземпляр модели на основе предустановленной архитектуры и весов. В приведенном выше коде строка "gemma2_instruct_2b_en" определяет предустановленную модель Gemma 2 2B с 2 миллиардами параметров. Также доступны модели Gemma с параметрами 7В, 9В и 27В . Вы можете найти строки кода для моделей Gemma в списках вариантов моделей на Kaggle .

Используйте summary метод, чтобы получить больше информации о модели:

gemma_lm.summary()

Как видно из резюме, модель имеет 2,6 миллиарда обучаемых параметров.

Определить вспомогательные функции форматирования

from IPython.display import Markdown
import textwrap

def display_chat(prompt, text):
  formatted_prompt = "<font size='+1' color='brown'>🙋‍♂️<blockquote>" + prompt + "</blockquote></font>"
  text = text.replace('•', '  *')
  text = textwrap.indent(text, '> ', predicate=lambda _: True)
  formatted_text = "<font size='+1' color='teal'>🤖\n\n" + text + "\n</font>"
  return Markdown(formatted_prompt+formatted_text)

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

Создание чат-бота

Модель gemma2_instruct_2b_en настроенная на инструкции Gemma, точно настроена для понимания следующих жетонов хода:

<start_of_turn>user\n  ... <end_of_turn>\n
<start_of_turn>model\n ... <end_of_turn>\n

В этом руководстве эти токены используются для создания чат-бота. Дополнительную информацию о токенах управления Gemma см. в инструкциях по форматированию и системе .

Создайте помощник чата для управления состоянием разговора.

class ChatState():
  """
  Manages the conversation history for a turn-based chatbot
  Follows the turn-based conversation guidelines for the Gemma family of models
  documented at https://ai.google.dev/gemma/docs/formatting
  """

  __START_TURN_USER__ = "<start_of_turn>user\n"
  __START_TURN_MODEL__ = "<start_of_turn>model\n"
  __END_TURN__ = "<end_of_turn>\n"

  def __init__(self, model, system=""):
    """
    Initializes the chat state.

    Args:
        model: The language model to use for generating responses.
        system: (Optional) System instructions or bot description.
    """
    self.model = model
    self.system = system
    self.history = []

  def add_to_history_as_user(self, message):
      """
      Adds a user message to the history with start/end turn markers.
      """
      self.history.append(self.__START_TURN_USER__ + message + self.__END_TURN__)

  def add_to_history_as_model(self, message):
      """
      Adds a model response to the history with start/end turn markers.
      """
      self.history.append(self.__START_TURN_MODEL__ + message)

  def get_history(self):
      """
      Returns the entire chat history as a single string.
      """
      return "".join([*self.history])

  def get_full_prompt(self):
    """
    Builds the prompt for the language model, including history and system description.
    """
    prompt = self.get_history() + self.__START_TURN_MODEL__
    if len(self.system)>0:
      prompt = self.system + "\n" + prompt
    return prompt

  def send_message(self, message):
    """
    Handles sending a user message and getting a model response.

    Args:
        message: The user's message.

    Returns:
        The model's response.
    """
    self.add_to_history_as_user(message)
    prompt = self.get_full_prompt()
    response = self.model.generate(prompt, max_length=2048)
    result = response.replace(prompt, "")  # Extract only the new response
    self.add_to_history_as_model(result)
    return result

Чат с моделью

Начните общаться с моделью.

chat = ChatState(gemma_lm)
message = "Tell me, in a few words,  how to compute all prime numbers up to 1000?"
display_chat(message, chat.send_message(message))

🙋‍♂️

Расскажите в двух словах, как вычислить все простые числа до 1000?
🤖

Решето Эратосфена.

Продолжайте разговор.

message = "Now in Python! No numpy, please!"
display_chat(message, chat.send_message(message))

🙋‍♂️

Теперь на Python! Нет нумпи, пожалуйста!
🤖
def sieve_of_eratosthenes(n):
  """Returns a list of prime numbers up to n."""
  primes = [True] * (n + 1)
  primes[0] = primes[1] = False
  for i in range(2, int(n**0.5) + 1):
    if primes[i]:
      for j in range(i * i, n + 1, i):
        primes[j] = False
  return [i for i, is_prime in enumerate(primes) if is_prime]

primes = sieve_of_eratosthenes(1000)
print(primes)

Объяснение:

  1. Инициализация:

    • primes = [True] * (n + 1) : Создает список primes логических значений, первоначально предполагая, что все числа являются простыми.
    • primes[0] = primes[1] = False : устанавливает 0 и 1 как непростые.
  2. Итерация:

    • for i in range(2, int(n**0.5) + 1): : выполняет итерацию от 2 до квадратного корня из n . Нам нужно проверить только квадратный корень, потому что любое составное число должно иметь простой делитель, меньший или равный его квадратному корню.
    • if primes[i]: : Если i помечен как простое:
      • for j in range(i * i, n + 1, i): Помечает все числа, кратные i , как непростые.
  3. Результат:

    • return [i for i, is_prime in enumerate(primes) if is_prime] : Создает список индексов, где primes[i] имеет значение True, представляющее простые числа.

Дайте мне знать, если вам нужно более подробное объяснение какой-либо части!

message = "Thank you, it works! Can you explain the code in French?"
display_chat(message, chat.send_message(message))

🙋‍♂️

Спасибо, работает! Можете ли вы объяснить код на французском языке?
🤖

Бьен сюр! Объяснение кода на французском языке:

def sieve_of_eratosthenes(n):
  """Retourne une liste de nombres premiers jusqu'à n."""
  primes = [True] * (n + 1)
  primes[0] = primes[1] = False
  for i in range(2, int(n**0.5) + 1):
    if primes[i]:
      for j in range(i * i, n + 1, i):
        primes[j] = False
  return [i for i, is_prime in enumerate(primes) if is_prime]

primes = sieve_of_eratosthenes(1000)
print(primes)

Объяснение:

  1. Инициализация:

    • primes = [True] * (n + 1) : Создайте список primes чисел логических значений, инициализация предполагает, что все номера являются первыми.
    • primes[0] = primes[1] = False : определены 0 и 1 как непремьер-министры.
  2. Итерация:

    • for i in range(2, int(n**0.5) + 1): : Itère de 2 jusqu'à la racine carrée de n . Мы не уверены в том, что мы играем в расистскую машину, но все составные имена делают нас фактом премьер-министра или равным расовой карре.
    • if primes[i]: : Si i est считается как премьер:
      • for j in range(i * i, n + 1, i): : Отметьте все кратные i , которые не являются премьер-министрами.
  3. Результат:

    • return [i for i, is_prime in enumerate(primes) if is_prime] : Создан список индексов или простых чисел primes[i] est vrai, представляющий первые числа.

N'hésitez pas à me require si vous avez besoin d'une explication plus détailllée de quelque выбрал!

message = "Great! Now add those explanations as comments in the code."
display_chat(message, chat.send_message(message))

🙋‍♂️

Отлично! Теперь добавьте эти пояснения в виде комментариев в код.
🤖
def sieve_of_eratosthenes(n):
  """Retourne une liste de nombres premiers jusqu'à n."""
  # Initialise une liste de boolean avec True pour tous les nombres de 0 à n
  primes = [True] * (n + 1)
  # Définit 0 et 1 comme non-premiers
  primes[0] = primes[1] = False
  # Itère de 2 à la racine carrée de n
  for i in range(2, int(n**0.5) + 1):
    # Si i est considéré comme premier
    if primes[i]:
      # Itère sur tous les multiples de i
      for j in range(i * i, n + 1, i):
        # Définit les multiples de i comme non-premiers
        primes[j] = False
  # Retourne la liste des indices des nombres premiers
  return [i for i, is_prime in enumerate(primes) if is_prime]

primes = sieve_of_eratosthenes(1000)
print(primes)

Объяснение:

  • Инициализация:
    • primes = [True] * (n + 1) : Создайте список primes чисел логических значений, инициализация предполагает, что все номера являются первыми.
    • primes[0] = primes[1] = False : определены 0 и 1 как непремьер-министры.
  • Итерация:
    • for i in range(2, int(n**0.5) + 1): : Itère de 2 jusqu'à la racine carrée de n . Мы не проверяем, что мы играем в расистскую машину, но все составные имена делают нас первым фактом, нижним или равным расовой карре.
    • if primes[i]: : Si i est считается как премьер:
      • for j in range(i * i, n + 1, i): : Отметьте все кратные i , которые не являются премьер-министрами.
  • Результат:
    • return [i for i, is_prime in enumerate(primes) if is_prime] : Создан список индексов или простых чисел primes[i] est vrai, представляющий первые числа.

Проверьте сгенерированный ответ, запустив сгенерированный код:

def sieve_of_eratosthenes(n):
  """Retourne une liste de nombres premiers jusqu'à n."""
  # Initialise une liste de boolean avec True pour tous les nombres de 0 à n
  primes = [True] * (n + 1)
  # Définit 0 et 1 comme non-premiers
  primes[0] = primes[1] = False
  # Itère de 2 à la racine carrée de n
  for i in range(2, int(n**0.5) + 1):
    # Si i est considéré comme premier
    if primes[i]:
      # Itère sur tous les multiples de i
      for j in range(i * i, n + 1, i):
        # Définit les multiples de i comme non-premiers
        primes[j] = False
  # Retourne la liste des indices des nombres premiers
  return [i for i, is_prime in enumerate(primes) if is_prime]

primes = sieve_of_eratosthenes(1000)
print(primes)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]

Используйте метод get_history , чтобы увидеть, как весь контекст сохранился классом Chat .

print(chat.get_history())
<start_of_turn>user
Tell me, in a few words,  how to compute all prime numbers up to 1000?<end_of_turn>
<start_of_turn>model
**Sieve of Eratosthenes.** 
<end_of_turn><start_of_turn>user
Now in Python! No numpy, please!<end_of_turn>
<start_of_turn>model

```python
def sieve_of_eratosthenes(n):
  """Returns a list of prime numbers up to n."""
  primes = [True] * (n + 1)
  primes[0] = primes[1] = False
  for i in range(2, int(n**0.5) + 1):
    if primes[i]:
      for j in range(i * i, n + 1, i):
        primes[j] = False
  return [i for i, is_prime in enumerate(primes) if is_prime]

primes = sieve_of_eratosthenes(1000)
print(primes)
```

**Explanation:**

1. **Initialization:**
   - `primes = [True] * (n + 1)`: Creates a list `primes` of boolean values, initially assuming all numbers are prime.
   - `primes[0] = primes[1] = False`: Sets 0 and 1 as non-prime.

2. **Iteration:**
   - `for i in range(2, int(n**0.5) + 1):`: Iterates from 2 to the square root of `n`. We only need to check up to the square root because any composite number must have a prime factor less than or equal to its square root.
   - `if primes[i]:`: If `i` is marked as prime:
     - `for j in range(i * i, n + 1, i):`: Marks all multiples of `i` as non-prime.

3. **Result:**
   - `return [i for i, is_prime in enumerate(primes) if is_prime]`: Creates a list of indices where `primes[i]` is True, representing the prime numbers.


Let me know if you'd like a more detailed explanation of any part! 
<end_of_turn><start_of_turn>user
Thank you, it works! Can you explain the code in French?<end_of_turn>
<start_of_turn>model
Bien sûr ! Voici une explication du code en français :

```python
def sieve_of_eratosthenes(n):
  """Retourne une liste de nombres premiers jusqu'à n."""
  primes = [True] * (n + 1)
  primes[0] = primes[1] = False
  for i in range(2, int(n**0.5) + 1):
    if primes[i]:
      for j in range(i * i, n + 1, i):
        primes[j] = False
  return [i for i, is_prime in enumerate(primes) if is_prime]

primes = sieve_of_eratosthenes(1000)
print(primes)
```

**Explication:**

1. **Initialisation:**
   - `primes = [True] * (n + 1)`: Crée une liste `primes` de valeurs booléennes, initialement supposant que tous les nombres sont premiers.
   - `primes[0] = primes[1] = False`: Définit 0 et 1 comme non-premiers.

2. **Itération:**
   - `for i in range(2, int(n**0.5) + 1):`: Itère de 2 jusqu'à la racine carrée de `n`. Nous ne devons vérifier que jusqu'à la racine carrée car tout nombre composite doit avoir un facteur premier inférieur ou égal à sa racine carrée.
   - `if primes[i]:`: Si `i` est considéré comme premier:
     - `for j in range(i * i, n + 1, i):`:  Marquer tous les multiples de `i` comme non-premiers.

3. **Resultat:**
   - `return [i for i, is_prime in enumerate(primes) if is_prime]`: Crée une liste des indices où `primes[i]` est vrai, représentant les nombres premiers.


N'hésitez pas à me demander si vous avez besoin d'une explication plus détaillée de quelque chose! 
<end_of_turn><start_of_turn>user
Great! Now add those explanations as comments in the code.<end_of_turn>
<start_of_turn>model

```python
def sieve_of_eratosthenes(n):
  """Retourne une liste de nombres premiers jusqu'à n."""
  # Initialise une liste de boolean avec True pour tous les nombres de 0 à n
  primes = [True] * (n + 1)
  # Définit 0 et 1 comme non-premiers
  primes[0] = primes[1] = False
  # Itère de 2 à la racine carrée de n
  for i in range(2, int(n**0.5) + 1):
    # Si i est considéré comme premier
    if primes[i]:
      # Itère sur tous les multiples de i
      for j in range(i * i, n + 1, i):
        # Définit les multiples de i comme non-premiers
        primes[j] = False
  # Retourne la liste des indices des nombres premiers
  return [i for i, is_prime in enumerate(primes) if is_prime]

primes = sieve_of_eratosthenes(1000)
print(primes)
```

**Explication:**

* **Initialisation:**
    * `primes = [True] * (n + 1)`:  Crée une liste `primes` de valeurs booléennes, initialement supposant que tous les nombres sont premiers.
    * `primes[0] = primes[1] = False`: Définit 0 et 1 comme non-premiers.
* **Itération:**
    * `for i in range(2, int(n**0.5) + 1):`: Itère de 2 jusqu'à la racine carrée de `n`. Nous ne devons vérifier que jusqu'à la racine carrée car tout nombre composite doit avoir un facteur premier inférieur ou égal à sa racine carrée.
    * `if primes[i]:`: Si `i` est considéré comme premier:
        * `for j in range(i * i, n + 1, i):`:  Marquer tous les multiples de `i` comme non-premiers.
* **Resultat:**
    * `return [i for i, is_prime in enumerate(primes) if is_prime]`: Crée une liste des indices où `primes[i]` est vrai, représentant les nombres premiers. 



<end_of_turn>

Резюме и дальнейшее чтение

В этом уроке вы узнали, как общаться с настроенной моделью Gemma 2B, используя Keras на JAX.

Ознакомьтесь с этими руководствами и учебными пособиями, чтобы узнать больше о Джемме: