# 04 - 插件架构设计 > 本文由 opsxcli 同名设计文档适配改写,结合 aiops Agent CLI 的 Web 实现(`backend/pkg/agentcli/`)。 > opsxcli 的「plugins/」CLI 插件层(mysql/ssh/ping 等 46+ 命令)在 aiops 中不适用 —— Web 版聚焦远程运维,工具精简为 2 个并改由 `tools.Tool` 接口承载。 ## 工具(Tool)= aiops 版的「插件」 opsxcli 有完整的 CLI 插件生态(46+ 命令插件);aiops Agent CLI 把「插件」概念收敛为更纯粹的 **Tool 接口**: - 不再有 CLI 命令、参数解析、帮助文本 - 工具的唯一职责是:被 LLM 调用 → 在目标主机做事 → 返回结构化结果 - LLM 通过 function calling 协议感知工具的存在与用法 > 这是合理的精简:Web Agent 的能力边界由「Tool 接口 + LLM 推理」共同决定,不再需要 CLI 命令那一层。 ## Tool 接口(5 方法) ```go // backend/pkg/agentcli/tools/registry.go type Tool interface { Name() string // 工具名(LLM 调用时用) Description() string // 给 LLM 看的描述 Parameters() map[string]interface{} // JSON Schema 参数定义 RiskLevel() RiskLevel // 静态风险等级 Execute(ctx context.Context, args map[string]interface{}) (*Result, error) } ``` 设计哲学:**接口最小化** —— 5 个方法覆盖工具的完整生命周期。 ### DynamicRiskTool 扩展接口 ```go type DynamicRiskTool interface { Tool RiskLevelForArgs(args map[string]interface{}) RiskLevel } ``` 部分工具的「静态风险」无法反映真实风险(如 `ssh_execute` 静态是 High,但 `df -h` 是 Safe、`rm -rf /` 是 Critical)。这些工具额外实现 `DynamicRiskTool`,安全控制器 `Check` 时优先调用动态评估。 ### Result 结构 ```go type Result struct { Success bool `json:"success"` Output string `json:"output"` Error string `json:"error,omitempty"` } ``` ## Registry 注册中心 ```go type Registry struct { tools map[string]Tool mu sync.RWMutex // 读写锁,支持并发注册和查询 } ``` 核心方法: | 方法 | 说明 | |------|------| | `NewRegistry()` | 创建空注册中心 | | `Register(tool)` | 注册工具(线程安全) | | `Get(name)` | 按名获取工具(LLM 调用时按名查找) | | `List()` | 列出所有工具(构建 Prompt Layer 3 工具描述) | | `ToLLMTools()` | 转换为 OpenAI function calling 格式(自动注入到 LLM `tools` 参数) | `ToLLMTools()` 是 Registry 与 LLM 协议的桥梁:注册的工具自动出现在 LLM 的 function 列表中,无需手动维护。 ## 已注册工具一览 > 与 opsxcli 的关键差异:opsxcli 有 6 个工具(local_bash / ssh_execute / scp_transfer / file_read / file_search / analyze_output),aiops 精简为 2 个。 | 工具 | 风险等级 | 功能 | 来源 | |------|----------|------|------| | `ssh_execute` | High(静态)/ Safe~Critical(动态) | 在目标主机远程执行 shell 命令 | aiops 既有 `pkg/remoteexec` | | `analyze_output` | Safe | 对冗长输出做摘要/错误提取 | 内置 Go 实现 | ### 为什么精简? | opsxcli 工具 | aiops 处理 | 原因 | |--------------|-----------|------| | `local_bash` | **剥离** | Web 后端不应在服务器本地执行命令(安全风险 + 多用户隔离) | | `scp_transfer` | **剥离** | 文件传输走 aiops 既有的「文件管理」模块,不混入 Agent | | `file_read` | **剥离** | 远程读文件用 `ssh_execute cat`,无需独立工具 | | `file_search` | **剥离** | 远程搜文件用 `ssh_execute grep/find` | | `ssh_execute` | **保留** | 核心远程运维能力 | | `analyze_output` | **保留** | 防止长输出 token 爆炸,辅助 LLM 聚焦关键信息 | 工具越少,LLM 的决策空间越收敛(呼应 Ashby 定律),首次做对的概率越高。 ## 工具分类标准(aiops 版) ### 放入内置工具集的条件(需同时满足) 1. 属于运维 Agent 高频需要的能力 2. 无法用现有工具简单组合完成(如 `analyze_output` 不能用 `ssh_execute` 替代 —— 它操作的是已有文本而非远程命令) 3. 实现简洁(单文件 < 300 行) ### 通过 `ssh_execute` 间接覆盖的能力 opsxcli 用独立插件实现的能力,在 aiops 中全部由 `ssh_execute` 执行远程命令覆盖: | opsxcli 插件能力 | aiops 等效 | |------------------|-----------| | `mysql -e "..."` | `ssh_execute "mysql -e \"...\""` | | `redis-cli ...` | `ssh_execute "redis-cli ..."` | | `ping / traceroute` | `ssh_execute "ping ..."` | | `cat / grep / find` | `ssh_execute "cat ..."` | | `systemctl status nginx` | `ssh_execute "systemctl status nginx"` | LLM 会根据任务自主决定执行什么命令,无需为每类命令提供独立工具。 ## 混合架构的好处 1. **职责单一**:每个工具只做一件事,`ssh_execute` 执行、`analyze_output` 分析 2. **协议简单**:LLM 只需理解 2 个 function,决策快、错误少 3. **风险可控**:所有远程操作统一走 `ssh_execute` 的风险评估(`AssessBashRisk`),不会因为工具增多而出现安全盲区 4. **扩展灵活**:未来若需要新工具(如 `kubectl_apply`),实现 Tool 接口注册即可 ## 扩展指南 ### 添加新工具 1. 实现 `Tool` 接口(必要时实现 `DynamicRiskTool`): ```go // pkg/agentcli/tools/kubectl_get.go type KubectlGetTool struct{ cfg remoteexec.SSHConfig } func (t *KubectlGetTool) Name() string { return "kubectl_get" } func (t *KubectlGetTool) Description() string { return "在目标主机执行 kubectl get 并返回结果" } func (t *KubectlGetTool) Parameters() map[string]interface{} { return map[string]interface{}{ "type": "object", "properties": map[string]interface{}{ "resource": map[string]interface{}{"type": "string", "description": "如 pods/deployments"}, }, "required": []string{"resource"}, } } func (t *KubectlGetTool) RiskLevel() tools.RiskLevel { return tools.RiskSafe } func (t *KubectlGetTool) Execute(ctx context.Context, args map[string]interface{}) (*tools.Result, error) { // 复用 remoteexec 执行 kubectl get } ``` 2. 在 `agentcli.NewEngine` 中注册: ```go registry.Register(tools.NewSSHExecuteTool(cfg.SSH, coreCfg.ToolTimeout)) registry.Register(tools.NewAnalyzeOutputTool()) registry.Register(tools.NewKubectlGetTool(cfg.SSH)) // 新增 ``` 3. 工具自动出现在 LLM 的 function 列表与 Prompt Layer 3 工具描述中。无需改 Prompt、controller、前端。 ## 常见陷阱 | 陷阱 | 解决方案 | |------|----------| | 忘记设置 `RiskLevel` 导致误判 | 默认按接口返回值,高危工具必须显式声明 | | 高危工具未实现 `DynamicRiskTool` | 静态等级无法反映参数差异(如 `ssh_execute` 看 `df` 还是 `rm -rf`),必须实现动态评估 | | 工具 Execute 无超时 | `Config.ToolTimeout=120s` 兜底(`context.WithTimeout`) | | 工具输出过长导致 token 爆炸 | `OutputMaxLength=10000` 截断 + 引导 LLM 调用 `analyze_output` | ## 总结 aiops Agent CLI 的「插件架构」是 opsxcli 的精简版:从「46+ CLI 插件」收敛为「2 个 Tool 接口实现」。这不是能力的退化,而是**收敛决策空间、聚焦远程运维、降低 LLM 误判概率**的有意设计。详细工具实现见 [05 - Builtin 内置工具](05-Builtin内置命令.md)。 > 作者:Logan.Li