Skip to content

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:

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

方面CoordinatorWorker
谁和用户对话是(通过聊天界面或 IM)不会 —— worker 输出回到 coordinator
工具袋宽:query_*、AgentTool、redirect stubs窄:persona tools: 白名单
Persona 名default(或按组织覆盖)specialist-*incident-investigatorreviewer
谁产生runtime(每个 chat session 一个)AgentToolreview_gate decorator
能否产生子 Agent是(worker)否(worker 不允许嵌套,按设计)
Session长生命、持久化每次 spawn 新 session,作用域一个 turn

coordinator 的活是 派发 + 分诊 + 综合。深挖工具放在 worker 上。coordinator 持有 RedirectStub 槽,专门收 LLM 已知会幻觉的工具名(host_bashget_host_load…);命中后返回一条 redirect 消息,引导模型改走 AgentTool。

AgentTool

coordinator 的派发原语。Wire name AgentTool(PascalCase,对齐 Claude Code 的工具目录)。LLM 可见的 schema:

json
{
  "type": "object",
  "properties": {
    "description":   {"type": "string"},
    "subagent_type": {"type": "string"},
    "prompt":        {"type": "string"}
  },
  "required": ["description", "subagent_type", "prompt"]
}
  • description —— SPA tile 用的 1 行任务摘要。
  • subagent_type —— persona name。注入 coordinator system prompt 的 catalog 列出有效值(persona registry,去掉 reviewerdefault)。
  • 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:

  1. basePrompt —— runtime 的统一前言,可以为空。
  2. agentProfile.SystemPrompt —— persona 的 markdown 正文。coordinator 可有可无(大多有),worker 一定有。
  3. agentProfile.CriticalReminder —— 包在 <critical-reminder>...</critical-reminder> 里。这是 persona 级别的常量;graph 层还会按 turn 重新以 <system-reminder> 注入,扛过长会话的 attention drift。
  4. 每个激活 skill:一个 [能力: <name>] 头 + skill 的 PromptBody

coordinator 在 skill 列表之前还有一个额外块:agent catalogbuildAgentCatalog)—— 一份 markdown bullet 列表,列出"可用 specialist"、descriptionwhen_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 干这几件事:

  1. 构造 proposal 载荷(actiontargetreasonblast_radiusoperator)。
  2. spawn reviewer worker(对 inner tool 视角是同步的),有自己独立的 60s 超时,与 inner tool 的 15s 无关。
  3. reviewer 返回 Decision: approve 时,调用穿透到 inner tool;否则 decorator 返回 ErrReviewRejected,包着 reviewer 的理由。

这就是 agent catalog 把 reviewer 删掉的原因:只有 decorator 能调它。放进 catalog 会让 coordinator 随手派 "review",啥也没把守。

完整状态机见 Reviewer

Worker 生命周期

Runtime.SpawnWorker 状态机:

text
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 workerSpawnWorker 只在 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、热加载、调试。