# 08 - Evolver 自进化引擎 > 本文由 opsxcli 同名设计文档适配改写,结合 aiops Agent CLI 的 Web 实现(`backend/pkg/agentcli/evolver/`)。 > **保留**:四层记忆架构(经验/环境/事实/程序)+ 进化循环思想(OBSERVE → ... → PREDICT)+ 异步非阻塞 + 优雅降级。 > **精简**:opsxcli 13 步循环 + 3300 行精简为 6 步核心循环 + ~400 行;剥离反射评分、经验整合去重、自动 Skill 提炼等重型子流程。这是有意的精简适配,保留学习能力和注入机制。 ## 包位置 ``` backend/pkg/agentcli/evolver/ ├── engine.go # 进化引擎核心(精简进化循环) └── memory.go # 四层记忆 + JSONL/JSON 文件存储 ``` ## 设计哲学 > **让 Agent 越用越聪明** —— 每次任务完成后自动学习经验,优化后续表现。 Evolver 借鉴 opsxcli 的设计理念:通过经验积累、LLM 反射分析和环境自适应,实现 Agent 的持续自我优化。用户使用越多,Agent 越了解服务器环境、最佳工具组合和已知事实。 **精简原则**:保留「学习 → 存储 → 注入」的核心闭环,剥离重型分析(评分、整合、Skill 提炼)。精简后的 Evolver 仍是真正的自学习引擎,而非装饰品 —— 它真的会把上次任务的经验存下来,并在下次同类任务时注入 Prompt。 ## 核心数据结构 ### EvolverEngine ```go // backend/pkg/agentcli/evolver/engine.go type EvolverEngine struct { mem *Memories // 四层记忆集合 llm llm.Client // 可选,用于提炼经验/事实(nil 时退化为规则学习) memDir string // 记忆目录(默认 data/agentcli) } ``` > 与 opsxcli 的差异:剥离了 `minSteps` / `simpleThresh` / `moderateThresh` / `onProgress` 等配置字段;剥离 `reflectionClient` 独立接口(直接用 `llm.Client`)。 ### TaskExecution(任务执行记录) 每次任务完成后由 `core.Agent.triggerEvolve` 构造: ```go type TaskExecution struct { Query string // 用户原始查询 ToolCalls []ToolCallRecord // 工具调用序列 TotalSteps int // 总迭代步数 TotalTokens int // 消耗的 token 数 Duration time.Duration // 执行耗时 Success bool // 是否成功 FinalAnswer string // 最终回答 Timestamp time.Time // 执行时间 ServerHost string // 目标主机(用于环境记忆) } ``` ### ToolCallRecord / EvolveResult ```go type ToolCallRecord struct { ToolName string Args map[string]interface{} Output string Duration time.Duration Success bool RiskLevel int } type EvolveResult struct { TaskType string // 自动分类的任务类型 LearnedHint string // 学到的经验提示 ToolSequence []string // 工具序列 ExperienceAdded bool // 是否新增经验 Consolidated bool // 是否触发整合(aiops 版保留字段,未实现) } ``` ## 精简进化循环(6 步) opsxcli 是 13 步(OBSERVE → EXTRACT → REFLECT → SCORE → COMPARE → LEARN → STORE → CONSOLIDATE → PREDICT → ADAPT → MEMORIZE → DISTILL → FEEDBACK),aiops 精简为 6 步核心: ``` ┌─────────────────────────────────────────────┐ │ Evolve 6 步核心循环 │ ├─────────────────────────────────────────────┤ │ │ │ Step 1: OBSERVE ── 观察工具序列 │ │ ↓ 提取 ToolSequence(如 ssh → analyze) │ │ │ │ Step 2: CLASSIFY ── 任务类型分类 │ │ ↓ 关键词规则匹配(11 类,无需 LLM) │ │ │ │ Step 3: LEARN ── 生成经验提示 │ │ ↓ LLM 优先提炼一句经验,失败降级规则生成 │ │ │ │ Step 4: STORE ── 存入经验 + 环境记忆 │ │ ↓ experience.jsonl + environment.json │ │ │ │ Step 5: MEMORIZE ── LLM 提炼持久事实 │ │ ↓ 异步,从 FinalAnswer 提炼事实存 factual │ │ │ │ Step 6: PREDICT ── 注入下次 Prompt │ │ ↓ GetContextForPrompt(下次任务开始时) │ │ │ └─────────────────────────────────────────────┘ ``` ### 各步骤详解 #### Step 1: OBSERVE(观察) 提取工具序列: ```go for _, tc := range exec.ToolCalls { result.ToolSequence = append(result.ToolSequence, tc.ToolName) } ``` 输出如 `["ssh_execute", "analyze_output", "ssh_execute"]`。 #### Step 2: CLASSIFY(任务分类) 关键词规则匹配(不调 LLM,零成本): ```go func classifyTask(query string, calls []ToolCallRecord) string { text := strings.ToLower(query) for _, c := range calls { if cmd, ok := c.Args["command"].(string); ok { text += " " + strings.ToLower(cmd) } } // 11 类规则匹配 rules := []struct{ typ string; kws []string }{ {"磁盘空间", []string{"disk", "空间", "df", "du", "inode", "磁盘", "满了"}}, {"网络", []string{"network", "网络", "ping", "netstat", "ss ", "端口", "tcp", "dns"}}, {"服务管理", []string{"service", "服务", "systemctl", "nginx", "mysql", "redis", "restart"}}, {"软件安装", []string{"install", "安装", "yum", "apt", "docker", "部署", "deploy"}}, {"进程排查", []string{"process", "进程", "ps ", "kill", "cpu", "top", "卡死"}}, {"内存排查", []string{"memory", "内存", "mem", "free", "oom", "swap"}}, {"日志排查", []string{"log", "日志", "journalctl", "tail", "grep"}}, {"权限问题", []string{"permission", "权限", "chmod", "chown", "denied", "拒绝"}}, {"性能调优", []string{"performance", "性能", "负载", "load", "慢", "slow"}}, {"配置管理", []string{"config", "配置", "conf", "vim", "sed"}}, } // ... 命中即返回,否则 "通用运维" } ``` **设计要点**:把 query + 实际命令拼起来分类,比单看 query 更准(用户问「检查 nginx」,实际命令可能是 `systemctl status nginx`,分类为「服务管理」更合理)。 #### Step 3: LEARN(生成经验提示) LLM 优先,失败降级规则: ```go func (e *EvolverEngine) learnHint(ctx context.Context, exec *TaskExecution, taskType string) string { tools := strings.Join(uniqueStrings(resultToolNames(exec.ToolCalls)), " → ") // 尝试用 LLM 提炼一句经验 if e.llm != nil { if hint := e.llmLearnHint(ctx, exec, taskType, tools, exec.Success); hint != "" { return hint } } // 降级:规则生成 if exec.Success { return fmt.Sprintf("完成「%s」类任务时,工具序列 %s 最终成功,可作为参考。", taskType, tools) } return fmt.Sprintf("尝试「%s」类任务时,工具序列 %s 未成功,下次可换用不同命令或思路。", taskType, tools) } ``` LLM 提炼的 prompt(中文): ``` 你是运维经验提炼器。根据以下任务执行记录,用一句中文(不超过80字)提炼经验提示, 说明下次做同类任务的关键要点或推荐工具顺序。只返回经验文本,不要多余解释。 任务: 工具序列: 结果: 成功/失败 ``` **降级策略**:LLM 不可用或超时 → 用规则模板生成(仍然有价值,只是不够精炼)。 #### Step 4: STORE(存储经验 + 环境记忆) ```go exp := ExperienceEntry{ TaskType: result.TaskType, Query: truncate(exec.Query, 200), Hint: result.LearnedHint, ToolSequence: result.ToolSequence, Success: exec.Success, Timestamp: exec.Timestamp.Unix(), } e.mem.AddExperience(exp) if exec.ServerHost != "" { e.mem.AddHost(exec.ServerHost) // 环境记忆 } ``` 写入 `data/agentcli/experience.jsonl`(追加)和 `environment.json`(去重合并)。 #### Step 5: MEMORIZE(LLM 提炼持久事实) 仅在任务成功 + 有 FinalAnswer + LLM 可用时触发,**异步执行不阻塞**: ```go if e.llm != nil && exec.Success && exec.FinalAnswer != "" { go e.memorizeFact(ctx, exec) // 异步 } ``` LLM 提炼 prompt: ``` 从以下运维任务记录中,提炼 1 条值得长期记住的事实(如某主机的固定配置、已知问题、约定)。 如果没有明显可沉淀的事实,回复「无」。只返回事实本身,一句话。 任务: 结论: ``` 提炼出的事实存入 `factual.jsonl`。 > 与 opsxcli 的差异:opsxcli 的 MEMORIZE 从执行过程中提取结构化事实(key-value),aiops 简化为让 LLM 自由提炼一句事实。更简单,覆盖面更广。 #### Step 6: PREDICT(注入下次 Prompt) `GetContextForPrompt(query)` 在下次任务开始时被 `core.Agent.Run` 调用: ```go evolveCtx := a.evolver.GetContextForPrompt(query) systemPrompt := prompt.BuildSystemPrompt(serverInfo, toolDescs, evolveCtx) ``` 注入内容会被放入 Prompt Layer 5(详见 [07 - Prompt 构建](07-Prompt构建与记忆注入.md))。 ## 四层记忆系统 aiops 保留 opsxcli 的四层记忆架构: ``` ┌──────────────────────────────────────────────────────────────┐ │ 四层记忆架构 │ ├──────────────────────────────────────────────────────────────┤ │ │ │ Layer 1: ExperienceMemory(经验层) │ │ 任务完成后的经验,按 task_type 分类 │ │ 存储: data/agentcli/experience.jsonl │ │ │ │ Layer 2: EnvironmentMemory(环境层) │ │ 已知主机列表 │ │ 存储: data/agentcli/environment.json │ │ │ │ Layer 3: FactualMemory(事实层) │ │ LLM 提炼的持久事实 │ │ 存储: data/agentcli/factual.jsonl │ │ │ │ Layer 4: ProceduralMemory(程序层) │ │ 程序性知识(接口位,未实现自动 Skill 提炼) │ │ 存储: data/agentcli/procedural.jsonl │ │ │ └──────────────────────────────────────────────────────────────┘ ``` ### Memories 结构 ```go // backend/pkg/agentcli/evolver/memory.go type Memories struct { dir string mu sync.Mutex expPath string // experience.jsonl facPath string // factual.jsonl sklPath string // procedural.jsonl envPath string // environment.json } ``` ### ExperienceEntry / FactEntry / SkillEntry ```go type ExperienceEntry struct { TaskType string `json:"task_type"` Query string `json:"query"` Hint string `json:"hint"` ToolSequence []string `json:"tool_sequence"` Success bool `json:"success"` Timestamp int64 `json:"timestamp"` } type FactEntry struct { Fact string `json:"fact"` Source string `json:"source"` Timestamp int64 `json:"timestamp"` } type SkillEntry struct { Name string `json:"name"` When string `json:"when"` Steps []string `json:"steps"` Timestamp int64 `json:"timestamp"` } ``` > 与 opsxcli 的差异: > - opsxcli 的 `Experience` 有 `SuccessRate` / `UsageCount` / `Tags`(用于整合去重),aiops 简化为 `Success` 布尔(剥离整合逻辑) > - opsxcli 的 `FactEntry` 是 key-value(`Key` / `Value` / `Category`),aiops 简化为单字段 `Fact`(一句话) > - opsxcli 的 `SkillEntry` 有完整的 ID/Version/Triggers/Pitfalls/SuccessRate,aiops 简化为 Name/When/Steps(接口位,未实际使用) ### 存储格式 #### experience.jsonl(追加写入) ```json {"task_type":"磁盘空间","query":"检查磁盘空间","hint":"对于磁盘满问题,先检查大日志文件再清理","tool_sequence":["ssh_execute","analyze_output"],"success":true,"timestamp":1748000000} ``` #### environment.json(整体读写) ```json { "hosts": ["192.168.1.10", "192.168.1.11"] } ``` #### factual.jsonl(追加写入) ```json {"fact":"生产 nginx 日志目录是 /var/log/nginx","source":"检查 nginx 启动失败","timestamp":1748000000} ``` ### 核心查询方法 | 方法 | 说明 | |------|------| | `AddExperience(e)` | 追加经验 | | `FindExperiences(taskType, n)` | 按类型查找,**优先成功**,取最近 n 条 | | `AddFact(f)` | 追加事实 | | `RelevantFacts(query, n)` | 按 query 关键词匹配事实(双向 Contains) | | `AddHost(host)` | 记录已知主机(去重) | | `Hosts()` | 已知主机列表 | | `CountStats()` | 各层条目数(供审计展示) | **`FindExperiences` 的排序策略**: ```go // 优先成功经验,按时间取最近 n 条 successFirst := ... // 过滤 success=true others := ... // 过滤 success=false out := append(pick(successFirst), pick(others)...) ``` 让 LLM 优先看到成功的经验。 ## 与 Agent 的集成 ### 初始化与优雅降级 在 `agentcli.NewEngine` 中: ```go ev, err := evolver.NewEvolverEngine(coreCfg.MemoryDir, client) if err != nil { ev = nil // 降级:无自学习,不影响主流程 } agent := core.NewAgent(client, registry, coreCfg, sc, ev) ``` **降级场景**: - 记忆目录无法创建(权限问题)→ `ev = nil` - 此时 Agent 正常运行,只是 Layer 5 为空 ### 异步进化流程 ``` 用户查询 → core.Agent.Run() ReAct 循环 → 任务完成 ↓ triggerEvolve()(异步 goroutine) ↓ 30s 超时上下文 + panic 恢复 ↓ EvolverEngine.Evolve() ↓ 存入 experience.jsonl / factual.jsonl ↓ 下次 Run() → GetContextForPrompt() → 注入 Layer 5 ``` **三层保护**: 1. **后台 goroutine**:不阻塞用户,答案立即返回 2. **30 秒超时**:`context.WithTimeout(ctx, 30*time.Second)` 3. **panic 恢复**:`defer func() { _ = recover() }()` ### 经验注入 下次任务开始时,`GetContextForPrompt(query)` 按 `task_type` 取相关经验注入 Layer 5: ``` 【历史经验(来自自进化引擎)】 【磁盘空间 类历史经验】 - (成功) 对于磁盘满问题,先检查大日志文件再清理 - (成功) 完成「磁盘空间」类任务时,工具序列 ssh_execute → analyze_output 最终成功 【已知事实】 - 生产 nginx 日志目录是 /var/log/nginx 【已知主机】192.168.1.10, 192.168.1.11 ``` ## 任务分类系统(11 类) `classifyTask` 把用户查询 + 实际命令分类为 11 类: | 任务类型 | 关键词(部分) | |----------|---------------| | 磁盘空间 | disk / 空间 / df / du / inode / 磁盘 / 满了 | | 网络 | network / 网络 / ping / netstat / ss / 端口 / tcp / dns | | 服务管理 | service / 服务 / systemctl / nginx / mysql / redis / restart | | 软件安装 | install / 安装 / yum / apt / docker / 部署 | | 进程排查 | process / 进程 / ps / kill / cpu / top / 卡死 | | 内存排查 | memory / 内存 / mem / free / oom / swap | | 日志排查 | log / 日志 / journalctl / tail / grep | | 权限问题 | permission / 权限 / chmod / chown / denied / 拒绝 | | 性能调优 | performance / 性能 / 负载 / load / 慢 / slow | | 配置管理 | config / 配置 / conf / vim / sed | | 通用运维 | (兜底) | ## 创建方式 ```go // 基础引擎(无 LLM 提炼,纯规则学习) engine, _ := evolver.NewEvolverEngine("data/agentcli", nil) // 带 LLM 提炼的引擎(推荐) engine, _ := evolver.NewEvolverEngine("data/agentcli", llmClient) ``` > 与 opsxcli 的差异:opsxcli 有 `NewEvolverEngine` 和 `NewEvolverEngineWithLLM` 两个工厂;aiops 合并为一个,通过 `client` 参数是否为 nil 区分。 ## 统计与监控 ```go func (e *EvolverEngine) GetStats() map[string]interface{} { return map[string]interface{}{ "enabled": true, "memory": e.mem.CountStats(), // {experience: N, factual: N, skill: N, hosts: N} } } ``` 由 `Engine.EvolveStats()` 暴露,供审计展示。 ## 精简决策说明 ### 剥离了什么 | opsxcli 步骤 | aiops 处理 | 原因 | |--------------|-----------|------| | Step 2.5 REFLECT(LLM 反射分析) | 合并进 Step 3 LEARN | 单次 LLM 调用同时做「分析 + 提炼」更高效 | | Step 3 SCORE(效率评分) | 剥离 | 评分用于整合决策,aiops 不做整合 | | Step 4 COMPARE(历史对比) | 简化为 `FindExperiences` 查询 | 不需要复杂相似度计算 | | Step 7 CONSOLIDATE(经验整合) | 剥离 | JSONL 追加 + 查询时去重足够,不需要主动合并 | | Step 9.7 DISTILL(自动 Skill 提炼) | 剥离 | Skill 提炼需要复杂条件判断 + 文件管理,价值/复杂比不高 | | Step 10 FEEDBACK(用户反馈消息) | 剥离 | Web 场景下经验学习对用户透明,不需要弹消息 | ### 保留了什么 - **四层记忆架构** —— 思想完整保留,只是程序层未实际使用 - **OBSERVE → LEARN → STORE → MEMORIZE → PREDICT 闭环** —— 真正的学习与注入 - **LLM 提炼 + 规则降级** —— 学习质量有保障 - **异步非阻塞 + 优雅降级** —— 工程可靠性 - **按 task_type 分类注入** —— 避免无关污染 精简后的 Evolver 仍是「真正的自学习引擎」,而非装饰品。 ## 设计亮点 1. **异步非阻塞**:进化在后台 goroutine,不增加用户等待 2. **优雅降级**:LLM 失败退化为规则学习,Evolver 初始化失败 Agent 正常运行 3. **四层记忆**:经验 + 环境 + 事实 + 程序,覆盖从瞬时到持久的认知链路 4. **会话级反馈**:上次任务的经验立即注入下次 Prompt 5. **线程安全**:`Memories.mu sync.Mutex` 保护文件读写 6. **零 DB 依赖**:纯文件存储,与引擎库「零业务依赖」原则一致 ## 常见陷阱 | 陷阱 | 解决方案 | |------|----------| | 记忆目录权限不足 | `NewEvolverEngine` 返回 error,`NewEngine` 把 ev 设为 nil 降级 | | LLM 提炼经验超时 | 30s 超时 + 降级为规则模板 | | 经验注入污染上下文 | 按 `task_type` 匹配 + 条数限制(3 条) | | 事实记忆累积过多无关项 | LLM prompt 明确「无明显事实回复『无』」+ 不写入 | | 并发写入 JSONL 冲突 | `Memories.mu sync.Mutex` 串行化写入 | | 程序层未实现却被引用 | 当前版本 `procedural.jsonl` 仅作为接口位,`GetContextForPrompt` 不读它 | ## 与 opsxcli 的差异总结 | 维度 | opsxcli | aiops | |------|---------|-------| | 进化步骤 | 13 步 | 6 步 | | 代码规模 | ~3300 行 | ~400 行 | | 记忆查询 | 复杂相似度 + 整合去重 | 简单 task_type 匹配 + 时间倒序 | | 经验字段 | SuccessRate / UsageCount / Tags | Success(布尔) | | Skill 提炼 | 自动(Step 9.7) | 未实现(接口位) | | 反射分析 | 独立 Step + JSON 结构 | 合并进 LEARN | | 用户反馈 | Step 10 弹消息 | 剥离(Web 透明) | **核心思想保留度**:四层记忆 ✓ / 进化闭环 ✓ / 异步降级 ✓ / 经验注入 ✓。精简的是重型分析,不是学习能力本身。 > 作者:Logan.Li