Coordinator
Le coordinator est la persona à laquelle l'utilisateur parle réellement. Chaque session de chat (UI web, Slack, Telegram, Feishu) appartient à une seule instance de coordinator. Ce n'est pas un worker — c'est la boucle ReAct longue durée qui pilote la conversation, décide quand répondre directement et décide quand dispatcher vers un specialist via AgentTool.
Identité
| Champ | Valeur |
|---|---|
| Nom de persona | default |
| Spawnable comme worker | Non — le catalogue d'agents exclut default |
| Modèle de session | Une ligne chat_sessions longue durée par (user, chat thread) |
| Sac d'outils | Large : query_*, AgentTool, SendMessage, TaskStop, redirect stubs |
| Corps de persona | Embarqué dans l'image manager ; override par organisation via fichier monté |
Si vous voulez modifier le comportement du coordinator pour toute la flotte, montez un default.md personnalisé par-dessus le fichier intégré (voir Agents personnalisés). Le seam AgentRegistry.Replace est ce qui alimente l'UI d'édition des user-agents ; un fichier d'override utilise le même chemin de code au démarrage.
Ce qu'il peut faire directement
Le sac d'outils du coordinator inclut tous les outils query en lecture seule qui fonctionnent au scope manager :
query_promql,query_logql,query_traceql— télémétrie. Stubbés sur le coordinator (redirection vers incident-investigator) pour les cas d'hallucination connus — voir plus bas.query_knowledge— RAG sur le vault + les uploads.query_incidents,get_incident_detail,query_alert_rules,query_devices— alerte / inventaire.query_change_events— mutations récentes de config / règle / device.expand_topology,find_topology_node— graphe de service.get_active_incidents— alertes ouvertes actuelles.- Outils BC handler — tout ce qu'un admin org/user ferait depuis l'UI.
Il ne porte délibérément pas d'outils host-shell ou d'inspection par host. Ceux-ci vivent sur les specialists.
Le trio d'outils de contrôle
Trois outils spéciaux ne vivent que sur le coordinator. Ils contrôlent l'orchestration multi-agent ; ils ne queryent rien.
AgentTool
Dispatche un worker. Synchrone. Le schéma complet, le comportement de dédoublonnage et le garde-fou « ne pas déléguer des broutilles » sont documentés sur l'Aperçu des agents. La forme :
{
"description": "Find which process is OOM-ing on node-01",
"subagent_type": "specialist-compute",
"prompt": "On device_id=7 we saw mem_used_pct=98 at 14:02. Find the top RSS processes and check dmesg for oom-killer hits. The user originally asked: 'who's eating memory on node-01?'"
}Le system reminder injecte le catalogue de personas pour que le LLM connaisse les valeurs subagent_type valides. Le rappel est par tour — même après dérive d'attention dans les longues sessions, le LLM n'oublie jamais quels specialists existent.
SendMessage
Envoie un message intermédiaire à l'utilisateur sans terminer le tour. Utilisé quand le coordinator veut dire « je dispatche vers specialist-network — laissez-moi une minute » avant que le dispatch ne se stabilise. Les workers ne portent pas cet outil — seul le coordinator parle à l'utilisateur.
Le pont IM s'en sert pour mettre à jour le message placeholder dans le chat (chat.update sur Slack, editMessageText sur Telegram, PUT /messages sur Feishu). L'UI web s'en sert pour streamer du texte intermédiaire dans la transcription avant la réponse finale.
TaskStop
Annule poliment un worker en cours d'exécution. Le coordinator émet TaskStop quand, par exemple, l'utilisateur change de sujet en plein dispatch et que la réponse du worker en cours n'est plus pertinente.
En interne il appelle Runtime.StopWorker, qui déclenche le context.CancelFunc du worker. Le worker observe ctx.Done() à son prochain appel d'outil et passe Status = killed.
Quand dispatcher vs répondre directement
Le prompt de persona du coordinator encode la règle :
AgentTool n'est pas l'option par défaut. Si l'on peut répondre avec les outils locaux en 1-2 étapes, on répond soi-même. Une investigation profonde et complexe (nécessitant 5+ étapes / multi-hosts / multi-signaux) seule justifie un dispatch.
Autrement dit : ne dispatcher que lorsque la tâche
- nécessite une itération profonde (5+ appels d'outils d'inspection focalisée),
- nécessite des outils côté host (
host_bash,host_probe_*,host_du_summary), ou - bénéficie d'un sac d'outils spécifique au domaine que le coordinator ne porte pas.
Pour « quelle est la charge sur node-01 ? », le coordinator répond directement avec un seul get_host_load (bon — avec un AgentTool(specialist-compute) médiatisé par redirect stub ; le principe est le même). Pour « pourquoi le service order renvoie des 502 et que dois-je faire ? », le coordinator dispatche vers incident-investigator.
Redirect stubs (anti-hallucination)
Le sac du coordinator porte des entrées RedirectStub pour les noms d'outils que le LLM est connu pour halluciner (host_bash, host_du_summary, host_restart_service, get_host_load, correlate_incident, …). Quand le LLM choisit un nom stubbé, le stub renvoie :
{
"status": "redirect",
"hint": "This tool is not available in coordinator scope. Re-invoke via AgentTool to dispatch to specialist-disk.",
"reason": "目录占用分析",
"suggested_call": "AgentTool(description=\"…\", subagent_type=\"specialist-disk\", prompt=\"<self-contained task>\", background=true)",
"why_stub_exists": "Coordinator's job is dispatch + triage. Deep-dive tools live on specialist workers; calling them inline is the wrong pattern."
}Sans ces stubs, le runtime de graphe d'eino abandonnerait avec [NodeRunError] tool X not found in toolsNode indexes et gâcherait le tour. Avec eux, le LLM apprend du résultat et réessaye avec le bon appel AgentTool à l'itération suivante. La liste de stubs vit dans CoordinatorRedirectStubs ; c'est de la donnée pure — à compléter au fil du temps à mesure que de nouvelles hallucinations apparaissent.
Ne shadowez pas tout le sac des specialists
Chaque stub mange un slot dans la liste de schémas présentée au LLM. Trop de stubs et le budget de prompt enfle ; le LLM peut commencer à considérer les stubs comme des options valides. Seuls les outils observés en hallucination dans les évals reçoivent un stub.
Ce que voit l'utilisateur
À chaque tour, le coordinator peut :
- Streamer les tokens directement — la réponse est courte et auto-contenue.
- Appeler des outils query en lecture seule inline —
query_incidents,expand_topology,query_knowledge. - Dispatcher un worker via AgentTool — la SPA affiche une « Agent tile » avec le nom de persona + la description d'une ligne pendant que le worker tourne. Le résultat final du worker arrive comme enfant de la tile.
- Envoyer un message intermédiaire via SendMessage — généralement avant qu'un dispatch lent ne se stabilise (« je regarde ça ; je spawn specialist-network »).
- Arrêter un worker via TaskStop — rare, généralement seulement quand l'utilisateur redirige en plein dispatch.
L'utilisateur ne voit jamais la transcription brute du worker. Le coordinator synthétise le Result du worker dans sa propre réponse.
Session et audit
- La session du coordinator vit dans
chat_sessionsavecagent_id = "default"etparent_session_id = NULL. - Les sessions de worker reçoivent un
parent_session_idpointant vers la ligne du coordinator. L'UI d'audit parcourt cet arbre pour rendre les exécutions parent → enfant. - Chaque appel d'outil reçoit une ligne
audit_logsavec la vue du LLM sur les arguments et le résultat tronqué (voir auto-observabilité).
Personnaliser le coordinator
Vous pouvez surcharger le fichier de persona du coordinator. Ce que vous voudriez typiquement changer :
- L'orientation de dispatch (votre équipe a une politique différente de « quand déléguer »).
- La langue / le ton de sortie (utilisez default_locale sur le canal ; ou épinglez via le corps de persona).
- La liste des outils inline en lecture seule que vous voulez que le coordinator utilise avant de dispatcher.
Ce qu'il ne faut pas changer :
- Le bloc de catalogue d'agents — il est généré automatiquement. L'éditer n'a aucun effet ; le prochain rechargement le régénère.
- La sémantique des redirect stubs — c'est du code, pas de la persona.
- Le
namedefault— le runtime cherche le coordinator par nom.
Voir Agents personnalisés pour l'histoire du hot-reload.