Эксперимент · Продвинутый уровень

Как память влияет на визуального агента: воспроизводим тест в Pokémon FireRed

Время чтения: 60 минут Обновлено: 30 июля 2026

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

1. Что именно мы проверяем

Визуальный агент получает изображение экрана, оценивает состояние игры и выбирает следующее допустимое действие. В Pokémon FireRed это может быть нажатие направления, подтверждение, отмена или ожидание.

Нас интересует не способность модели один раз распознать сцену, а её поведение в длинной последовательности. Главный вопрос:

При одинаковом стартовом состоянии, интерфейсе управления и бюджете какая модель достигает большего проверяемого прогресса — и какую роль в разнице играют сохранение состояния, восстановление контекста и повторение маршрутов?

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

Почему недостаточно цены вызова

Пусть модель A тратит меньше на один запрос, но делает 600 действий, а модель B — дороже, но укладывается в 250. Сравнение только по средней цене запроса скрывает:

  • повторное прохождение одного маршрута;
  • циклы у стены, двери или NPC;
  • потерю цели после смены экрана;
  • необоснованные проверки меню и инвентаря;
  • неправильное восстановление позиции;
  • расход токенов на исправление собственных ошибок.

Поэтому единицей эффективности будет не вызов модели, а подтверждённое изменение игрового состояния.

2. Дизайн сравнения

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

Независимая переменная

Основная независимая переменная — модель. Если вы исследуете именно архитектуру памяти, используйте одну модель в двух условиях: без долговременной памяти и с ней. Не смешивайте эти два типа эксперимента в одной таблице.

Контролируемые переменные

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

Единица прогона

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

Порядок запусков следует чередовать: A–B, B–A, A–B. Это уменьшает влияние прогрева инфраструктуры, изменений задержки и ошибок оператора. Количество повторов определите до первого измеряемого запуска.

3. Фиксируем игровое окружение

Pokémon FireRed удобен тем, что прогресс можно проверять по дискретным событиям: смене карты, предмету в инвентаре, завершённому диалогу, исходу боя или значению сюжетного флага. Но эмуляция добавляет скрытые источники случайности.

Выберите короткий, но составной маршрут

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

  1. выйти из здания;
  2. пройти по маршруту с препятствиями;
  3. взаимодействовать с конкретным персонажем;
  4. вернуться в исходную область;
  5. подтвердить результат через меню или игровой флаг.

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

Не используйте неопределённую цель

Фраза «продвинься как можно дальше» плохо проверяется. Вместо неё задайте упорядоченные контрольные точки:

  1. агент покинул стартовую комнату;
  2. перешёл на целевую карту;
  3. достиг нужного объекта или NPC;
  4. выполнил обязательное взаимодействие;
  5. вернулся или перешёл к финальному состоянию.

Манифест эксперимента

{
  "experiment_id": "firered-memory-v1",
  "environment": {
    "emulator_version": "<зафиксированная версия>",
    "game_revision": "<контрольная сумма локального образа>",
    "save_sha256": "<контрольная сумма сохранения>",
    "speed": "1x",
    "frame_skip": 0,
    "viewport": {"width": 480, "height": 320}
  },
  "budget": {
    "max_actions": 500,
    "max_wall_time_seconds": 3600,
    "max_cost": "<одинаковый предел для обеих моделей>"
  },
  "controls": ["UP", "DOWN", "LEFT", "RIGHT", "A", "B", "START", "WAIT"],
  "checkpoints": [
    {"id": "c1", "definition": "<наблюдаемый критерий>"},
    {"id": "c2", "definition": "<наблюдаемый критерий>"},
    {"id": "c3", "definition": "<наблюдаемый критерий>"}
  ]
}

Хешируйте файлы до запуска. Команды ниже не публикуют содержимое файлов:

sha256sum experiment.json
sha256sum saves/firered-memory-v1.sav
sha256sum screenshots/start.png

Не распространяйте образ игры. Для воспроизводимости достаточно документировать его ревизию и контрольную сумму; каждый исследователь должен использовать собственную законную копию.

4. Контракт памяти агента

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

Оперативный контекст

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

Структурированное состояние

После каждого действия агент обновляет компактную запись:

{
  "current_goal": "достичь следующей контрольной точки",
  "location": {
    "map_label": "unknown",
    "local_landmarks": ["дверь снизу", "NPC справа"],
    "confidence": 0.62
  },
  "last_action": "LEFT",
  "last_action_effect": "позиция изменилась",
  "completed_checkpoints": ["c1"],
  "route_memory": [
    {"from": "landmark-door", "action": "UP", "result": "blocked"}
  ],
  "open_questions": ["совпадает ли текущая карта с целевой"],
  "recovery_plan": "при неопределённости сверить два ориентира"
}

Значения здесь иллюстрируют формат, а не результаты теста. Модель должна отличать наблюдение от предположения и указывать уверенность там, где состояние нельзя установить напрямую.

Журнал событий

Журнал событий хранится вне модели и не переписывается агентом. Это источник истины для анализа:

{"step":1,"observation":"frames/000001.png","action":"UP","cost":null,"latency_ms":null}
{"step":2,"observation":"frames/000002.png","action":"LEFT","cost":null,"latency_ms":null}

Поля стоимости и задержки заполняются фактическими значениями провайдера или локального сервера. Не подставляйте расчётные цены без фиксации тарифа и единицы биллинга.

Одинаковый контракт для обеих моделей

Обе модели должны получать:

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

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

5. Метрики, которые нельзя заменить одной ценой

5.1. Прогресс

Определите вектор контрольных точек C = (c1, c2, …, ck). Простейшая метрика:

progress = completed_checkpoints / total_checkpoints

Если этапы различаются по сложности, веса допустимы только при назначении до запуска:

weighted_progress =
  sum(weight[i] for completed checkpoint i) / sum(all weights)

Не меняйте веса после просмотра результатов.

5.2. Число действий

Эффективность действий измеряет, сколько команд потребовалось на единицу прогресса:

actions_per_checkpoint = total_actions / completed_checkpoints

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

5.3. Полная стоимость

total_cost =
  model_input_cost
  + model_output_cost
  + image_processing_cost
  + retry_cost
  + external_tool_cost

Основная нормализованная величина:

cost_per_checkpoint = total_cost / completed_checkpoints

Также храните стоимость одного действия, но не используйте её как единственный вывод.

5.4. Скорость прогресса

checkpoints_per_hour =
  completed_checkpoints / wall_time_hours

Для локальных моделей дополнительно фиксируйте характеристики оборудования. Для удалённых API сохраняйте задержку каждого ответа и число повторных запросов.

5.5. Повторение маршрутов

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

Порог повторов задайте заранее. Для каждого цикла храните начало, конец, длину, число повторов и действие выхода.

5.6. Ошибки памяти

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

Код Тип Проверяемый признак
M1 Забытая цель Действия перестают соответствовать сохранённой текущей цели без нового события
M2 Ложное завершение Агент объявляет этап выполненным, хотя критерий не наблюдался
M3 Повтор отвергнутого пути Агент снова пробует маршрут, ранее записанный как заблокированный
M4 Потеря позиции Агент действует на основании прежней карты после подтверждённой смены области
M5 Несогласованное обновление Структурированная память противоречит наблюдению или журналу действий
M6 Неудачное восстановление После прерывания агент не использует доступные ориентиры и повторяет уже исключённые гипотезы

5.7. Цена ошибки памяти

memory_error_action_cost =
  actions_until_recovery - actions_at_error_onset

Полезно различать число ошибок и их последствия. Одна ошибка, вызвавшая длинный возврат, может быть важнее пяти быстро исправленных неточностей.

6. Практическая реализация

Шаг 1. Подготовьте каталог

experiment/
├── experiment.json
├── prompts/
│   └── agent-system.txt
├── saves/
│   └── start.sav
├── runs/
│   ├── model-a/
│   └── model-b/
└── scripts/
    ├── run_episode.py
    ├── verify_run.py
    └── summarize.py

Шаг 2. Зафиксируйте формат ответа

Агент должен возвращать одну команду и обновлённое состояние. Машиночитаемый формат уменьшает различия между интеграциями:

{
  "observation": {
    "screen_type": "overworld|battle|dialog|menu|unknown",
    "landmarks": [],
    "state_change": "описание наблюдаемого изменения"
  },
  "memory_update": {
    "current_goal": "",
    "completed_checkpoints": [],
    "blocked_routes": [],
    "uncertainties": []
  },
  "action": "UP|DOWN|LEFT|RIGHT|A|B|START|WAIT",
  "reason": "краткая проверяемая причина"
}

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

Шаг 3. Ограничьте атомарность

Атомарное действие — одна команда с заранее фиксированной длительностью. Не разрешайте одной модели отправлять «идти вверх 30 кадров», если другая выбирает направление после каждого кадра. Удобный вариант:

  • одно решение модели;
  • одно нажатие фиксированной длительности;
  • фиксированное ожидание стабилизации;
  • один новый скриншот.

Шаг 4. Сохраняйте артефакты до следующего шага

Минимальная запись одного шага:

{
  "run_id": "model-a-seed-01",
  "step": 42,
  "timestamp_utc": "<ISO 8601>",
  "frame_before": "frames/000042-before.png",
  "frame_after": "frames/000042-after.png",
  "memory_before": "memory/000042-before.json",
  "model_response": "responses/000042.json",
  "action_requested": "LEFT",
  "action_executed": "LEFT",
  "checkpoint_events": [],
  "usage": {
    "input_tokens": null,
    "output_tokens": null,
    "provider_cost": null
  },
  "technical_retry_count": 0
}

Шаг 5. Запускайте модели одинаковой командой

python scripts/run_episode.py \
  --manifest experiment.json \
  --model-config configs/model-a.json \
  --save saves/start.sav \
  --output runs/model-a/run-01

python scripts/run_episode.py \
  --manifest experiment.json \
  --model-config configs/model-b.json \
  --save saves/start.sav \
  --output runs/model-b/run-01

Файлы конфигурации не должны содержать секреты. Передавайте ключи через защищённые переменные окружения и не сохраняйте их в журнале. Названия параметров адаптируйте к используемому раннеру.

Шаг 6. Отделите игровые сбои от модельных

Раннер должен классифицировать остановку:

SUCCESS
ACTION_BUDGET_EXHAUSTED
COST_BUDGET_EXHAUSTED
TIME_BUDGET_EXHAUSTED
MODEL_API_FAILURE
EMULATOR_FAILURE
INVALID_MODEL_OUTPUT
MANUAL_ABORT

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

7. Как размечать ошибки памяти

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

Процедура разметки

  1. Разметчик не знает, какая модель создала прогон.
  2. Он видит последовательность кадров, действий и память агента.
  3. Для каждого кандидата указывает тип ошибки, начало и момент восстановления.
  4. Он цитирует поле памяти или наблюдаемое событие, которое подтверждает конфликт.
  5. Неуверенные случаи получают метку UNCERTAIN и не смешиваются с подтверждёнными.

Форма аннотации

{
  "run_id": "anonymous-03",
  "error_id": "e-007",
  "type": "M3",
  "start_step": 118,
  "recovery_step": 137,
  "evidence": {
    "prior_memory_step": 91,
    "conflicting_decision_step": 118,
    "frame_refs": ["000091-after.png", "000118-before.png"]
  },
  "confidence": "high",
  "notes": "краткое описание без предположений о модели"
}

Два разметчика для неоднозначных случаев

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

Что не считать ошибкой памяти

  • модель впервые неверно распознала непонятный объект;
  • случайное игровое событие изменило ожидаемое состояние;
  • команда не исполнилась из-за потери фокуса окна;
  • кадр был захвачен во время переходной анимации;
  • нужная информация была удалена раннером и не могла быть восстановлена;
  • модель исследует альтернативу, не утверждая, что прежний путь забыт.

8. Анализ без придуманных победителей

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

Метрика Модель A Модель B
Завершённые эпизоды / все эпизоды Заполнить после теста Заполнить после теста
Медианный прогресс Заполнить после теста Заполнить после теста
Медиана действий на контрольную точку Заполнить после теста Заполнить после теста
Полная стоимость Заполнить после теста Заполнить после теста
Стоимость на контрольную точку Заполнить после теста Заполнить после теста
Подтверждённые ошибки памяти Заполнить после теста Заполнить после теста
Действия, потерянные из-за ошибок памяти Заполнить после теста Заполнить после теста
Число циклов без прогресса Заполнить после теста Заполнить после теста
Технические повторы Заполнить после теста Заполнить после теста

Сравнивайте распределения, а не только среднее

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

Используйте попарное сравнение

Сопоставляйте эпизоды, начатые из одного сохранения и проведённые при одинаковом бюджете. Для каждой пары вычисляйте:

delta_progress = progress_B - progress_A
delta_actions = actions_B - actions_A
delta_cost = cost_B - cost_A
delta_memory_errors = memory_errors_B - memory_errors_A

Разложите стоимость

Если модель дороже, выясните почему:

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

Конкретный разбор одного случая

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

  1. развилка до и после боя действительно эквивалентна;
  2. заблокированный проход присутствовал в доступной памяти;
  3. после боя не появилось события, которое могло открыть путь;
  4. повтор не был сознательной проверкой с явно указанной причиной.

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

9. Проверка воспроизводимости

Проверка до запуска

  • манифест одинаков для обеих моделей;
  • контрольная сумма сохранения совпадает;
  • разрешение кадров совпадает;
  • тайминг атомарного действия фиксирован;
  • валидатор ответов один и тот же;
  • бюджеты заданы до запуска;
  • критерии контрольных точек наблюдаемы;
  • правила ошибок памяти записаны заранее.

Проверка каждого эпизода

python scripts/verify_run.py \
  --manifest experiment.json \
  --run runs/model-a/run-01

Верификатор должен проверить:

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

Повторное воспроизведение

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

Минимальный комплект публикации

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

10. Типичные сбои и способы обработки

Кадр захвачен во время анимации

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

Окно эмулятора потеряло фокус

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

Модель возвращает несколько действий

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

Агент застрял в меню

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

Модель бесконечно исследует

Не останавливайте её субъективно. Используйте общий лимит действий и формальное правило цикла. Иначе терпеливость оператора станет скрытой переменной.

Стоимость недоступна в ответе API

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

Обновилась модель с тем же именем

Фиксируйте точный идентификатор версии или снимка, если провайдер его предоставляет. Если версия не закрепляется, сохраняйте дату и время каждого запуска и прямо отмечайте ограничение воспроизводимости.

Один прогон повреждён

Правило исключения должно быть задано заранее. Не заменяйте неудачный модельный эпизод, но повторите технически повреждённый — сохранив и исходный сбой, и причину повторения.

11. Ограничения эксперимента

  • Один маршрут не представляет всю игру. Навигация, бой, диалоги и управление инвентарём предъявляют разные требования к памяти.
  • Визуально похожие состояния трудно сравнивать. Без доступа к внутренним координатам часть циклов останется спорной.
  • Структурированная память меняет задачу. Она может помогать одной модели больше, чем другой, даже при одинаковой схеме.
  • Эмуляция не устраняет случайность. Встречи, бои и тайминг могут развести попарные прогоны.
  • Стоимость меняется со временем. Публикуйте исходное использование, чтобы расчёт можно было обновить.
  • Малое число эпизодов ограничивает выводы. Результат описывает выбранный сценарий и конфигурацию, а не универсальное превосходство модели.
  • Наблюдаемая ошибка не всегда раскрывает причину. Повтор маршрута может возникнуть из-за памяти, распознавания, планирования или неисполненной команды.

12. Итоговый протокол

  1. Определите одну составную задачу и наблюдаемые контрольные точки.
  2. Создайте эталонное сохранение и зафиксируйте контрольные суммы.
  3. Закрепите версии игры, эмулятора, моделей, промпта и раннера.
  4. Дайте моделям одинаковые изображения, действия, память и бюджеты.
  5. Используйте атомарные команды и сохраняйте кадры до и после каждой команды.
  6. Записывайте ответы, память, использование, задержки и технические повторы.
  7. Чередуйте порядок моделей и запускайте несколько попарных эпизодов.
  8. Оценивайте прогресс, действия, время и полную стоимость.
  9. Размечайте ошибки памяти по заранее заданной таксономии.
  10. Отдельно считайте потерянные действия до восстановления.
  11. Проверяйте целостность каждого прогона автоматическим валидатором.
  12. Публикуйте сырые значения и ограничения, не только средние показатели.

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