Перейти к основному содержимому

Управление состоянием важнее памяти: заметка о проектировании персистентности агентов

Большинство сбоев «памяти» агента — это сбои управления состоянием. Retrieval по прошлым ходам не может обеспечивать инварианты; журнал транзакций может.

Close-up of a sleek prosthetic hand interacting with a robotic arm in a high-tech environment.

Путаница между памятью и состоянием

Когда агент забывает, что заказ уже был размещён, инстинктивно хочется добавить векторное хранилище. Обычно это неверное решение, потому что сбой здесь не в припоминании. Он в авторитетности.

В большинстве продуктов «память» означает retrieval по прошлым ходам: эмбеддинг разговора, эмбеддинг нового запроса, извлечение ближайших чанков, вставка их в контекстное окно. Этот механизм действительно полезен для преемственности тона, для ссылок, которые пользователь делал три сессии назад, для фоновых фактов, влияющих на решение. Это вероятностный фильтр релевантности по append-only груде текста.

Состояние — другой объект. Состояние — это авторитетная запись того, к чему задача уже обязалась: какие шаги выполнены, какие побочные эффекты произошли, какие обязательства остаются открытыми, какие факты в данный момент считаются истинными и на чьих доказательствах. У состояния есть инварианты. Если заказ был размещён, заказ существует ровно один раз, и никакая семантическая близость этого не меняет.

Retrieval улучшает припоминание. Он не может обеспечивать инварианты. Retriever может выдать предложение «Я разместил заказ 4471» и с равным успехом может не выдать его или выдать устаревшее предложение, утверждающее, что заказ был отменён. Затем агент бегло рассуждает над теми фрагментами, которые победили в конкурсе на схожесть. Ничто в пайплайне не может утверждать, что обязательство произошло ровно один раз.

Паттерн повторяется во всех командах: workflow, который иногда списывает деньги дважды, повторно отправляет письмо или заново открывает закрытый тикет; сессия отладки, которая завершается выводом «агент забыл»; предложение повысить качество модели эмбеддингов или top-k. Реальный пробел — отсутствующий журнал транзакций. Эмбеддинги просят выполнять работу реестра, а реестр — это не задача о схожести.

Что должен гарантировать слой состояния

Слой состояния — это не база данных с более красивым названием. Это набор гарантий, которые остальная система вправе предполагать. Три из них важнее всего.

Идемпотентность. Повторный запуск шага не должен дублировать его побочные эффекты. Это означает, что каждое внешне видимое действие несёт стабильный ключ, производный от идентичности задачи и идентичности шага, и исполнитель проверяет, не был ли этот ключ уже зафиксирован, прежде чем действовать. Проверка и фиксация должны быть атомарны относительно действия или, по крайней мере, упорядочены так, чтобы сбой между ними был восстановим. Без этого повторные попытки — которые нужны любому надёжному рантайму агента — становятся источником порчи данных.

Упорядоченность. Агент должен знать, какие обязательства предшествуют каким. Некоторые зависимости причинны (нельзя отгрузить до того, как платёж прошёл), некоторые лишь последовательны (нельзя дописать в журнал до его создания). Упорядоченность — это то, что позволяет возобновлённому запуску решить, что ещё законно делать. У мешка извлечённых фактов нет упорядоченности; у конечного автомата она есть.

Detailed view of an ATEM Micro Panel used for video production control in a studio environment.

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

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

Минимальная схема состояния

Наименьшая полезная модель состояния разделяет три вида информации, которые обычно смешаны в один контекстный блок.

Эпизодический контекст — что было сказано. Ходы, выводы инструментов, извлечённые документы, резюме. Это естественный дом для эмбеддингов. Он объёмный, низкоавторитетный и по своей природе с потерями.

Долговечные факты — что истинно. Каждый факт версионирован, несёт источник и несёт метку времени. Факт никогда не перезаписывается на месте; новая версия вытесняет старую, а старая остаётся читаемой. Противоречия — это конфликты, которые нужно разрешить, а не молчаливые обновления.

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

Конкретная форма, в псевдосхеме:

facts(id, subject, predicate, value, source, observed_at, superseded_by)
obligations(id, task_id, kind, key, state, created_at, deadline)
episodes(id, task_id, role, content_ref, created_at)

key у обязательства — это ключ идемпотентности. superseded_by у факта — это связь разрешения конфликта. task_id связывает всё обратно с одним запуском.

Вторая половина проектирования — это экспозиция. Чтения и записи состояния должны быть явными инструментами, а не неявными побочными эффектами рантайма. Когда агент вызывает state.read_facts(subject) или state.commit(obligation_id, result), эти вызовы появляются в трейсе наравне с любым другим вызовом инструмента. Это делает переходы состояния аудируемыми и отлаживаемыми теми же механизмами, что используются для всего остального. Это также делает режим отказа видимым: запуск, который никогда не фиксирует обязательство, очевидно

Close-up of a plastic bottle in a modern factory bottling production line.

Компромисс — многословность. Явные инструменты состояния потребляют контекст и добавляют ходы. Команды, скрывающие состояние за рантаймом, получают более короткие трейсы и худшую диагностику; команды, выставляющие его наружу, платят токенами и выигрывают в наблюдаемости. Для длинногорizontных задач обмен обычно того стоит.

Тестовые случаи, обнажающие пробел

Три теста отделяют настоящий слой состояния от слоя retrieval, надевшего костюм состояния.

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

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

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

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

Где retrieval всё ещё уместен

Ничто из этого не аргументирует против retrieval. Эпизодический контекст действительно объёмен, действительно нечёток и действительно полезен, когда суммирован и доступен для поиска. Аргумент — об авторитетности: retrieval может информировать решение, но он не должен быть тем, что решает, существует ли уже обязательство.

Заключение

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

ПоделитьсяXLinkedInПостоянная ссылка6 мин чтения

Связанное чтение

На какие вопросы это отвечает

Why doesn't a vector store fix an agent that forgets commitments?

A vector store retrieves text by similarity. It cannot assert that a side effect happened exactly once, that one commitment precedes another, or that a resumed run should skip completed steps. Those are invariants, and invariants require an authoritative, ordered record.

What is the minimum viable state layer for an agent?

Three separated stores: episodic context for what was said, versioned durable facts for what is true, and pending obligations for what is owed. Each obligation carries a stable idempotency key, and state reads and writes are exposed as explicit tools so they appear in traces.

How do you test whether an agent has real state or just retrieval?

Kill the process mid-run and resume; replay the same tool call twice and assert one side effect; inject a superseded fact and require the agent to detect the conflict. Systems without versioned state fail the third test silently.