feat: 新增 Agent CLI — Web 版 AI 运维 Agent(参考 opsxcli 移植)

后端引擎 backend/pkg/agentcli/(纯引擎库,零业务依赖,剥离 CLI/TUI 外壳):
- llm: OpenAI 兼容客户端,复用 model.LLMConfig
- tools: ssh_execute(复用 pkg/remoteexec)+ analyze_output + 风险评估黑名单
- safety: 三级安全模式 + 五级风险 + WebSocket 异步确认
- prompt: 五层 System Prompt
- core: ReAct 16 轮循环 + 自适应检查点 + 循环检测
- evolver: 四层记忆 + 进化循环,data/agentcli/ 文件存储

集成层:
- controller/agent_cli.go: WebSocket 控制器(事件流推流 + 高危确认 + 会话持久化)
- model/agent_cli.go: agent_cli_sessions/messages 表 + AutoMigrate
- 路由 /ws/agent-cli + /api/v1/aiops/agent-cli/sessions
- seed 权限 aiops:agent-cli / aiops:llm-config

前端:
- AgentCLI.tsx: 对话流 + 工具块 + 高危确认 + 四模块 tips 面板
- LLMConfig.tsx: 大模型设置独立页
- api/agentCli.ts + Sidebar/App 菜单路由

文档:
- docs/agent/ 11 篇(opsxcli 同名文档适配改写 + 00-README 映射总览)

其他:
- CLAUDE.md 补充 agent-cli 模块说明
- 修正 .gitignore 根级二进制规则(前导 /,避免误伤 frontend/src/components/aiops/)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
attackerandClaude committed 2026-06-27 09:55:17 +08:00
1 parent f2069fe3f0
commit 92a2247390
37 files changed
+6449 -6

No files matched your search

+177
View File
@@ -0,0 +1,177 @@
# 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