后端引擎 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>
170 lines
4.2 KiB
Go
170 lines
4.2 KiB
Go
// 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
|
||
}
|