Модуль 3 · Датчики и ограничения · урок 13 из 24
Наблюдаемость для агента: логи, метрики, браузер
Тесты отвечают на вопрос «выполняется ли то, что мы догадались проверить». Работающее приложение отвечает на вопрос «что происходит на самом деле». Пока агент видит только код и вывод тестов, проверка поведения остаётся за человеком, и при росте числа изменений он становится узким местом. Этот урок — о том, какие каналы наблюдения открыть агенту, в каком порядке и с какими ограничениями.
Что говорит источник
В эксперименте OpenAI, описанном в статье Harness engineering, узким местом в какой-то момент стал именно человеческий QA. Ответ команды — сделать UI, логи и метрики напрямую доступными Codex:
- приложение поднимается на каждый git worktree, у каждого изменения свой экземпляр;
- в рантайм агента подключён Chrome DevTools Protocol и навыки для DOM-снимков, скриншотов и навигации — Codex сам воспроизводит баги и проверяет исправления;
- на каждый worktree поднимается эфемерный стек наблюдаемости: логи с запросами на LogQL, метрики на PromQL, трейсы; после задачи стек удаляется.
Благодаря этому становятся выполнимыми промпты вроде «сервис должен стартовать быстрее 800 мс» или «ни один span в четырёх критичных сценариях не дольше двух секунд». По одному промпту агент в их репозитории записывает видео с багом до исправления и после. Авторы оговариваются: это поведение держится на структуре и инструментах конкретного репозитория и не переносится без сопоставимых вложений.
Наш вывод. Важна не конкретика стека (Loki, Prometheus), а свойство: у агента есть запрос, который возвращает короткий ответ о поведении именно его экземпляра. Если хотя бы одно из трёх не выполнено — логи общие на всех, ответ на мегабайт, данные с прода, — канал не работает или опасен.
Канал первый: браузер
Для веб-проекта это самый дешёвый и самый ценный канал. Anthropic в описании длинных задач пишет, что агенты работали заметно лучше, когда их просили проверять фичу через браузерную автоматизацию, как пользователь: юнит-тесты и curl пропускали ошибки. Там же названа слепая зона — нативные модальные окна браузера агент не видел.
Варианты в экосистеме Codex на октябрь 2026:
- Playwright MCP — работает с деревом доступности страницы, а не с пикселями. Его README прямо предупреждает, что это не граница безопасности; для кодинг-агентов там же советуют Playwright CLI с навыками как более экономный по токенам путь.
- Встроенный браузер в режиме Codex в ChatGPT desktop app — воспроизведение на localhost, аннотации, трассировки производительности. Полный CDP (Developer mode) требует разрешения для каждого сайта и может быть отключён администратором. В облачных окружениях этого браузера нет.
- Свой скрипт на Playwright, который агент вызывает как обычную команду: открыть URL, сделать скриншот и снимок DOM, собрать ошибки консоли и упавшие запросы.
Третий вариант часто оказывается самым надёжным, потому что вы контролируете объём вывода.
import { chromium } from '@playwright/test';
async function main(): Promise<void> {
const url = process.argv[2] ?? 'http://localhost:8001/';
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
const problems: string[] = [];
page.on('console', (m) => m.type() === 'error' && problems.push(`console: ${m.text()}`));
page.on('response', (r) => r.status() >= 400 && problems.push(`${r.status()} ${r.url()}`));
const started = Date.now();
await page.goto(url, { waitUntil: 'networkidle' });
await page.screenshot({ path: 'test-results/agent/page.png', fullPage: true });
console.log(JSON.stringify({
url,
loadMs: Date.now() - started,
title: await page.title(),
h1: await page.locator('h1').allInnerTexts(),
problems: problems.slice(0, 20),
}, null, 2));
await browser.close();
}
main().catch((e) => { console.error(e); process.exit(1); });Запуск — npx tsx scripts/agent/inspect-page.ts http://localhost:8011/cases. Агент получает двадцать строк JSON и путь к скриншоту, который может открыть как изображение. Для проверки адаптива тот же скрипт стоит прогонять по матрице ширин — от 360 px до ultra-wide.
Канал второй: логи
Логи полезны агенту, только если по ним можно искать. Три требования:
- Структура. Одна запись — один JSON: уровень, сообщение, контекст, идентификатор запроса. В OctoberCMS, как и в Laravel, это настраивается в канале логирования через
formatter. - Корреляция. Middleware присваивает запросу идентификатор, процессор Monolog кладёт его в
extra.request_id, а ответ возвращает его в заголовке. Браузерный скрипт может вывести заголовок, а агент — найти по нему записи. - Узкий инструмент. Не «прочитай storage/logs/system.log», а команда, которая возвращает записи по фильтру и с лимитом.
'channels' => [
'agent' => [
'driver' => 'single',
'path' => storage_path('logs/agent.jsonl'),
'level' => 'debug',
'formatter' => Monolog\Formatter\JsonFormatter::class,
],
],#!/usr/bin/env bash
# Использование: scripts/agent/logs.sh <request_id|level> [limit]
set -euo pipefail
filter="$1"; limit="${2:-30}"
jq -c --arg f "$filter" \
'select(.extra.request_id == $f or .level_name == ($f | ascii_upcase))
| {t: .datetime, l: .level_name, m: .message, c: .context}' \
storage/logs/agent.jsonl | tail -n "$limit"Это принцип из статьи Anthropic об инструментах для агентов: несколько целевых инструментов с фильтрацией, пагинацией и усечением лучше одного «дай всё».
Канал третий: метрики и трейсы
Полный стек с LogQL и PromQL на каждый worktree — уровень команды, у которой агенты ведут продукт целиком. Для сайта на OctoberCMS разумнее начать с малого:
- заголовок
Server-Timingв dev-окружении — время контроллера, запросов к базе, рендера Twig; агент читает его из того же браузерного скрипта; - счётчик SQL-запросов на страницу — ловит N+1 после правки компонента;
- бюджет производительности в тесте: страница кейса собирается не дольше заданного порога на локальном стенде.
Как только метрика стала числом с порогом, её можно сделать критерием готовности в промпте: «время ответа /cases на локальном стенде не выше, чем на main, число SQL-запросов не больше 15». Это и есть «промпт со SLO» из статьи OpenAI, только масштабом поменьше.
Не путайте наблюдаемость приложения с телеметрией самого агента. Ключ [otel] в конфиге Codex экспортирует события Codex — полезно для аудита и анализа сессий, но о вашем приложении он ничего не скажет.
Мобильные приложения
Принцип тот же, инструменты другие. Скриншот и журнал симулятора iOS — через xcrun simctl io booted screenshot и xcrun simctl spawn booted log stream с предикатом по подсистеме приложения, Android — adb exec-out screencap -p и adb logcat с фильтром по тегу. Обязательно оборачивайте их в скрипты с фильтром и лимитом: сырой logcat за минуту переполнит контекст.
Границы
Только тестовые данные. Агент не должен читать продовые логи с персональными данными клиентов — ни напрямую, ни через «удобный» MCP-сервер.
Содержимое страницы — недоверенный ввод. Текст на странице может содержать инструкции для агента. Браузер, MCP и Computer Use не проходят через сетевой прокси песочницы Codex, поэтому браузерного агента направляйте только на локальные и тестовые стенды.
Свой экземпляр. Если все агенты пишут в один лог и смотрят на один порт, их наблюдения смешиваются. Как развести окружения — следующий урок, об изолированных окружениях.
Попробуйте сами
10–15 мин на рабочем месте- Добавьте в проект скрипт осмотра страницы по образцу выше и строку в AGENTS.md: «после правок вёрстки запусти
scripts/agent/inspect-page.tsдля изменённой страницы и приложи скриншот к отчёту». - Переведите один канал логирования в JSON и напишите узкий скрипт поиска с лимитом. Попросите Codex воспроизвести известный баг, опираясь только на этот скрипт.
- Выберите одну страницу и сформулируйте для неё численный критерий (время ответа, число запросов). Дайте агенту задачу с этим критерием в разделе «Done when».
Коротко
- Канал наблюдения работает, если есть запрос, короткий ответ и данные именно экземпляра агента.
- Начинайте с браузера: скриншот, DOM, ошибки консоли и упавшие запросы дают больше всего.
- Логи — структурированные, с идентификатором запроса и узким инструментом поиска.
- Метрика с порогом превращается в критерий готовности в промпте.
- Никаких продовых данных, а содержимое страниц считайте недоверенным вводом.