Оформление
Свой внешний агент
Что нужно реализовать, чтобы собственный сервис заработал в EVA как внешний агент.
Что вообще требуется
Агент это обычный веб-сервис, который отвечает на несколько запросов по протоколу EACP. Платформа не запускает его, не следит за его процессом и не планирует его работу. Агент работает сам, а платформа только управляет им и собирает его события.
Минимально нужны три обработчика. Всё остальное необязательно, и платформа сама определит по описанию, что вы поддерживаете.
Шаг 1. Обязательный минимум
| Обработчик | Что вернуть |
|---|---|
GET /manifest | Описание себя: версия протокола, сведения об агенте, список возможностей |
GET /health/ready | Готовность |
GET /status | Живое состояние: чем занят, сколько задач активно и в очереди |
В описании обязательно указать версию протокола, начинающуюся с 1., иначе платформа откажется подключаться.
Раздел возможностей это ваше заявление о том, что вы умеете. Что укажете, то платформа и будет использовать. Например если не объявить поток событий, платформа не станет его читать.
Шаг 2. Авторизация
Платформа передаёт при каждом обращении заголовок с токеном, который администратор ввёл при подключении.
Authorization: Bearer <ваш service token>Ваша задача проверять этот токен и отвечать 401 при неверном и 403 при недостатке прав.
Дополнительно приходит уникальный идентификатор обращения. Его полезно писать в свои логи: так одно и то же обращение можно найти и у вас, и в платформе.
Шаг 3. Адрес
Соблюдайте требования к адресу, иначе платформа его не примет.
| Правило | Подробности |
|---|---|
| Схема | Только http или https |
| Данные для входа в адресе | Нельзя |
| Параметры запроса и якорь | Нельзя |
Принято оканчивать базовый адрес на /agent-api/v1.
Шаг 4. Настройки, если они у вас есть
Не описывайте свои поля в платформе. Вместо этого отдайте их схему, и платформа нарисует форму сама.
| Обработчик | Что делает |
|---|---|
GET /settings/schema | Схема настроек в формате JSON Schema |
GET /settings | Текущие значения |
PATCH /settings | Применить изменения |
GET /settings/history | История изменений, постранично |
Смысл такого подхода
Платформа сознательно не знает полей конкретного агента. Благодаря этому добавление нового агента с любыми настройками не требует правок EVA.
Шаг 5. Поток событий
Это то, ради чего платформа держит с вами постоянную связь.
| Обработчик | Что делает |
|---|---|
GET /events | Постраничная история, начиная с указанного номера |
GET /events/stream | Поток, начиная с указанного номера |
Требования к событиям:
Номер должен монотонно возрастать. Платформа хранит номер последнего прочитанного события и продолжает с него. Так события не теряются при обрыве связи и не удваиваются.
У каждого события должен быть свой идентификатор. Платформа проверяет уникальность и по номеру, и по идентификатору.
Маскирование персональных данных обязательно
Каждое событие обязано быть помечено как прошедшее маскирование. Событие без такой пометки платформа отклонит с ошибкой и не запишет.
Ответственность за само маскирование лежит на вас. Платформа только проверяет наличие пометки и не даёт немаскированным данным попасть в свою базу.
События несут только изменения. Поэтому если вы объявляете проекцию спорных случаев, платформа один раз выполнит полную загрузку текущего состояния, а дальше будет применять изменения из потока.
Шаг 6. Команды, если нужны
| Обработчик | Что делает |
|---|---|
POST /commands | Принять команду, вернуть код 202 и идентификатор операции |
GET /operations/{operationId} | Отдать состояние операции |
Список возможных команд объявляйте в описании себя. Платформа его не задаёт.
Команда приходит с ключом идемпотентности. Повторная команда с тем же ключом не должна выполняться дважды.
Шаг 7. Спорные случаи, если работа требует человека
Когда агент не может решить сам, отложите случай и отдайте его платформе. Оператор разберёт его и вернёт вам решение.
| Обработчик | Что делает |
|---|---|
GET /attention-cases | Очередь случаев |
GET /attention-cases/{id} | Один случай |
GET /attention-cases/{id}/source-file | Исходный файл |
POST /attention-cases/{id}/corrections | Применить исправление полей |
POST /attention-cases/{id}/select-... | Применить выбор кандидата |
POST /attention-cases/{id}/resume | Продолжить обработку |
POST /attention-cases/{id}/resolve | Завершить вручную |
POST /attention-cases/{id}/replacement-document | Принять замену файла |
Каждое изменяющее обращение приходит с четырьмя вещами, и все четыре нужно учитывать:
| Что приходит | Что с этим делать |
|---|---|
| Ожидаемая версия | Сравнить со своей. Не совпало, значит случай уже изменился, отклоните |
| Кто выполняет | Записать в свой аудит |
| Причина | Обязательна, записать в аудит |
| Ключ идемпотентности | Не применять то же действие дважды |
Шаг 8. Свои разделы в интерфейсе, если нужны
Расширение протокола версии 1.1 позволяет объявить свои экраны, и платформа нарисует их сама, без правок EVA.
| Обработчик | Что делает |
|---|---|
GET /ui/manifest | Описание разделов |
GET /ui/views/{viewId}/data | Данные раздела |
GET /ui/views/{viewId}/records/{recordId} | Одна запись |
POST /ui/views/{viewId}/actions/{actionId} | Выполнить объявленное действие |
GET /ui/views/{viewId}/export | Выгрузка раздела файлом |
Доступные виды разделов: таблица, карточка записи, форма, показатели, лента событий, произвольные данные.
| Требование | Подробности |
|---|---|
| Размер описания | Не больше 512 КБ |
| Условный запрос | Поддержите метку и ответ «не изменилось», платформа кэширует описание |
| Идентификаторы, а не адреса | Объявляйте идентификаторы разделов. Путь платформа соберёт сама |
| Права на действия | Указывайте требуемое право у каждого действия, платформа его проверит |
Адреса платформе передавать нельзя
Это принципиальное правило. Агент не даёт платформе готовых адресов для обращения: она собирает их сама из идентификатора раздела. Так агент не может заставить платформу обратиться в произвольное место.
Про строгость разбора
Описание разделов разбирается не строгой проверкой, а нормализацией с ухудшением. Неизвестный вид раздела превратится в показ произвольных данных, неизвестный формат в текст, лишние поля будут отброшены. Ошибки разбора и список ухудшений платформа сохраняет и показывает оператору.
Встроенные страницы через iframe объявить можно, но по умолчанию они выключены. Платформа покажет оператору пояснение вместо содержимого.
Шаг 9. Модель от платформы, если она вам нужна
Если агенту нужен доступ к языковой модели, не храните свои ключи к провайдерам. Объявите соответствующую возможность, и платформа выдаст вам служебный ключ, разрешённую модель и адрес своего OpenAI-совместимого шлюза.
| Обработчик | Что делает |
|---|---|
GET /llm-binding | Отдать текущую привязку |
PUT /llm-binding | Принять привязку от платформы |
DELETE /llm-binding | Удалить привязку |
Расход при этом попадёт в общий учёт платформы и будет отнесён на вашего агента.
Шаг 10. Формат ошибок
Отвечайте по стандарту описания проблем:
json
{
"type": "urn:eva:error:unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "Invalid token",
"code": "UNAUTHORIZED",
"request_id": "0f3c..."
}Проверка перед подключением
| Что проверить | Как |
|---|---|
| Версия протокола | Начинается с 1. |
| Адрес | Соответствует требованиям, оканчивается на /agent-api/v1 |
| Токен | Проверяется, неверный даёт 401 |
| Описание себя | Отдаётся и содержит раздел возможностей |
| Готовность | Отдаётся |
| События помечены как замаскированные | Иначе платформа их отклонит |
| Ключи идемпотентности учитываются | Повтор не выполняется дважды |
После подключения администратор нажимает проверку соединения. Платформа запросит описание и готовность и покажет результат.
Отладка
В платформе есть отладочная заглушка агента, реализующая протокол. Её можно поднять локально и посмотреть, как платформа взаимодействует с настоящим агентом, не имея его под рукой.
Полное описание вызовов на странице Контракт EACP.