Авторинг кастомных агентов
Кастомные персоны расширяют Ongrid вашими собственными specialist. Они живут на диске как файлы <name>.md с YAML frontmatter, ровно так же, как встроенные — тот же загрузчик, тот же реестр, тот же путь диспетчеризации. Напишите одну, смонтируйте, и coordinator сможет на неё диспетчировать.
Эта страница — контракт.
Раскладка файла
Персона — один Markdown-файл с YAML frontmatter:
---
name: specialist-clickhouse
description: ClickHouse 查询性能 / 分区健康 / mutation backlog 专家
when_to_use: |
When the user asks about:
- ClickHouse query plan / scan / shuffle slow
- Partition merges / mutation backlog
- Replication lag between replicas
- System.parts / system.mutations inspection
tools:
- query_knowledge
- query_clickhouse_system # custom BaseTool you registered
- query_promql # for clickhouse_* metrics
- host_bash
- get_edge_summary
disallowed_tools:
- host_restart_service
permission_mode: read-only
max_turns: 12
model: anthropic/claude-sonnet-4-7
critical_reminder: |
You're read-only. Never propose direct ALTER / OPTIMIZE without
citing the system.mutations evidence first. Always check the
replication lag before recommending any maintenance command.
---
# specialist-clickhouse
You are Ongrid's ClickHouse specialist.
## Step 0: knowledge base check (mandatory)
Before any inspection, call `query_knowledge` once with a natural-
language description of the question. Hit (score >= 0.6) → follow
the playbook. Cite as `(参考 KB: <title>)` in your final reply.
## Working style
1. Start with `query_clickhouse_system` for system.parts /
system.mutations / system.replication_queue. One call, broad
snapshot.
2. If a specific table is suspect, drill into `system.parts` for
that table with bytes / rows / merge_state.
3. For replication: `system.replication_queue` for failures,
`clickhouse_replica_delay_seconds` PromQL series for trend.
4. For query perf: `system.query_log` with `query_duration_ms`
sort + `read_rows` to find the heavy query.
## Output
- 现状 (1-2 sentences): which table, which metric, what's wrong.
- 证据 (2-3 lines): system.* row excerpts + PromQL value.
- 建议 (1 line): observation only, or "recommend dispatching
specialist-ops to run OPTIMIZE/ALTER under reviewer".Справочник frontmatter
Поля, которые понимает парсер (ParseAgentMd):
| Поле | Обязательно | Тип | Назначение |
|---|---|---|---|
name | да | string | Ключ порождения. Должен быть уникальным. snake_case или kebab-case. |
description | да | string | Появляется в каталоге агентов coordinator. |
when_to_use | да | string | Первая строка появляется в каталоге. Строго обязательно, потому что coordinator не может выбрать персону без неё. |
tools | нет | []string | Whitelist имён BaseTool. Пустой = ничего не наследуется. |
disallowed_tools | нет | []string | Blacklist. Перевешивает whitelist; поддерживает wildcards (*_skill). |
permission_mode | нет | string | read-only / mutating-with-confirm / dual-sign-required. Сегодня информационно; будущие версии могут автоматически подключать декораторы на основе этого. |
max_turns | нет | int | Жёсткое ограничение цикла ReAct. По умолчанию 15. |
model | нет | string | Идентификатор LLM (например, anthropic/claude-sonnet-4-7). Откатывается к org default. |
critical_reminder | нет | string | Обёрнут в <critical-reminder>...</critical-reminder> в системном промпте. Также переинъецируется на каждом ходе графовым слоем. |
initial_prompt | нет | string | Дописывается перед первым user-ходом воркера. Редко используется. |
background | нет | bool | true = асинхронное порождение (UI не блокируется). Используется reviewer. |
omit_claude_md | нет | bool | Подавить базовый промпт рантайма для этой персоны. |
metadata | нет | map | Свободная форма. metadata.ongrid.{scope, min_ongrid_version} читается реестром; остальное проходит насквозь. |
Неизвестные поля сохраняются в Agent.UnknownFields, так что будущие дополнения формата персон Claude Code (effort, isolation, mcp_servers, hooks, …) не ломают загрузку.
tools vs disallowed_tools
Whitelist + blacklist, чёрный побеждает. Так что:
tools: ["query_*", "host_bash"] # everything starting with query_, plus bash
disallowed_tools: ["query_devices"] # but not this oneоставляет query_promql, query_logql, query_traceql, query_knowledge, … и host_bash, минус query_devices.
Wildcards: *_skill сопоставляется с любым именем инструмента, заканчивающимся на _skill. Так reviewer одной строкой блокирует все выполнения скиллов.
AgentTool также автоматически вычищается из набора любого воркера — воркеры не могут порождать воркеров. Вам не нужно перечислять его под disallowed_tools.
Где живут персоны
Рантайм обходит два корня:
- Корень, запечённый в образ —
/app/agents/внутри контейнера manager. Содержит шесть поставляемых персон. Read-only внутри образа; переживает рестарт контейнера, но не пользовательский код. - Marketplace-корень —
/var/lib/ongrid/agents/(монтированный том). Авторские персоны пользователей приземляются сюда через UI Settings → Agents или через путь установки marketplace.
Оба сливаются в один AgentRegistry. При коллизии имён загрузчик записывает предупреждение и оставляет первую загрузку. Чтобы переопределить встроенную персону, сохраните вашу версию с тем же name через UI Settings — AgentRegistry.Replace делает upsert на месте.
С чего начать
Самый быстрый путь — скопировать agents/specialist-disk.md в редактор, переименовать и подогнать набор инструментов. Форма несёт все соглашения (KB-first, 4-шаговая инструкция, формат вывода), которые хорошо работают с coordinator.
Горячая перезагрузка vs рестарт
| Действие | Горячо перезагружаемо? | Как |
|---|---|---|
| Редактировать тело персоны (system prompt) | Да | Settings → Agents → Save |
| Изменить whitelist инструментов | Да | То же. Фильтр применяется per spawn. |
Изменить model / max_turns | Да | То же. Новые порождения берут новые значения. |
| Добавить новую персону | Да | Settings → Agents → New, или drop file + Reload |
| Удалить персону | Да | Settings → Agents → Delete, или удалить файл + Reload |
Переопределить встроенную (тот же name) | Да | Replace делает upsert; coordinator использует новую. |
| Изменить, какие инструменты есть в наборе | Нет | Регистрация BaseTool — на стороне бинаря. |
| Добавить новый BaseTool | Нет | Требует изменения кода + рестарта manager. |
Изменить семантику default_locale | Нет | Это runtime-код. |
Блокировка вокруг AgentRegistry — это sync.RWMutex. In-flight ход coordinator, который уже получил указатель на персону, продолжает использовать снапшот; следующий ход coordinator видит новую персону.
Отладка
«Coordinator никогда не диспетчирует на мою персону»
- Проверьте каталог агентов в системном промпте coordinator (manager логирует отрендеренный промпт при старте с
--log-level=debug). Ваша персона должна появиться с еёdescriptionи первой строкойwhen_to_use. - Если каталог её не имеет: загрузчик записал предупреждение. Проверьте
AgentRegistry.Warnings()через API (GET /api/v1/agents/warnings) или поищите строкиchatruntime: parse <path>в логе manager. - Если каталог её имеет, но LLM её не выбирает: затяните
when_to_use. Ведите конкретным триггер-паттерном; LLM подсказана читать первую строку как matching hint.
«Воркер порождается, но сразу падает»
Частые причины:
- Whitelisted инструмент отсутствует в наборе. Рантайм фильтрует и молча отбрасывает всё, чего нет; воркер не может вызвать то, чего там нет. Проверьте
GET /api/v1/skillsдля активного набора. - Неверный идентификатор модели. Resolver чат-модели маппит
anthropic/<x>наdefault_provider, если не сконфигурировано. Поставьтеdefault_providerвanthropicв Settings → LLM или закрепите конкретный provider+model в персоне. max_turnsслишком мал. Воркер, у которого кончаются ходы до того, как он произведёт финальное assistant-сообщение, возвращается какfailed. Поднимите до 15+ для любой нетривиальной персоны.
«Воркер возвращает OK, но вывод — мусор»
Тело персоны — это ваш системный промпт. Затяните:
- Начните со Step 0: единственный форсированный KB-вызов. Заякоривает воркера.
- Укажите формат вывода дословно в теле. Coordinator парсит на этот формат.
- Используйте
critical_reminderдля жёстких ограничений (read-only, no PII, язык вывода). Он обёрнут в<critical-reminder>И переинъецируется на каждом ходе — LLM видит его на каждой итерации.
Тестирование вашей персоны
Две точки интеграции:
Из чат-поверхности
Откройте /chat, задайте вопрос, который соответствует when_to_use вашей персоны. Смотрите на SPA — если coordinator диспетчирует, появится «Agent tile» с name вашей персоны + description AgentTool. Кликните для транскрипта воркера.
Из API
curl -X POST http://localhost:8080/api/v1/chat \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{"prompt": "<the question that should trigger your persona>"}'Стриминговый ответ показывает:
textdeltas — проза coordinator.agent_tileenvelopes — каждая диспетчеризация AgentTool.task_notificationenvelopes — завершение воркера.
Если ваша персона диспетчируется, соответствующий agent_tile.persona будет вашим name.
Когда НЕ писать кастомную персону
- Задача — ответ на 1 инструмент. Не оборачивайте «запрос моего кастомного Prometheus» в персону. Зарегистрируйте кастомный BaseTool и пусть coordinator его вызывает.
- Задача разовая. Персоны для повторяющихся паттернов. Для one-shot исследования просто спросите coordinator напрямую.
- Задача требует вызовов по всем 5 specialist. Это ровно то, для чего coordinator существует; не пишите meta-specialist, чтобы воссоздать поведение coordinator.
Хорошее правило: пишите персону, когда одинаковая форма вопроса повторяется, ответ требует 5+ вызовов инструментов, а набор инструментов уже, чем у coordinator.
Раздача персон
- Положите файл
.mdв вашopsрепозиторий. Смонтируйте его в контейнер manager под/var/lib/ongrid/agents/. Реестр подхватит его при старте (или на вызове Reload). - Для org-wide роллаута отправляйте через marketplace скиллов — установка marketplace бандлит персоны + скиллы вместе и автоматически триггерит
Reload.
Связанное
- Обзор агентов — полная картина.
- Формат персоны — каждое поле, без прозы.
- Манифест скилла — companion-формат для отгрузки персон рядом с кастомными скиллами.