Пам’ять клієнта для штучних інтелектуальних агентів за суворим бюджетом токенів.
Як шар пам’яті агента видобуває факти, оцінює їхню важливість, усуває дублікати за критерієм косинуса 0,92, зберігає вектори у pgvector та здійснює пошук у межах ліміту у 2 048 токенів із механізмом видалення.
Джерела: Engineering a Multi-Agent AI Platform — Part 6: Memory Under Token Constraints
Агент підтримки спілкується з клієнтом, і все необхідне має поміститися в одне вікно контексту. GPT-4o пропонує 128K токенів, тоді як менші моделі можуть мати 32K або менше. У цьому вікні мають бути системний запит, визначення інструментів, отримані знання, поточна розмова та все, що агент пам’ятає про конкретну особу. У цій статті описана схема пам’яті для такої конфігурації: як факти витягуються з завершених розмов, оцінюються, усуваються дублікати, зберігаються у вигляді векторів та знову отримуються в межах суворого ліміту токенів.
Вікно — це бюджет, а не ємність
Усе, що відомо про клієнта, вкладається у запит, а інші дані змушені компресуватися. Отримання знань обривається, історія розмов скорочується, а системний запит може відхилятися настільки далеко, що модель втрачає контроль над власними інструкціями.
Якщо нічого не вказати, агент буде ставитися до кожної розмови як до першої. Клієнт, який запитує про час зустрічі, отримує відповідь „У мене немає цієї інформації“, хоча надав її ще минулого вівторка.
Вихід із цієї ситуації — це встановлення фіксованої кількості місця для зберігання інформації про клієнта. У описаній тут схемі ця кількість становить 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's 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 усуває найслабкіші висновки, але не всі. Дедуплікація допомагає опосередковано, оскільки вигадані висновки рідко повторюються, тож вони залишаються як рядки, які використовуються рідко, поки їх не видалить.
Тут немає готового рішення. Обидві проблеми контролюються за допомогою ліміту, політики видалення та сигналу частоти доступу, які разом сприяють зберіганню останніх, часто використовуваних та важливих фактів. Старі припущення та застарілі уподобання опускаються на дно та зникають, коли з’являється потреба у просторі.
Два підходи у короткому огляді
Після розмови консолідаційний процес витягує факти за допомогою LLM, оцінює їхню важливість, фільтрує їх на рівні 0,5, генерує ембеддинги, видаляє дублікати при пороговому значенні косинусного коефіцієнта 0,92, зберігає нову інформацію та видаляє її, коли досягається ліміт у 500 фактів. Перед надсиланням відповіді вхідне повідомлення ембеддується, найважливіші факти отримуються за допомогою косинусної схожості, збираються в межах бюджету у 2 048 токенів та вставляються до контексту агента.