Память клиента для ИИ-агентов при строгом лимите токенов
Как слой памяти агента извлекает факты, оценивает их важность, устраняет дубликаты с использованием косинусного коэффициента 0,92, хранит векторы в pgvector и выполняет поиск в пределах лимита в 2 048 токенов с механизмом удаления старых данных.
Источники: Engineering a Multi-Agent AI Platform — Part 6: Memory Under Token Constraints
Агент поддержки общается с клиентом, и вся необходимая информация должна помещаться в одно окно контекста. GPT-4o предлагает 128 тыс. токенов, тогда как более мелкие модели могут иметь всего 32 тыс. токенов или меньше. В это окно должны входить системные указания, определения инструментов, полученные знания, текущий диалог и всё, что агент помнит о конкретном клиенте. В этом тексте описывается конструкция памяти для такой схемы: как факты из завершённых разговоров извлекаются, оцениваются, удаляются дубликаты, сохраняются в виде векторов и снова загружаются при соблюдении строгого лимита токенов.
Окно контекста — это бюджет, а не бесконечный резервуар
Все известные сведения о клиенте помещаются в системные указания, из-за чего остальные данные вынуждены умещаться в ограниченном пространстве. Получение знаний становится неполным, история разговоров сокращается, а системные указания могут отодвигаться настолько далеко назад, что модель теряет нить собственных инструкций.
Если ничего не указывать, агент рассматривает каждый чат как первую встречу. Клиент, спрашивающий о времени встречи, получает ответ «У меня нет этой информации», хотя он указал её ещё в прошлый вторник.
Выход из этой ситуации — установление фиксированного лимита на память клиента. В описанной здесь схеме этот лимит составляет 2 048 токенов. В рамках этого лимита система сохраняет те факты, которые наиболее важны для данного клиента в текущем разговоре. Не все факты, не случайные, а только те, что действительно нужны.
Извлечение фактов из завершённых разговоров
После окончания разговора проходит процесс обработки, направленный на поиск фактов, которые стоит сохранить. Для извлечения информации используется большая языковая модель (GPT-4o-mini) с структурированным запросом, в котором задаётся вопрос о том, какую фактическую информацию о клиенте можно получить, а также требуется оценить каждый факт от 0 до 1 по критериям конкретности, практической применимости и частоты возникновения.
Ключевое слово — «конкретный». Факты должны описывать именно этого клиента, а не содержать общие замечания. «Предпочитает утренние встречи» — это факт. «Задал вопрос» — нет.
Модель отвечает массивом JSON, в котором каждый элемент содержит строку текста и оценку важности. Система пропускает только те факты, оценка которых составляет не менее 0,5. Этот порог позволяет исключить незначимые замечания, оценка которых обычно находится в диапазоне 0,2–0,3, и сохранять всё, что может пригодиться позже.
В типичном обмене десятью сообщениями получается от двух до четырех подходящих фактов, а в длительной сессии по устранению проблем — от шести до восьми. В большинстве разговоров выделяется хотя бы один факт.
Что отражает оценка важности
Это единственное число от 0,0 до 1,0 учитывает три критерия.
- Конкретность. Насколько конкретно данное утверждение относится к этому клиенту? Утверждение «Предпочитает электронную почту телефону» является конкретным, тогда как «Является клиентом» — нет.
- Практическая польза. Может ли сотрудник использовать это для лучшего ответа в следующий раз? Утверждение «Имеет постоянную проблему с счетом №4821» подходит, в то время как «Поздоровался» — нет.
- Повторяемость. Будет ли это важно в нескольких разговорах? Информация о часовом поясе UTC+3 упоминается каждый раз при планировании, но вопрос о погоде сегодня возникает лишь один раз.
Команда, разрабатывавшая эту систему, пробовала присваивать отдельные оценки по каждому критерию и обнаружила, что смешанная оценка позволяет лучше калибровать результаты и сохранять простоту формулировок. По их оценкам, порог в 0,5 позволяет исключить примерно 60% извлеченных фактов, оставляя только наиболее значимые.
Эмбеддинги и контроль дубликатов
Каждый сохранившийся факт представлен в виде 3072-мерного вектора, что соответствует размеру выходных данных используемой модели эмбеддинга — OpenAI text-embedding-3-large. Большее количество измерений позволяет более точно определять степень сходства, что критически важно при необходимости отличить перефразированную информацию от по-настоящему новых данных.
Перед сохранением нового факта он сравнивается со всеми существующими фактами у данного клиента. Косинусное сходство выше 0.92 означает «дубликат, пропустить».
Почему именно это число? Люди могут выразить одну и ту же мысль по-разному. Фразы вроде «предпочитает общение по электронной почте», «хочет, чтобы с ним связывались по электронной почте» и «сказал, что редко проверяет телефон, вместо этого использует электронную почту» описывают один и тот же факт. Значение 0,92 позволяет системе надежно выявлять такие семантические повторения. Более низкие пороговые значения, такие как 0,85 или 0,88, приводили к слиянию действительно разных фактов, в то время как более высокие значения, например 0,95 или 0,97, позволяли слишком большому количеству перефразировок накапливаться.
Проверка выполняется на каждом цикле консолидации. Без нее клиент, упоминающий свой часовой пояс в каждом чате, собирал бы десятки практически идентичных записей, что приводило к избыточному использованию памяти и ресурсов на обработку повторяющейся информации.
Почему Postgres с pgvector
Факты хранятся в PostgreSQL с использованием расширения pgvector для поиска по сходству. Запись customer_memories содержит:
content— факт в виде обычного текстаembedding— столбец вида vector(3072), используемый для поиска по сходствуimportance— оценка, присвоенная при извлеченииsource_channel— источник, откуда был получен факт (веб-чат, WhatsApp, голосовой чат и т. д.)created_at— время первой записиlast_accessed_at— последнее время, когда он использовался в чате
Обычной альтернативой является специализированный хранилище, такое как Qdrant или Pinecone, однако против него есть три аргумента.
- Коллекции очень маленькие. У одного клиента не более 500 фактов. Использование отдельного сервиса добавляет сложности с сетевыми переходами, обработкой соединений и обеспечением целостности данных, которые не являются необходимыми при таком объеме данных.
- Транзакции имеют большое значение. Факты принадлежат к записи клиента. Когда клиент удаляется в соответствии с GDPR, все его данные должны исчезнуть вместе со всем остальным. В pgvector это осуществляется за счёт одной транзакции, тогда как отдельный хранилище векторов потребовало бы обеспечения распределённой согласованности.
- Запрос прост. Необходимо отфильтровать данные по параметру customer_id с использованием точного совпадения, затем отсортировать их по степени сходства векторов, что pgvector эффективно обрабатывает с помощью составного индекса.
База знаний — это уже другая ситуация. Документация к продуктам, часто задаваемые вопросы и руководства по правилам хранятся в Qdrant, поскольку объём этих данных велик — тысячи документов на каждого арендатора, система обрабатывает большой трафик, и ей не требуется транзакционная связь с реляционными данными. Разные задачи — разные инструменты.
Поиск с ограничением по количеству токенов
Когда поступает новое сообщение и агент должен на него ответить, применяется поиск в памяти:
- Встраивайте поступающее сообщение с использованием той же 3072-мерной модели, что и для хранения.
- Выбирайте десять ближайших записей из
customer_memoriesдля данного customer_id, отсортированных по значению<=>— расстоянию между каждым сохраненным встраиваемым представлением и вектором запроса. - Проходите по результатам в порядке их сходства, постоянно подсчитывая общее количество токенов.
- Оценивайте количество токенов в каждом факте как
len(content) / 4— это приблизительное, но консервативное значение. - Прекращайте обработку, как только добавление следующего факта приведет к превышению лимита в 2 048 токенов.
- Обновляйте значение
last_accessed_atдля каждого извлеченного факта.
Оператор <=> вычисляет косинусное расстояние, поэтому чем меньше его значение, тем более близким является совпадение с текущим сообщением.
Лимит составляет 2 048 токенов. Агент получает наиболее релевантные факты, отсортированные по степени значимости. Если самый важный факт занимает 800 токенов, вместиться может только два-три факта; если же каждый факт короткий — от 50 до 80 токенов, — то вместиться может от пятнадцати до двадцати фактов. Бюджет автоматически адаптируется к реальному содержимому без необходимости ручной настройки. По умолчанию задано десять строк, но на практике это редко имеет значение, поскольку обычно сначала срабатывает лимит токенов; тем не менее это предотвращает бесконечное увеличение объема запросов к базе данных.
Запись в поле last_accessed_at выполняет две функции: она указывает политике удаления, какие факты по-прежнему сохраняются, и показывает, на какие данные действительно опирается агент, а какие остаются невостребованными.
Лимит в 500 фактов и кто удаляется
У клиента может храниться не более 500 фактов. Такой лимит позволяет предсказать стоимость хранения на клиента и обеспечивает высокую скорость поиска, поскольку косинусное сходство для 500 векторов остается быстрым и значимым, тогда как для 50 000 векторов оно становится неточным.
Когда система консолидации пытается сохранить новый факт, а у клиента уже достигнут лимит в 500 фактов, начинается процесс удаления. Порядок удаления:
- Факты, которые не трогались в течение 90 дней или более; они устарели и, скорее всего, теперь неактуальны.
- Среди оставшихся — факты с наименьшей оценкой важности.
- В случае равенства оценок — факты с наиболее ранней датой
created_at.
Девяносто дней — это период, уместный в деловом контексте. Факт, узнанный три месяца назад и с тех пор не использовавшийся, вряд ли будет иметь значение, но факт, узнанный шесть месяцев назад и применяемый еженедельно, например, для указания часового пояса, остается актуальным бесконечно, поскольку его поле last_accessed_at постоянно обновляется. Процедура удаления данных происходит после любой консолидации, превысившей установленный лимит, и в ходе неё удаляются только необходимые данные, обычно от одного до трех фактов, а не всё сразу.
Память и знания — это разные вещи
Эти две системы решают разные задачи и конкурируют за один и тот же ресурс.
Память хранится для каждого клиента, имеет небольшие объемы, носит личный характер и формируется в процессе взаимодействия: имя дочери — Амара, отчеты должны быть в формате PDF, ранее поступившая жалоба на доставку была урегулирована предоставлением кредита в размере 15%. Знания же хранятся для каждого арендатора или являются общими, имеют большие объемы, делятся между пользователями и создаются людьми: документация к продукту, таблицы цен, правила возврата и руководства по устранению неполадок.
У каждого есть свой собственный бюджет токенов: 2 048 для памяти и более крупный, обычно от 4 096 до 8 192, для знаний. Они делят окно контекста модели, не влияя друг на друга. Даже если память исчерпает весь свой лимит, знания всё равно останутся с полным бюджетом.
Такое разделение предотвращает нежелательные ситуации. Без отдельных бюджетов клиент с 500 подробными фактами мог бы занять всё пространство для поиска знаний, в результате чего агент будет помнить всё о человеке, но забыть документацию к продукту, необходимую для оказания помощи.
Как память влияет на глубину рассуждений
Память также по двум способам питает классификатор сложности, который определяет, какой уровень рассуждений требуется к запросу.
Первым является сигнал «зависимости от контекста». Когда процесс поиска возвращает высоко релевантные факты, что означает низкое значение косинусового расстояния до текущего сообщения, значение показателя context_dependency повышается. Классификатор интерпретирует это как «правильный ответ зависит от данных конкретного клиента» и может направить запрос на более высокий уровень обработки. Вопрос «Можете проверить мой заказ?» получает более высокий балл, если в сохранённых фактах упоминается заказ в ожидании, чем при аналогичном вопросе от клиента без истории заказов.
Во-вторых, существует конкуренция за ресурсы, предназначенные для обработки мыслительного процесса. В режиме полной последовательности мышления модель выделяет 4 096 или 16 384 токенов на обработку информации в зависимости от сложности задачи. Факты из памяти, включаемые в запрос, также потребляют токены из того же ограниченного объема, поэтому пользователь, имеющий 2 048 токенов памяти, оставляет меньше ресурсов, чем тот, у кого их 200. Эти лимиты управляются независимо друг от друга и представляют собой жесткие ограничения, поэтому система никогда не меняет один лимит на другой.
Аспекты, которые остаются сложными
Два типа трудностей не отражены на схеме архитектуры.
Изменение фактов. Предпочтения могут меняться. Утверждение «предпочитает утренние встречи» через три месяца может превратиться в «предпочитает послеобеденные встречи». Система не обнаруживает автоматически противоречия между новыми и старыми фактами. Порог в 0,92 иногда позволяет их выявить, когда новое утверждение достаточно похоже на старое для совпадения, но это не происходит всегда надежно. В настоящее время старые факты удаляются в соответствии с политикой срока действия и доступа, а улучшение обработки противоречий включено в планы развития.
Галлюцинации при извлечении информации. ИИ-модель, выполняющая извлечение, иногда делает выводы, которые никто не высказывал. Нейтральный вопрос, сформулированный определенным образом, может быть сохранен как «клиент, по-видимому, недоволен продуктом». Порог в 0,5 устраняет наименее достоверные выводы, но не все. Дедупликация косвенно помогает, поскольку выдуманные выводы редко повторяются, поэтому они остаются в виде редко используемых записей до тех пор, пока их не удалят из-за нехватки места.
Ничто из сказанного здесь не является окончательным решением. Оба проблемы регулируются с помощью лимитов, политики удаления и показателя частоты доступа, которые в совокупности отдают предпочтение недавним, часто используемым и важным фактам. Устаревшие предположения и привычки оказываются внизу списка и удаляются при нехватке места.
Два основных подхода
После разговора система обработки данных извлекает факты с помощью большой языковой модели, оценивает их важность, фильтрует их при пороговом значении 0,5, генерирует векторные представления, удаляет дубликаты при пороговом значении косинусного сходства 0,92, сохраняет новые данные и удаляет старые при достижении лимита в 500 фактов. Перед формированием ответа входящее сообщение преобразуется в векторное представление, наиболее важные факты выбираются по косинусному сходству, собираются в рамках лимита в 2048 токенов и вставляются в контекст агента.