Глава 3

Память ИИ-агентов: от состояния до RAG

LLM-серверы не имеют состояния. Вся память — история диалога, факты о пользователе, знания из документов — должна управляться вами. Разберем, какие механизмы существуют, чем они отличаются и как выбрать подходящий.

От задачи к работающей системе
  1. Архитектура ИИ-агентов: графы, ReAct и HITL
  2. Инструменты ИИ-агентов: контракты и безопасность
  3. Память ИИ-агентов: состояние, чекпойнтер и RAG
  4. Продакшн ИИ-агентов: надежность и наблюдаемость
Содержание страницыСостояние, чекпойнтер и долговременное хранилищеDurable backend против in-memoryИдентификаторы и изоляцияСуммаризация: цена сжатияRAG: знания и доказательстваПайплайн поиска: от запроса до контекстаРеранкинг и фильтрацияНенадежное содержимое и отказ от ответаРазбор сценария: поиск информации о заказе

Состояние, чекпойнтер и долговременное хранилище

Состояние (State) — данные, которыми обмениваются узлы графа: запрос, сообщения, результаты инструментов и текущая задача. Без отдельного сохранения оно не переживает потерю процесса; с чекпойнтером нужные снимки состояния могут сохраняться и загружаться при продолжении работы.

Чекпойнтер (checkpointer) сохраняет состояние графа между вызовами в рамках одного потока (thread_id). Это позволяет продолжать диалог: каждый новый вызов с тем же thread_id видит историю предыдущих. Чекпойнтер — это механизм сохранения состояния, а не база данных для произвольных фактов.

Долговременное хранилище (store) — это отдельное прикладное хранилище для данных, которые должны жить между сессиями и потоками. Например, предпочтения пользователя, факты о нем, результаты длительных операций. Store — это ваша база данных, вы определяете ее схему и политику хранения.

  • State: данные между узлами в рамках одного запуска.
  • Checkpointer: сохранение состояния между вызовами с одним thread_id.
  • Store: прикладное хранилище для данных между сессиями.
  • Чекпойнтер — это механизм, store — это ваша база данных.
  1. Запуск 1: state -> checkpointer (thread_id=1)
  2. Запуск 2: checkpointer -> state (thread_id=1)
  3. Store: данные, доступные для любого thread_id
  4. RAG: знания из документов, добавляемые в контекст

Durable backend против in-memory

Хранилище состояния в оперативной памяти удобно для прототипов, но теряет данные при остановке процесса. Для рабочих задач выбирают поддерживаемый постоянный backend, например PostgreSQL. Сохранность определяется также настройками записи, доступностью базы и резервированием; название технологии само по себе её не гарантирует.

Выбор backend зависит от требований к надежности и масштабированию. Если потеря истории диалога недопустима, используйте durable storage. Если вы готовы к потере при сбое, можно начать с in-memory, но это риск.

Помните: чекпойнтер хранит состояние графа, а не произвольные данные. Для долгосрочных фактов используйте store.

  • In-memory: быстро, но данные исчезают при перезапуске.
  • Durable backend: PostgreSQL, Redis и др.
  • Для продакшна выбирайте durable storage.
  • Чекпойнтер хранит состояние графа, store — произвольные данные.

Идентификаторы и изоляция

thread_id — это ключ, по которому чекпойнтер находит состояние. В качестве thread_id можно использовать ID клиента, ID сессии или другой уникальный идентификатор. Важно, чтобы разные пользователи не имели доступа к состоянию друг друга.

Изоляция данных — критический аспект. Если вы используете один store для всех пользователей, убедитесь, что каждая запись имеет владельца (например, user_id) и что запросы фильтруются по владельцу. Не полагайтесь только на thread_id.

В схеме хранилища полезно явно хранить владельца записи. Проверку доступа выполняет сервер на основании подтверждённой личности пользователя; фильтр owner_id и thread_id, полученные от клиента или модели, сами по себе не являются авторизацией.

  • thread_id: ключ для поиска состояния.
  • Используйте ID клиента или сессии как thread_id.
  • Изоляция: каждая запись в store должна иметь владельца.
  • Всегда фильтруйте запросы к store по владельцу.
  • Определите, что будет thread_id: client_id, session_id.
  • Добавьте поле owner_id в схему store.
  • Фильтруйте все запросы к store по owner_id.
  • Проверьте, что чекпойнтер не смешивает состояния разных потоков.

Суммаризация: цена сжатия

Длинную историю можно заменить кратким изложением или оставить рабочее окно последних сообщений. Это сокращает контекст, но может потерять детали. В учебных примерах встречаются готовые классы памяти; конкретный API нужно выбирать по документации установленной версии, а не переносить старый пример без проверки.

Суммаризация — это lossy-операция. Модель может упустить важные факты или исказить их. Поэтому для критически важных данных используйте долговременное хранилище, а не полагайтесь на суммаризацию.

Альтернативы: хранить только последние k сообщений (window memory), удалять старые результаты инструментов, выносить факты в store. Выбирайте стратегию в зависимости от задачи.

  • Суммаризация экономит токены, но теряет детали.
  • Суммаризация — lossy-операция.
  • Для критических фактов используйте store.
  • Window memory: хранить только последние k сообщений.

RAG: знания и доказательства

RAG (Retrieval-Augmented Generation) — это подход, при котором агент ищет информацию в базе знаний и добавляет ее в контекст. Это позволяет отвечать на вопросы, выходящие за пределы обучающих данных модели.

Важно: RAG не гарантирует истинность. Найденные документы могут быть устаревшими, нерелевантными или содержать ошибки. Модель может неправильно интерпретировать найденное. Поэтому RAG требует постобработки: фильтрации, реранкинга и проверки.

Результаты поиска должны рассматриваться как доказательства, а не как истина. Агент должен уметь сказать «я не нашел информации» или «информация противоречива», а не выдумывать ответ.

  • RAG: поиск в базе знаний и добавление в контекст.
  • RAG не гарантирует истинность.
  • Документы могут быть устаревшими или нерелевантными.
  • Результаты поиска — доказательства, а не истина.
  • Агент должен уметь сказать «не знаю».

Пайплайн поиска: от запроса до контекста

Полный пайплайн поиска состоит из этапов: определить, нужен ли поиск; сформулировать поисковый запрос; получить список релевантных страниц; извлечь содержимое; отфильтровать; реранжировать; упаковать в контекст.

Фильтрация учитывает права доступа, дубликаты, область применимости и актуальность источников. Реранкер повторно оценивает соответствие запросу; он может работать локально или через сервис. Дополнительная стоимость и задержка оправданы, только если на задачах проекта улучшается полезность найденных материалов.

Упаковка в контекст: выберите top-n документов, нормализуйте текст, добавьте метаданные (источник, дата), сожмите при необходимости. Цель — дать модели релевантную информацию без перегрузки контекста.

  • Этапы: need_search -> query -> search -> extract -> filter -> rerank -> pack.
  • Фильтрация: дедупликация, надежность, актуальность.
  • Реранкинг: повторная оценка релевантности.
  • Упаковка: top-n, нормализация, метаданные, сжатие.
  1. Запрос пользователя
  2. Узел: нужен ли поиск?
  3. Формирование поискового запроса
  4. Поиск: получение URL и сниппетов
  5. Извлечение содержимого страниц
  6. Фильтрация: дедупликация, надежность
  7. Реранкинг: оценка релевантности
  8. Упаковка top-n документов в контекст

Реранкинг и фильтрация

Поисковые движки оптимизированы на скорость, а не на точность. В выдаче может быть много нерелевантных документов. Реранкинг — это второй этап оценки, который использует более точную (и более медленную) модель для переупорядочивания результатов.

Реранкер принимает запрос и список документов и возвращает оценки релевантности для каждого. Вы можете отобрать top-n документов с наивысшими оценками. Это улучшает качество ответа, но добавляет задержку и стоимость.

Фильтрация — это более грубый этап: удаление дубликатов, черный список источников, проверка даты. Реранкинг — это более точная сортировка. Оба этапа важны для качества RAG.

  • Поисковые движки оптимизированы на скорость.
  • Реранкинг: более точная оценка релевантности.
  • Реранкеры работают локально и могут быть дорогими.
  • Фильтрация: дедупликация, черный список, дата.
  • Реранкинг: сортировка по релевантности.

Ненадежное содержимое и отказ от ответа

Содержимое, полученное из поиска или документов, ненадежно. Оно может содержать ошибки, устаревшие данные или вредоносные инструкции. Модель должна обрабатывать его как данные, а не как истину.

Если агент не нашел релевантной информации, он должен сказать об этом, а не выдумывать ответ. Если информация противоречива, агент должен указать на противоречие. Это повышает доверие к системе.

Реализуйте механизм clarify/abstain: если уверенность в ответе низкая, агент задает уточняющий вопрос или отказывается отвечать, объясняя причину.

  • Содержимое из поиска ненадежно.
  • Агент должен уметь сказать «не знаю».
  • При противоречиях указывайте на них.
  • Clarify/abstain: уточняющий вопрос или отказ от ответа.

Разбор сценария: поиск информации о заказе

В учебном примере с задержанным заказом сначала проверяют право клиента видеть этот заказ и получают его фактический статус из внутренней системы. Общий регламент доставки может объяснять правила, но не устанавливает причину конкретной задержки.

Для дополнительного поиска используется разрешённый внутренний индекс. Номер заказа и данные клиента не отправляются во внешний веб-поиск. Из десяти условно найденных документов можно убрать дубликаты и отобрать два наиболее применимых, но возраст сам по себе не делает документ устаревшим: важны период действия и версия.

В ответе разделяются статус из системы заказов, применимый регламент и непроверенная причина задержки. Если подтверждённой причины нет, агент прямо указывает пробел и предлагает запросить ответ у ответственной службы. Это полезнее уверенной догадки по общему документу.

  • need_for_search: решить, нужен ли поиск.
  • search: сформулировать запрос и выполнить поиск.
  • filter: удалить дубликаты и устаревшие документы.
  • rerank: выбрать top-n релевантных документов.
  • pack: добавить документы в контекст с метаданными.
  • Ответ: на основе документов или отказ от ответа.

Что взять в свой проект

Память агента — это несколько механизмов с разными целями. Состояние для передачи данных между узлами, чекпойнтер для истории диалога, store для долгосрочных фактов, RAG для знаний. Выбирайте механизм под задачу и не забывайте об изоляции и свежести данных.

Источники и документация

  • Состояние и память ИИ-агентов (учебные материалы Сбера)
  • Поиск в LLM-агентах и LangGraph (учебные материалы Сбера)
  • Разработка и применение мультиагентных систем в корпоративной среде (Сбер)