Мета-инжиниринг AI-систем: от трейсов к улучшению памяти
Автоматический перевод
Эта статья была автоматически переведена с оригинальной английской версии.
Эта статья открывает цикл «Мета-инжиниринг AI-систем» — руководство из шести частей по замкнутому AI-инжинирингу: использованию агентов для расследования сбоев, тестирования изменений и применения результатов для улучшения AI-систем.
Поведение AI-приложения зависит не только от его модели. На результат влияют промпты, retrieved-информация, сохранённая память, инструменты и код приложения. Когда ответ неверен, правдоподобными могут выглядеть сразу несколько изменений. Инженерная задача — определить, какое изменение помогает, какова его цена и что ещё оно может сломать.
Под мета-инжинирингом я здесь понимаю проектирование самого процесса улучшения: какие данные видит агент, что ему разрешено менять, как мы тестируем его предложения и кто решает, принимать ли их. Замкнутый контур описывает, как этот процесс учится на своих экспериментах. Каждый результат влияет на то, что мы пробуем или используем дальше, в том числе когда предложенное изменение не срабатывает.
Мы можем автоматизировать эту работу поэтапно. Человек может указать точные изменения для тестирования, задать набор разрешённых альтернатив для алгоритма поиска или делегировать следующее предложение LLM-агенту. Раннер тестирует каждого кандидата и сохраняет данные для следующего решения. Этот цикл статей посвящён подключению агентов к такому процессу при явном контроле исполнения, эвалуации и принятия изменений.
Главный вопрос всех шести частей — сколько такой работы можно делегировать агенту, сохранив надёжность данных и решения о принятии изменения. Сначала мы разберём всю систему, а затем соберём небольшую рабочую версию вокруг памяти агента.
Что замыкает контур
Нужно различать два цикла. Внутри агентного приложения рантайм-цикл выбирает действие, вызывает инструмент, наблюдает результат и продолжает текущую задачу пользователя. Цикл улучшения работает между версиями этого приложения. Он исследует поведение завершённых запусков и тестирует изменения, призванные улучшить последующие запуски.
Цикл улучшения начинается с данных: неправильного ответа, нежелательного изменения состояния, чрезмерной стоимости или другого наблюдаемого сбоя. Трейс фиксирует шаги, которые привели к результату. Пропозер выбирает кандидата — конкретную версию изменения. Раннер выполняет кандидата на заданных задачах, а эвалуатор проверяет получившееся поведение относительно требований. В живом эксперименте этой статьи пропозером выступает LLM-агент:
Эвалуация информирует решение, но не даёт разрешение автоматически. Кто-то должен решить, оправдывает ли измеренная польза принятие изменения с учётом его влияния на стоимость, разрешения и другие обязательные свойства. В этом цикле статей мы начинаем с ревью человеком. Пропозер может предложить изменение, но не может переписать проверки, увеличить собственный бюджет или выдать себе одобрение.
Есть два обратных пути. История экспериментов питает последующие предложения, в том числе когда кандидат отклонён. Если кандидат одобрен и принят, его поведение поставляет новые данные из эксплуатации. Возможность отката важна, когда эти данные противоречат исходному эксперименту. Записать оценку — лишь один шаг; контур замыкается, когда данные меняют то, что мы пробуем или используем дальше.
Улучшаемый объект — это цель. Ею может быть политика памяти, retrieval-пайплайн, код выбора инструментов или программа, собирающая контекст модели. Ещё одним вариантом вмешательства остаётся обучение модели. Контур может работать с фиксированными весами модели: агент способен улучшать окружающую программу, не обучая модель. В этой первой демонстрации внешний LLM-агент уже присутствует. В следующих частях мы усилим эвалуатор и проверим, оправдывает ли агентный поиск свою стоимость по сравнению с более простыми методами.
Выберите, какую часть поиска делегировать
Предположим, вы уже знаете, что попробовать: сравнить две модели на этапе извлечения или протестировать пороги памяти 0.6, 0.7 и 0.8. Можно самостоятельно задать эти варианты и автоматизировать исполнение, подсчёт метрик и отчётность. Ознакомившись с результатами, вы выбираете следующий эксперимент. Цикл обратной связи работает, даже если система сама не изобретала кандидатов.
Чтобы сделать такое разделение наглядным, я использую четыре рабочих режима. На рисунке показано, как можно постепенно делегировать проектирование экспериментов: начать с точных вариантов моделей, разрешить системе искать настройки и одобренные компоненты или попросить агента расследовать сбои и выбрать следующий эксперимент. Человек задаёт меньше деталей каждой попытки, но по-прежнему определяет правила поиска.
Названия режимов описывают практические схемы, используемые в этом цикле, а не общепринятую шкалу автономности. Что можно менять и кто выбирает изменение — разные решения. Примеры поискового пространства Optuna объединяют выбор модели с диапазонами параметров. Поиск пайплайна в Scikit-learn сравнивает альтернативные компоненты с помощью обычного перебора по сетке. Поэтому сама по себе замена компонента не делает процесс более агентным. Ширина областей на рисунке иллюстрирует распределение работы в этих примерах; это не измеренные доли контроля или усилий.
Расследование под управлением агента описывает, как выбирается следующая попытка. Агент читает сбои и предыдущие результаты, предлагает изменение и адаптируется после теста. Это соответствует различию в workflow и агентных паттернах Anthropic: предопределённый процесс может автоматизировать исполнение, а агент направляет следующие шаги на основе обратной связи. Возможны и гибридные методы: MIPROv2 в DSPy использует модель для предложения инструкций и Bayesian optimization для поиска их комбинаций. Для фиксированного сравнения моделей LLM-пропозер не нужен; его результаты попадают в цикл обратной связи, когда помогают выбрать следующий эксперимент или версию системы.
Полномочия на предложение, исполнение и принятие остаются раздельными. Агент может готовить изменение для одобрения перед каждым запуском или автономно тестировать разрешённые изменения, пока человек отдельно рассматривает принятие. Даже список одобренных компонентов требует совместимых реализаций; разрешение выбрать адаптер не даёт разрешения написать его. В каждом режиме агент остаётся в пределах разрешённых изменений, фиксированных проверок и бюджета и не может выдать себе одобрение на деплой. Делегирование большего объёма работы всё равно оставляет место для надзора: исследование Anthropic о развёрнутых агентах описывает переход пользователей от одобрения отдельных действий к мониторингу и вмешательству.
Все режимы могут использовать один и тот же журнал экспериментов: запись каждой попытки изменения. Сохраняйте кандидата и его родителя, точное изменение и того, кто его предложил, версии тестов и окружения, результат, стоимость, а также любой сбой или отказ. Эта история позволяет человеку передать следующее предложение агенту — или забрать его обратно, — не теряя данные. Оценки из разных версий тестов всё равно нужно различать.
Эта демонстрация объединяет поиск конфигурации с расследованием под управлением агента. Мы задаём пять настроек, тесты, бюджет и правило выбора. Агент выбирает значения и следующую гипотезу на основе обратной связи; Python автоматически запускает тесты. Ревью человеком перед релизом остаётся отдельным этапом. Репозиторий также принимает JSON-кандидата, переданного человеком через lab evaluate. Переборы моделей, адаптеры компонентов и код, написанный агентом, — более широкие варианты для следующих частей, но не реализованные режимы этой демонстрации памяти.
Почему это стоит изучить сейчас
Принцип обратной связи хорошо знаком инженерной практике. Меня интересуют недавние работы, в которых coding-агенты помещаются внутрь процесса расследования и экспериментов. Они дают конкретные реализации для изучения, вместо того чтобы просить нас предположить, что автономное улучшение сработает.
Autoresearch Karpathy задаёт компактный эксперимент: изменить программу обучения, запустить её при фиксированном бюджете времени обучения, изучить результат на валидации и записать, была ли попытка сохранена, отброшена или завершилась сбоем. Инструкции отделяют редактируемый файл обучения от фиксированного кода эвалуации. Благодаря этому предложенную работу и критерий успеха можно проверить.
Meta-Harness, препринт от марта 2026 года, исследует другую цель: код, управляющий тем, какую информацию LLM-приложение сохраняет, извлекает и показывает своей модели. Его пропозер может через файловую систему изучать исходный код, оценки и трейсы исполнения предыдущих кандидатов. История экспериментов становится рабочим материалом для следующего расследования.
Эти проекты формулируют инженерный вопрос цикла: если агент умеет расследовать и предлагать изменения, что должна делать окружающая система, чтобы такие эксперименты приносили пользу? Одного увеличения числа попыток недостаточно для более качественных решений. Слабый эвалуатор может вознаградить вредное изменение, а поисковый процесс — многократно эксплуатировать эту слабость. Мы проверим ценность агентных предложений относительно более простых альтернатив, а не будем заранее предполагать их преимущество.
Как шесть частей соберут одну систему
В статьях будет развиваться один общий companion-проект. Каждая часть берёт вопрос, оставшийся после предыдущего эксперимента, и добавляет механизм, необходимый для его исследования.
| Часть | Вопрос | Что добавляется в ту же систему |
|---|---|---|
| 1. От трейсов к улучшению памяти | Можно ли превратить сбой в улучшение, пригодное для ревью? | Инструмент памяти, LLM-пропозер, ограниченные эксперименты, обратная связь и сохранённые данные. |
| 2. Сделаем это оцениваемым | Распознаёт ли эвалуатор полезные изменения, включая кажущиеся улучшения, которые причиняют вред? | Более сильная эвалуация, намеренно созданные ложные улучшения и проверки того, что доказывают оценки. |
| 3. Харнесс улучшения | Какие части можно переиспользовать для разных целей и рабочих режимов? | Общие исполнение, история и полномочия для человеческих, классических и LLM-пропозеров. |
| 4. Сравним стратегии поиска | Какой объём работы по предложениям стоит делегировать агенту? | Сравнение с человеческим и классическим поиском при сопоставимых бюджетах и разрешённых изменениях. |
| 5. Гарантированное улучшение | Каких данных достаточно для принятия кажущегося победителя? | Более глубокое adversarial-тестирование, поэтапное принятие и управление откатом. |
| 6. От истории к обучающим данным | Могут ли проверенные эксперименты улучшить обучаемый компонент? | Небольшой эксперимент с обучением verifier или policy, сравнённый с более простыми исправлениями. |
Проверки приватности и ревью человеком должны присутствовать уже в первой версии. В части 5 эта защита усилится по мере роста возможностей пропозера. Аналогично, часть 6 исследует возможное применение накопленных данных; при этом каждая предыдущая часть должна оставаться полезной и без обучения новой модели.
Дайте внешнему агенту небольшую и проверяемую цель
Представьте ассистента, который помнит данные аккаунта Ады. 1 января он узнаёт, что она живёт в Берлине. 3 января он узнаёт о переезде в Париж, который состоится 10 января. На вопрос о городе 5 января он отвечает «Париж».
В памяти есть оба факта. Правило retrieval отдаёт предпочтение недавно полученному факту, не проверяя, когда тот становится действительным. Это конкретный сбой, который может расследовать агент улучшения.
Цель намеренно ограничена инструментом памяти, а не полноценным ассистентом. Инструмент получает подготовленные факты, сохраняет или отклоняет их и извлекает значение по запросу. Его writer, обработка дат, retrieval и выбор ответа реализованы обычным Python. Извлечение из диалога и генерацию ответа на естественном языке мы оставляем за пределами эксперимента, чтобы точно определить эффект изменения правила.
LLM находится во внешнем цикле Python-эксперимента. Агент получает результаты тестов, решает, какие настройки изменить, и получает следующий результат обратно. В записанных кампаниях эти изменения выбирала реальная модель.
Такое разделение позволяет тестировать инженерный цикл, не добавляя второй источник модельного поведения внутрь инструмента памяти. В большом приложении обе петли могут использовать модели. Здесь одного LLM достаточно, чтобы сделать процесс улучшения агентным. Та же роль пропозера может быть передана другому LLM; его предложения должны соответствовать той же схеме и проходить те же проверки.
Изучите эксперимент
В companion-репозитории на GitHub находятся внешний агент, инструмент памяти, тесты и компактные отчёты о трёх реальных LLM-кампаниях. Полные запросы, ответы и трейсы доступны в архиве данных с контрольными суммами. В отчёте об эксперименте прослеживаются предложенные изменения, их измеренные результаты и каждое решение остановиться. Позже в статье мы используем репозиторий для запуска новой кампании.
Изучите один тест до того, как читать оценку
Сценарий — это одна завершённая тестовая история. Событие — одно действие, отправленное инструменту памяти: запись, запрос или удаление. Сценарий с будущим переездом состоит из четырёх событий:
- Сохранить
city = Berlin, действующий с 1 января. - Сохранить
city = Paris, полученный 3 января, но действующий с 10 января. - Спросить город 5 января. Ожидается Берлин.
- Спросить город 12 января. Ожидается Париж.
Входные данные уже структурированы. Например, факт о Париже содержит владельца (north workspace, пользователь ada), субъект (account), свойство (city), значение (Paris) и дату начала действия. Строки Berlin и Paris взяты из тестовых данных, а не сгенерированы моделью из диалога.
Confidence — это переданная оценка, по которой решается, сохранять ли предложенный факт. Writer сравнивает её с min_confidence. Предложение delivery = courier с оценкой 0.4 отклоняется при базовом пороге 0.7, но сохраняется при пороге 0.2. Оценку задаёт автор теста; это не измеренная вероятность корректности предложения. Мы оцениваем, как правило хранения обрабатывает эти оценки, а не то, насколько надёжно модель умеет их предсказывать.
Каждый сценарий начинается с пустого списка записей памяти в Python. Принятые обновления закрывают период действия предыдущего значения и добавляют новую запись. После двух записей о городе записи выглядят так:
| Значение | Получено | Действует с | Действует до |
|---|---|---|---|
| Берлин | 1 января | 1 января | 10 января, не включая дату |
| Париж | 3 января | 10 января | Без даты окончания |
Функция ответа возвращает первую найденную запись с запрошенным свойством. Эвалуатор сравнивает это значение с ожидаемым ответом. Сценарий считается пройденным, только если каждый ответ корректен и пройдены все применимые проверки правил данных. Для удаления, изоляции владельцев и запрещённых записей есть отдельные проверки наряду с качеством ответов.
Тесты передают ID владельцев напрямую; в этой демонстрации нет системы аутентификации. Реальный сервис должен получать эти ID из аутентифицированного запроса. Отклонение входных данных, явно помеченных как инструкция, также не демонстрирует обнаружение инструкций, спрятанных в обычном тексте.
Пусть у памяти тоже будет схема
Фактам также нужны собственные правила. Для этого паттерна, в котором схемы управляют сохранённым состоянием и его жизненным циклом, я использую Schema-Guided Agent Memory (SGAM). Здесь мы демонстрируем лишь небольшую часть подхода: типизированные факты, владение, ссылки на источники, интервалы действия и удаление. Позже схема SGR будет управлять тем, что может предлагать внешний агент; эта схема памяти управляет тем, что инструмент может сохранять.
Запись о Париже после второй записи содержит:
{
"tenant": "north",
"user": "ada",
"entity": "account",
"key": "city",
"value": "Paris",
"confidence": 0.95,
"source": "user",
"valid_from": "2026-01-10",
"schema_version": 1,
"memory_type": "fact",
"id": "m002",
"source_event_id": "future-move:event-2",
"observed_at": "2026-01-03",
"valid_to": null,
"supersedes_memory_id": "m001"
}
source_event_id указывает на событие, предоставившее информацию о Париже. supersedes_memory_id связывает Париж с записью о Берлине, m001. schema_version: 1 определяет формат записи; это не означает, что программа умеет автоматически мигрировать старые данные.
MemoryRecord и Memory.write() обеспечивают соблюдение этого формата. Отсутствующие ссылки на источники, некорректные даты и поля неправильного формата отклоняются до изменения сохранённой истории. Закрытый интервал должен заканчиваться после своего начала. Берлин может заканчиваться 10 января, а Париж начинаться в тот же день; ни у одной записи не будет пустого интервала.
Предположим, следующая запись сообщает Рим, также действующий с 10 января. Writer отклоняет этот конфликт, а Париж остаётся без изменений. Вторая запись о Париже с той же датой просто переиспользует существующую запись. Обновление с более ранней датой начала действия также отклоняется: этот небольшой writer не восстанавливает историю задним числом. Это фиксированные политики, которые внешний агент менять не может. Его настройка deduplicate управляет повторными подтверждениями с более поздней датой начала действия.
В базовой версии при чтении по-прежнему намеренно игнорируются фильтры субъекта и даты. Она сохраняет действительные записи, но может выбрать неправильную. Именно этот дефект мы предлагаем агенту исправить. Изоляция владельцев действует для любой конфигурации, а удаление убирает все версии запрошенного свойства в пределах субъекта этого владельца.
Это in-memory-демонстрация правил SGAM. В ней нет постоянной базы данных, сервиса хранения или системы миграций. Отдельные регрессионные тесты writer проверяют отклонённые записи и границы интервалов; это не дополнительные сценарии в оценке кампании из 20 историй.
Пусть агент выберет изменение
Кампания — это одна попытка улучшить исходную конфигурацию, начинающаяся с новой истории агента. Итерация — один вызов, в котором агент предлагает изменение или решает остановиться. Следующая итерация получает обратную связь от предыдущих.
Кампания начинается только с запуска базовой версии. Она проходит 13 из 20 сценариев. Затем мы передаём агенту:
- текущие настройки и их значения;
- измерения базовой версии;
- трейсы проваленных сценариев, отклонённых записей и повторных подтверждений;
- изменения, которые ему разрешено предлагать;
- предыдущие предложения и их результаты, если они есть.
Первый запрос не содержит готовых улучшенных конфигураций. В репозитории также есть четыре подготовленные вручную конфигурации для объяснения механики памяти, но в живой кампании агент не получает эти ответы заранее.
Агент может изменить пять настроек существующего инструмента:
| Настройка | Что меняется |
|---|---|
min_confidence | Меняется минимальная переданная оценка, необходимая для сохранения факта. |
filter_entity | Retrieval ограничивается запрошенным субъектом, например домом вместо работы. |
time_aware | Retrieval ограничивается фактами, действующими на запрошенную дату. |
deduplicate | Идентичный активный факт переиспользуется вместо сохранения ещё одного подтверждения. |
top_k | Задаётся число записей, выбираемых перед упаковкой контекста ответа. |
Предложение может изменить не более двух настроек. Числовые значения ограничены диапазонами: confidence — от 0 до 1, а top_k — от 1 до 8. В контракте зафиксированы разрешённые изменения конфигурации инструмента; схема агента и валидатор добавляют правила для предложений.
У агента нет инструментов shell или filesystem в этом процессе. Он не может редактировать Python, ожидаемые ответы, изоляцию владельцев, поведение удаления, схему памяти, обработку конфликтов, подсчёт оценок, бюджеты или полномочия на релиз. Его вывод — это данные, которые Python может принять или отклонить. Это небольшой эксперимент с конфигурацией, а не сэндбокс для произвольного кода, написанного агентом.
Сделайте каждое предложение записью решения SGR
Я использую Schema-Guided Reasoning, чтобы сделать решение проверяемым. Каждый ответ модели содержит одни и те же поля:
| Поле | Что читатель должен иметь возможность проверить |
|---|---|
observations | Какой переданный сценарий и событие подтверждают предлагаемое изменение? |
hypothesis | Какое правило, по-видимому, вызывает проблему? |
predicted_effect | Что должно улучшиться при тестировании изменения? |
action | Агент предлагает изменение или останавливается? |
patch | Какие разрешённые настройки нужно изменить? |
Запрос OpenAI Responses использует строгую JSON Schema, сгенерированную из моделей Pydantic. Объекты отклоняют дополнительные поля, а каждое поле патча обязательно, но может быть null — то есть «оставить эту настройку без изменений». Structured Outputs ограничивает форму ответа. Python по-прежнему проверяет существование ссылок, допустимость значений и то, что предложенная конфигурация ещё не тестировалась.
Схема не доказывает гипотезу и не раскрывает внутреннее рассуждение модели. Это краткие записи решений, которые можно сопоставить с данными.
В первой записанной итерации агент обнаружил retrieval между разными субъектами и возврат фактов за пределами их интервала действия. В фактическом ответе он предложил такой патч:
{
"min_confidence": null,
"filter_entity": true,
"time_aware": true,
"deduplicate": null,
"top_k": null
}
Эти две настройки выбрала модель. Раннер передал ID родителя и назначил ID кандидата; модель не могла перенаправить изменение на произвольного родителя или файл.
Проследите изменение в Python
И базовая, и новая конфигурация сохраняют одни и те же записи о Берлине и Париже. Предложенное изменение влияет на то, какие записи может рассматривать retrieval.
В Memory.query() эти переключатели включают два фильтра:
if self.config.filter_entity:
eligible = [r for r in eligible if r["entity"] == event["entity"]]
if self.config.time_aware:
eligible = [r for r in eligible if valid_at(r, event["as_of"])]
Проверка действия включает дату начала и исключает дату окончания:
def valid_at(item: dict, at: str) -> bool:
return item["valid_from"] <= at and (
item["valid_to"] is None or at < item["valid_to"]
)
Для дат используется YYYY-MM-DD, поэтому порядок строк совпадает с календарным порядком. Для вопроса 5 января Париж исключается, поскольку становится действительным 10 января. Берлин остаётся доступным. Для вопроса 12 января Париж действителен, а Берлин уже исторический.
Python запускает предложенную конфигурацию на всех 20 историях. Это первое изменение повышает результат с 13/20 до 19/20, при этом все реализованные обязательные проверки проходят. Оно одновременно меняет два фильтра, поэтому прирост на всём наборе измеряет их совместный эффект. Трейс города показывает, что именно сделал фильтр даты в этом конкретном случае.
Раннер выбирает эту конфигурацию родителем следующего эксперимента. Это не означает её деплой. В следующем запросе модель получает измеренный результат, выбранные настройки и оставшиеся данные.
Следующее решение должно использовать результат
Вот полная первая кампания. Каждая строка — реальный ответ модели, а не заранее написанный шаг демонстрационного скрипта:
| Итерация | Что предложил агент | Что сделал Python | Текущий лучший результат |
|---|---|---|---|
| 1 | Включить фильтры субъекта и даты | Валидировал и протестировал; выбрал улучшение | 19/20 |
| 2 | Удалять дубликаты идентичных подтверждений | Протестировал; выбрал, поскольку объём хранения снизился без ухудшения ответов | 19/20 |
| 3 | Снизить min_confidence с 0.7 до 0.6 | Протестировал; выбрал, поскольку последний проваленный сценарий прошёл | 20/20 |
| 4 | Остановиться | Записал решение об остановке; дальнейших изменений не делал | 20/20 |
Во втором ответе агент сослался на сценарий с повторным подтверждением. В этой истории language = German записывается три раза. Дедупликация сохраняет одну запись вместо трёх, не меняя ответ. По всему набору среднее число сохранённых записей снизилось с 1,70 до 1,60, а результат остался 19/20.
Третье предложение касалось другой ошибки. Полезное языковое предпочтение имело переданную confidence 0.6, ниже текущего порога 0.7. Снижение порога до 0.6 позволило сохранить его и при этом по-прежнему отклонять сомнительное предложение о курьере с оценкой 0.4. Результат достиг 20/20; среднее число сохранённых записей стало 1,65, поскольку память теперь сохраняла дополнительный полезный факт.
На четвёртом вызове агент решил остановиться: по предоставленным данным у него не было другого обоснованного изменения. Это решение модели, а не доказательство глобальной оптимальности конфигурации.
Следующий запрос содержит текущие результаты и предыдущие решения. Увидев, что исправление retrieval помогло, агент перешёл к хранению и допуску записей. Раннер не передавал ему эти следующие патчи и не предоставлял заранее написанную последовательность шагов.
Правило выбора фиксировано: требовать прохождения всех обязательных проверок, предпочитать более высокий результат по полным сценариям, а при одинаковом результате — меньшее число сохранённых записей. Худший результат оставляет предыдущего родителя. Тесты также проверяют путь отклонения с помощью заранее заданного ухудшающего предложение; это не было измеренным регрессом качества в трёх живых кампаниях.
Отдельный development-запуск содержит реальное отклонение при валидации: агент сослался на agent-01, ID кандидата, как будто это был сценарий. Ответ соответствовал JSON Schema, но ссылка не указывала на переданное событие, поэтому Python отклонил его до эвалуации. Контроллер возвращает отклонённый ответ и конкретную ошибку валидации как обратную связь; offline-тесты проверяют это поведение. В трёх описанных ниже кампаниях ошибок валидации не было.
Повторяйте поисковую кампанию, а не детерминированный тест
Одна и та же конфигурация памяти и одни и те же входные данные дают одни и те же ответы. Повторение этой эвалуации не добавляет данных о качестве ответов. Раннер проверяет новую конфигурацию один раз и использует ранее проверенные результаты родительских конфигураций для сравнений.
Внешний агент может выбирать разные предложения, поэтому мы запустили три независимые кампании. Каждая начиналась с одного и того же baseline 13/20, получала новую историю и включала не более четырёх решений модели. Ни одна кампания не получала открытия предыдущей.
| Кампания | Решения модели | Оценено предложений | Отклонено до эвалуации | Выбранный результат | Причина завершения |
|---|---|---|---|---|---|
| 1 | 4 | 3 | 0 | 20/20 | Агент остановился |
| 2 | 4 | 3 | 0 | 20/20 | Агент остановился |
| 3 | 4 | 3 | 0 | 20/20 | Агент остановился |
Все три кампании выбрали одну и ту же последовательность: включить оба retrieval-фильтра, удалить дубликаты подтверждений, снизить порог confidence до 0.6, затем остановиться.
Всего было 12 вызовов модели: девять предложений, которые оценил Python, затем три решения остановиться. Каждая кампания выполняла baseline плюс три новые конфигурации на 20 историях: 80 запусков инструмента памяти на кампанию. 20 историй всё время оставались одинаковыми.
Все три кампании выбрали одинаковые финальные настройки. Это небольшое наблюдение для одной модели, одного промпта, одной цели и одного публичного тестового набора. Оно не оценивает, насколько надёжно оптимизатор будет улучшать незнакомые системы. Более сильное сравнение относится к следующим частям цикла: повторным кампаниям при одинаковых бюджетах, конкурирующим методам предложений и тестам, которые пропозер не может изучить.
Оценивайте качество и стоимость на правильном уровне
У эксперимента есть две разные стоимости. Запуск инструмента памяти использует локальное CPU-время и не делает вызовов модели. Запуск внешнего пропозера использует входные и выходные токены. Нулевое поле стоимости провайдера в отчёте об эвалуации памяти описывает только внутренний инструмент, а не стоимость кампании.
В записанном исследовании от 11 сентября 2026 года мы использовали GPT-5.6 Luna (gpt-5.6-luna), effort ризонинга low, сохранённые схему SGR и инструкции, а также максимум 4 096 выходных токенов на вызов. Программа отключала автоматические ретраи SDK и задавала тайм-аут запроса 60 секунд. Точные запросы, возвращённые ID моделей, usage и длительность вызовов сохранены.
Оценка стоимости на основе токенов для 12 вызовов модели составляет USD 0.039177 при настроенном бюджете USD 0.50. Расчёт использует опубликованные тарифы модели, включает надбавку за запись в кэш, указанную в usage, и игнорирует скидки на чтение из кэша. Это консервативная оценка по записанному usage, а не счёт. Стоимость железа и разработки в эту цифру не входит.
Перед каждым вызовом раннер резервирует верхнюю оценку на основе ограниченного размера входных данных и максимального числа выходных токенов. Если оставшегося бюджета недостаточно для этого резерва, он останавливается. Неудачные или прерванные вызовы остаются в журнале; если usage недоступен, зарезервированная сумма сохраняется, а не считается нулевой.
Что касается качества ответов, 20/20 означает, что на этих 20 подготовленных историях прошли все ответы и применимые обязательные проверки. Это не означает, что память готова к продакшену. Все истории — публичные development-кейсы; выбранные трейсы и обратная связь по набору доступны пропозеру. Они охватывают обновления, исторические вопросы, неопределённость, дубликаты, отвлекающие факты, разделение владельцев, удаление и запрещённые записи. Метки search, evaluation и adversarial организуют исходный набор; они не превращают эти случаи в скрытый тестовый набор.
Этот небольшой набор вдохновлён идеями из LongMemEval, MemoryAgentBench, VehicleMemBench и GateMem. Входные данные и подсчёт метрик здесь собственные; результаты не воспроизводят эти бенчмарки.
Вы также можете сравнить четыре подготовленные вручную конфигурации в репозитории. Они показывают, почему хранение большего числа фактов может ухудшить ответы и как можно улучшить хранение без роста качества ответов. Кроме того, они демонстрируют сторону той же экспериментальной инфраструктуры, где варианты задаёт человек, а Python их оценивает. Это полезные учебные сравнения, но не доказательство того, что агентный поиск превосходит компетентного человека или другой метод поиска.
Запустите новую агентную кампанию
Чтобы агент выбирал новые предложения, клонируйте companion-репозиторий и скачайте записанные данные:
git clone --branch v0.2.2 --depth 1 https://github.com/slavadubrov/meta-engineering-ai-lab.git
cd meta-engineering-ai-lab
uv sync --frozen
uv run --frozen python scripts/fetch_evidence.py
uv run --frozen python -m lab verify artifacts/agent-study-03 --source
Загрузка проверяет SHA-256 и восстанавливает полные записи в artifacts/. Она не делает вызовов модели. Если данные уже скачаны, пропустите этот шаг и выполните команду проверки.
Сохраните OPENAI_API_KEY в локальном файле .env.local. Репозиторий игнорирует этот файл. Затем выполните:
uv run --frozen --env-file .env.local python -m lab campaign \
--live --campaigns 3 --iterations 4 --budget-usd 0.50 \
--output artifacts/my-agent-study
--live явно включает вызовы провайдера. Наличие ключа в окружении не превращает offline-команды памяти или браузер в живого агента. --campaigns 3 создаёт три независимые истории агентов; --iterations 4 ограничивает число решений в каждой. Для каждого исследования используйте новый выходной каталог: существующие данные никогда не перезаписываются.
Откройте artifacts/my-agent-study/report.md, чтобы увидеть результаты кампаний и ссылки на каждый запрос, ответ и Python-эвалуацию. Сравните предложенные изменения с записанной выше кампанией: агент может выбрать иначе, даже если тесты памяти детерминированы.
README содержит карту кода и команд. Зафиксированный отчёт кампании и контрольная сумма архива и индекс примеров позволяют напрямую изучить данные этой статьи.
Храните историю экспериментов отдельно от памяти пользователя
Инструмент памяти хранит город и язык Ады. История эксперимента хранит то, что видел агент, предложенный патч, возможное отклонение, полученные измерения и то, какая конфигурация стала следующим родителем. У этих хранилищ разные задачи.
Каждая итерация сохраняет точный запрос с инструкциями и схемой, ответ провайдера, usage и время выполнения, результат валидации и завершённую эвалуацию, если она была. Проваленные предложения остаются видимыми. Хэши файлов связывают сохранённые данные с реализацией и входными данными, использованными в эксперименте.
Это синтетические факты, поэтому публичная запись может хранить состояния целиком. Для реальных трейсов нужна отдельная политика хранения: удаление факта из инструмента памяти не удаляет предыдущие копии из журналов экспериментов или бэкапов. Тест удаления в демонстрации проверяет записи инструмента и последующие чтения, а не стирание из каждого возможного хранилища.
Что должна проверить следующая статья
Теперь у нас есть агент внутри цикла улучшения. Он предлагает изменение, получает измеренный результат, выбирает следующее изменение и может решить остановиться. Некорректные предложения проходят отдельный путь отклонения и остаются в журнале. Его полномочия ограничены конфигурацией; тестирование и ревью перед релизом остаются отдельными обязанностями.
Следующий риск — сам эвалуатор. Если успех вознаграждает сохранение каждого факта, агент может научиться сохранять догадки. Если набор спрашивает только о текущем городе, он может не заметить изменение, уничтожающее полезную историю. Более мощный пропозер способен эффективнее эксплуатировать слабые измерения.
Часть 2, «Сначала сделайте это оцениваемым, потом автономным», рассматривает, как проверить такие измерения до того, как предоставить пропозеру больше свободы. Результат первой кампании 20/20 — отправная точка этого исследования.