Skip to content

Авторинг кастомных агентов

Кастомные персоны расширяют Ongrid вашими собственными specialist. Они живут на диске как файлы <name>.md с YAML frontmatter, ровно так же, как встроенные — тот же загрузчик, тот же реестр, тот же путь диспетчеризации. Напишите одну, смонтируйте, и coordinator сможет на неё диспетчировать.

Эта страница — контракт.

Раскладка файла

Персона — один Markdown-файл с YAML frontmatter:

markdown
---
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нет[]stringWhitelist имён BaseTool. Пустой = ничего не наследуется.
disallowed_toolsнет[]stringBlacklist. Перевешивает whitelist; поддерживает wildcards (*_skill).
permission_modeнетstringread-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нетbooltrue = асинхронное порождение (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, чёрный побеждает. Так что:

yaml
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.

Где живут персоны

Рантайм обходит два корня:

  1. Корень, запечённый в образ/app/agents/ внутри контейнера manager. Содержит шесть поставляемых персон. Read-only внутри образа; переживает рестарт контейнера, но не пользовательский код.
  2. 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 никогда не диспетчирует на мою персону»

  1. Проверьте каталог агентов в системном промпте coordinator (manager логирует отрендеренный промпт при старте с --log-level=debug). Ваша персона должна появиться с её description и первой строкой when_to_use.
  2. Если каталог её не имеет: загрузчик записал предупреждение. Проверьте AgentRegistry.Warnings() через API (GET /api/v1/agents/warnings) или поищите строки chatruntime: parse <path> в логе manager.
  3. Если каталог её имеет, но 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

bash
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>"}'

Стриминговый ответ показывает:

  • text deltas — проза coordinator.
  • agent_tile envelopes — каждая диспетчеризация AgentTool.
  • task_notification envelopes — завершение воркера.

Если ваша персона диспетчируется, соответствующий 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.

Связанное