Память чат-бота: реализуйте свой собственный алгоритм с нуля

Память чат-бота: реализуйте свой собственный алгоритм с нуля

2 ноября 2024 г.

Введение

Есть одна проблема при реализации собственного чат-бота, и это управление памятью во время разговора. Конечно, вы можете использовать готовые библиотеки, такие как 'Langchain', 'Ollama' и т. д... Но что, если вы хотите реализовать свой собственный алгоритм с нуля?


Мы представляем здесь подход к управлению кратковременной памятью в чат-ботах, используя комбинацию методов хранения и автоматического резюмирования для оптимизации разговорного контекста. Представленный метод опирается на динамическую структуру памяти, которая ограничивает размер данных, сохраняя при этом важную информацию с помощью интеллектуальных резюмирований.


Такой подход не только улучшает текучесть взаимодействий, но и обеспечивает контекстную непрерывность во время длительных сеансов диалога. Более того, использование асинхронных методов гарантирует, что операции управления памятью не будут мешать отзывчивости чат-бота.

Математическое моделирование управления разговором

В этом разделе мы математически формализуем управление памятью разговора в чат-боте. Память структурирована как список пар, представляющих обмены между пользователем и ботом.


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

Структура памяти разговора

Память разговора можно определить как упорядоченный список пар (u_i, d_i), где u_i представляет собой ввод пользователя, а d_i — ответ бота для i^th обмена. Этот список обозначается как C:


C = [(u1, d1), (u2, d2), ..., (un, dn)]


Где n — общее количество обменов в текущей истории.

Обновление памяти

При возникновении нового обмена в память добавляется новая пара (u_{n+1}, d_{n+1}). Если размер C превышает предопределенный максимальный предел M_max, самый старый обмен удаляется:


C = if |C| < M_max:
  C ∪ {(u_{n+1}, d_{n+1})} 
else:
  (C \\ {(u1, d1)}) ∪ {(u_{n+1}, d_{n+1})}

Количество слов

Чтобы управлять пространством памяти и решать, когда необходимо сжатие, мы вычисляем общее количество слов W(C) в памяти:


W(C) = Σ (|ui| + |di|)


Где |ui| и |di| — количество слов в ui и di соответственно.

Сжатие памяти

Когда W(C) превышает пороговое значение W_max, память сжимается для сохранения релевантного контекста. Это сжатие выполняется моделью резюмирования S, такой как BART:


C_сжатый = S(C)


Где C_compressed — это обобщенная версия памяти, сокращающая общее количество слов, но сохраняющая суть прошлых взаимодействий.

Реализация кода для управления памятью чат-бота

В этом разделе мы рассмотрим пример кода Python, иллюстрирующий управление памятью в чат-боте. Код использует PyTorch и трансформеры Hugging Face для управления и сжатия истории разговора.

Настройка среды

Начнем с проверки доступности графического процессора, что позволит при необходимости ускорить обработку.

import torch from transformers import pipeline import logging

if torch.cuda.is_available():
  device: int = 0 
else: 
  device: int = -1

MAX_MEMORY_SIZE: int = 2000


Определение класса ChatbotMemory

Класс ChatbotMemory управляет историей разговоров и выполняет операции обновления и сжатия. Каждый раз, когда вызывается update_memory, текст памяти подсчитывается и обрабатывается по мере необходимости.


class ChatbotMemory: 
def init(self, conv: list = []): 
  self.conversation_history = conv

def update_memory(self, user_input: str, bot_response: str) -> None:
    self.conversation_history.append(f"'user': {user_input}, 'bot': {bot_response}")

    if memory_counter(self.conversation_history) > 1000:
        self.conversation_history = compressed_memory(self.conversation_history)
        logging.info("Memory compressed.")

    if len(self.conversation_history) > MAX_MEMORY_SIZE:
        self.conversation_history.pop(0)
        logging.info("Memory reduced.")
    return 0

def get_memory(self):
    return self.conversation_history

Сжатие памяти и подсчет

Функция _get_compressed_memory использует модель BART для обобщения истории разговоров.

def _get_compressed_memory(sentence: str) -> str:
  summarizer = pipeline("summarization", model="facebook/bart-large-cnn", device=device) 
  summary = summarizer(sentence, max_length=50, min_length=5, do_sample=False) 
  return summary[0]['summary_text']


Функция compress_memory применяет функцию _get_compressed_memory к каждому сегменту истории разговора. Это оптимизируется путем обработки партиями. Этот метод отделен от _get_compressed_memory, чтобы обеспечить введение новых методов сжатия.

def compressed_memory(conv_hist: list) -> list:
  return [_get_compressed_memory(' '.join(conv_hist[i:i+5])) for i in range(0, len(conv_hist), 5)]


Функция memory_counter подсчитывает общее количество слов в истории. (Обратите внимание, что может быть интересно выполнить этот шаг с токенами вместо слов.)

def memory_counter(conv_hist: list) -> int:
  st = ''.join(conv_hist) 
  return len(st.split())

Заключение

Этот код устанавливает эффективную структуру для управления памятью в чат-боте, используя методы сжатия для поддержания релевантного контекста и повышения общей производительности системы. Использование моделей резюмирования, таких как BART, гарантирует, что даже при сжатии памяти сохраняется существенный контекст.


Надеюсь, эта небольшая демонстрация помогла вам понять, что моделировать общие процессы и внедрять их в код довольно просто. Это базовый, но важный шаг, который позволяет вам понять, как все работает:


  • 1: Я определяю все шаги действия
  • 2: Я моделирую их математически
  • 3: код!

Код на GitHub


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE