EnglishРусский Map

Лог и есть агент

title
Лог и есть агент
type
summary
summary
ActiveGraph меняет архитектуру агентов: лог событий служит источником истины, а граф - его проекцией
tags
ai-agents, architecture, event-sourcing, memory, provenance
created
2026-07-23
updated
2026-07-23
lang
ru
translation_of
log-is-the-agent
source_updated
2026-07-23
translated
2026-09-01
translator
lllm/antigravity/gemini-3.7-flash-medium

Статья Ёхэя Накадзимы (Yohei Nakajima) об ActiveGraph (arXiv 2605.21997, 21 мая 2026 года) - среде исполнения, которая переворачивает привычный порядок построения агентных фреймворков. Обычно их собирают методом постепенного наслоения: начинают с цикла диалога (chat loop), поскольку беседа - это интерфейс, под который обучалась модель; добавляют инструменты, когда нужно действовать; вводят правила, когда поведение начинает плыть; прикручивают логирование под требования продакшена и сохраняют некую сжатую форму взаимодействий, чтобы агент мог "помнить". В такой схеме лог оказывается лишь выхлопом - побочным артефактом аудита, который пишется параллельно с настоящими вычислениями.

ActiveGraph делает сам лог вычислением. Дополняемый поток событий (append-only event stream) выступает единственным источником истины, рабочий граф является его детерминированной свёрткой (fold), а поведения (behaviors) реагируют на изменения графа и порождают новые события. В статье прямо подчёркивается системный характер работы: авторы не заявляют о росте качества решения задач и не приводят бенчмарков в сравнении с базовыми решениями. Среда исполнения доступна под лицензией Apache-2.0 - программная сторона описана в activegraph.

Субстрат

Все составляющие состояния агента сводятся к одной сущности. Цель, правила работы (включая их изменение прямо посреди прогона), доступные инструменты, каждый вызов и ответ на него, трасса рассуждений и любой созданный артефакт - всё это события в едином упорядоченном логе. Обычно они размазаны по шести разным местам: промпт, системное сообщение, внутренности фреймворка, транскрипт, база данных и хранилище памяти с неточным поиском по сходству. Их объединение превращает три сложных вопроса в тривиальные запросы: почему этот факт оказался в рабочей выборке, во что агент верил до изменения правила R и что произошло бы при выборе другой ветки на шаге 42.

Событие содержит идентификатор, тип, полезную нагрузку, создавшего его актора, опциональный указатель caused_by на вызвавшее его событие и метку времени. Состояние графа, то есть типизированные объекты и связи, никогда не меняется внешним кодом напрямую; оно пересчитывается прогонкой событий вперёд. Каждый объект несёт блок provenance с именем создавшего его поведения и событием-причиной, поэтому ничто не существует без отслеживаемого источника. Загрузка прогона, его форк и валидация выполняются через одну и ту же операцию повторного воспроизведения (replay).

Поведение - это реакция, а не шаг алгоритма. Оно декларирует подписку - тип события, опциональный предикат и паттерн топологии графа на подмножестве Cypher - и тело. Тела бывают четырёх видов: простая функция, класс для поведений с конфигурацией, процедура на базе LLM, чьи запрос и ответ сами логируются как события, и relation-behavior - логика, привязанная к типизированному ребру, благодаря чему само связывание двух объектов производит вычисления.

Почему граф, а не просто лог

В статье отдельно обосновывается выбор графа, и эту часть часто пропускают зря. Один лишь event sourcing даёт только лог и плоскую проекцию текущих значений. Для трёх вещей критически важна топология. Подписки опираются на структурные паттерны, поэтому поведение может сработать, например, на "утверждение, отвечающее на открытый вопрос" - предикат, который плоский поток событий выразить не может, если только потребитель сам не соберёт граф заново. Для relation-behaviors типизированные рёбра должны быть сущностями первого класса, а в проекции вида "ключ-значение" их некуда прикрепить. Наконец, структурный diff между двумя прогонами - это diff топологий (какие объекты, связи и патчи различаются), который корректно определён только потому, что проекция представляет собой граф, а не непрозрачный бинарный блоб. Лог обеспечивает воспроизводимость состояния, а граф даёт выразительность для реактивности и сравнений.

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

Контракт детерминизма

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

Этот контракт не проверяется статически. Нарушающее правила поведение нормально отработает в первый раз, но будет поймано позже - при воспроизведении или форке - как ошибка расхождения (divergence error), указывающая на первое событие, которое не удалось воспроизвести.

Исключением является самый важный случай. Вызов модели не является детерминированной функцией от входов, поэтому поведение на базе LLM не удовлетворяет контракту при первом запуске, и фреймворк этого не требует. Вызов уходит во внешний сервис, а ответ сохраняется как событие; контракт вступает в силу при воспроизведении (replay), когда записанный ответ отдаётся из кэша. Важная мысль статьи: детерминизм здесь является свойством повторного проецирования уже существующего лога, а не обещанием воспроизводимости прогона агента с нуля. Это честная формулировка гарантии, которую обычно преувеличивают, и именно так архитектура справляется с вариативностью, описанной в llm-output-variance - среда исполнения не пытается воспроизвести ответы модели, она просто отказывается запрашивать их дважды.

Кэш адресован по содержимому (content-addressed). Ответ модели индексируется по хэшу всего запроса: системное сообщение, сообщения пользователя, идентификатор модели, описания инструментов и схема вывода. Ответ инструмента индексируется по имени инструмента и детерминированному хэшу его аргументов. При повторном воспроизведении сработавшее поведение с совпадающим хэшем запроса получает записанную полезную нагрузку llm.responded или tool.responded, и новый вызов не отправляется. Плата за это - место на диске, ограниченное размером прогона. Пример события llm.requested в статье фиксирует temperature на 0.0, top_p на 1.0, содержит хэш промпта, флаг cache_hit и расчётную стоимость в долларах.

Воспроизведение работает в двух режимах. Нестрогий (permissive) используется по умолчанию при загрузке прогона: кэш отдаёт ответы на любые запросы с совпавшим хэшем, а поведения, чьи хэши изменились (например, из-за правки промпта), делают свежие вызовы, которые записываются как новые события. Строгий режим (strict) повторно запускает поведения и пошагово сравнивает живой поток событий с записанным, выбрасывая ошибку при первом же расхождении. Успешный строгий replay доказывает воспроизводимость прогона и служит инструментом контроля за соблюдением контракта: поведение, читающее системные часы, пройдёт нестрогий replay, но упадет в строгом с указанием на проблемное событие.

Ветвление

Форк ответвляет прогон от выбранного события: события родителя копируются вплоть до точки отсечения, после чего прогон продолжается в собственном логе. Префикс не пересчитывается повторным запуском поведений. Он воспроизводится в памяти графа форка с отдачей всех ответов моделей и инструментов из кэша, а реальное выполнение возобновляется только с момента отсечения. Если форкнуть прогон из 200 шагов ради изменения одной настройки на шаге 150, платить придётся только за шаги с 150-го и далее, получив первые 149 шагов (включая вызовы моделей) бесплатно. Большинство агентных фреймворков вообще не поддерживают форки, так как их состояние невозможно восстановить, а те, что поддерживают, обычно заново прогоняют весь префикс за полную стоимость.

Преемственность здесь проверяема, а не просто декларируема: события форка с 1 по k в точности являются событиями родителя с 1 по k с теми же идентификаторами, что легко проверить сравнением двух логов. После точки отсечения форк получает собственное монотонное пространство идентификаторов для исключения коллизий, а структурный diff наглядно показывает, какие именно объекты, связи и патчи изменились из-за правки в точке ветвления.

Более лёгкий примитив внутри прогона - фрейм (frame) - обслуживает параллельные подконтексты, которые сходятся обратно внутри одного прогона и делят его лог. Правило выбора здесь - долговечность: делайте форк, если ветки расходятся навсегда либо требуют независимого сохранения и сравнения через diff; используйте фрейм, если ветки короткоживущие и затем объединяются. Рекомендуемый паттерн: исследовать варианты во фреймах, а форкать только те ветки, которые имеет смысл сохранить.

Практический пример

В комплекте со средой исполнения идёт пак (pack) для due diligence: набор типов объектов, поведений, инструментов, промптов и политик под конкретный домен. По названию компании он генерирует исследовательские вопросы, ищет информацию по хранилищу документов, извлекает утверждения с подтверждающими фактами, находит противоречия, выявляет риски и формирует отчёт (memo). В поставку включены записанные фикстуры, поэтому команда activegraph quickstart отрабатывает офлайн без API-ключа менее чем за тридцать секунд, выдавая побайтово идентичные логи от запуска к запуску.

Приведённые в статье цифры: 671 событие, 93 объекта (3 компании, 24 вопроса, 9 документов, 25 утверждений, 25 свидетельств, 1 противоречие, 3 риска, 3 отчёта), 76 связей на базе 103 вызовов моделей и 48 вызовов инструментов - и всё это без единой строчки оркестрационного кода.

Сам отчёт - не главное. Объект-утверждение вроде "Выручка Northwind в третьем квартале выросла на 28% год к году до $42M" несёт в себе provenance с указанием создавшего его поведения (document_researcher), вызвавшего события и конкретного события запроса к модели. Через типизированные связи он соединён с вопросом, на который отвечает, документом, из которого выведен, и фактом, который его подтверждает. Для аудита, комплаенса или научных задач именно эта восстановимая цепочка от цели к результату и является главным продуктом.

Самоулучшение только как возможность

Раздел 7 тщательно очерчивает границы: архитектура лишь устраняет конкретные препятствия для самоулучшения, но сама статья не демонстрирует и не измеряет самообучающегося агента. Устраняемое препятствие состоит в том, что в традиционных средах самомодификация незаметна и необратима. Здесь же изменение правила - это событие, поэтому прогон можно воспроизвести в состоянии до правки, а строгий replay покажет, как именно разошлось поведение после неё. Более мощная возможность - подход fork-and-diff как примитив оценки: предложить изменение, сделать форк в точке предложения, применить его, прогнать вперёд и структурно сравнить результат с родителем через diff. Поскольку общий префикс берётся из кэша, каждое потенциальное улучшение оценивается без повторной оплаты предшествующей истории.

Связанные работы и аргумент в пользу blackboard

Раздел о системах памяти рассматривает стек решений, за которыми уже следит этот vault. MemGPT/Letta подгружает контекст в фиксированное окно и выгружает его по аналогии с виртуальной памятью. Graphiti от Zep ведёт темпоральный граф знаний. Mem0 нацелен на извлечение и поиск в продакшене. Hindsight ближе всего подходит к позиции ActiveGraph, предлагая рассматривать память как "субстрат первого класса" с разделением наблюдений и выводов и аудируемым процессом обновлений, однако всё равно остаётся лишь слоем памяти, питающим в остальном не хранящую состояние модель. Общая предпосылка, с которой спорит Накадзима, заключается в том, что память считают производным состоянием, надстроенным над агентом, чьё основное представление живёт где-то ещё - из-за чего provenance в лучшем случае оказывается частичным. Он отмечает, что именно его собственные ранние исследования графовой памяти подтолкнули к этой инверсии: многослойные архитектуры памяти постоянно упирались в отсутствие единой достоверной истории, из которой можно строить проекции. В agent-memory-anatomy системы Mem0, Graphiti и Letta разбираются с точки зрения терминологии, а agent-memory-components описывает общую для них схему экстрактор-хранилище-ретривер.

Наиболее удачный раздел статьи посвящён blackboard-архитектурам. Системы Нии (Nii) 1970-х и 80-х годов организовывали решение задач вокруг разделяемой структуры знаний, из которой независимые источники знаний читали данные и в которую записывали результат, не вызывая друг друга напрямую. Поведения, реагирующие на общий граф, структурно делают ровно то же самое. В ту эпоху модель похоронили две проблемы: источники знаний были хрупкими экспертными системами ручной сборки, а логику управления очерёдностью их работы приходилось писать вручную. LLM снимают обе проблемы, поскольку поведение может быть универсальной функцией на базе модели, а координирующую логику можно описать на естественном языке или сгенерировать. Накадзима идёт дальше и предполагает, что модель "среагируй и запиши ответ" архитектуры blackboard подходит для LLM лучше, чем диалоговый цикл, в который их обычно оборачивают. Он называет ActiveGraph не столько новой идеей, сколько реваншем старой концепции, получившей субстрат, которого ей не хватало. Тот же паттерн разделяемого хранилища данных встречается в behavior-tree, где доска объявлений (blackboard) отвязывает узлы условий от действий, записавших проверяемые значения.

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

Ограничения, названные в самой статье

Поскольку поведения порождают события, запускающие другие поведения, прогон может разойтись или зациклиться. Единственная защита - бюджет на прогон, ограничивающий число событий, вызовов поведений, вызовов моделей, патчей, глубину рекурсии, астрономическое время и финансовые затраты; статья прямо называет это грубым инструментом, а не строгой гарантией остановки. Стоимость воспроизведения растёт с длиной лога, а контрольных точек (checkpointing) или сжатия (compaction) пока нет - прогон на миллион событий сегодня придётся воспроизводить целиком. Эволюция схем поддерживается миграциями, но остаётся операционной сложностью. Внешние инструменты с побочными эффектами безопасны для replay только в том смысле, что воспроизводится сама запись об изменении; реальный мир всё равно был изменён при первом запуске. Главный открытый вопрос - параллелизм: порядок чётко определён внутри дополняемого лога одного прогона, а параллельные писатели или конкуренция нескольких агентов за общий граф пока не решены.

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

Место в vault'е

Наиболее полезно сопоставить статью с заметкой memorizing-session-transcripts, где утверждается, что сохранение и поиск по протоколу действий агента дают худшие результаты, чем дистилляция опыта в артефакты. Противоречие здесь меньше, чем кажется на первый взгляд. theahura критикует работу с текстом транскрипта через поиск по сходству, когда агенты перечитывают черновые рассуждения, которые сами же обоснованно отбросили. ActiveGraph никогда не подсовывает лог модели напрямую для поиска - модель видит проекцию графа, а лог нужен для replay, форков и отслеживания происхождения. Другая его претензия о том, что агенты не умеют удалять контекст и воспринимают каждый токен как намерение, ортогональна этой конструкции и скорее даже решается ею: типизированный причинно-следственный граф с provenance у каждого объекта - это как раз та структура, которая позволяет ответить на вопрос "кто это утверждал, по какой причине и на основе каких свидетельств", чего, по его мнению, и не хватает.

В agent-memory-anatomy уже приводился аргумент о том, что агентам не нужно имитировать биологическое забывание: диск стоит дёшево, а сохранение всего обеспечивает прозрачный аудит. Это та же позиция со стороны систем памяти, и она находится в неразрешённом противоречии с agent-memory-decay, где эта статья неявно принимает ту же сторону. memory-conflict-detection представляет собой более узкую версию того, что diligence pack делает с помощью поведения для поиска противоречий.

Дешёвое ветвление с переиспользованием общего префикса развивает ту же экономику, которую oak реализует в контроле версий, только с другой стороны: Oak делает дешёвым ветвление рабочего дерева, а ActiveGraph делает дешёвым ветвление прогона. Концепция agent-identity-attribution получает атрибуцию из похожей структуры - дополняемого подписанного следа событий - и хорошо объединяется с этим подходом. Реактивная половина архитектуры, где производное состояние пересчитывается при изменении входных данных, реализует принцип из reactive-signals, применённый к гораздо более масштабному объекту.