# 自进化系统指南 / Evolution System Guide Flyto Agent Engine 的自进化系统(C 方案核心),让 Agent 在运行时自我改进. ## 目录 - [设计理念](#设计理念) - [系统架构](#系统架构) - [三大能力](#三大能力) - [CreateTool -- 运行时创建工具](#createtool----运行时创建工具) - [LearnSkill -- 学习可复用技能](#learnskill----学习可复用技能) - [Reflect -- 自我反思与调整](#reflect----自我反思与调整) - [安全模型](#安全模型) - [审批流程](#审批流程) - [持久化存储](#持久化存储) - [使用示例](#使用示例) - [配置](#配置) ## 设计理念 自进化不是黑盒魔法.每一步都: 1. **可追溯** -- 每个进化行为都有 ID,时间戳,理由,审批记录 2. **可撤销** -- 进化产物存储在磁盘上,删除文件即可撤销 3. **需审批** -- Agent 不能在没有人类审批的情况下改造自己 4. **可累积** -- 进化产物跨会话持久化,Agent 会越来越了解项目和用户 ``` Agent 想进化 │ ▼ 生成 EvolutionProposal │ ▼ 持久化提案到磁盘 │ ▼ ApprovalFunc 审批 │ ├── 拒绝 → 记录 StatusRejected → 结束 │ └── 批准 → 执行进化 → 记录 StatusApplied → 结束 ``` ## 系统架构 ``` Evolver(主控制器) │ ┌──────────────┼──────────────┐ │ │ │ ToolBuilder SkillLearner SelfReflector │ │ │ │ │ │ └──────────────┼──────────────┘ │ EvolutionStore │ 磁盘目录结构: / proposals/ 进化提案 JSON tools/ 工具定义 JSON skills/ 技能定义 JSON reflections/ 反思记录 JSON ``` ## 三大能力 ### CreateTool -- 运行时创建工具 Agent 发现当前工具集无法解决问题时,自己编写新工具. #### 工具定义结构 ```go type ToolDefinition struct { Name string // 工具名称(必须唯一,不能与内置工具冲突) Description string // 工具描述(模型看到的说明) InputSchema json.RawMessage // JSON Schema 输入定义 ExecutionType ToolExecType // 执行方式:script / command / composite Script string // shell 脚本(script 模式) Command string // 命令模板(command 模式) Version int // 版本号 ConcurrencySafe bool // 是否可并发 ReadOnly bool // 是否只读 Tags []string // 分类标签 Rationale string // 创建原因 } ``` #### 三种执行方式 **Script 模式** -- Agent 编写完整的 bash 脚本,参数通过环境变量传入: ```json { "name": "TerraformFmt", "description": "Format Terraform files in the current directory", "execution_type": "script", "script": "#!/bin/bash\ncd ${TOOL_INPUT_PATH:-.}\nterraform fmt -recursive\necho \"Formatted $(find . -name '*.tf' | wc -l) files\"", "input_schema": { "type": "object", "properties": { "path": {"type": "string", "description": "Directory to format (default: cwd)"} } }, "read_only": false, "rationale": "Project uses Terraform, need a quick format tool" } ``` 环境变量命名规则:`TOOL_INPUT_` **Command 模式** -- Agent 编写带占位符的命令模板: ```json { "name": "DockerLogs", "description": "View logs of a Docker container", "execution_type": "command", "command": "docker logs --tail {{.lines}} {{.container}}", "input_schema": { "type": "object", "properties": { "container": {"type": "string", "description": "Container name or ID"}, "lines": {"type": "integer", "description": "Number of lines (default 100)", "default": 100} }, "required": ["container"] }, "read_only": true, "concurrency_safe": true, "rationale": "Frequently checking Docker container logs" } ``` 模板语法:`{{.param_name}}` **Composite 模式** -- 组合现有工具(尚未实现). #### 安全限制 - 不能覆盖内置工具名(Bash, Read, Edit, Write, Glob, Grep, Agent, WebFetch, WebSearch, ToolSearch) - 工具名不能包含空格,tab,换行,斜杠 - 每个会话最多创建 5 个工具(可配置) - 新工具默认 `ConcurrencySafe=false, ReadOnly=false` - 新工具的执行受 Engine 权限系统管控 --- ### LearnSkill -- 学习可复用技能 Agent 完成复杂任务后,将成功的工作流保存为可复用技能. #### 技能 vs 工具 | | 工具 | 技能 | |--|------|------| | 粒度 | 原子操作 | 工作流模板 | | 执行方式 | Engine 调度 | 模型自主执行 | | 内容 | 代码/脚本 | 步骤描述 + 提示词模板 | | 触发 | API 返回 tool_use | 模型在系统提示中看到后自主判断 | #### 技能定义结构 ```go type SkillDefinition struct { Name string // 技能名称 Description string // 简短描述 WhenToUse string // 使用条件(注入系统提示) Steps []SkillStep // 执行步骤 Prompt string // 提示词模板 RequiredTools []string // 需要的工具 Tags []string // 分类标签 SuccessRate float64 // 成功率(自我评估) UsageCount int // 使用次数 LearnedFrom *LearningSource // 学习来源 } type SkillStep struct { Order int // 步骤顺序 Description string // 步骤描述 ToolName string // 使用的工具(可选) InputTemplate string // 输入模板 Condition string // 执行条件 Fallback string // 失败回退 } ``` #### 技能示例 ```json { "name": "go-module-add", "description": "Add a new Go module dependency and update imports", "when_to_use": "When user asks to add a Go package or dependency", "steps": [ {"order": 1, "description": "Search for the package on pkg.go.dev", "tool_name": "WebFetch"}, {"order": 2, "description": "Run go get to add the dependency", "tool_name": "Bash"}, {"order": 3, "description": "Find files that need the import", "tool_name": "Grep"}, {"order": 4, "description": "Add import statements", "tool_name": "Edit"}, {"order": 5, "description": "Run go mod tidy", "tool_name": "Bash"}, {"order": 6, "description": "Run tests to verify", "tool_name": "Bash", "condition": "test files exist"} ], "required_tools": ["Bash", "Grep", "Edit", "WebFetch"], "success_rate": 0.9, "usage_count": 5, "learned_from": { "session_id": "sess_abc123", "task_description": "Add the zerolog logging library", "turn_count": 8, "tools_used": ["Bash", "Grep", "Edit", "WebFetch"] } } ``` #### 技能注入到系统提示 Engine 启动时加载所有已学习的技能,格式化后注入系统提示: ```markdown # Learned Skills The following skills were learned from previous sessions. Use them when applicable: ## go-module-add When to use: When user asks to add a Go package or dependency Success rate: 90% (5 uses) 1. Search for the package on pkg.go.dev 2. Run go get to add the dependency 3. Find files that need the import 4. Add import statements 5. Run go mod tidy 6. Run tests to verify (if test files exist) ``` #### 成功率追踪 使用指数移动平均更新成功率: ``` 成功: new_rate = old_rate * 0.8 + 0.2 失败: new_rate = old_rate * 0.8 ``` 每个会话最多学习 10 个技能(可配置). --- ### Reflect -- 自我反思与调整 分析自身表现,识别模式,记录教训. #### 反思类型 | 类型 | 触发时机 | |------|----------| | `post_session` | 会话结束后 | | `on_error` | 出错后 | | `periodic` | 每 N 次会话 | #### 反思结构 ```go type Reflection struct { ID string // 唯一标识 SessionID string // 来源会话 Type ReflectionType // 反思类型 Summary string // 反思摘要 Observations []Observation // 观察到的模式 Adjustments []Adjustment // 建议的调整 Metrics *SessionMetrics // 会话指标 } type Observation struct { Pattern string // 模式描述 Frequency string // 出现频率 Impact string // 影响评估 Example string // 具体例子 } type Adjustment struct { Type AdjustmentType // prompt / tool_priority / context / workflow / lesson Description string // 调整描述 Target string // 调整目标 Suggestion string // 具体建议 Priority int // 优先级 1-5 Applied bool // 是否已应用 } ``` #### 调整类型 | 类型 | 说明 | 示例 | |------|------|------| | `prompt` | 调整系统提示词 | "添加提示:优先使用 Grep 而非 Bash grep" | | `tool_priority` | 调整工具偏好 | "搜索代码时优先使用 Grep 而非 Bash" | | `context` | 调整上下文策略 | "项目使用 monorepo,应该先读 go.work 文件" | | `workflow` | 调整工作流程 | "修改代码前先运行测试,确认基线状态" | | `lesson` | 记录教训 | "这个项目的 CI 需要 3 分钟,不要等 CI 结果" | #### 教训注入到系统提示 `lesson` 类型的调整会被提取并注入到后续会话的系统提示中: ```markdown # Lessons from Previous Sessions 1. This project uses a custom build system, run `make build` instead of `go build` 2. The test database needs to be running before integration tests 3. Always check .env.example for required environment variables ``` #### 反思示例 ```json { "id": "ref_20260401_120000", "session_id": "sess_abc123", "type": "post_session", "summary": "Task completed in 15 turns. Main bottleneck was repeated file searches.", "observations": [ { "pattern": "Searched for the same file 3 times using different tools", "frequency": "3 times in this session", "impact": "Wasted ~500 input tokens and 2 extra turns", "example": "Searched for 'config.go' with Glob, then Grep, then Bash find" } ], "adjustments": [ { "type": "workflow", "description": "Cache file locations after first search", "target": "file_search", "suggestion": "After finding a file with Glob, remember its path for subsequent reads/edits", "priority": 3, "applied": false }, { "type": "lesson", "description": "Project file structure lesson", "target": "project", "suggestion": "This project keeps all config files in /internal/config/, check there first", "priority": 4, "applied": false } ], "metrics": { "turn_count": 15, "total_input_tokens": 45000, "total_output_tokens": 12000, "total_cost_usd": 0.234, "tool_use_counts": {"Glob": 5, "Grep": 4, "Read": 8, "Edit": 3, "Bash": 2}, "error_count": 1, "task_completed": true } } ``` ## 安全模型 ``` 人类 │ │ 审批/拒绝 │ ┌─────▼─────┐ │ Approval │ ←── 安全边界 │ Func │ └─────┬─────┘ │ │ 批准后 │ ┌─────▼─────┐ │ Evolver │ ←── Agent 的进化能力被 ApprovalFunc 约束 └───────────┘ ``` 安全保障: 1. **审批函数** -- 所有进化必须经过 `ApprovalFunc` 审批.`nil` 则自动拒绝所有提案 2. **只读自动批准** -- 可配置 `AutoApproveReadOnly=true`,自动批准技能学习(只是保存信息,不执行代码) 3. **会话限制** -- 每个会话最多创建 N 个工具 / 学习 N 个技能 4. **内置工具保护** -- 不能覆盖内置工具名 5. **权限系统** -- 新工具的执行和内置工具一样受权限系统管控 6. **持久化可审计** -- 所有提案和产物保存为 JSON 文件,可随时审查 ## 审批流程 ### Go SDK 中的审批 ```go evolver, err := evolve.NewEvolver(&evolve.Config{ StoreDir: "/path/to/evolution-store", ApprovalFunc: func(ctx context.Context, proposal *evolve.EvolutionProposal) (bool, error) { fmt.Printf("Agent wants to evolve:\n") fmt.Printf(" Type: %s\n", proposal.Type) fmt.Printf(" Title: %s\n", proposal.Title) fmt.Printf(" Rationale: %s\n", proposal.Rationale) fmt.Printf("Approve? [y/N] ") var input string fmt.Scanln(&input) return input == "y" || input == "Y", nil }, AutoApproveReadOnly: true, // 自动批准技能学习 MaxToolsPerSession: 5, MaxSkillsPerSession: 10, }) ``` ### 提案状态流转 ``` pending → approved → applied │ └→ (执行失败时保持 approved,不会变成 applied) pending → rejected ``` ## 持久化存储 所有进化产物存储在 `StoreDir` 指定的目录下: ``` / proposals/ evo_1711929600000000000.json 进化提案 evo_1711929700000000000.json tools/ TerraformFmt.json 工具定义 DockerLogs.json skills/ go-module-add.json 技能定义 react-component.json reflections/ 20260401_120000_post_session.json 反思记录 20260401_143000_on_error.json ``` Engine 启动时可以调用 `ToolBuilder.LoadAll()` 和 `SkillLearner.LoadAll()` 恢复之前的进化产物. ## 使用示例 ### 初始化自进化系统 ```go evolver, err := evolve.NewEvolver(&evolve.Config{ StoreDir: filepath.Join(home, ".flyto", "evolution"), ApprovalFunc: myApprovalFunc, AutoApproveReadOnly: true, MaxToolsPerSession: 5, MaxSkillsPerSession: 10, }) if err != nil { log.Fatal(err) } ``` ### 提交进化提案 ```go proposal := &evolve.EvolutionProposal{ Type: evolve.EvolveNewTool, Title: "Create TerraformFmt tool", Description: "A tool to format Terraform files in the project", Rationale: "User frequently asks to format .tf files, a dedicated tool is more efficient", Content: evolve.ToolDefinition{ Name: "TerraformFmt", Description: "Format Terraform files", ExecutionType: evolve.ExecScript, Script: "terraform fmt -recursive ${TOOL_INPUT_PATH:-.}", InputSchema: json.RawMessage(`{"type":"object","properties":{"path":{"type":"string"}}}`), }, } err := evolver.Propose(context.Background(), proposal) ``` ### 查看进化历史 ```go proposals, err := evolver.History() for _, p := range proposals { fmt.Printf("[%s] %s - %s (%s)\n", p.Status, p.Type, p.Title, p.CreatedAt) } ``` ### 加载已有工具和技能 ```go // 加载之前创建的工具 tools, err := evolver.ToolBuilder().LoadAll() for _, def := range tools { // M1 方案 β: 显式传 execenv.Executor (本地 CLI 用 DefaultExecutor{}, // 云端 SaaS 由 platform 层传 sandbox.Backend). runtimeTool := evolve.NewRuntimeTool(def, cwd, execenv.DefaultExecutor{}) // 注册到 Engine... } // 加载已学习的技能(双清单:成功列表 + 各文件独立错误) skills, errs := evolver.SkillLearner().LoadAll() if len(errs) > 0 { // 有损坏文件时可上报,但 skills 中仍包含其余成功加载的技能 log.Printf("partial load: %d file(s) failed", len(errs)) } // 格式化为系统提示片段 fragment, err := evolver.SkillLearner().FormatForSystemPrompt() // 获取教训列表 lessons, err := evolver.Reflector().GetLessons() ``` ## 配置 | 配置项 | 默认值 | 说明 | |--------|--------|------| | `StoreDir` | (必需) | 进化产物存储目录 | | `ApprovalFunc` | `nil` | 审批回调(nil 则自动拒绝所有) | | `AutoApproveReadOnly` | `false` | 是否自动批准只读进化 | | `MaxToolsPerSession` | `5` | 单次会话最多创建工具数 | | `MaxSkillsPerSession` | `10` | 单次会话最多学习技能数 | ## Dream 系统与自进化的关系 AutoDream(记忆巩固)是 KAIROS 系统的核心,与自进化系统直接关联. ### 数据流 ``` 会话结束 │ ▼ Dream 触发检查(时间 + 会话数 + 文件锁) │ ├── 条件不满足 → 跳过 │ └── 条件满足 → Dream 四阶段执行 │ ├── Phase 1: Orient(扫描记忆目录现状) ├── Phase 2: Gather(收集新信号:日志、转录) ├── Phase 3: Consolidate(合并新信号到现有话题) └── Phase 4: Prune(清理索引,保持 <25KB) │ ▼ 整理后的记忆文件 │ ┌─────────┼──────────────┐ ▼ ▼ ▼ Reflect LearnSkill CreateTool │ │ │ │ 基于整理后 │ 基于项目记忆 │ 基于使用模式 │ 的记忆做 │ 学习工作流 │ 创建新工具 │ 自我反思 │ 技能 │ │ │ │ ▼ ▼ ▼ 教训注入 技能注入 工具注册 系统提示 系统提示 到 Registry ``` ### Dream -> 记忆整理 -> 自进化基于整理后的记忆 自进化的质量取决于记忆的质量.Dream 系统的核心价值: 1. **去重合并** -- 多次会话中发现的同一个项目特征,合并为一条记忆 2. **日期规范化** -- "昨天" "上周" 等相对日期转换为绝对日期 3. **过时清理** -- 不再有效的记忆标记为过时(如已修复的 bug) 4. **索引维护** -- 保持记忆索引在合理大小(<25KB),方便快速查找 整理后的记忆是 Reflect 的输入源.Reflect 分析整理后的记忆发现模式("我总是在这个项目上搜索同一个文件"),生成教训注入到后续会话. LearnSkill 也依赖整理后的记忆.项目记忆中记录的技术栈和工作流模式,帮助 SkillLearner 生成更准确的技能定义. ### MemoryExtractor 与 Dream 的关系 `MemoryExtractor` 接口(`pkg/memory/extractor.go`)负责**会话中实时提取**记忆,而 Dream 负责**会话后批量整理**记忆.两者互补: ``` 会话进行中 会话结束后 │ │ ▼ ▼ MemoryExtractor Dream ├── ShouldExtract(每 5 轮检查) ├── Orient(扫描现状) ├── BuildPrompt(构建提取提示) ├── Gather(收集新信号) ├── SubAgent fork 执行提取 ├── Consolidate(合并整理) └── 保存新记忆 └── Prune(清理索引) │ │ └──────── 记忆存储 ◄────────────────┘ ``` 关键设计:MemoryExtractor 只定义策略("提取什么"),不持有 API client.执行由 Engine 的 SubAgent fork 模式负责.这种配方/厨房分离让 Extractor 完全不知道 API,模型,token 这些执行细节,职责清晰. `DefaultCodeExtractor` 是内置的编程场景提取器.仓储/法律等场景可实现自定义 Extractor. ### 触发机制 Dream 在 stop hook 中检查触发条件.当查询循环结束时,引擎异步检查: ``` if timeSinceLastDream >= minHours && sessionsSinceLastDream >= minSessions && acquireFileLock() { go runDream() } ``` 关键设计: - **异步执行** -- Dream 不阻塞主流程 - **文件锁** -- 防止多进程并发 consolidation(使用 flock) - **锁回滚** -- 任务被 kill 时恢复 mtime - **扫描节流** -- 10 分钟间隔,避免频繁 stat 文件系统