Память LLM: мой подход
viktorproggerDisclaimer: описание составлено спонтанно и немного сумбурно, за что прошу прощения. Если будет интересно - перепишу более корректно и полно.
Я довольно долго, хоть и с перерывами, занимаюсь одним любопытными проектом: памятью для LLM. Потому что считаю, что LLM способны на гораздо большее за существенно меньшие деньги.
Начну с самого интересного: что она принесет.
Кратко: самообучающиеся LLM будут не нужны, если у них появится долговременная память. Это переводит LLM из разряда бездушных предсказателей токенов в полноценные ассистенты вроде Джарвиса в "Железном человеке": они будут знать ваши привычки, состояние здоровья, предпочтения. Смогут развивать собственную личность и взаимоотношения с людьми, если захотите.
Само собой, это если я смогу довести ее до полностью рабочего состояния 😄
А теперь - по порядку.
Для исторической справки - вот основные подходы к созданию памяти LLM
Часть скучная и нудная, за мякоткой стоит пролистать дальше.
1. In-memory, он же - "контекстное окно". Весь диалог пересылается LLM при каждом новом сообщении. Это стандарт индустрии, присутствует начиная с самых примитивных версий Chatgpt и до новейших harness агентов.
2. RAG. Можно взять огромный документ, разбить его на небольшие кусочки текста, по каждому кусочку построить числовой вектор, отражающий направленность смысла этой части, и при запросе пользователя сравнивать вектор запроса с векторами документов. Так мы получаем из БД части текста, максимально близкие по смыслу к вопросу пользователя. Но это не память в буквальном понимании этого слова. Скорее доступ к библиотеке, но с кучей оговорок и условностей.
3. Текстовый поиск по файлам (привет, OpenClaw) и БД (привет, Hermes). Мне кажется очевидным, что с ростом объема данных у такой памяти начнется деменция. Но надо подождать ещё как минимум полгода, прежде чем эта проблема станет очевидной в массах.
4. memGPT. Интересный концепт, но во главе угла стоит LLM: она принимает все решения: когда записать в память, когда что оттуда достать, какой слой памяти использовать. Это даёт низкую точность, низкую скорость и высокую стоимость.
5. Менее популярные опенсорс-проекты. Основное отличие всего, что я видел - снова все строится вокруг LLM, где она должна принимать решения. Самое интересное на первый взгляд - это мемзеро (mem-0): они используют связку из KV-хранилища, векторной БД и графовой БД. Но, как оказалось, у них есть та же болячка: они просто собирают данные и на авось скармливают LLM, получая на выходе просто набор текста, векторов и примитивный граф связей. Хотя разработчики под эту систему даже денег на YCombinator подняли.
6. Самое неинтересное - продукты за закрытыми дверями: openai, google и пр. Никто не знает, что и как они внедряют, но вроде что-то делают.
Итак, я пришел к выводу, что можно и лучше, и в опенсорсе. Но что же именно?
Главная идея - что память агента должна работать схожим с человеческой образом. То есть:
- Должна быть активна всегда: перед получением ответа надо достать воспоминания, а все, что попало на вход от пользователей - запомнить. Это не опция и не выбор.
- Выстраивать ассоциативные связи.
- Со временем и количеством должна помогать лучше, а не хуже.
- Понимать текущий контекст как в примитивных случаях (связный диалог на одну тему), так и в комплексных (10+ участников, несколько параллельных тем обсуждения, частые отсылки местоимениями или по временным меткам, включая "когда произошло Х").
Для этого я реализовал несколько подходов, схожих с памятью человека:
- понимание текущего контекста по одному сообщению и метаданным
- затухание неиспользуемых связей с усилением активных
- дедупликация сущностей и их разделение (несколько копий одной сущности с разными названиями vs несколько разных сущностей с одним названием)
- разрешение анафор ("оно того стоило?")
- фоновая обработка данных (аналог сна у человека: более глубокий анализ накопленного за день)
Возможно, есть что-то ещё, что я не вспомнил сразу.
Основной сценарий использования - ассистент, который всегда рядом: в чате на телефоне и компьютере, во время разработки, через микрофоны дома и на работе, мидлварью во время телефонных разговоров...
Поэтому ещё один плюс - приватность из коробки: LLM не получит воспоминания, недоступные кому-то из присутствующих в чате. Ее можно будет использовать и в корпоративном сегменте, и у себя дома.
Сложности
- В первую очередь - внедрение. Агент, использующий такую память, должен уметь с ней работать: LLM учили, что она всегда находится в контексте диалога с пользователем. Другие сценарии использования ее "ломают". Но, допустим, как запущу память - так и агента соответствующего сделаю 😁 Это куда проще задача. Уже в каком-то смысле начата.
- Не получится забубенить тонну информации. Это не RAG, это память для ассистента а-ля человеческая. Для поиска по книгам и документам надо использовать соответствующий инструмент. То же и про вычисление по структурным данным (таблицы, счета, программный код и т.п.).
- Неизвестно, как она поведет себя на объемах данных в миллионы сообщений и больше. Я начал писать тестовый датасет чата на пару тысяч сообщений, и уверен, что с ним проблем не возникнет: только найдутся баги, которые можно исправить. Это даёт гарантию на работу с десятками тысяч сообщений и хорошую уверенность с сотнями тысяч. Что же будет дальше - увидим только на практике. В какой-то момент нужно будет включать шардирование. А еще наберут огромный вес "божественные узлы": например, в нашем чате "программирование" и PHP будут иметь невероятное количество связей, но грузить все эти ассоциации на каждый запрос бессмысленно. На небольших объемах отфильтровать лишнее намного проще.
- Система сильно полагается на временные связи. Это значит, что для нормальной обработки последовательного текста все равно надо подавать сообщения по одному, при желании проставив явные временные метки.
- Пока что она медленная. Когда основные датасеты будут стабильно проходить - займусь оптимизацией, и смогу сильно сократить как минимум "горячий путь" (когда сообщение приходит прямо в чате; "холодный" - это постобработка накопленных данных)
Чем это решение лучше других
Описанное полагается в первую очередь на математику: считаем косинусное сходство и центроиды векторов, увеличиваем и уменьшаем веса графовых связей, запоминаем не "важное" по мнению LLM, а повторяемое. LLM тоже используется: для переводов (я сначала все перевожу на английский для унификации), извлечения сущностей (NER) и определения интента (есть смысл в сообщении или нет). Плюс более сложные сценарии в "ночном режиме" тоже требуют принятия сложных решений. Сейчас я для всего беру gpt-4o-mini, а потом можно будет в некоторых сценариях использовать специализированные быстрые решения (например, GLiNER).
Что дальше?
- Сейчас я пишу большой датасет в виде лога чата, растянутого на 2-3 года и состоящего из пары тысяч сообщений. Это позволит проверить память абсолютно во всех возможных сценариях. Когда он будет целиком проходить все тесты - можно будет сказать, что эта память на 100% рабочая.
- Написание первых агентов. Разные задачи требуют разного агентского окружения. Я бы даже сказал, разные субличности. Поэтому 1 агент будет просто отвечать в чате, другой - кодить, третий - разбирать файлы и строить аналитические отчеты. И у всех у них будет единая память и единая базовая личность. Под нее я пока хочу сделать домовенка Кузю, кстати 😄