[!NOTE] Автоматический перевод Эта статья была автоматически переведена с оригинальной английской версии.
ИИ-агенты и память: типизированные состояния под управлением схем для долгоживущих систем
Долгоживущие ИИ-агенты часто извлекают устаревшие данные, поскольку обычная семантическая память не содержит правил для определения того, какое значение является актуальным.
Когда пользователь меняет срок действия паспорта с 15 июля на 30 июня, векторный поиск может вернуть оба значения. Слой памяти, обеспечивающий хранение состояний, должен фиксировать, что значение от 30 июня имеет приоритет перед более ранним.
Кратко: рассматривайте надёжную память ИИ-агента как типизированное состояние приложения. Извлекайте кандидаты на хранение из данных через структурированный интерфейс вывода, сохраняйте записи с указанием сферы применения, временных окон действия, порядка замены значений, информации о происхождении данных и версий схемы, а при чтении — извлекайте только самые актуальные данные. Для нечёткого поиска используйте векторный поиск; изменяемые данные читайте из текущих записей с определённой сферой применения.
Ловушка контекстного окна
Контекстное окно — это объём данных, доступный при одном вызове модели. Приложение может передавать сообщения в последующие вызовы, но политика приложения должна определять, какие старые данные остаются верными и кто имеет право их видеть.
Долгоживущим ИИ-агентам необходимо запоминать предпочтения, статус задач, данные клиентов, решения, связанные с инструментами, информацию о соответствии требованиям и прошлые ошибки. Простой способ — добавлять краткие сводки или сохранять старые записи в векторном хранилище. Этот подход работает до тех пор, пока одно из запомненных данных не изменится.
Тогда у агента появляются два срока действия паспорта, два предпочтительных формата или два решения по проекту. Семантический поиск может вернуть оба варианта; сводка может перезаписать один из них; длинный контекст может содержать устаревшую информацию рядом с актуальной. Такие решения позволяют извлекать текст, но не обеспечивают соблюдения текущего значения.
Необходимо чётко ответить на следующие вопросы:
- Каково текущее состояние?
- Каково было состояние 2 июня?
- Кто это сказал?
- Какому пользователю принадлежат эти данные?
- Какое старое значение было заменено этим?
- Могу ли я удалить или истечь срок действия этих данных?
Память ИИ-агента под управлением схем (SGAM) хранит ответы на эти вопросы в виде полей и связей, вместо того чтобы оставлять их в неявной форме в тексте.
Что означает SGAM
Три похожих по названию концепции определяют сферу применения SGAM.
Схема-руководство для диалога (SGD) — это датасет задач-ориентированных диалогов Google 2019 года. Его схема описывает API-сервисы, намерения и поля, что позволяет модели диалога отслеживать состояние сервисов, которые она ранее не видела. Это полезный пример использования схем для отслеживания состояний, но его применение ограничено диалоговыми сервисами.
Схема-руководство для памяти (SGM) — это исследовательский термин, используемый Mei и коллегами в работе According to Me: Long-Term Personalized Referential Memory QA. В этой работе сравниваются текстовые описательные записи памяти (DM) с элементами памяти в формате ключ-значение с фиксированной схемой. Обе формы представления содержат одни и те же исходные данные, но в разных структурах.
В данной статье термин Память ИИ-агента под управлением схем (SGAM) означает инженерный паттерн, при котором схемы управляют операциями записи, обновления, извлечения и удаления данных. Схема определяет состояние приложения и его жизненный цикл.
ATM-Bench демонстрирует, почему такая форма представления важна. В нём используются данные личного характера за примерно четыре года в виде электронных писем, изображений и видео. Вопросы требуют упоминания личных данных, местоположения, нескольких источников информации и обновлений со временем. При использовании традиционных методов производительность снижается, тогда как SGM показывает лучшие результаты по сравнению с DM, поскольку механизм поиска может напрямую обращаться к полям времени, источника, местоположения, сущностям и тегам.
Вопрос о хранении данных, связанный с противопоставлением SGM и DM, заключается в следующем: следует ли сохранять информацию в виде свободного текста или использовать именированные поля? Однако у производственного ИИ-агента существует дополнительная проблема ещё до момента сохранения — ему необходимо провести ризонинг на основе неструктурированного диалога для определения возможных обновлений памяти. Метод Schema-Guided Reasoning (SGR) определяет алгоритм принятия такого решения: анализ доказательств, выявление субъекта и атрибута, проверка того, изменяет ли факт текущее состояние, после чего формируется кандидат на запись. После этого вызова модели применяются правила оркестрации и управления жизненным циклом данных, заданные методом SGAM.
Разделение процесса извлечения модели и механизма управления памятью
Запись в память проходит через три уровня обработки. Structured Output (SO) обеспечивает соблюдение строгой структуры кандидата на объект. Schema-Guided Reasoning (SGR) задаёт последовательность шагов, которые модель должна выполнить для формирования данного кандидата. Schema-Guided Agent Memory (SGAM) отвечает за преобразование кандидата в устойчивое состояние после завершения работы модели.
Решения, маршруты или планы обычно утрачивают силу с окончанием текущего запроса. Однако при последующих запусках система может ознакомиться с кандидатом в памяти спустя несколько дней или использовать его для выбора операции с инструментами. Для такого удлинённого срока существования требуются правила хранения, которые не предусмотрены методом SGR.
Метод SGR ограничивает один вызов модели, определяя структуру её ризонинга. Для записи в память схема может требовать наличия исходных доказательств, нормализованных значений субъекта и атрибута, сравнения с текущим состоянием, а уже затем — предложенного обновления. Для описания такой структуры используются форматы Pydantic или JSON Schema. Встроенные механизмы Structured Output или специализированные среды декодирования, такие как XGrammar, предотвращают пропуск полей или вывод моделью данных в неверной форме.
Схема не может гарантировать получение корректного результата. Она лишь делает процесс принятия решения прозрачным и поддающимся анализу, включая указание доказательств и этапов сравнения, которые привели к формированию кандидата.
Метод SGAM определяет дальнейшую судьбу объекта после его создания: следует ли его сохранить, заменит ли он более старый факт, кто имеет право на доступ к нему, является ли он актуальным или историческим, а также какой источник информации его подтверждает.
В таблице указаны правила принадлежности объектов к тому или иному уровню и способы обработки возможных сбоев:
| Размер | SO | SGR | SGAM |
|---|---|---|---|
| Назначение | Возвращать объект, соответствующий схеме | Направлять модель по заранее определённому пути ризонинга | Управлять долговременной памятью после вызова модели |
| Область применения | Один генерируемый ответ | Один путь ризонинга и принятия решения в рамках одного вызова модели | Записи, используемые между вызовами, сессиями и запусками |
| Роль в схеме | Определяет поля вывода, их типы и допустимые значения | Определяет промежуточные этапы ризонинга и окончательное решение | Определяет сохраняемые записи, связи между ними и жизненный цикл |
| Механизм обеспечения соблюдения | Блоки ограниченной декодировки предотвращают вывод данных, не соответствующих схеме | Использует SO для обязательного выполнения каждого указанного этапа и принятия окончательного решения | Проверка приложения, ограничения базы данных и правила урегулирования конфликтов |
| Время существования | Текущий вызов, если только приложение не сохранит объект | След ризонинга обычно удаляется после принятия решения | Сохраняется до обновления, истечения срока или удаления |
| Формы сбоев | Валидная структура, но неверное значение | Необходимые шаги присутствуют, но ризонинг может всё равно быть ошибочным | Устаревшие, загрязнённые, неограниченные или непроверяемые состояния |
На пути записи последовательность выглядит следующим образом:
SGR reasoning schema + Structured Output -> candidate write -> SGAM policy and persistence
Приведённый ниже пример из memory_models.py определяет объект, передаваемый от этапа извлечения в сервис записи SGAM:
from datetime import datetime
from pydantic import BaseModel, Field
class MemoryDelta(BaseModel):
tenant_id: str = Field(description="Isolation boundary, e.g. acme")
subject: str = Field(description="Normalized entity ID, e.g. mira")
attribute: str = Field(description="Property being updated")
value: str = Field(description="New value")
valid_from: datetime
source_episode_id: str
MemoryDelta отражает то, что извлекла модель. Сервис записи SGAM всё равно решает, следует ли отклонить, объединить или сохранить этот объект.
Пути записи и чтения выполняют разные задачи
SGAM имеет путь записи и путь чтения. Только путь записи изменяет сохраняемое состояние. Путь чтения выбирает записи для текущего запроса.
Поток ввода — это путь записи:
- Захватить необработанный эпизод из сообщений, результатов работы инструментов или бизнес-событий.
- Выделить структурированные кандидаты через форматированный вывод.
- Проверить соответствие схеме и отклонить невалидные записи.
- Урегулировать конфликты, закрыть устаревшие факты и сохранить информацию о происхождении.
- Заложить запись в хранилище SGAM.
Поток запросов — это путь чтения:
- Начать с вопроса пользователя.
- Определить, требуется ли текущее состояние или состояние в определённый момент времени.
- Профилировать по арендатору, типу памяти, теме, атрибуту и окну действительности.
- Добавлять векторное или графовое расширение только в том случае, если точного поиска по состоянию недостаточно.
- Собрать минимальный необходимый контекст для модели.
Читайте эту диаграмму слева направо, разделив её на две полосы. В верхней полосе происходит запись памяти, а в нижней — её чтение. Обе полосы используют одно и то же хранилище.
Что должно входить в схему памяти
Минимальная запись SGAM требует большего, чем text.
tenant_id
memory_id
subject
attribute
value
memory_type
schema_version
valid_from
valid_to
supersedes_memory_id
source_episode_id
confidence
retention_policy
Благодаря этим полям новый срок действия паспорта может заменить предыдущий, не удаляя историю записей. Тот же таблицевый формат позволяет обрабатывать как текущие, так и точечные запросы, после чего отслеживать происхождение полученных результатов до соответствующей эпизодической записи. schema_version обеспечивает поддержку миграций, в то время как retention_policy указывает задачам на удаление, какие ещё элементы необходимо устранить.
Для извлечения документов используется технология RAG, а для поддержания изменяемого состояния — SGAM. Векторный поиск по‑прежнему сохраняется в системе для обеспечения размытого поиска, кластеризации и расширения результатов. Текущее значение mira.passport_deadline должно браться из записи с ограниченным диапазоном доступа, а не из того чанка, который случайно занял первое место в ранжировании.
Пример устаревшей информации
Рассмотрим синтетический пример двухэпизодного трейса, представленного в виде базовой модели DM и журнала SGAM:
e1: Mira prefers concise answers. Her passport deadline is 2026-07-15.
e2: Mira corrected the deadline. It is now 2026-06-30.
Базовая модель DM хранит оба эпизода в виде свободного текста, поэтому поиск по тексту может вернуть e1, поскольку в нём присутствуют нужные слова. SGAM извлекает из каждого эпизода типизированные факты, ключи к которым формируются на основе арендатора, субъекта и атрибута. Он должен возвращать e2 в качестве текущего состояния и сохранять e1 для запросов к историческим данным.
Приведённая ниже функция является кодом пути записи в SGAM; она будет находиться в модуле хранения, например sgam_store.py. У модели DM нет аналогичного компонента, поскольку она не поддерживает отдельную строку для каждого атрибута. Перед тем как вызывающий код вставит замену, эта функция закрывает текущую строку:
def close_previous_fact(db: sqlite3.Connection, fact: MemoryFact) -> int | None:
row = db.execute(
"""
select fact_id
from memory_facts
where tenant_id = ?
and subject = ?
and attribute = ?
and valid_to is null
order by valid_from desc
limit 1
""",
(fact.tenant_id, fact.subject, fact.attribute),
).fetchone()
if not row:
return None
db.execute(
"update memory_facts set valid_to = ? where fact_id = ?",
(fact.valid_from, row["fact_id"]),
)
return int(row["fact_id"])
Когда приходит e2, функция устанавливает valid_to для факта, извлечённого из e1, на временную метку e2. Затем вызывающий код вставляет новый факт с открытым статусом valid_to. У модели DM нет аналогичного шага обновления, поэтому старый текст может продолжать иметь более высокий приоритет перед исправленным вариантом.
Выполнение запросов на текущие и исторические сроки действия в обоих форматах даёт разные результаты:
Naive text memory:
returned episode: e1 -> passport deadline is 2026-07-15
SGAM current state:
mira.passport_deadline = 2026-06-30
valid_from=2026-06-03T10:00:00Z, source=e2
SGAM point-in-time state:
on 2026-06-02, mira.passport_deadline = 2026-07-15
В производственной среде эту транзакцию следует сочетать с структурированным извлечением данных на этапе записи. База данных обновляет временную действительность записей, тогда как модель извлекает кандидатские факты, но не определяет, какая из сохранённых строк остаётся актуальной.
Выбор средств хранения определяется способом извлечения данных
В проектах для различных компонентов этой архитектуры используются разные названия: хранилища памяти, контекстные графы, профили, долгосрочные хранилища, графовый RAG и агенты с состоянием.
| Инструмент или фреймворк | Основной слой хранения | Механизм временного состояния | Механизм схемы | Практическое применение |
|---|---|---|---|---|
| Zep / Graphiti | Neo4j, FalkorDB, Neptune, поддержка устаревших решений Kuzu | Интервалы действительности фактов вместе с информацией о источнике и эпизоде | Типы сущностей и рёбер на основе Pydantic, временные рёбра, данные происхождения | Память временных графов |
| LangGraph / LangMem | Хранилища LangGraph, хранилища с базой Postgres | Временные метки и поля, находящиеся в ведении приложения, в записях хранилища | Хранилища в формате JSON плюс извлечение профилей или коллекций с помощью Pydantic | Приложения-агенты, уже разработанные на LangGraph |
| Mem0 | Управляемая стековая архитектура, бэкенды Valkey / Redis / vector в OSS-решениях | Обновления памяти; правила управления временем остаются в ведении приложения | Типы памяти, пользовательские категории, шаблоны для извлечения данных | Услуга по хранению памяти пользователей, агентов и сессий |
| Letta / MemGPT | Состояние агента и блоки памяти, хранящиеся в базе данных | Редактируемые блоки без интервалов действительности на уровне полей | Редактируемые маркированные блоки памяти | Агенты со состоянием и механизмом управления контекстом в стиле операционных систем |
| Cognee | Графы плюс бэкенды векторных и реляционных структур | История зависит от онтологии и выбранного бэкенда | Извлечение и проверка данных с учётом онтологии | Память корпоративных знаний в виде графов |
| LlamaIndex property graph | Хранилища свойственных графов плюс векторные хранилища | Поля времени определяются схемой графа и хранилищем | SchemaLLMPathExtractor с указанием допустимых сущностей и связей | Извлечение данных из документов и трейсов с использованием графов |
Graphiti — это конкретная open‑source реализация реляционной временной памяти. Она отслеживает изменения фактов, сохраняет указатели на исходные эпизоды и поддерживает гибридный способ поиска. LangGraph разделяет чекпоинты потоков от хранилищ между потоками. Mem0 предоставляет операции с памятью в виде управляемой услуги. Letta использует редактируемые блоки контекста вместо механизма SGAM на уровне полей, но всё равно рассматривает состояние агента как постоянные данные.
Начните с модели данных. Если основной операцией является точный поиск фактов, обычно достаточно реляционной таблицы с JSON‑данными, столбцами, указывающими на действительность, индексами для разных пользователей, и векторным компонентом в качестве дополнения. Граф добавляйте тогда, когда требуется просмотр связей между элементами, а не только потому, что демонстрация работы с графом выглядит впечатляюще.
Сначала создаем путь записи в графе
Сначала определяем, что продукт имеет право запоминать. Вопрос выбора между графом и векторами рассматривается позже.
Агент поддержки может хранить информацию о уровне аккаунта, открытых заявках и предпочтениях пользователя по контактам. Однако он не должен переводить каждую жалобу пользователя в состояние профиля. Агент-программист может запоминать конвенции репозитория и нерешённые задачи. Ему также не следует сохранять личные заметки вечно только потому, что они были извлечены один раз.
Начните с пути записи и рассматривайте память как небольшое изменение состояния:
- Укажите тип памяти, субъект, диапазон тенантов и класс хранения.
- Извлеките кандидатские записи с использованием структурированного вывода.
- Проверьте содержимое записи с помощью Pydantic или слоя схем, уже используемого в вашей архитектуре.
- Устраните конфликты перед вставкой, включая определение того, заменяет ли новая запись старую.
- Сохраняйте указатель на исходный источник — первоначальную запись, результат работы инструмента, файл, тикет или подтверждение пользователя, которые привели к созданию записи.
- Записывайте версию схемы вместе с каждой записью, а не оставлять её только в коде приложения.
Первый хранилище SGAM может быть реляционной таблицей с колонкой JSON и несколькими индексами. Граф становится полезным, когда продукту необходимо анализировать связи между объектами, такие как «клиент — аккаунт», «аккаунт — политика», «задача — результат работы» или «проект — принятое решение».
Основной путь записи и фоновые операции
Немедленная запись оправдана, если следующий шаг зависит от новой информации. Если пользователь говорит: «Запомните, что я предпочитаю краткие ответы», системе не нужна еженочная обработка, чтобы изменить своё поведение.
Большинство шагов не требуют немедленной записи. Сохраняйте первоначальную запись вместе с метаданными тенанта, сессии и инструмента, а затем пусть фоновый работник извлечёт кандидатские записи позже. Благодаря методу консолидации на основе рекурренции работник накапливает слабые сигналы и добавляет факт в базу только после повторения похожих данных или подтверждения пользователя. Это приводит к задержке обновления информации. Такой подход приемлем для случаев, когда «пользователь часто просит экспорт в CSV», но рискован, если речь идёт о ситуациях вроде «клиент изменил адрес доставки».
Сделайте путь чтения детерминированным. Сначала обеспечьте соблюдение диапазона тенантов и условий действительности, а затем используйте фаззи-поиск только тогда, когда он может добавить полезный контекст.
- Фильтруйте данные по тенанту, типу памяти и временному окну действительности.
- Сначала извлекайте точное структурированное состояние, а затем — семантические аналоги.
- Для подтверждающих доказательств, связанных объектов и примеров используйте расширение с помощью векторов или графа, но не делайте его основанием для текущих фактов.
- Собирайте минимальный необходимый контекст, который позволяет ответить на вопрос.
Рассматривайте миграцию схем как изменение продукта, поскольку она влияет на то, что агент может вспоминать, цитировать или удалять. Она также может изменить то, какие исторические факты считаются актуальными. Планируйте скрипты миграции, процедуры восстановления данных, двойные окна чтения и правила удаления в рамках одного релиза.
Когда SGAM оправдан из-за сложности реализации
Используйте SGAM в тех случаях, когда факты могут меняться со временем:
- предпочтения пользователя, которые можно обновить или отменить;
- данные о клиентах или аккаунтах, требующие аудита;
- состояние задач для долгосрочных ассистентов;
- память проектов у агентов-программистов;
- общее состояние в мультиагентных системах;
- записи, связанные с соблюдением норм, где важна происхожденность данных;
- временные вопросы вроде «Что мы считали до миграции?».
SGAM представляет собой чрезмерное решение в тех случаях, когда память имеет ограниченную жизненную продолжительность, используется исследовательские цели или её можно быстро пересчитать. Если ИИ-агенту требуется лишь небольшое количество этапов поддержания континуитета, достаточно использовать чекпоинт вместе с сокращённой историей сообщений. Для статической проверки качества документов может оказаться достаточным только подход RAG. Кроме того, в сферах с высокой динамикой, где схемы меняются ежедневно, использование типизированной памяти замедлит работу команды.
Чек-лист оценки
Необходимо оценивать не только конечный ответ, но и весь цикл жизни памяти. Система может сгенерировать правдоподобный ответ даже после записи неверного факта, получения устаревшей информации или нарушения границ тенанта.
Я применяю ту же поэтапную структуру оценки, что и в своей статье об оценке RAG. Оценка должна проводиться на этапах, где может возникнуть сбой, а не ограничиваться только генерируемым текстом. Принципы трейсинга из статьи об оценке агентов также актуальны, поскольку ошибки памяти часто проявляются уже в истории выполнения задач до того, как появится ответ.
Для тестирования SGAM рекомендуется использовать метод реплея: подавать фиксированную последовательность эпизодов в механизм записи памяти, проверять содержимое «бухгалтерской книги» после каждого значимого шага, а затем задавать вопросы о текущем состоянии или о данных определённого момента времени на основе полученных данных.
| Слой | Тип сбоя, на который следует обратить внимание | Показатели оценки |
|---|---|---|
| Запись и извлечение | Агент пропустил факт, выдумал его или сгенерировал некорректную структуру | Коэффициент корректных записей согласно схеме, точность/покрытие извлечения, степень охвата исходных эпизодов |
| Обработка конфликтов | Устаревший факт остался актуальным или был заменён действительным старым фактом | Корректность замены, частота дубликатов, точность аннулирования устаревших данных |
| Изоляция и политики | Память просочилась между пользователями или сохранилась после истечения срока действия политики | Ошибки изоляции тенантов, корректность удаления данных, соблюдение правил хранения |
| Получение данных | Правильная запись существует, но считывающий модуль её не загрузил | Точность данных о текущем состоянии, точность данных определённого момента времени, показатель recall@k среди всех записей памяти |
| Обоснование ответа | Ответ основан на памяти без соответствующей поддержки или указан неверный источник | Наличие подтверждающих данных из исходных эпизодов, точность цитирования, корректность разрешения конфликтов |
| Операционные аспекты | Путь доступа к памяти слишком медленный, устаревший или дорогой | Задержка записи p95, отставание по свежести данных, задержка чтения, стоимость одного запроса |
Такие бенчмарки, как LoCoMo, LongMemEval и ATM-Bench, предоставляют публичные тестовые случаи. Однако они не заменяют специфичные тестовые наборы для конкретной области применения. Кодинг-ассистенты, боты поддержки клиентов и копилоты для соблюдения нормативов требуют разных схем, фильтров, правил хранения данных и тестов на выявление сбоев.
Ограничения
SGAM — это мой собственный термин для определённого паттерна, а не стандарт. Другие проекты решают аналогичную проблему иначе. LangGraph memory и LangMem описывают механизмы хранения краткосрочной и долгосрочной информации, профили, коллекции, операции записи в «горячие» пути и фоновые менеджеры памяти. Zep Graphiti использует понятие временной контекстной графа. Letta обеспечивает сохранение редактируемых блоков памяти, тогда как Mem0 предоставляет управляемый слой памяти. Microsoft GraphRAG, свойственные графы LlamaIndex и Cognee рассматривают соответствующие аспекты задачи как знаниевые графы.
Пользовательский профиль, журнал эпизодов, граф документов и блок памяти, доступный для редактирования ИИ-агентом, решают разные задачи по извлечению и обновлению данных. Я отношу к категории SGAM только ту память, которая обеспечивает долговременное хранение текущего состояния приложения и поэтому требует наличия схемы, проверки корректности данных, учёта происхождения информации, механизмов разрешения конфликтов, правил хранения и миграции данных.
Даже в типизированной памяти могут возникать ошибки. Схема помогает легче выявлять некорректные записи, но не делает их надёжными. Требуется по-прежнему доверие к источникам данных, подтверждение пользователя по поводу чувствительной информации, политика разрешения конфликтов, возможность удаления данных и их мониторинг.
Миграция схем — это сложная задача. Как только данные становятся частью состояния системы, необходимо учитывать версионирование, восстановление старых записей, их поведение при удалении и т.д. Если пренебречь этими аспектами, старые записи могут оставаться актуальными дольше, чем семантика или правила хранения, которые их создали.
Список литературы
- According to Me: Long-Term Personalized Referential Memory QA — статья Mei и соавт., в которой представлены ATM-Bench и схема управления памятью.
- Towards Scalable Multi-Domain Conversational Agents: The Schema-Guided Dialogue Dataset — статья Rastogi и соавт. о датасете SGD.
- LongMemEval: Benchmarking Chat Assistants on Long-Term Interactive Memory — бенчмарк Wu и соавт. для оценки способностей к долгосрочному хранению информации у чат-ассистентов.
- Graphiti: Build Temporal Context Graphs for AI Agents
- Zep: A Temporal Knowledge Graph Architecture for Agent Memory
- Mem0 Platform Overview
- Mem0: Building Production-Ready AI Agents with Scalable Long-Term Memory
- LangGraph Memory Overview
- LangGraph Persistence
- LangMem documentation
- Letta: Introduction to Stateful Agents
- Microsoft GraphRAG documentation
- LlamaIndex: Using a Property Graph Index
- Cognee Documentation
- Pydantic model validation docs
- Python sqlite3 documentation