«Не вижу прайс», "Нет исходных данных" - и все это в одном чате. Или зачем я сделал двойную память для своего ИИ-ассистента.
Пользователь задаёт уточняющий вопрос на 45-м сообщении, а #бот отвечает «не вижу сумму» или начинает галлюцинировать.
Причина банальна: лимит токенов обрезает историю, а векторный поиск теряет последовательность.
Я потратил пару месяцев на отладку и пришёл к архитектурному решению, которое реально работает в проде: разделил память на два независимых контура. Оперативная "STM" держит нить диалога, долгосрочная "MNEMOS" - про нее я уже писал ранее накапливает опыт между сессиями.
Вместе они убирают 90% проблем с потерей контекста и снижают количество правок вручную.
Почему одной памяти недостаточно
Долгосрочная база знаний отлично справляется с задачей «учиться на всех диалогах». Но внутри одного треда из 50 и более сообщений возникает классическая проблема character limit:
- Прайс-лист загружается в начале диалога, но на 20-м сообщении выпадает из окна контекста
- Векторная БД ищет смысл, а не порядок. Ассистент путается в датах и позициях.
- Результат: «какой курс?», «опишите подробнее», «не вижу сумму». Это не баги модели, это архитектурный пробел.
MNEMOS про это не знает — он оперирует Q&A-парами и тематическими коллекциями. Для оперативной памяти внутри треда нужна отдельная система. Я назвал её STM.
Как устроена двойная архитектура
Решение строится на трёх слоях оперативной памяти, которые собираются в единый промпт перед каждым вызовом LLM:
Слой 1: Якоря вместо автосохранений
Якорь — это короткая заметка, которая всегда висит в system_prompt. Она содержит текущую тему диалога и ключевые данные. Система ставит их автоматически:
- каждые ~3000 символов (страховка);
- при резкой смене темы (основной триггер);
- при обновлении данных (после расчётов или поиска).
Это не просто метки, а save points. Если #контекст потеряется из-за лимита, STM найдёт ближайший якорь и восстановит нить. Чем чаще якоря — тем меньше потеря информации.
Слой 2: Порядок важнее семантики
Для истории диалога важна именно хронология, а не смысловое сходство. Поэтому я использую прямой SQL-запрос к таблицеchat_history: берём последние N строк, сканируем назад и обрезаем ровно по лимиту токенов. Это гарантирует, что пользователь видит логичную последовательность без «провалов» в середине треда.
Слой 3: Интеллектуальный поиск внутри треда
Когда пользователю нужно уточнить данные, которые выпали из окна, LLM не гадает. Она пишет маркер SEARCH_HISTORY: ЛДСП цена.
Парсер перехватывает его, делает мгновенный #sql LIKE-поиск по всей истории диалога и инжектит найденные строки обратно в промпт для второго прохода модели.
Почему SQL, а не векторы?Для таблицы на 100–500 строк запрос выполняется за 1–5 мс. Никакого оверхеда индексов, никакой потери точности. Полностью покрывает потребность в поиске по текущему треду.
Чем это отличается от MemGPT и Letta
Аналоги оперируют единой моделью памяти (core/archival/recall) с ручным управлением жизненным циклом. Мой подход строже:
-Разделение ответственности:STM очищается при смене треда (контекст месяца давности не нужен в новом чате). MNEMOS живёт вечно.
-Авто-размещение якорей: Не требует ручной настройки agent'а. Триггеры работают по длине, смене темы и обновлению данных.
Что это даёт клиентам и бизнесу
Переход на двойную память дал измеримый эффект в продакшене:
-Снижение доли «человек в контуре»: Ассистент сам достает данные из истории, не спрашивает повторных уточнений и не галлюцинирует на цифрах.
-Стабильность сложных расчётов: Прайс-листы, курсы валют и спецификации теперь фиксируются в якорях и сохраняются до конца сессии.
-Экономия времени поддержки: Цикл самообучения (Sufler → fail → ЛИКБЕЗ) сокращает время на дообучение моделей. Ошибки не повторяются, потому что система хранит антипаттерны и подтягивает верные примеры.
Для разработчика это значит меньше дебага контекстных окон и предсказуемый аптайм ассистента. Для бизнеса — стабильное качество ответов без роста стоимости поддержки.
Архитектура включает модули
microgoals.py, chat_history.py, experience_bank/ ,research.py и кастомный ассемблер промптов.
Выводы: Разделение памяти на оперативный и долгосрочный контуры устраняет главную слабость стандартного RAG — потерю контекста внутри длинных диалогов. Готовая архитектура снижает количество галлюцинаций, ускоряет ответы и сокращает затраты на ручную корректировку.
Полный разбор архитектуры, схемы взаимодействия доступны в моей серии статей: 3.STM + МНЕМОС: двойная память AI-ассистента
Если вы уже экспериментировали с dual-memory в проде или сталкивались с проблемами очистки состояния — делитесь опытом в комментариях.
Какие триггеры для якорей работали стабильнее всего на ваших проектах?
Где SQL LIKE начал тормозить, а где векторы оказались избыточны?