English translation is not available yet. Showing Russian content.
Настроить recurrent memory для long context
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить recurrent memory для long context
1. Цель задачи
Реализовать механизм рекуррентной памяти для LLM, который позволяет модели сохранять важные факты между сессиями диалога без внешней RAG-системы. Память должна обновляться после каждого сеанса и встраиваться в контекст при старте нового. Ключевой результат Рабочий прототип чат-бота, способного запоминать информацию о пользователе на протяжении нескольких сессий (до 10+ фактов) и корректно отвечать на запросы, требующие этих знаний, с точностью не ниже 80%.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Предобученная генеративная модель (LLM) | Hugging Face Hub, например gpt2 или meta-llama/Llama-2-7b-hf |
| Тестовые диалоговые сценарии для проверки памяти | Составить самому (минимум 5 сессий по 2-5 реплик) |
| Датасет для оценки (опционально, например, bAbI) | https://research.facebook.com/downloads/[babi](/wiki/bAbI)/ или синтезировать |
| Среда разработки с GPU (Colab / локальная) | Локальная машина / Google Colab Pro |
| Библиотеки: PyTorch, transformers, numpy, pytest | Установить через pip |
Если нет возможности запустить большую модель — симулируем:
- Используем GPT-2 (small) — она достаточно легковесна.
- Если нет GPU — работаем на CPU (инференс будет медленным, но для тестов достаточно).
- Memory-модуль можно тестировать отдельно от LLM, подавая на вход эмбеддинги из sentence-transformers.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Язык и фреймворк | Python 3.10+, PyTorch 2.0+ | Реализация модуля памяти и интеграции |
| Работа с моделями | Hugging Face transformers | Загрузка и инференс LLM |
| Векторные представления | Sentence Transformers, PyTorch | Кодирование текста для памяти |
| Тестирование | pytest, unittest | Юнит-тесты модуля памяти |
| Логирование и мониторинг | wandb / просто принты | Отслеживание качества запоминания |
| Версионирование | Git + DVC (опционально) | Хранение данных и кода |
4. Этапы выполнения
Этап 1: Исследование и проектирование архитектуры памяти (1–2 часа)
Действия
- Изучите три подхода к долгосрочной памяти без RAG:
- Memory Networks (Sukhbaatar et al., 2015) — явная память с вниманием.
- Transformer-XL / Compressive Transformer — рекуррентные скрытые состояния.
- Recurrent Memory — GRU/LSTM поверх эмбеддингов диалога.
- Выберите один подход для реализации. Рекомендация гибрид — кодировать каждую сессию в вектор через GRU, хранить пул таких векторов, а при новом сеансе выбирать top-k по косинусной близости и вставлять в промпт.
- Нарисуйте схему data flow:
- Пользовательский ввод → LLM → ответ.
- После сессии: конкатенация всего диалога → кодирование GRU → обновление памяти.
- Перед новой сессией: поиск похожих векторов памяти → конвертация в текст → вставка в system prompt.
Ожидаемый результат этапа Документ (markdown) с выбором подхода, схемой и расчётом необходимого размера памяти (например, 512 dim, 10 слотов).
Этап 2: Реализация модуля рекуррентной памяти (2–3 часа)
Действия
- Создайте класс
RecurrentMemory:class RecurrentMemory(nn.Module): def __init__(self, input_dim=768, hidden_dim=512, num_slots=10): super().__init__() self.encoder = nn.GRU(input_dim, hidden_dim, batch_first=True) self.memory = nn.Parameter(torch.zeros(num_slots, hidden_dim)) self.num_slots = num_slots def update(self, sequence_embeds): # [batch, seq_len, input_dim] # seq_embeds == эмбеддинги предложений сессии _, h_n = self.encoder(sequence_embeds) # h_n: [1, batch, hidden_dim] new_mem = h_n.squeeze(0) # [batch, hidden_dim] # Заменяем самый старый слот (простая очередь) self.memory = torch.roll(self.memory, shifts=-1, dims=0) self.memory[-1] = new_mem.detach() return self.memory def retrieve(self, query_embed, k=3): # query_embed: [1, hidden_dim] (кодировка начала новой сессии) scores = F.cosine_similarity(query_embed, self.memory, dim=-1) topk_indices = scores.topk(k).indices return self.memory[topk_indices] - Напишите юнит-тесты:
test_update_slots— проверка, что после 12 обновлений заполнились все слоты.test_retrieve_returns_topk— проверка, что retrieve возвращает правильное количество.test_memory_persistence— память сохраняется между вызовами.
Ожидаемый результат этапа Файл memory_module.py с классом RecurrentMemory и набором тестов (все проходят).
Этап 3: Интеграция памяти с LLM (1–2 часа)
Действия
- Загрузите модель LLM (например, GPT2LMHeadModel from transformers).
- Напишите функцию chat_with_memory(user_input, memory, model, tokenizer):
- Если memory содержит слоты → декодируем top-3 воспоминания в текст (через предобученный декодер или просто храним сам текст).
- Формируем system prompt:
"You have the following memories: {memories}. User says: {input}". - Генерируем ответ.
- После окончания сессии (по команде
/endили timeout) вызываем memory.update(embeddings_of_session).
- Реализуйте простой CLI-чат, который запускает сессии (каждая сессия — последовательность реплик).
- Сохраняйте состояние памяти на диск (pickle) между запусками программы.
Ожидаемый результат этапа Скрипт chat_memory.py, который можно запустить, проверить сохранение факта через сессии.
Этап 4: Тестирование долгосрочной памяти (1–2 часа)
Действия
- Составьте набор тестовых сценариев (не менее 5):
- Сценарий A Сессия 1: "My name is Alice." / Сессия 2: "What is my name?" → должен ответить "Alice".
- Сценарий B Сессия 1: "I work at Google." / Сессия 2: "Where do I work?" → "Google".
- Сценарий C Пересечение: "I like pizza." / Сессия 3: "What is my favorite food?" → "pizza".
- Сценарий D Множественные факты: 3 факта за 1 сессию, проверка в сессии 5.
- Сценарий E Конфликт: в сессии 2 меняется факт (например, "I changed my name to Bob"), проверка, что новая информация перезаписывает старую.
- Для каждого сценария записывайте:
- Запустите тесты 5 раз для оценки стабильности.
Ожидаемый результат этапа Отчёт test_report.md с таблицами результатов и графиком accuracy.
Этап 5: Бенчмаркинг и сравнение с RAG-подходом (1 час)
Действия
- Реализуйте простую RAG-альтернативу: те же факты хранятся в ChromaDB, поиск по косинусной близости query-эмбеддинга.
- Сравните по трём метрикам:
- Сформируйте сравнительную таблицу.
- Напишите вывод: в каких сценариях recurrent memory предпочтительнее RAG (например, низкий latency, приватность, offline).
Ожидаемый результат этапа Файл benchmark.pdf или benchmark.md с таблицей и выводами.
5. Критерии приемки (Definition of Done)
- Реализован модуль
RecurrentMemoryс методамиupdateиretrieve. - Модуль покрыт unit-тестами (минимум 3 теста, все проходят).
- Интегрированный чат-бот способен запомнить и извлечь до 10 независимых фактов из прошлых сессий.
- Accuracy на тестовом наборе сценариев ≥ 80%.
- Время инференса (с учётом памяти) не более 2x от baseline (без памяти).
- Память сохраняется между перезапусками программы (сериализация/десериализация).
- Создан отчёт с тестированием и сравнением с RAG.
- Код выложен в Git-репозиторий с README и инструкцией по запуску.
6. Ожидаемый результат
Основной артефакт Репозиторий со следующей структурой:
├── memory_module.py # класс RecurrentMemory
├── chat_memory.py # CLI-чат с интеграцией
├── tests/
│ ├── test_memory.py # unit-тесты
│ └── test_scenarios.py # end-to-end сценарии
├── report.md # отчёт тестирования и бенчмарк
├── requirements.txt
└── README.md
Содержимое отчёта accuracy по 5 сценариям, среднее время генерации, сравнение с RAG.
Опциональные дополнительные результаты
- Код для визуализации заполнения слотов памяти (matplotlib).
- Веса обученного memory encoder (если обучение было).
- Демо-видео работы чат-бота.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Модель не следует инструкциям из system prompt | Использовать более свежие модели (GPT-2 слаб в следовании инструкциям); перейти на Llama-2-7b или GPT-3.5 API; добавить fine-tuning на паре примеров. |
| Память не обновляется (застревает) | Убедитесь, что update вызывается только после завершения сессии; используйте детерминированное кодирование (GRU с seed). |
| Большое потребление памяти при многих сессиях | Ограничьте число слотов (например, 10) и используйте FIFO; рассмотрите сжатие через MLP. |
| Сложность выбора k при retrieve | Экспериментально подберите k (рекомендация: 3); можно автоматически по порогу cosine similarity > 0.7. |
| Медленный инференс из-за кодирования GRU | Используйте batch-кодирование; перенесите GRU на GPU; для небольших тестов CPU подойдёт. |
| Текстовая декодировка памяти | Храните в памяти не только эмбеддинги, но и краткое текстовое описание (суммаризацию каждой сессии). |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| 1. Исследование и проектирование | 1–2 ч |
| 2. Реализация модуля памяти | 2–3 ч |
| 3. Интеграция с LLM | 1–2 ч |
| 4. Тестирование долгосрочной памяти | 1–2 ч |
| 5. Бенчмаркинг и сравнение с RAG | 1 ч |
| Итого | 6–10 ч |
Примечание При первом выполнении возможны задержки на отладку и переключение между этапами — рекомендуем заложить +20% времени.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 42 | Что такое RAG и когда его использовать |
| 57 | Настройка recurrent memory (текущее ТЗ) |
| 123 | Архитектура Transformer-XL |
| 45 | Рекуррентные нейронные сети (RNN, GRU, LSTM) |
| 89 | Longformer и большие контексты |
| 234 | Memory Networks (Sukhbaatar) |
| 56 | Как увеличить effective context length |
| 78 | Self-attention и position encoding |
| 301 | Метрики качества для диалоговых систем |
| 145 | Knowledge distillation для сжатия памяти |
10. Чек-лист самопроверки
- Я реализовал класс
RecurrentMemoryс методамиupdateиretrieve, и все юнит-тесты проходят. - Я протестировал чат-бота на 5 сценариях и получил accuracy ≥ 80%.
- Я убедился, что память сохраняется между сессиями (факт из сессии 1 доступен в сессии 3).
- Я сравнил своё решение с RAG-подходом и зафиксировал метрики.
- Я написал отчёт и разместил код в Git-репозиторий с README.