job_id для опроса AgentEye. Результаты сохраняются и отображаются на панели управления.
Это руководство охватывает:
- Как определяется завершение сеанса.
- HTTP-контракт, который должен реализовать оценщик.
- Конфигурирование сервера AgentEye.
- Просмотр результатов.
- Устранение неполадок.
agenteye-evaluator на PyPI.
Как это работает
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 /evaluate | JSON 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.
Терминальная ошибка на стороне оценщика:
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 | /evaluations | evaluations: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/aggregate | evaluations:read | Свёрнутое здоровье оценок для отфильтрованного среза: общее количество, разбивка done/error/timeout, статистика по ключам оценки (count/avg/min/max/p50 по произвольным ключам scores), и временная шкала по периодам. Принимает те же параметры фильтра как /evaluations плюс featured_keys (CSV ключей оценки для тренда) и latest_per_session. Питает функцию Dashboards; метрики точны над целым совпадающим набором, не выбираются. |
GET | /evaluations/environments | evaluations:read | Отличные значения окружения из таблицы evaluations. Используется для заполнения выпадающих меню фильтра, ограниченных данными, доступными для чтения оценок. |
GET | /evaluation-jobs | evaluations:read | Видимость в полёте оценок. Фильтр по status (pending/polling). |
GET | /events | events: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/export | events:read | Возвращает точное тело JSON, которое оценщик получит для этого сеанса, поданное как загружаемое вложение с именем session-<id>.json. Полезно для повторного воспроизведения сеансов производства через agenteye-evaluator для автономного тестирования. Байты идентичны тому, что отправляет конвейер оценщика. |
POST | /sessions/:session_id/re-evaluate | evaluations:trigger | Поставить в очередь свежую оценку для сеанса; работает независимо от того, существует ли предыдущая оценка. Новый результат добавляется на временную шкалу оценки сеанса вместо перезаписи предыдущей, поэтому предыдущие оценки остаются видимыми как история. Возвращает 202 при постановке в очередь, 404 для неизвестного сеанса, 409 если оценка уже выполняется. Используйте это после развёртывания нового оценщика или для сеансов, которые никогда не излучали agent_end. |
Фильтрация по диапазону оценок: score_filters
GET /evaluations принимает необязательный параметр score_filters, который сужает результаты по числовым значениям внутри объекта scores. Параметр — это список, разделённый запятыми, записей key:min..max; либо граница может быть опущена. Несколько записей объединяются с логическим И. Строки, где названный ключ отсутствует или не является числовым, исключаются. Запрос может содержать не более 20 записей фильтра; превышение возвращает HTTP 400.
Примеры:
/evaluations имеет эти поля:
| Поле | Тип | Примечания |
|---|---|---|
evaluation_id | string (UUID) | Канонический идентификатор для этой терминальной оценки. Каждая терминальная оценка получает новый UUID; один сеанс может содержать несколько. |
id | string (UUID) | Обратная совместимость псевдоним, несущий то же значение как evaluation_id. |
session_id | string | Сеанс, против которого выполнялась оценка. Сеанс может иметь несколько оценок на временной шкале. |
agent_id | string | Идентифицирует агента, который произвёл сеанс. |
environment | string | Метка окружения, скопированная из сеанса. |
status | enum | Один из "done", "error", "timeout". |
scores | object | null | Оценки, возвращённые вашим оценщиком. |
reasoning | object | null | Необязательная карта обоснования для каждой оценки, возвращённая вашим оценщиком. Ключи обычно отражают те, что в scores. На панели управления каждая запись отображается под полосой оценки. |
summary | string | null | Необязательное однопараграфное общее описание, возвращённое вашим оценщиком. На панели управления это отображается выше разбивки per-score как заголовок оценки. |
error | string | null | Заполнено только на "error" / "timeout". |
attempt_count | integer | Количество попыток отправки (≥ 1). |
duration_ms | integer | null | Длительность последней попытки. |
completed_at | string (ISO 8601 UTC) | Когда был записан терминальный результат. Результаты упорядочены по completed_at (новое в первую очередь). |
created_at | string (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 ниже).


Панели управления
Страница Dashboards (/dashboards) позволяет вам сохранить комбинацию фильтров оценок как названное, переиспользуемое представление и видеть, как этот срез оценок делает дела с одного взгляда. Панели управления совместно используются всей вашей организацией; все, у кого есть dashboards:read, видят один и тот же набор.
Каждая панель управления закрепляет:
- Фильтры: те же элементы управления как на странице сеансов: окружение, статус, агент, скользящее временное окно и фильтры диапазона оценок (
key:min..max). - Конфигурацию отображения: какие ключи оценок выделять, пороги здоровья зелёный/жёлтый/красный, какие панели показывать и свёртывать ли в последнюю оценку на сеанс.
GET /evaluations/aggregate), поэтому числа точны, а не выбираются.

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, если ваш оценщик законно нуждается дольше, чем по умолчанию.
