Как проверить память ИИ-агентов и устранить галлюцинации. Эксперимент с контаминацией памяти, механизмы отзыва и верификации. Читайте, чтобы защитить свои системы.
Мы часто говорим о том, чтобы дать ИИ-агентам постоянную память — построить «второй мозг» или «операционную систему знаний», где агенты могут записывать решения и получать контекст. Но что происходит, когда эта память ошибочна? Я исследовал разрыв между механическим исполнением (агент вызвал инструмент, код скомпилировался, код возврата 0) и семантической истиной (вывод, сделанный из этого исполнения, на самом деле корректен). Легко предположить, что если механический слой надёжен, то и семантический последует за ним. Но я начал подозревать, что это опасное допущение.
Чтобы проверить это, я провёл контролируемый эксперимент на своём MCP-сервере codebase-intelligence (Python, 50K строк кода), в котором есть IntelligenceStore — слой постоянной памяти, где агенты могут записывать инциденты и собирать Architectural Decision Records (ADR). Я хотел узнать: если память агента отравлена смесью истинных и ложных фактов, проверит ли он их по коду или слепо доверится памяти?
Я построил детерминированного прокси-агента и запустил его на контролируемом наборе фактов. Важное замечание о методологии: я не подключал живую LLM, поэтому использовал детерминированного прокси-агента на основе эвристик. Это означает, что результаты измеряют структурную способность системы, а не психологическое поведение живой модели. Живая модель может быть ленивее или умнее — я всё ещё пытаюсь это выяснить.
Я внедрил 50 фактов в изолированное хранилище памяти:
Я протестировал три конфигурации агентов:
Для научной строгости эксперимент был повторён с независимым набором фактов (N=50) и проверен по 6 осям (включая аудит таблицы истинности и независимый аудит LLM «свежим взглядом»). Результаты были идентичны.
Вот как я интерпретировал эти цифры:
Текущий отраслевой консенсус для слоёв доверия «ОС знаний» — использовать временные метки, приоритет источников и отношения supersedes/contradicts. Мой первоначальный эксперимент показал, что этого недостаточно. Временные метки и ссылки «supersedes» решают только историю на уровне узлов. Если ADR заменён, узел памяти обновляется, но нижестоящий код, тесты и документация, созданные на основе старого предположения, всё ещё находятся в графе. Они структурно устарели, но поисковый движок продолжает их подтягивать. Я предположил, что нужен явный переход состояния: VERIFIED → REFUTED.
Я реализовал механизм RetractionReceipt в своей системе:
Я снова запустил эксперимент (Эксперимент 1-R). Честному агенту разрешалось использовать инструмент отзыва в сессии 1. Затем в сессии 2 запускался свежий memory_first агент для чтения памяти после отзыва.
Жизненный цикл отзыва сработал. Уровень принятия ленивого агента упал со 100% до 12%. Постоянные ложные факты сократились на 88%, а размер токенового контекста уменьшился на 45%, потому что опровергнутые факты отфильтровывались до попадания в LLM.
Мой ADR предсказывал, что принятие упадёт до 0. Этого не произошло. Оно упало до 0.12. Оставшиеся 12% были SILENT-фактами. Явный статус REFUTED требуется, чтобы программно исключить зависимые компоненты из конвейера извлечения. Но это работает только при наличии противоречащего сигнала в коде. Если память утверждает «мы используем Celery», а кодовая база вообще не упоминает Celery, у агента нет доказательств для запуска отзыва. Чтобы достичь нуля, я понял, что нужна «проверка при чтении» — механизм, который оспаривает утверждение памяти против кодовой базы, даже когда код молчит.
Я реализовал ленивый слой валидации (ADR-0003). Когда load_memory() извлекает узел, он извлекает лёгкие «якоря» из текста памяти (например, имена файлов, операторы импорта, переменные окружения). Затем он проверяет, существуют ли эти якоря в живом слепке кодовой базы (текущий git HEAD).
Я запустил эксперимент в последний раз (Эксперимент 1-V) с этим активным слоем. Чтобы предотвратить всплески задержки, валидация работает в строгом бюджете 50 мс на извлечение, с TTL-кэшем на git HEAD 30 секунд, так что чтение в стабильном состоянии стоит почти ничего.
Слой проверки при чтении достиг цели. Принятие ложных фактов честным агентом упало до абсолютного нуля, даже для SILENT-фактов. Поскольку система теперь активно проверяет, действительно ли кодовая база содержит то, что память утверждает, тихие галлюцинации перехватываются на границе извлечения и отфильтровываются до того, как отравят контекст LLM.
Я не буду притворяться, что это идеальное серебряное пуленепробиваемое решение. Эксперимент выявил два крайних случая:
Построение надёжных ИИ-систем — это не просто предоставление им большего контекста. Это признание того, что память имеет жизненный цикл. Если ваша система не может программно опровергнуть память, ложные факты накапливаются и отравляют окно контекста со временем. Внедрение явного перехода состояния VERIFIED → REFUTED резко снижает контаминацию и экономит токены. Кроме того, добавление слоя «проверки при чтении» закрывает последний разрыв на «тихих» галлюцинациях, доводя контаминацию честного агента до нуля без значительной задержки.
Однако семантический дрейф остаётся сложной проблемой. Механическая проверка всё ещё может быть обманута «ловушками присутствия», если агент не читает окружающий контекст. Следующий шаг — перенести извлечение якорей на путь записи, чтобы воспоминания создавались со строгими проверяемыми ссылками с самого начала.
Что делать прямо сейчас: если вы строите систему с памятью для ИИ-агентов, добавьте явные статусы для узлов памяти и инструмент для их аннулирования. Реализуйте проверку при чтении, чтобы сопоставлять утверждения памяти с фактическим кодом. Начните с малого: выберите один тип памяти (например, ADR) и добавьте проверку якорей. Это снизит галлюцинации и сэкономит токены.
Если ваша система обрабатывает семантический дрейф иначе или вы решили проблему «ловушки присутствия», я искренне хотел бы услышать, как вы к этому подходите.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →