逐文件还原 Ongrid 的运维大脑
一个 Ops AI + 根因分析(RCA)+ 远程执行平台——Coordinator + Specialist 多 Agent 架构、零入站端口反向隧道、自带 Prometheus/Loki/Tempo 可观测性栈、Slack/Telegram/飞书双向 IM 与浏览器 SSH。所有结论来自源码文本,含真实函数名与算法。
# ongridio/ongrid · Go (Chi + cloudwego/eino + singchia/geminio) + TypeScript/React · Apache-2.0
分层架构与三 BC
一句话定位:ongrid 把"运维 AI"拆成三个互不 import 的 Bounded Context——iam(用户/鉴权)、manager(控制面 + AIOps 大脑)、edgeagent(每台主机上的只读探针 + 执行器)。
三者通过 .go-arch-lint.yml 强制隔离,只能借 internal/pkg/**(业务无关共享层)和 api/ 通信。技术栈:Go(Chi router + cloudwego/eino agent 框架 + singchia/geminio 反向隧道)+ TypeScript/React SPA + MySQL/SQLite + frontier broker + Docker Compose。
设计哲学:深度数据查询和高危执行能力都下沉到 edge 和 specialist,coordinator 只做"派给谁 / 直接答 / 直接拒"的调度,并通过 cmdpolicy 沙箱 + ReviewGate 二审把"AI 误操作"的爆炸半径压到最小。边缘 agent 永远是发起方(dial-out);manager 想调用 edge 的能力是通过 frontier broker 反向调用边缘已注册的 RPC handler,而非主动连边缘端口。
浏览器 SPA (web/ React+TS) IM 平台
┌──────────────────────┐ Slack / Telegram / 飞书(Lark)
│ /chat /webshell │ DingTalk / WeCom / Webhook
│ /topology /incidents │ │
└──────────┬───────────┘ │ (webhook + 长连接 stream)
│ HTTP / WebSocket / SSE │
┌────────────────────────────────────┼─────────────────────────────┼──────────────────────────┐
│ cmd/ongrid (manager + iam 装配) │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────────────────┐ ┌────────────────────────────────────┐ │
│ │ internal/manager/server (Chi handlers) │ │ internal/manager/biz/imbridge │ │
│ │ aiops/http webshell/http edgeauth ... │ │ bridge → adapter → AgentSession │ │
│ └───────────────────────┬───────────────────────┘ │ provider/{feishu,slack,telegram} │ │
│ ▼ │ StreamSupervisor (长连接 reconcile)│ │
│ ┌─────────────────────────────────────────────────┐ └──────────────────┬─────────────────┘ │
│ │ chatruntime.Runtime (eino ReAct 图引擎) │◄───────────────────┘ │
│ │ ┌──── COORDINATOR (persona="default") ────────┐ │ │
│ │ │ 受限 toolBag: query_devices / query_incidents│ │ │
│ │ │ get_topology / query_knowledge / search_web│ │ ┌──────────────────────────────┐ │
│ │ │ read_source/grep_source + AgentTool │ │ │ internal/pkg/llm (router) │ │
│ │ └──────────────┬───────────────────────────────┘ │────►│ OpenAI/Anthropic/GLM/ │ │
│ │ AgentTool.SpawnWorker (同步派活) │ │ │ DeepSeek/Gemini/Kimi 热路由 │ │
│ │ ▼ │ │ └──────────────────────────────┘ │
│ │ ┌──── SPECIALIST WORKERS (各自 persona) ───────┐│ │ │
│ │ │ specialist-compute / -disk / -network / -ops ││ │ ReviewGate 二审装饰器 │
│ │ │ specialist-sre / incident-investigator ││ │ (write/destructive → spawn reviewer)│
│ │ │ 每个 worker = filterToolsForAgent 后的子 bag ││ │ │
│ │ └──────────────┬───────────────────────────────┘│ │ │
│ └─────────────────┼─────────────────────────────────┘ │ │
│ tools/ (BaseTool + 装饰器链) │ │
│ query_promql/logql/traceql correlate_incident │ 数据存储 │
│ expand_topology host_bash host_restart_service ... │ MySQL/SQLite topology graph │
└─────────────────┬───────────────────────────────────────┴────────────────────────────────────┘
│ tunnel.Caller.Call(edgeID, method, body) ▲ AcceptStream (webshell forward)
▼ │
┌──────────────────────────────────────────────────────────────┐
│ frontier broker (singchia/frontier:1.2.5) —— 路由/鉴权中枢 │
└──────────────────────────────┬───────────────────────────────┘
▲ edge 主动 Dial 出站 (TCP/TLS),零入站端口
│ geminio RetryEnd 自动重连
┌───────────────────────────────┴───────────────────────────────┐
│ cmd/ongrid-edge (装在被管主机上) │
│ tunnel.Client → register_edge / heartbeat / push_* │
│ RPC handlers: get_host_load / get_process_list / execute_skill│
│ cmdpolicy 沙箱(只读 binary 白名单) webshell TCP 转发到 :22 │
│ plugins: hostmetrics / metrics / logs / traces / procmetrics │
└───────────────────────────────────────────────────────────────┘
Prometheus ◄── remote_write ── Loki ◄── push ── Tempo
用户 / 鉴权
独立 Bounded Context,负责身份与权限。其余 BC 不能直接 import 它,只能走 api/ 与 internal/pkg/** 共享层。
控制面 + 大脑
装配 Chi handlers、IM bridge、chatruntime.Runtime(eino ReAct 图)。AIOps 全在 manager 进程内。
探针 + 执行器
装在每台主机上的只读探针 + 受限执行器,dial-out 连 broker,注册 RPC handler 供 manager 反向调用。
tunnel.Caller.Call(edgeID, method, body),经 broker 路由到该 edge 已注册的 handler——主机上不开 22 / 80 / 443 任何入站口。核心模块拆解
系统由两个二进制(cmd/ongrid 云端主进程 + cmd/ongrid-edge 边缘 agent)和五大业务域组成。下表是逐文件阅读后梳理出的模块职责映射。
| 模块 / 路径 | 作用 |
|---|---|
cmd/ongrid/main.go | 云端主进程:装配 iam + manager,buildAIOpsRuntime 把 LLM router / toolBag / SkillRegistry / AgentRegistry 拼成 chatruntime.Runtime,注册 "default" coordinator persona |
cmd/ongrid-edge/main.go | 边缘 agent:tunnel.NewClient 拨号,注册 collector / host_files / restart_service / bash / webshell handler,启动 plugins supervisor |
aiops/chatruntime/runtime.go | 协调员主循环 Handle:归属校验 → @-mention 内联 → 持久化 user 消息 → 解析 skill/persona → 组 system prompt → BuildReActGraph → Invoke → 翻译 Reply |
aiops/chatruntime/worker.go | Specialist 子 agent 生命周期(SpawnWorker / SendToWorker / StopWorker),filterToolsForAgent 按 persona 白/黑名单裁剪 toolBag,KB-first 预热 |
aiops/graph/react.go | BuildReActGraph:外层 MessageAssembler → ReActSubgraph → OutputProjector,内层复用 eino 的 react.Agent;每轮注入 <system-reminder> 反漂移块 |
aiops/tools/ + decorators/ | 30+ BaseTool(promql/logql/traceql/correlate_incident/expand_topology/host_*),AgentTool 派活工具;装饰器链 tenant_bind → review_gate → timeout → audit → ratelimit → metric |
aiops/investigator/investigator.go | 告警触发时的主动诊断(后台 worker pool,直接调 correlate_incident + 单轮 LLM) |
edgeagent/cmdpolicy/ | host_bash 只读 binary 白名单(ClassReadFS/ReadSystem/Mixed/Network/Denied),write 子命令拒绝;sandbox 加 path/network allowlist |
edgeagent/webshell/handler.go | 把边缘变成纯 TCP 转发器:manager 开 stream → edge dial 127.0.0.1:22 → 双向 io.Copy |
internal/pkg/tunnel/ | 基于 geminio 的反向隧道:client.go 指数退避 + RetryEnd 自动重连 + 路由失效检测重连;messages.go 手写 JSON 消息体 |
manager/biz/imbridge/ | IM 双向桥:bridge.go inbound 归一化 → session 映射 → 渐进编辑;stream_supervisor.go 长连接 reconcile;provider/{feishu,slack,telegram} |
主进程 + 边缘
cmd/ongrid(manager+iam)与 cmd/ongrid-edge(探针+执行器)。
AIOps 内核
新内核在 graph/,与旧 agent.go 并存,本文聚焦 graph 内核。
装饰器链
每个 BaseTool 过同一条装饰器链,横切关注点统一注入。
反向隧道
internal/pkg/tunnel 把 manager↔edge 双向 RPC 收口到一处。
Coordinator + Specialist 多 Agent 协作
模型:Coordinator 和 Specialist 是同一个 chatruntime.Runtime 实例里的不同 persona,区别只在 toolBag 和 system prompt。Coordinator = sess.AgentID 为空/"default";其余 agents/*.md 里定义的都是 worker。
buildAIOpsRuntime(main.go:2376)是整个 AIOps 装配的咽喉——它把每个依赖恰好穿过一次。Coordinator 的 coordinatorToolNames(main.go:2362)被刻意收窄成只读定位 + 知识工具,注释直言这是 "rule 1 的物理执行":coordinator 的 toolBag 里根本没有 query_promql / host_bash 这类深度工具,所以 LLM 即使想 inline 查也调不到,只能走 AgentTool 派给 specialist。
var coordinatorToolNames = []string{
"query_devices", "query_incidents", "get_topology", "query_knowledge",
"search_web", "list_repo_sources", "read_source", "grep_source",
}
派活路径:coordinator 的 LLM 调 AgentTool(PascalCase,刻意对齐 claude-code 的工具名以利模型选择,见 agent_tool.go:91)。AgentTool 是 coordinator-only 工具,tools 包不能 import chatruntime(会循环),所以它通过 WorkerSpawner 窄接口调用,由 main.go 装配处把 *chatruntime.Runtime shim 成该接口。AgentTool 默认同步派活,拿到 worker 结论后强制 coordinator 收口:
w, err := t.spawner.SpawnWorker(ctx, SpawnWorkerRequest{
AgentName: args.SubagentType,
Prompt: args.Prompt,
Locale: basetool.LocaleFromContext(ctx), // 把 UI 语言透传给 specialist
})
// ...
res.Hint = "Specialist " + args.SubagentType + " 已经返回最终结论(见 result 字段)。" +
"直接基于它给用户写最终答复;**不要再调用任何工具**…"
Worker 隔离(worker.go:522 runWorker):每个 worker 跑独立 graph.Invoke,toolBag 经 filterToolsForAgent 用 persona 的白名单 + 黑名单裁剪(black wins),并强制剥离 coordinatorOnlyTools(AgentTool/SendMessage/TaskStop)——worker 不能 spawn 嵌套 worker。worker 有自己的 session id(worker-<8hex>),消息历史对父不可见。
var coordinatorOnlyTools = map[string]bool{
"AgentTool": true, "SendMessage": true, "TaskStop": true,
}
func filterToolsForAgentRole(bag, agentDef, isCoordinator, viewerOnly) []BaseTool {
// viewer 降级:先砍掉所有 Class!=read 的工具
// coordinator-only 工具只在 isCoordinator=true 时保留
// 否则按 persona 白名单过滤,再减黑名单(支持 *_skill 通配)
}
Agent loop(graph/react.go):外层包一个 eino react.Agent,关键修正是 MaxStep = MaxIterations*2 + 2——因为 eino 把每个节点 visit 都算一步,一轮 ReAct = ChatModel + ToolsNode = 2 步,不 ×2 会让 LLM 在 30 轮上限时只跑到 ~15 轮就 ErrExceededMaxSteps。反漂移机制:每轮在 user 消息前注入独立的 <system-reminder> user-role 消息(graph/react.go:271 buildSystemReminder),内容 = 硬编码基线规则 + persona 的 critical_reminder + runtime 动态启发式(runtime.go:863 calcDynamicHints:同工具连续失败、迭代数过高、重复调用同一 (tool,args)、"承诺但没发 tool_call" 检测)。
CoordinatorStubs(redirect_stub.go)占住 host_bash / get_host_load 等高幻觉名,返回"请用 AgentTool 派给 specialist-X"而非崩溃(runtime.go:519)。AgentTool 用 sha256(subagent_type+prompt) 做 90s dedupe(agent_tool.go:137),命中时返回"重复派活拦截" hint。零入站端口的反向隧道 / Browser SSH
源码:internal/pkg/tunnel/client.go + edgeagent/webshell/handler.go。边缘 agent 用 gclient.NewRetryEndWithDialer 主动连 frontier broker——主机上不开任何入站口。
dial-out:首次拨号指数退避 1s→2s→…封顶 60s;连上后断线由 geminio RetryEnd 透明重连。手柄 blob Meta{AccessKey, SecretKey} 在 connect 时塞进 geminio 不透明 Meta,server 端解码后做 AuthFunc。manager 想调边缘能力时是反向 Call:tunnel.Caller.Call(edgeID, method, body) 经 broker 路由到该 edge 已注册的 handler。一个微妙坑——manager 重启会清掉 broker 路由表但 edge 的 TCP 还活着,所以 client 额外检测 broker 路由失效错误重连:
func shouldReconnect(err error) bool {
msg := err.Error()
return strings.Contains(msg, "not found") ||
strings.Contains(msg, "mismatch clientID")
}
Browser SSH:架构经过一次重构——SSH 协议栈完全搬到 manager 侧,边缘退化成"一屏 TCP 转发器"。manager 用一个携带 {"target":"127.0.0.1:22"} Meta 的 stream 进 edge,edge 校验 target 在 allowlist 内后 dial 本地 sshd,双向 io.Copy:
var allowedTargets = map[string]bool{
"127.0.0.1:22": true, "localhost:22": true,
}
// localhost narrow scope 是安全边界——否则被攻破的 manager 能把 edge 当跳板打内网
manager 侧 biz/webshell/router.go 维护 SessionID → Sink 目录,把 edge 推回的 stdout 路由到对应浏览器 WebSocket;记录 per-session 字节数、支持 admin kill、idle watchdog、per-user/per-device 并发限制。SSH 口令 SSHPass 是一次性的,Dial 后从 edge 内存抹掉,永不落盘/落日志(messages.go:84 注释)。
根因 RCA:拓扑 + 信号关联
RCA 由两条路组成:被动(用户在 /chat 问)和主动(investigator 告警触发)。两者都吃同一个核心工具 correlate_incident——一次性把告警周围的四类信号打成一个 bundle,让 LLM 不用 chain 十次工具。
type correlateIncidentBundle struct {
Incident incidentSummary // 规则名/severity/target/fired_at/labels
Window windowRange // 以 first_fired_at 为中心 ±window/2
MetricPanel []metricSeries // PromQL range,top-3 series by magnitude
LogPanel []logEntry // Loki: {edge_id} |~ "(?i)error|panic|oom|fatal|fail"
TracePanel []traceEntry // Tempo: service.name 过滤
Edge *edgeSnapshot // 当前 cpu/mem/up + 24h flap 计数
Skipped map[string]string // 哪个面板因何跳过(无 client/无 edge_id…)
Truncated map[string]int // 100KB 上限时砍 logs→traces→metric values
}
PromQL 表达式由 metricExprFor 从规则的闭集 metric 名(cpu_pct/mem_pct/disk_used_pct/load1…)翻译,再用 wrapPerEdge 用 ... and on(edge_id) (group by (edge_id) ({edge_id="N"})) 限定到单台。每个子查询有独立短 deadline(trace/log/edge 互不阻塞),整体 60s 封顶,bundle 超 100KB 时按"先砍 logs 再砍 traces 最后砍 metric values"降级,并在 Truncated 里告知 LLM "你看的不是全貌"。
拓扑关联 BFS
在业务 topology graph 上做 BFS,默认只走"传播失败"的边(PropagatesFailure 的 relation:depends_on/deployed_on/routes_to),direction 支持 downstream(爆炸半径)/ upstream(谁导致我挂)/both。一次拉全 relation 进内存(假设 ≤10k/tenant),每个命中带 hop 数 + relation 类型 + semantics tag。
因果回溯到 0 号病人
persona 把 RCA 定义成"输出一条因果链 根因→…→告警症状"而非现象摘要,强调"找最早偏离的,不是最显眼的",用 query_change_events(产品侧变更常是 0 号病人)、expand_topology 往上游走、query_traceql 找慢 span 发起方逐层上溯。
主动诊断 pool
告警 first fire 时后台 spawn——3 worker + 100 buffer 的 pool,直接调 correlate_incident 拿 bundle,单轮 LLM 出 ai_initial_diagnosis Event 写回,SPA 在 incident 详情顶部高亮。完全 additive,LLM 没配/失败都静默退出,不阻塞告警 ingestion。
rule_key 不存完整 ConditionsJSON,所以 promExprForIncident 用启发式(rule_key 命中闭集名 / labels["metric"] hint / annotations hint)近似,匹配不上则 metric panel 标 skipped。IM 双向集成:飞书 / Telegram / Slack
源码:manager/biz/imbridge/bridge.go。provider 各自的 webhook/stream handler 先验签 + 解密,归一化成 InboundMessage,bridge 保持平台无关。
inbound 流程(HandleInbound):去重(provider:app_id:event_id,防长轮询 replay 重复应答)→ 解析 app/thread 映射(按 (im_app_id, im_chat_id, thread_id) 一聊一 session,群里所有人共享)→ /new 等命令重置 session → 发 "✦ 思考中…" placeholder → 跑 agent + 节流编辑器渐进编辑 IM 消息。outbound 渐进编辑:newStreamEditor 把 agent SSE 的 assistant chunk 节流后不断 edit 同一条 IM 消息。
飞书验签/解密(provider/feishu/verify.go)有个反直觉点——飞书 v2 events 用的是 SHA-256 拼接而非 HMAC:
// sig = sha256(timestamp + nonce + encryptKey + body), hex
func VerifyEventSignature(timestamp, nonce, encryptKey string, body []byte, signatureHex string) error {
h := sha256.New()
h.Write([]byte(timestamp)); h.Write([]byte(nonce))
h.Write([]byte(encryptKey)); h.Write(body)
// ...
}
// DecryptEvent: AES-256-CBC,key=sha256(encrypt_key),IV=密文前16字节,PKCS#7 去填充
长连接管理(stream_supervisor.go):每个启用的 stream-mode IM app 一个 goroutine,30s reconcile DB——新增 app 拉起 client、禁用/密钥轮换则 cancel 重建。runClientWithRestart 指数退避封顶 60s。locale:每个 channel 可 pin locale,bridge 在 user content 后追加语言指令(localeDirective),coordinator 再透传给 specialist,避免 GLM 默认中文答英文问题。
serviceUserID),per-IM-user 绑定(S3)未落地(adapter.go:31)。README 提到 DingTalk/WeCom,但 provider/ 目录只看到 feishu/slack/telegram 三个实现。Specialist 能力边界 与 mutating 纪律
能力边界由 agents/*.md frontmatter 的 tools 白名单 + permission_mode + max_turns + worker.go 的 filterToolsForAgent 共同物理约束。所有 specialist 都 permission_mode: read-only、max_turns: 15、第 0 步强制 query_knowledge。
| Persona | 领域 | 关键工具(白名单) | 边界 |
|---|---|---|---|
specialist-compute | CPU/内存/load/进程/OOM/NUMA/sysctl | get_host_load, get_host_processes, rank_edges, find_outlier_edges, query_promql, host_bash | 不碰磁盘IO/网络/服务启停 |
specialist-disk | 文件系统/磁盘容量/inode/大文件 | host_find_large_files, host_du_summary, host_stat_file, host_bash | 不碰网络/进程/业务日志,不删改文件 |
specialist-network | OVS/netfilter/netns/conntrack/bpftool/路由 | host_bash, host_probe_{http,dns,tcp}, host_netns_inspect, query_promql | 只读,不碰文件系统/磁盘 |
specialist-ops | 服务状态/启停重启/journalctl/cron/部署 | host_bash, get_host_processes, host_restart_service, query_promql/logql | 唯一带 mutating 工具者;重启走 ReviewGate 二审 |
specialist-sre | 集群健康/趋势/告警优先级/SLO/错误预算 | correlate_incident, get_active_incidents, find_outlier_edges, rank_edges, query_promql | 不做单机操作,给优先级 P0-P3 |
incident-investigator | 单 incident 端到端因果回溯 | correlate_incident, query_{change_events,traceql,logql,promql}, expand_topology | max_turns=40,disallowed_tools 禁 execute_skill/host_restart_service |
reviewer | mutating 提案 SOP 二审 | get_incident_detail, get_edge_summary, get_sop_text | background=true 异步,model 钉死 claude-opus,disallowed_tools: ["*_skill"] |
没有专门的 "DB specialist"——README 说 "SRE / network / DB sub-agents",但 agents/ 里实际是 compute/disk/network/ops/sre/investigator/reviewer 七个,DB 诊断目前落在 specialist-ops(service 状态)+ host_bash(mysql/redis 进程)。
mutating 纪律(cmdpolicy + ReviewGate 双闸):
- ① edge 侧 cmdpolicy(policy.go):
host_bash的 binary 分五类。systemctl restart等 write 子命令直接拒(specialist-ops.md 明说"不要用 host_bash 跑 systemctl restart 绕开二审——那条命令在 cmdpolicy 里被拒")。ip netns exec因为是"递归 shell 可绕过 cmdpolicy"被显式拒。shells/脚本语言/rm/dd/chmod 全在 ClassDenied。Mixed 类默认拒。 - ② manager 侧 ReviewGate(decorators/review_gate.go):任何
Class=write|destructive的工具调用前,自动 spawnreviewerworker 审 proposal,只有解析到Decision: approve才放行内层工具;reject/解析失败/spawn 失败一律默认拒(safe default)。spawner 为 nil 时也是 "always reject",防止误配置。
func isMutatingClass(class string) bool {
switch strings.ToLower(strings.TrimSpace(class)) {
case "write", "destructive": return true
default: return false
}
}
// 三态:approve→跑内层+MarkExecuted;reject→ErrReviewRejected;解析不出 Decision→ErrReviewUndecided(按reject)
chat_mutating_proposals 而非 execution 行)。整条装饰器链是 tenant_bind → REVIEW_GATE → timeout → audit → ratelimit → metric。关键技术与失败模式总览
把前面各节出现的边界、触发条件与对策汇成一张表——这是 ongrid 对抗"弱模型 + 高危执行 + 分布式断连"的护栏全景。
| 场景 / 边界 | 触发条件 | 处理方式 |
|---|---|---|
| LLM 幻觉工具名 | coordinator LLM 调 schema 外的 host_bash 等 | CoordinatorStubs 占名返回"用 AgentTool 派活";apology 兜底 |
| 协调员死循环 | 弱模型 30 轮 / 122 tool calls 空转 | persona MaxTurns=10 收口 + 每轮 dynamicHints 注入"该收口了" + AgentTool 90s dedupe |
| 重复派同一 specialist | 同 (subagent_type, prompt) <90s | sha256 dedupe 命中,返回"重复派活拦截" hint |
| user 消息丢失 | graph 调用中途崩溃 | LLM 调用前先持久化 user 消息(coordinator + worker 都遵守) |
| manager 重启路由失效 | broker route 表清空但 edge TCP 仍活 | shouldReconnect 检测 "not found"/"mismatch clientID" → 异步 redial + re-register |
| webshell 被当跳板 | 被攻破的 manager 伪造 target Meta | edge allowedTargets 只允许 127.0.0.1:22 / localhost:22 |
| host_bash 越权 | LLM 想跑 systemctl restart / rm / ip netns exec | cmdpolicy write 子命令 + ClassDenied + 递归 shell 全拒 |
| mutating 误操作 | 任何 write/destructive 工具 | ReviewGate spawn reviewer,default-reject;reviewer 三门控(SOP/无并行/有回滚) |
| viewer 越权 | viewer 角色聊天 | toolBag 先砍所有 Class!=read 工具,连 AgentTool 都看不到 |
| correlate bundle 过大 | bundle > 100KB | 先砍 logs(>10)→traces(>5)→metric values,Truncated 告知 LLM |
| IM 长轮询重复应答 | Telegram getUpdates reconnect replay | dedupSet 按 provider:app_id:event_id 去重 |
| worker session 泄漏 | SpawnWorker 后 session 行 closed_at=NULL | goroutine defer CloseSession(曾累积 161 行 orphan) |
| 子 agent 答错语言 | GLM persona 中文答英文问 | locale 经 ctx 透传 coordinator→specialist + 每轮 reminder 重申 |
| 告警风暴打爆 LLM | rule storm 大量 incident | investigator 3 worker + 100 buffer,超出直接丢弃并 warn,不阻塞 ingestion |
生态意义与技术亮点
"调度优于全能"的多 Agent 范式:coordinator 不是更强的 specialist,而是更克制的——它的 toolBag 被物理收窄到只能"派/答/拒",深度能力强制下沉到 specialist。
这把"一个大 prompt 干所有事"的脆弱性换成了"小而专的子 agent + 明确边界",并用 dedupe/MaxTurns/dynamicHints 一整套护栏对抗弱模型的死循环——这是把 SOTA agent 套路(claude-code 的 AgentTool/system-reminder)落到生产 SRE 场景的实践样本。
零信任执行面
双层闸(edge cmdpolicy 只读白名单 + manager ReviewGate 二审)让"AI 远程跑命令"从不可接受变成可审计、可回滚、爆炸半径可控。reviewer 用最强模型、default-reject、三门控。
零入站端口 + Browser SSH
边缘只出站拨号,主机不开任何入站口,却仍能被远程巡检/执行/开 shell。SSH 栈收在 manager 侧让审计/并发/踢人单点可控。
RCA 工程化
correlate_incident 把 metric+log+trace+edge+变更打成单个带降级策略的 bundle,配合拓扑 BFS 和"回溯到 0 号病人"的 persona,告警诞生瞬间就产出带证据的因果链。
自托管 + BYO-model + 多 IM
docker compose up 起全栈(含 Prometheus/Loki/Tempo/Grafana/frontier/searxng),模型层热路由 6 家 provider,IM 层 Slack/Telegram/飞书双向,避免厂商锁定。
附:待确认项
本次拆解基于 cmd/、internal/manager/biz/aiops、internal/edgeagent、internal/pkg/tunnel 的逐文件阅读;以下几项仍待与 README / 仓库其余部分对齐。
- Stars 数:未在仓库内体现,待确认(页面展示为「未知 / —」)。
- DB specialist:README 提及 "DB sub-agents",但
agents/仅含 compute/disk/network/ops/sre/investigator/reviewer,独立 DB persona 待确认(当前 DB 诊断落在 specialist-ops + host_bash)。 - DingTalk / WeCom:README 列为支持渠道,但
imbridge/provider/仅实现 feishu/slack/telegram,钉钉/企微实现待确认。 - web/ SPA 组件实现:本次只读了
web/src/api/*.ts层,具体 React 组件(聊天/拓扑/webshell 渲染)实现细节待确认。 - 旧
agent.go内核:与 graph 内核并存,本文聚焦 graph 内核(runtime.go/worker.go),旧内核细节未深读。