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:
1 parent
f2069fe3f0
commit
92a2247390
37 files changed
+6449
-6
No files matched your search
@@ -0,0 +1,169 @@
|
||||
// Package tools 提供 Agent CLI 引擎的工具注册中心与工具接口。 // Logan.Li
|
||||
// 设计参考 opsxcli/internal/agent/tools,剥离 CLI 专属工具(local_bash 本地执行、scp)。
|
||||
// Web 版聚焦远程运维:ssh_execute(目标主机执行)+ analyze_output(输出分析)。
|
||||
// 风险评估逻辑(黑名单 + AssessBashRisk)置于本包,避免与 safety 包形成循环依赖。
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"ezops/pkg/agentcli/llm"
|
||||
)
|
||||
|
||||
// RiskLevel 工具风险等级 // Logan.Li
|
||||
type RiskLevel int
|
||||
|
||||
const (
|
||||
RiskSafe RiskLevel = iota // 只读操作(cat/grep/df/ps)
|
||||
RiskLow // 低风险(mkdir/touch)
|
||||
RiskMedium // 中风险(chmod/文件修改)
|
||||
RiskHigh // 高风险(远程服务控制/reboot)
|
||||
RiskCritical // 危险操作(rm -rf //mkfs/dd)
|
||||
)
|
||||
|
||||
// String 返回风险等级字符串 // Logan.Li
|
||||
func (r RiskLevel) String() string {
|
||||
switch r {
|
||||
case RiskSafe:
|
||||
return "safe"
|
||||
case RiskLow:
|
||||
return "low"
|
||||
case RiskMedium:
|
||||
return "medium"
|
||||
case RiskHigh:
|
||||
return "high"
|
||||
case RiskCritical:
|
||||
return "critical"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// Display 返回风险等级中文显示 // Logan.Li
|
||||
func (r RiskLevel) Display() string {
|
||||
switch r {
|
||||
case RiskSafe:
|
||||
return "安全"
|
||||
case RiskLow:
|
||||
return "低风险"
|
||||
case RiskMedium:
|
||||
return "中风险"
|
||||
case RiskHigh:
|
||||
return "高风险"
|
||||
case RiskCritical:
|
||||
return "危险"
|
||||
default:
|
||||
return "未知"
|
||||
}
|
||||
}
|
||||
|
||||
// Result 工具执行结果 // Logan.Li
|
||||
type Result struct {
|
||||
Success bool `json:"success"`
|
||||
Output string `json:"output"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// Tool 核心工具接口(5 方法) // Logan.Li
|
||||
type Tool interface {
|
||||
Name() string // 工具名
|
||||
Description() string // 给 LLM 看的描述
|
||||
Parameters() map[string]interface{} // JSON Schema 参数定义
|
||||
RiskLevel() RiskLevel // 静态风险等级
|
||||
Execute(ctx context.Context, args map[string]interface{}) (*Result, error)
|
||||
}
|
||||
|
||||
// DynamicRiskTool 动态风险评估接口 // Logan.Li
|
||||
// 工具可额外实现此接口,依据运行时参数动态计算风险(如 ssh_execute 看具体命令)。
|
||||
// 安全控制器 Check 时优先调用此接口。
|
||||
type DynamicRiskTool interface {
|
||||
Tool
|
||||
RiskLevelForArgs(args map[string]interface{}) RiskLevel
|
||||
}
|
||||
|
||||
// Registry 工具注册中心(线程安全) // Logan.Li
|
||||
type Registry struct {
|
||||
tools map[string]Tool
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewRegistry 创建空注册中心 // Logan.Li
|
||||
func NewRegistry() *Registry {
|
||||
return &Registry{tools: make(map[string]Tool)}
|
||||
}
|
||||
|
||||
// Register 注册工具 // Logan.Li
|
||||
func (r *Registry) Register(tool Tool) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.tools[tool.Name()] = tool
|
||||
}
|
||||
|
||||
// Get 按名获取工具 // Logan.Li
|
||||
func (r *Registry) Get(name string) (Tool, error) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
t, ok := r.tools[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("工具未找到: %s", name)
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// List 列出所有工具 // Logan.Li
|
||||
func (r *Registry) List() []Tool {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
list := make([]Tool, 0, len(r.tools))
|
||||
for _, t := range r.tools {
|
||||
list = append(list, t)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// ToLLMTools 转换为 LLM function calling 格式 // Logan.Li
|
||||
func (r *Registry) ToLLMTools() []llm.Tool {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
out := make([]llm.Tool, 0, len(r.tools))
|
||||
for _, t := range r.tools {
|
||||
out = append(out, llm.Tool{
|
||||
Type: "function",
|
||||
Function: llm.ToolFunction{
|
||||
Name: t.Name(),
|
||||
Description: t.Description(),
|
||||
Parameters: t.Parameters(),
|
||||
},
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ---- 参数解析辅助 ---- // Logan.Li
|
||||
|
||||
// StringParam 取字符串参数 // Logan.Li
|
||||
func StringParam(args map[string]interface{}, key string) string {
|
||||
if v, ok := args[key]; ok {
|
||||
if s, ok := v.(string); ok {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// IntParam 取整型参数(兼容 int/float64/int64) // Logan.Li
|
||||
func IntParam(args map[string]interface{}, key string) int {
|
||||
if v, ok := args[key]; ok {
|
||||
switch val := v.(type) {
|
||||
case int:
|
||||
return val
|
||||
case float64:
|
||||
return int(val)
|
||||
case int64:
|
||||
return int(val)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
Reference in new issue
Block a user