Перейти к основному содержанию
AgentEye оценивает завершённые сеансы агента, отправляя полную стенограмму событий с помощью POST-запроса на единственный сервис оценки, принадлежащий клиенту. Оценщик возвращает оценки либо сразу, либо передав job_id для опроса AgentEye. Результаты сохраняются и отображаются на панели управления. Это руководство охватывает:
  1. Как определяется завершение сеанса.
  2. HTTP-контракт, который должен реализовать оценщик.
  3. Конфигурирование сервера AgentEye.
  4. Просмотр результатов.
  5. Устранение неполадок.
Для вспомогательного пакета Python, который реализует контракт за вас, см. пакет agenteye-evaluator на PyPI.

Как это работает

Когда SDK AgentEye излучает событие agent_end для сеанса, сервер планирует оценку. Затем он отправляет POST-запрос с полной стенограммой событий на ваш сервис оценки, который может:
  • Вернуть результат сразу с {"status":"done", "scores":{...}, "reasoning":{...}, "summary":"..."}. Результат добавляется на временную шкалу оценки сеанса. Поля reasoning и summary являются необязательными.
  • Отложить с {"status":"pending", "job_id":"abc-123"}. AgentEye затем вызывает GET {EVALUATOR_ENDPOINT}/evaluate/abc-123 до тех пор, пока ваш оценщик не вернёт {"status":"done", ...} или {"status":"error", "error":"..."}. Частота опроса зависит от задачи: ответ pending может включать next_poll_secs для переопределения; в противном случае AgentEye использует значение default_poll_interval_secs из GET /config; в противном случае сервер возвращается к EVALUATOR_POLLING_INTERVAL_SECS (по умолчанию 10s). Все значения ограничены диапазоном [1s, 1h].
Сеансы, которые никогда не излучают agent_end (например, процесс агента, который упал), также могут быть обработаны: GET /config оценщика может вернуть {"inactivity_timeout_secs": 1800}, и AgentEye будет оценивать любой сеанс, простаивающий так долго. Установите это поле в null или опустите его, чтобы отключить этот резервный вариант. Конвейер полностью неоперативен, когда EVALUATOR_ENDPOINT не установлен. Сеанс может накапливать несколько терминальных оценок со временем: каждое событие agent_end (и каждый ручной переоценка с панели управления) добавляет новую строку оценки. Это рекомендуемый способ оценить возобновленный диалог: пользователь завершает агента, возвращается позже, отправляет больше событий, снова завершает агента, и выполняется вторая оценка для полной обновлённой стенограммы. На панели управления показывается последняя оценка как основной результат, а предыдущие оценки — как сворачиваемая временная шкала. Пока одна оценка выполняется для сеанса, дополнительные события agent_end для этого сеанса игнорируются; следующее после завершения текущей оценки поставит в очередь новую оценку как обычно. Резервный вариант неактивности повторно включается и на возобновлённых сеансах: если новые события поступают после предыдущей терминальной оценки и сеанс затем переходит в режим ожидания свыше inactivity_timeout_secs, новая оценка ставится в очередь. Временные сбои (5xx, 429, таймауты, ошибки сети) повторяются с экспоненциальной задержкой до EVALUATOR_MAX_ATTEMPTS; ответы 4xx являются терминальными. AgentEye можно безопасно запускать с несколькими горизонтально масштабируемыми экземплярами серверов; работа распределена так, чтобы один и тот же сеанс никогда не отправлялся дважды одновременно.

HTTP-контракт

Все аутентифицированные маршруты используют аутентификацию с маркером-носителем. Одно и то же значение должно быть настроено на обеих сторонах:
  • Сервер AgentEye: переменная окружения EVALUATOR_TOKEN
  • Сервис оценки: настроено так же (SDK agenteye-evaluator по соглашению читает EVALUATOR_TOKEN)
Если EVALUATOR_TOKEN не установлен, сервер не отправляет заголовок Authorization; оценщик может затем принимать анонимные запросы, что приемлемо для внутренней сети, но не рекомендуется в открытом интернете.

Маршруты, которые должен обслуживать оценщик

МаршрутТело / параметрыОтвет
GET /healthнет{"status":"ok"} (открыто, без аутентификации)
GET /configнет{"inactivity_timeout_secs": <int> | null, "default_poll_interval_secs": <int> | опущено}
POST /evaluateJSON EvalRequest{"status":"done", ...} или {"status":"pending", "job_id":"..."}
GET /evaluate/{id}неттакая же форма ответа как /evaluate

Тело запроса EvalRequest, отправляемое сервером

Формы ответа

Синхронно (выполнено):
reasoning (карта обоснования для каждой оценки) и summary (общее однопараграфное описание) являются необязательными. Ключи в reasoning должны соответствовать ключам в scores; панель управления отображает каждую запись в строке под полосой оценки. Более старые оценщики, которые возвращают только scores, продолжают работать без изменений; reasoning и summary просто отображаются как null, и соответствующие элементы интерфейса опускаются. Асинхронно (отложено):
next_poll_secs является необязательным; если опущено, сервер возвращается к default_poll_interval_secs оценщика из /config, затем к своей переменной окружения EVALUATOR_POLLING_INTERVAL_SECS. Терминальная ошибка на стороне оценщика:
Сервер обрабатывает любое другое тело 2xx как ошибку протокола и записывает терминальную error для сеанса.

Написание оценщика с помощью SDK

Пакет agenteye-evaluator Python предоставляет типизированную обёртку FastAPI, которая реализует HTTP-контракт выше. Установите его из PyPI:
Минимальный жизнеспособный оценщик:
Экземпляр app вызывается ASGI, поэтому uvicorn module:app запускает его. Для оценщиков, которым нужно отложить дорогостоящую работу, возвращайте JobPending и зарегистрируйте обработчик @app.job_lookup; сервер AgentEye опрашивает GET /evaluate/{job_id} до тех пор, пока вы не вернёте терминальный статус или не истечёт лимит EVALUATOR_MAX_POLL_DURATION_SECS (по умолчанию 1 ч). Полная ссылка API, асинхронный шаблон и схема событий: README agenteye-evaluator поставляется внутри каждого архива выпуска на странице выпусков agenteye-enterprise, или вы можете прочитать его на странице пакета в PyPI.

Запуск оценщика на Kubernetes

Оценщик — это ваш сервис: AgentEye не поставляет контейнер оценщика по умолчанию. Выпуск включает ссылочные манифесты Kubernetes в deploy/examples/evaluator/, которые вы можете применить как есть после замены вашего образа и общего маркера-носителя.

1. Контейнеризируйте ваш оценщик

Минимальный Dockerfile для вашего оценщика:
runAsNonRoot (UID 10001) сохраняет совместимость контейнера с профилями ограниченной безопасности Pod.

2. Создайте общий маркер-носитель

Используйте то же значение как EVALUATOR_TOKEN на сервере AgentEye. Сервер отправляет Authorization: Bearer <token> при каждом запросе; SDK использует hmac.compare_digest для проверки в постоянное время и отклоняет несоответствия с HTTP 401.

3. Примените примеры манифестов

Пример включает:
  • Развёртывание с 2 репликами с runAsNonRoot, файловой системой только для чтения, всеми возможностями отключены, проверки живости и готовности на /health
  • ClusterIP сервис на порту 9000
  • Шаблон secret.example.yaml (намеренно исключён из Kustomization; создайте реальный секрет вне пределов, чтобы ни один маркер не попал в git)

4. Подключите AgentEye к нему

На сервере AgentEye установите:
Сервер распределяет EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH одновременных запросов по всем подам оценщика (по умолчанию: 2 × 4 = 8). Масштабируйте replicas и лимиты ресурсов на поде в соответствии с этими серверными переключателями.

Проверка

После полного запуска агента GET /evaluations на сервере AgentEye должен вернуть строку со статусом "done" и оценками, которые производит ваш оценщик.

Конфигурирование сервера AgentEye

Установите в процессе сервера:
Переменная окруженияЗначение
EVALUATOR_ENDPOINTБазовый URL вашего оценщика (http://evaluator:9000). Не установлено = конвейер отключён.
EVALUATOR_TOKENМаркер-носитель. Должен соответствовать значению, которое настроено на сервисе оценщика.
EVALUATOR_WORKERSРабочие задачи на экземпляр сервера (по умолчанию 2).
EVALUATOR_CLAIM_BATCHСтроки, запрашиваемые за тик работника (по умолчанию 4). Пакеты обрабатываются параллельно; фактическое параллелизм на вашей конечной точке оценщика — это EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH.
EVALUATOR_POLL_IDLE_SECSКак долго работник спит между попытками отправки, когда оценка не назначена (по умолчанию 2s).
EVALUATOR_POLLING_INTERVAL_SECSОкончательный резервный вариант для частоты GET /evaluate/{id} когда ни per-response next_poll_secs, ни default_poll_interval_secs оценщика не установлены (по умолчанию 10s).
EVALUATOR_REQUEST_TIMEOUT_MSТаймаут для каждого запроса (по умолчанию 30000).
EVALUATOR_MAX_ATTEMPTSПосле этого количества временных сбоев результат записывается как терминальная error (по умолчанию 5).
EVALUATOR_CONFIG_REFRESH_SECSЧастота GET /config (по умолчанию 300).
EVALUATOR_MAX_POLL_DURATION_SECSМаксимальное реальное время, в течение которого сеанс может оставаться в очереди опроса, прежде чем он будет завершён как timeout (по умолчанию 3600s). Защищает от оценщика, который продолжает возвращать pending навечно.
Чтобы включить автоматическое оценивание для всего экземпляра, подготовьте секрет agenteye-evaluator с обоими установленными ключами. В поставляемых манифестах Kubernetes сервер читает EVALUATOR_ENDPOINT и EVALUATOR_TOKEN из этого необязательного секрета. Создайте его через стандартный процесс управления секретами вашей организации, затем перезагрузите развёртывание сервера, чтобы подхватить изменение. Переключатели настройки выше по умолчанию не подключены; выставьте соответствующие переменные окружения на контейнере сервера в манифесте развёртывания, если вам нужно переопределить значения по умолчанию. См. deployment.md для полной таблицы переменных окружения.

Ссылка API

МетодПутьТребуемое разрешениеНазначение
GET/evaluationsevaluations:readЗапросить терминальные результаты. Поддерживает session_id, agent_id, environment, status (done/error/timeout), ts_from, ts_to, cursor, limit, score_filters, latest_per_session. limit по умолчанию 50 и ограничен 200 (обратите внимание, это отличается от /events, который ограничен 1000). environment принимает список, разделённый запятыми (например, environment=prod,staging); отдельные значения по-прежнему работают. С latest_per_session=true ответ содержит не более одной строки на session_id (самой свежей по completed_at), используемой на странице списка сеансов для свёртывания временной шкалы оценки сеанса в его текущий заголовок. По умолчанию false (возвращает полную историю).
GET/evaluations/aggregateevaluations:readСвёрнутое здоровье оценок для отфильтрованного среза: общее количество, разбивка done/error/timeout, статистика по ключам оценки (count/avg/min/max/p50 по произвольным ключам scores), и временная шкала по периодам. Принимает те же параметры фильтра как /evaluations плюс featured_keys (CSV ключей оценки для тренда) и latest_per_session. Питает функцию Dashboards; метрики точны над целым совпадающим набором, не выбираются.
GET/evaluations/environmentsevaluations:readОтличные значения окружения из таблицы evaluations. Используется для заполнения выпадающих меню фильтра, ограниченных данными, доступными для чтения оценок.
GET/evaluation-jobsevaluations:readВидимость в полёте оценок. Фильтр по status (pending/polling).
GET/eventsevents:readПоток необработанных событий сеанса. Поддерживает session_id, agent_id, event_type (CSV), environment (CSV), ts_from, ts_to, cursor, limit и order. order — это desc (новое в первую очередь, по умолчанию) или asc (старое в первую очередь); неправильное значение возвращается к desc. Постраничное переключение курсора через next_cursor ответа (id события): передайте его как cursor для получения следующей страницы; с asc следующая страница — события после этого id, с desc события до него. limit по умолчанию 50 и ограничен 1000.
GET/sessions/:session_id/exportevents:readВозвращает точное тело JSON, которое оценщик получит для этого сеанса, поданное как загружаемое вложение с именем session-<id>.json. Полезно для повторного воспроизведения сеансов производства через agenteye-evaluator для автономного тестирования. Байты идентичны тому, что отправляет конвейер оценщика.
POST/sessions/:session_id/re-evaluateevaluations:triggerПоставить в очередь свежую оценку для сеанса; работает независимо от того, существует ли предыдущая оценка. Новый результат добавляется на временную шкалу оценки сеанса вместо перезаписи предыдущей, поэтому предыдущие оценки остаются видимыми как история. Возвращает 202 при постановке в очередь, 404 для неизвестного сеанса, 409 если оценка уже выполняется. Используйте это после развёртывания нового оценщика или для сеансов, которые никогда не излучали agent_end.

Фильтрация по диапазону оценок: score_filters

GET /evaluations принимает необязательный параметр score_filters, который сужает результаты по числовым значениям внутри объекта scores. Параметр — это список, разделённый запятыми, записей key:min..max; либо граница может быть опущена. Несколько записей объединяются с логическим И. Строки, где названный ключ отсутствует или не является числовым, исключаются. Запрос может содержать не более 20 записей фильтра; превышение возвращает HTTP 400. Примеры:
Каждый объект ответа /evaluations имеет эти поля:
ПолеТипПримечания
evaluation_idstring (UUID)Канонический идентификатор для этой терминальной оценки. Каждая терминальная оценка получает новый UUID; один сеанс может содержать несколько.
idstring (UUID)Обратная совместимость псевдоним, несущий то же значение как evaluation_id.
session_idstringСеанс, против которого выполнялась оценка. Сеанс может иметь несколько оценок на временной шкале.
agent_idstringИдентифицирует агента, который произвёл сеанс.
environmentstringМетка окружения, скопированная из сеанса.
statusenumОдин из "done", "error", "timeout".
scoresobject | nullОценки, возвращённые вашим оценщиком.
reasoningobject | nullНеобязательная карта обоснования для каждой оценки, возвращённая вашим оценщиком. Ключи обычно отражают те, что в scores. На панели управления каждая запись отображается под полосой оценки.
summarystring | nullНеобязательное однопараграфное общее описание, возвращённое вашим оценщиком. На панели управления это отображается выше разбивки per-score как заголовок оценки.
errorstring | nullЗаполнено только на "error" / "timeout".
attempt_countintegerКоличество попыток отправки (≥ 1).
duration_msinteger | nullДлительность последней попытки.
completed_atstring (ISO 8601 UTC)Когда был записан терминальный результат. Результаты упорядочены по completed_at (новое в первую очередь).
created_atstring (ISO 8601 UTC)Несёт тот же временной штамп как completed_at (семантика write-once).

Разрешения

РазрешениеПредоставляет
evaluations:readСписок результатов оценок, просмотр оценок на панели управления и загрузка метрик здоровья панели управления.
evaluations:triggerРучная постановка оценки для сеанса в очередь через POST /sessions/:session_id/re-evaluate или кнопку re-evaluate на панели управления.
dashboards:readПросмотр сохранённых панелей управления (также требует evaluations:read для загрузки их метрик).
dashboards:writeСоздание и редактирование панелей управления.
dashboards:deleteУдаление панелей управления.
Администратор начальной загрузки (ADMIN_KEY, ADMIN_EMAIL) автоматически получает эти.

Просмотр результатов

  • /sessions/<id>: временная шкала событий + правая колонка, показывающая оценки сеанса и любую ошибку из попытки отправки. Если ваш ключ имеет evaluations:trigger, рядом с кнопкой экспорта появляется кнопка re-evaluate, полезная для сеансов, которые никогда не излучали agent_end, или для обновления оценок после развёртывания нового оценщика. Панель управления опрашивает новый результат и обновляет правую колонку, когда он прибывает.
  • /sessions: фильтруемая сетка сеансов; столбец оценки показывает статус оценки каждого сеанса и оценки с одного взгляда.
  • /dashboards: сохранённые представления здоровья оценок (см. Dashboards ниже).
Сетка Sessions с таблетками статуса оценки per-session и раскрашенными в цвет значками оценки (helpfulness, factuality, tool_efficiency, safety, coherence) Сетка сеансов показывает статус оценки каждого запуска и оценки с одного взгляда; красные/жёлтые/зелёные значки выделяют низкие оценки. Представление деталей сеанса с оценками оценки и состоянием отправки в правой колонке Открытие сеанса показывает его полную временную шкалу рядом с оценками оценки и любой ошибкой диспетчера в правой колонке.

Панели управления

Страница Dashboards (/dashboards) позволяет вам сохранить комбинацию фильтров оценок как названное, переиспользуемое представление и видеть, как этот срез оценок делает дела с одного взгляда. Панели управления совместно используются всей вашей организацией; все, у кого есть dashboards:read, видят один и тот же набор. Каждая панель управления закрепляет:
  • Фильтры: те же элементы управления как на странице сеансов: окружение, статус, агент, скользящее временное окно и фильтры диапазона оценок (key:min..max).
  • Конфигурацию отображения: какие ключи оценок выделять, пороги здоровья зелёный/жёлтый/красный, какие панели показывать и свёртывать ли в последнюю оценку на сеанс.
Каждая карточка показывает количество совпадающих сеансов, разбивку done/error/timeout, среднее для каждой выделенной оценки и маленький трендовый спарклайн. Открытие панели управления показывает полномасштабные панели; open in sessions переносит вас на страницу сеансов предварительно отфильтрованную на точно этот срез. Метрики вычисляются серверной стороной по целому совпадающему набору (через GET /evaluations/aggregate), поэтому числа точны, а не выбираются. Панель управления оценкой-здоровьем с полосами средней оценки на измерение оценщика, разбивкой инструмента ok-vs-error, лучшими инструментами и трендом events-per-hour Разрешения: просмотр требует обоих dashboards:read и evaluations:read; создание и редактирование требует dashboards:write; удаление требует dashboards:delete. Администратор начальной загрузки автоматически получает все эти.

Устранение неполадок

Сеансы существуют, но оценки не создаются. Подтвердите, что EVALUATOR_ENDPOINT установлен в процессе сервера, что сервер и оценщик совместно используют то же значение EVALUATOR_TOKEN, и что конечная точка /health оценщика достижима с сервера. Когда EVALUATOR_ENDPOINT не установлен, конвейер неоперативен. Оценки в полёте накапливаются. Запросите GET /evaluation-jobs, чтобы увидеть очередь в полёте. Проверьте attempt_count, next_attempt_at и last_error для каждой строки. Частые причины: сервис оценщика недостижим или возвращает 5xx (повторяется с задержкой), неправильный EVALUATOR_TOKEN (401 является терминальным), или асинхронный оценщик, который возвращает pending бесконечно (см. ниже). Сеансы завершены, но нет терминальной оценки. Запросите GET /evaluation-jobs?status=polling; результат всё ещё может быть в полёте. Если задача зависает в pending, сервер имеет проблемы с достижением оценщика; проверьте, что оценщик работает и что EVALUATOR_TOKEN совпадает. HTTP 401 from evaluator: invalid bearer token. EVALUATOR_TOKEN на сервере не совпадает со значением, которое настроено на сервисе оценщика. Они должны быть идентичны. Асинхронный оценщик возвращает pending навечно. Сервер опрашивает GET /evaluate/{job_id} до тех пор, пока оценщик не вернёт done или error, или пока не истечёт EVALUATOR_MAX_POLL_DURATION_SECS (по умолчанию 1 ч). После лимита оценка записывается как timeout и удаляется из очереди в полёте. Поднимите EVALUATOR_MAX_POLL_DURATION_SECS, если ваш оценщик законно нуждается дольше, чем по умолчанию.