Créer des agents personnalisés
Les personas personnalisées étendent Ongrid avec vos propres specialists. Elles vivent sur disque sous forme de fichiers <name>.md avec frontmatter YAML, exactement comme les personas intégrées — même loader, même registre, même chemin de dispatch. Écrivez-en une, montez-la, et le coordinator peut dispatcher vers elle.
Cette page est le contrat.
Layout de fichier
Une persona est un seul fichier Markdown avec frontmatter YAML :
---
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".Référence du frontmatter
Les champs que le parser comprend (ParseAgentMd) :
| Champ | Requis | Type | Rôle |
|---|---|---|---|
name | oui | string | Clé de spawn. Doit être unique. snake_case ou kebab-case. |
description | oui | string | Affiché dans le catalogue d'agents du coordinator. |
when_to_use | oui | string | La première ligne apparaît dans le catalogue. Strictement requis parce que le coordinator ne peut pas choisir une persona sans. |
tools | non | []string | Whitelist de noms BaseTool. Vide = hérite de rien. |
disallowed_tools | non | []string | Blacklist. L'emporte sur la whitelist ; supporte les wildcards (*_skill). |
permission_mode | non | string | read-only / mutating-with-confirm / dual-sign-required. Informationnel aujourd'hui ; les versions futures pourraient auto-câbler des décorateurs en fonction. |
max_turns | non | int | Plafond dur de la boucle ReAct. Défaut 15. |
model | non | string | Identifiant LLM (par ex. anthropic/claude-sonnet-4-7). Retombe sur le défaut de l'organisation. |
critical_reminder | non | string | Emballé dans <critical-reminder>...</critical-reminder> dans le system prompt. Aussi ré-injecté par tour par la couche de graphe. |
initial_prompt | non | string | Préfixé au premier tour utilisateur du worker. Rarement utilisé. |
background | non | bool | true = spawn asynchrone (l'UI ne bloque pas). Utilisé par reviewer. |
omit_claude_md | non | bool | Supprime le prompt de base du runtime pour cette persona. |
metadata | non | map | Forme libre. metadata.ongrid.{scope, min_ongrid_version} est lu par le registre ; le reste est pass-through. |
Les champs inconnus sont préservés dans Agent.UnknownFields pour que les ajouts futurs au format de persona Claude Code (effort, isolation, mcp_servers, hooks, …) ne cassent pas le chargement.
tools vs disallowed_tools
Whitelist + blacklist, le noir l'emporte. Donc :
tools: ["query_*", "host_bash"] # everything starting with query_, plus bash
disallowed_tools: ["query_devices"] # but not this onelaisse query_promql, query_logql, query_traceql, query_knowledge, … et host_bash, moins query_devices.
Wildcards : *_skill matche tout nom d'outil se terminant par _skill. C'est ainsi que le reviewer bloque toutes les exécutions de skills en une ligne.
L'AgentTool est aussi retiré du sac de chaque worker automatiquement — les workers ne peuvent pas spawner de workers. Vous n'avez pas besoin de le lister sous disallowed_tools.
Où vivent les personas
Le runtime parcourt deux racines :
- La racine cuite dans l'image —
/app/agents/à l'intérieur du conteneur manager. Contient les six personas livrées. Lecture seule à l'intérieur de l'image ; survit au redémarrage du conteneur mais pas au code personnalisé. - La racine marketplace —
/var/lib/ongrid/agents/(volume monté). Les personas créées par l'utilisateur atterrissent ici via l'UI Settings → Agents ou via le chemin d'installation du marketplace.
Les deux sont fusionnées dans le même AgentRegistry. En cas de collision de nom, le loader enregistre un warning et garde le premier chargement. Pour surcharger une persona intégrée, sauvegardez votre version avec le même name via l'UI Settings — AgentRegistry.Replace upserte en place.
Par où commencer
Le chemin le plus rapide est de copier agents/specialist-disk.md dans votre éditeur, de renommer, et d'ajuster le sac d'outils. La forme porte toutes les conventions (KB-first, recette en 4 étapes, format de sortie) qui fonctionnent bien avec le coordinator.
Hot reload vs redémarrage
| Action | Hot-reloadable ? | Comment |
|---|---|---|
| Éditer le corps de la persona (system prompt) | Oui | Settings → Agents → Save |
| Changer la whitelist d'outils | Oui | Idem. Le filtre est appliqué par spawn. |
Changer model / max_turns | Oui | Idem. Les nouveaux spawns prennent les nouvelles valeurs. |
| Ajouter une nouvelle persona | Oui | Settings → Agents → New, ou déposer fichier + Reload |
| Supprimer une persona | Oui | Settings → Agents → Delete, ou retirer fichier + Reload |
Surcharger une intégrée (même name) | Oui | Replace upserte ; le coordinator utilise la nouvelle. |
| Changer quels outils existent dans le sac | Non | L'enregistrement BaseTool est côté binaire. |
| Ajouter un nouveau BaseTool | Non | Nécessite un changement de code + redémarrage manager. |
Changer la sémantique de default_locale | Non | C'est du code runtime. |
Le verrou autour d'AgentRegistry est un sync.RWMutex. Un tour de coordinator en vol qui a déjà récupéré un pointeur de persona continue à utiliser le snapshot ; le prochain tour de coordinator voit la nouvelle persona.
Débogage
« Le coordinator ne dispatche jamais vers ma persona »
- Vérifiez le catalogue d'agents dans le system prompt du coordinator (le manager logge le prompt rendu au démarrage avec
--log-level=debug). Votre persona devrait apparaître avec sadescriptionet la première ligne dewhen_to_use. - Si le catalogue ne l'a pas : le loader a enregistré un warning. Vérifiez
AgentRegistry.Warnings()via l'API (GET /api/v1/agents/warnings) ou cherchez des ligneschatruntime: parse <path>dans le log du manager. - Si le catalogue l'a mais le LLM ne le choisit pas : resserrez
when_to_use. Commencez par un pattern de déclenchement concret ; le LLM est prompté à lire la première ligne comme l'indice de matching.
« Le worker spawne mais échoue immédiatement »
Causes courantes :
- Un outil whitelisté n'est pas dans le sac. Le runtime filtre et laisse tomber silencieusement tout ce qui n'est pas présent ; le worker ne peut pas appeler ce qui n'existe pas. Vérifiez
GET /api/v1/skillspour le sac actif. - L'identifiant de modèle est faux. Le résolveur de modèle de chat mappe
anthropic/<x>àdefault_providersi non configuré. Mettezdefault_provideràanthropicdans Settings → LLM ou épinglez un provider+model concret dans la persona. max_turnsest trop bas. Un worker qui épuise ses tours avant de produire un message d'assistant final revient commefailed. Montez à 15+ pour toute persona non triviale.
« Le worker renvoie OK mais la sortie est du n'importe quoi »
Le corps de la persona est votre system prompt. Resserrez :
- Commencez par Step 0 : un seul appel KB forcé. Ancre le worker.
- Spécifiez le format de sortie verbatim dans le corps. Le coordinator parse sur ce format.
- Utilisez
critical_reminderpour les contraintes dures (lecture seule, pas de PII, langue de sortie). Il est emballé dans<critical-reminder>ET ré-injecté par tour — le LLM le voit à chaque itération.
Tester votre persona
Deux points d'intégration :
Depuis la surface de chat
Ouvrez /chat, posez une question qui matche le when_to_use de votre persona. Regardez la SPA — si le coordinator dispatche, une « Agent tile » apparaît avec le name de votre persona + la description de l'AgentTool. Cliquez pour la transcription du worker.
Depuis l'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>"}'La réponse en streaming fait apparaître :
- des deltas
text— la prose du coordinator. - des enveloppes
agent_tile— chaque dispatch AgentTool. - des enveloppes
task_notification— fin du worker.
Si votre persona est dispatchée, l'agent_tile.persona correspondant sera votre name.
Quand ne PAS écrire de persona personnalisée
- La tâche est une réponse à 1 outil. N'enveloppez pas « query mon Prometheus personnalisé » dans une persona. Enregistrez un BaseTool personnalisé et laissez le coordinator l'appeler.
- La tâche est ponctuelle. Les personas sont pour des patterns répétés. Pour une investigation unique, demandez directement au coordinator.
- La tâche doit appeler à travers les 5 specialists. C'est exactement à quoi sert le coordinator ; n'écrivez pas un méta-specialist pour recréer le comportement du coordinator.
Une bonne règle : écrire une persona quand la même forme de question revient, que la réponse nécessite 5+ appels d'outils, et que le sac d'outils est plus étroit que ce que porte le coordinator.
Partager des personas
- Déposez le fichier
.mddans votre repoops. Montez-le dans le conteneur manager sous/var/lib/ongrid/agents/. Le registre le prend au démarrage (ou sur un appel Reload). - Pour un déploiement à l'échelle de l'organisation, livrez via le marketplace de skills — l'installation marketplace empaquette personas + skills ensemble et déclenche un
Reloadautomatiquement.
Voir aussi
- Aperçu des agents — la vue d'ensemble.
- Format de persona — chaque champ, sans prose.
- Manifeste de skill — format compagnon pour livrer des personas aux côtés de skills personnalisés.