Files
aiops/backend/pkg/agentcli/tools/builtin.go
T
attackerandClaude 92a2247390 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>
2026-06-27 09:55:17 +08:00

107 lines
3.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// builtin.go - 内置只读工具 // Logan.Li
// analyze_output:对冗长命令输出做摘要/错误提取,避免 token 爆炸,辅助 LLM 聚焦关键线索。
package tools
import (
"context"
"fmt"
"strings"
)
// AnalyzeOutputTool 输出分析工具(只读,Safe) // Logan.Li
type AnalyzeOutputTool struct{}
// NewAnalyzeOutputTool 创建输出分析工具 // Logan.Li
func NewAnalyzeOutputTool() *AnalyzeOutputTool { return &AnalyzeOutputTool{} }
// Name 工具名 // Logan.Li
func (t *AnalyzeOutputTool) Name() string { return "analyze_output" }
// Description 给 LLM 的说明 // Logan.Li
func (t *AnalyzeOutputTool) Description() string {
return "分析一段(可能很长的)命令输出文本:统计行数、提取疑似错误/告警行、必要时截断保留首尾。" +
"当 ssh_execute 返回内容过长时调用此工具提炼关键信息再继续推理。"
}
// Parameters 参数定义 // Logan.Li
func (t *AnalyzeOutputTool) Parameters() map[string]interface{} {
return map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"output": map[string]interface{}{
"type": "string",
"description": "待分析的文本输出",
},
"focus": map[string]interface{}{
"type": "string",
"description": "可选关注点,如 error、memory、disk",
},
},
"required": []string{"output"},
}
}
// RiskLevel 静态风险(只读安全) // Logan.Li
func (t *AnalyzeOutputTool) RiskLevel() RiskLevel { return RiskSafe }
// Execute 执行输出分析 // Logan.Li
func (t *AnalyzeOutputTool) Execute(ctx context.Context, args map[string]interface{}) (*Result, error) {
output := StringParam(args, "output")
focus := strings.ToLower(StringParam(args, "focus"))
if output == "" {
return &Result{Success: true, Output: "(空输出)"}, nil
}
lines := strings.Split(output, "\n")
total := len(lines)
// 超长截断:保留前 40 + 后 40 行,中间用省略标注
truncated := false
if total > 120 {
head := lines[:40]
tail := lines[total-40:]
lines = append(append(head, fmt.Sprintf("... [已省略 %d 行] ...", total-80)), tail...)
truncated = true
}
// 提取疑似错误/告警行
errorKeywords := []string{"error", "fail", "exception", "traceback", "denied",
"permission", "timeout", "refused", "unavailable", "critical", "fatal",
"错误", "失败", "拒绝", "超时", "无法", "异常"}
if focus != "" {
errorKeywords = append([]string{focus}, errorKeywords...)
}
var errorLines []string
for _, line := range lines {
low := strings.ToLower(line)
for _, kw := range errorKeywords {
if strings.Contains(low, kw) {
errorLines = append(errorLines, strings.TrimSpace(line))
break
}
}
}
if len(errorLines) > 20 {
errorLines = errorLines[:20]
}
// 组装分析摘要
var sb strings.Builder
sb.WriteString(fmt.Sprintf("总行数: %d", total))
if truncated {
sb.WriteString("(已截断保留首尾)")
}
sb.WriteString("\n")
if len(errorLines) > 0 {
sb.WriteString(fmt.Sprintf("疑似错误/告警行 (%d):\n", len(errorLines)))
for _, l := range errorLines {
sb.WriteString(" " + l + "\n")
}
} else {
sb.WriteString("未发现明显错误关键词\n")
}
sb.WriteString("\n输出片段:\n" + strings.Join(lines, "\n"))
return &Result{Success: true, Output: sb.String()}, nil
}