Agent 总览
Ongrid 是一个多 Agent ReAct 系统。用户始终和 coordinator 对话 —— 聊天界面顶层那个 persona。当任务进入某个专业领域(深度根因排查、写操作复核、网络深挖)时,coordinator 通过 AgentTool 派发给 sub-agent(一个 "worker")。每个 worker 跑同一套 graph kernel,但拿的是过滤后的工具袋,最终把一个答案返回给 coordinator,由后者揉进自己的回复。
这页是地图。每个 persona 的详细页讲单个 Agent。
Persona 不是聊天线程
persona 是描述一个 Agent 干什么的磁盘文件。标准布局 —— 形态对齐 Claude Code 的 agent 格式,键用 snake_case:
---
name: specialist-disk
description: 文件系统 / 磁盘容量专家 — du / find / stat / inode / 挂载 / 大文件
when_to_use: |
When the task is about disk / filesystem health:
- Disk full / utilization climbing
- Hunt for large files / large directories
- inode exhaustion / mount point inspection
tools:
- query_knowledge
- host_find_large_files
- host_du_summary
- host_stat_file
- host_bash
- query_promql
- get_host_load
permission_mode: read-only
max_turns: 15
---
[markdown body — this becomes the system prompt]frontmatter 之下的正文就是 SystemPrompt。两个同 name 的 persona 文件会撞名,加载器记 warning。每个字段见 persona 格式参考。
Persona 在 manager 镜像里位于 ./agents/(容器内是 /app/agents/)。Ongrid 把内置 persona 打进镜像,同时也从挂载目录读用户自写的 persona —— 见 Custom agents。
Coordinator vs worker
| 方面 | Coordinator | Worker |
|---|---|---|
| 谁和用户对话 | 是(通过聊天界面或 IM) | 不会 —— worker 输出回到 coordinator |
| 工具袋 | 宽:query_*、AgentTool、redirect stubs | 窄:persona tools: 白名单 |
| Persona 名 | default(或按组织覆盖) | specialist-*、incident-investigator、reviewer |
| 谁产生 | runtime(每个 chat session 一个) | AgentTool 或 review_gate decorator |
| 能否产生子 Agent | 是(worker) | 否(worker 不允许嵌套,按设计) |
| Session | 长生命、持久化 | 每次 spawn 新 session,作用域一个 turn |
coordinator 的活是 派发 + 分诊 + 综合。深挖工具放在 worker 上。coordinator 持有 RedirectStub 槽,专门收 LLM 已知会幻觉的工具名(host_bash、get_host_load…);命中后返回一条 redirect 消息,引导模型改走 AgentTool。
AgentTool
coordinator 的派发原语。Wire name AgentTool(PascalCase,对齐 Claude Code 的工具目录)。LLM 可见的 schema:
{
"type": "object",
"properties": {
"description": {"type": "string"},
"subagent_type": {"type": "string"},
"prompt": {"type": "string"}
},
"required": ["description", "subagent_type", "prompt"]
}description—— SPA tile 用的 1 行任务摘要。subagent_type—— personaname。注入 coordinator system prompt 的 catalog 列出有效值(persona registry,去掉reviewer和default)。prompt—— 完整任务简报。worker 看不到 coordinator 的上下文 —— 把所有必要细节(incident_id、device_id、原话)打包进来。
调用从 coordinator 视角是同步的,阻塞直到 worker 进入 completed / failed / killed。早期版本有过 background: true 异步开关;弱模型一拿到就用,返回一个 task_id 给用户后再也不跟进。今天这个标志已删(事后注释见 agent_tool.go)。唯一的异步路径是 reviewer —— 而那是 decorator 驱动,不是 LLM 驱动。
内建去重
一个 120s LRU,key 是 sha256(subagent_type + canonical(prompt)),把两次相同 AgentTool 调用的第二次短路。LLM 看到上一次的结果加一句"你已经派发过这条"。能砍掉 coordinator 死循环(E2E eval D1 不去重时 240s 调 122 次工具)。
system prompt 怎么组装
ComposeSystemPrompt 按顺序拼出 LLM 收到的 prompt:
basePrompt—— runtime 的统一前言,可以为空。agentProfile.SystemPrompt—— persona 的 markdown 正文。coordinator 可有可无(大多有),worker 一定有。agentProfile.CriticalReminder—— 包在<critical-reminder>...</critical-reminder>里。这是 persona 级别的常量;graph 层还会按 turn 重新以<system-reminder>注入,扛过长会话的 attention drift。- 每个激活 skill:一个
[能力: <name>]头 + skill 的PromptBody。
coordinator 在 skill 列表之前还有一个额外块:agent catalog(buildAgentCatalog)—— 一份 markdown bullet 列表,列出"可用 specialist"、description 和 when_to_use 的第一行。catalog 有意排除 reviewer(只有 ReviewGate decorator 才能 spawn 它)和 default(顶层虚拟 persona —— 列进 spawnable sub-agent 会让 coordinator 递归 spawn 自己)。
Agent registry
AgentRegistry 在内存里保存解析过的 persona。启动时 Load 一次;Reload() 在一个 sync.RWMutex 下原子换,coordinator 跑到一半永远不会观察到半成品 registry。
| 方法 | 何时 |
|---|---|
Load(root) | 启动。递归走 <root>/**/*.md。 |
Reload(root, ...) | 应用市场安装/卸载。原子替换。 |
ByName(name) | spawn 时查名。miss 返回 (nil, false)。 |
Replace(ag) | 用户自编 Agent。原地 upsert —— 活 registry,无需重启。 |
Remove(name) | 用户删 Agent。 |
单文件解析错误以 warning 落地,不中断整次 walk(和 skill registry 同政策)。agent root 不存在不算错 —— 你拿到一个空 registry,而不是启动失败。
Reviewer 和 review gate
reviewer 是特殊的:coordinator 不能 spawn 它。它由 ReviewGate decorator 把守,所有 Class 为 "write" 或 "destructive" 的工具被它拦下。decorator 干这几件事:
- 构造 proposal 载荷(
action、target、reason、blast_radius、operator)。 - spawn
reviewerworker(对 inner tool 视角是同步的),有自己独立的 60s 超时,与 inner tool 的 15s 无关。 - reviewer 返回
Decision: approve时,调用穿透到 inner tool;否则 decorator 返回ErrReviewRejected,包着 reviewer 的理由。
这就是 agent catalog 把 reviewer 删掉的原因:只有 decorator 能调它。放进 catalog 会让 coordinator 随手派 "review",啥也没把守。
完整状态机见 Reviewer。
Worker 生命周期
Runtime.SpawnWorker 状态机:
pending → running → completed
↘ failed
↘ killed (StopWorker called while running)chat_sessions行预先创建好,所以审计 + 父→worker 树查询在 worker 还在跑时也能解析到。- 后台 spawn 从长生命的 runtime context 派生,HTTP 请求结束时不会把 worker 拆掉;同步 spawn 继承调用方的 ctx。
- 所有终止路径(包括 panic)都关闭 session 行(设
closed_at)—— 否则会累积孤儿行(修复前测试环境累了 161 个)。
worker 不能 spawn worker。SpawnWorker 只在 Runtime 上暴露,disabledForWorker filter 把任何 worker 的工具袋里的 AgentTool 剥掉。一个 coordinator、N 个并行 worker,没有更深嵌套。
接下来
- Coordinator —— 默认 persona、三个控制工具、何时派发 vs 直接答。
- Incident investigator —— 把根因追到 "patient zero"、18 次工具预算、F1 eval。
- Specialists —— compute / disk / network / ops / sre,各自掌管什么、coordinator 怎么挑。
- Reviewer —— 写操作上的 SOP 双签门。
- Custom agents —— 自写 persona、热加载、调试。