# Hermes Intelligence Pipeline Design > 基于 Hermes Agent (Nous Research) 竞品分析,吸收 4 个核心理念到 ZCLAW 的详细设计方案。 > 架构方案:Pipeline Closure — 闭合现有管线断点,不引入新架构层。 ## Context Hermes Agent 验证了"一个管家 + 记忆飞轮"的方向,其 4 个核心创新对 ZCLAW 发布后迭代有直接参考价值: 1. **自我改进闭环** — 执行 → 评估 → 提取技能 → 改进 → 复用 2. **用户建模** — 三层记忆栈 + 统一用户画像 3. **自然语言 Cron** — LLM 解析自然语言为定时任务 4. **轨迹压缩** — 工具调用链 → 结构化 JSON → RL 基础 **关键诊断:** ZCLAW 缺的不是模块,是管线没接通。现有 PainAggregator、SolutionGenerator、Reflection、Heartbeat、MemoryExtractor 等组件已就位,但彼此断开。本设计闭合这些断点。 **范围约束:** - 管家路由器(ButlerRouterMiddleware + SemanticSkillRouter 接通)由另一个会话推进,本设计标注为外部依赖 - 发布后迭代,不影响当前发布计划 - 4 个理念全部设计,按优先级排序:自我改进闭环 > 用户建模 > NL Cron > 轨迹压缩 **总代码量估算:** ~2200 行新增/修改(~1700 新增 + ~500 修改) ### 类型约定 本设计使用以下 ID 类型约定: ```rust // 所有 Rust 原生结构体使用强类型 use uuid::Uuid; use zclaw_types::{AgentId, SessionId}; // 为新实体定义类型别名(newtype wrapper 在 Tauri 命令层解包为 String) type ExperienceId = String; // Uuid::new_v4().to_string() type ProposalId = String; // 与现有 Proposal.id 一致 type TrajectoryId = String; // Uuid::new_v4().to_string() ``` Rust 内部结构体使用 `AgentId`、`SessionId`;Tauri 命令边界使用 `String`(Tauri serialize 要求)。 ### 统一完成状态枚举 跨 Section 1/4 使用统一的完成状态: ```rust /// 通用完成状态,所有 Outcome 枚举的基础 enum CompletionStatus { Success, Partial, Failed, Abandoned, // Section 1 不使用此变体(运行时约定,非编译时约束) } ``` Section 1 的 Experience 使用 `CompletionStatus`(不含 Abandoned),Section 4 的 CompressedTrajectory 使用完整版。 --- ## Section 1: 自我改进闭环 ### 目标 用户反馈痛点 → 自动识别 → 自动生成方案 → 方案成功后提取为可复用经验 → 下次类似问题直接复用。 ### 数据流 ``` 用户消息 → PainAggregator(已有) ↓ confidence >= 0.7 SolutionGenerator(已有,改为自动触发) ↓ 生成 Proposal 等待用户反馈(成功/失败) ↓ 成功 ExperienceExtractor(新增) ↓ 生成结构化经验 ExperienceStore(新增,SQLite) ↓ 下次对话 MemoryMiddleware(已有)注入相关经验 ``` ### 关键断点修复 **断点 1:PainAggregator → SolutionGenerator(未自动触发)** - 文件:`desktop/src-tauri/src/intelligence/pain_aggregator.rs` - 当 `confidence >= 0.7` 时,通过 Tauri event 自动调用 `butler_generate_solution` - 新增 `PainConfirmedEvent` 事件结构体 **断点 2:方案结果反馈(无反馈机制)** - 新增 `ProposalFeedback` 结构体 - 在聊天流中检测用户隐式反馈关键词("好了""解决了""没用") - 新增 Tauri 命令 `butler_submit_proposal_feedback` **断点 3:成功方案 → 结构化经验(完全缺失)** - 新增 `ExperienceExtractor`:从成功方案中提取经验 - LLM 辅助提取(复用现有 LlmDriver),fallback 到模板提取 - 存入 VikingStorage(使用 scope 前缀 `experience://{agent_id}/`) **断点 4:经验复用(完全缺失)** - 扩展 `MemoryMiddleware`:用户新消息时,通过 VikingStorage 检索相关经验 - 使用 scope 过滤 `experience://` 前缀 + TF-IDF 相关性匹配 - 相似度 > 阈值时,注入"过往经验"到 system prompt - 格式:`[过往经验] 类似情况 X 做过 Y,结果是 Z` ### 数据结构 ```rust // 新增文件:desktop/src-tauri/src/intelligence/experience.rs use zclaw_types::AgentId; use uuid::Uuid; struct Experience { id: ExperienceId, agent_id: AgentId, pain_pattern: String, // 触发模式(关键词摘要) context: String, // 问题上下文 solution_steps: Vec, // 解决步骤 outcome: CompletionStatus, // Success | Partial(经验只记录成功的) source_proposal_id: Option, reuse_count: usize, created_at: DateTime, } struct ProposalFeedback { proposal_id: ProposalId, outcome: CompletionStatus, // Success | Failed | Partial user_comment: Option, detected_at: DateTime, } struct PainConfirmedEvent { pain_point_id: String, // PainPoint.id (Uuid String) pattern: String, confidence: f32, } ``` ### 存储策略 经验存储在现有 VikingStorage 中,使用 scope 前缀区分: ```rust // Experience 存储为 VikingStorage memory entry scope: "agent://{agent_id}/experience/{pattern_hash}" // 遵循 OpenViking URI 约定 content: JSON(Experience) // 序列化的完整 Experience 结构体 ``` **为什么不用独立的 experiences + FTS5 表:** - VikingStorage 已有成熟的 FTS5 + TF-IDF + embedding 检索管道 - MemoryMiddleware 已与 VikingStorage 集成,增加 scope 前缀即可区分 - 避免维护两套独立的 FTS5 索引 独立的 `experience_store.rs` 文件负责 VikingStorage CRUD + scope 过滤,不创建新表。 ### 迁移策略 不需要新数据库表或 schema 变更。经验数据通过 VikingStorage 的现有 memory 表存储,使用 scope 前缀区分。 ### 错误处理 - ExperienceExtractor LLM 调用失败 → fallback 到模板提取(固定格式提取 solution_steps) - ProposalFeedback 检测失败 → 不阻塞对话,静默跳过 - 经验注入失败 → MemoryMiddleware 记录 warn 日志,不注入,不影响正常对话 - 所有错误遵循代码库约定:非关键路径使用 `log::warn!` / `log::error!`,不阻塞主流程 ### 测试计划 | 测试目标 | 文件位置 | 覆盖场景 | |----------|---------|---------| | ExperienceExtractor | `experience.rs` 内联 `#[cfg(test)]` | LLM 提取成功/failure fallback、模板提取 | | ExperienceStore | `experience_store.rs` 内联 | CRUD 往返、scope 过滤、VikingStorage 集成 | | PainConfirmedEvent 触发 | `pain_aggregator.rs` 测试扩展 | confidence >= 0.7 触发事件 | | 经验注入 | MemoryMiddleware 测试 | 相关性过滤、token 限制、空结果处理 | | ProposalFeedback 检测 | `solution_generator.rs` 测试扩展 | 隐式反馈关键词匹配 | ### 文件清单 | 文件 | 用途 | 预估行数 | |------|------|---------| | `desktop/src-tauri/src/intelligence/experience.rs` | ExperienceExtractor + 逻辑 | ~250 | | `crates/zclaw-growth/src/experience_store.rs` | VikingStorage scope CRUD | ~120 | | 改动 `pain_aggregator.rs` | 自动触发 SolutionGenerator | ~30 | | 改动 `solution_generator.rs` | Proposal feedback 槽位 | ~40 | | 改动 `intelligence_hooks.rs` | 新增 post-proposal-evaluation hook | ~50 | | 改动 MemoryMiddleware | 经验注入逻辑(scope 过滤) | ~60 | | 改动 `crates/zclaw-memory/src/lib.rs` | 导出新模块 | ~5 | **预估:~555 行新增/修改** --- ## Section 2: 用户建模 ### 目标 从每次对话中持续提取用户特征,聚合为结构化画像,注入到路由和生成环节。 ### 数据流 ``` 对话消息 → MemoryExtractor(已有) ↓ UserProfiler(新增) ↓ 聚合到 UserProfile UserProfileStore(新增,SQLite) ↓ ├→ ButlerRouter(外部依赖,另一个会话) │ → 路由决策考虑用户偏好 └→ MemoryMiddleware(已有) → system prompt 注入用户画像摘要 ``` ### 设计决策 **为什么新建 UserProfile 而不沿用 IdentityManager.user_profile?** 现有 user_profile 是非结构化 markdown,无法做条件查询。Profile injection 已被有意禁用(`identity.rs:291-298`),因为它导致模型过度关注旧话题。需要结构化画像做相关性过滤后注入。 **单用户桌面场景:** 桌面版使用 `"default_user"` 作为 user_id(与 PainAggregator 一致),仅维护一条 UserProfile 记录。 ### 数据结构 ```rust // 新增文件:crates/zclaw-memory/src/user_profile_store.rs struct UserProfile { user_id: String, // "default_user"(桌面版单用户) // 静态属性(低频更新) industry: Option, // "医疗" "制造业" role: Option, // "行政主任" "厂长" expertise_level: Option, // Beginner / Intermediate / Expert communication_style: Option, // Concise / Detailed / Formal / Casual preferred_language: String, // "zh-CN" // 动态属性(高频更新) recent_topics: Vec, // 最近 7 天的话题 active_pain_points: Vec, // 当前未解决痛点 preferred_tools: Vec, // 常用技能/工具 // 元数据 updated_at: DateTime, confidence: f32, // 画像置信度 } enum Level { Beginner, Intermediate, Expert } enum CommStyle { Concise, Detailed, Formal, Casual } ``` ### 聚合逻辑(UserProfiler) 1. **MemoryExtractor 输出 → 分类**:已提取的记忆按 `UserPreference` / `UserFact` / `AgentLesson` 分类 2. **分类后聚合**: - `UserPreference` → 更新 `communication_style`, `preferred_tools` - `UserFact` → 更新 `industry`, `role`, `expertise_level` - `AgentLesson` → 更新 `recent_topics` - PainAggregator 的活跃痛点 → 更新 `active_pain_points` 3. **去重 + 衰减**:相似属性合并,超过 30 天无佐证的属性降低 confidence 4. **存储**:单用户单条记录(upsert),SQLite `user_profiles` 表 ### 注入逻辑 ```rust // 在 MemoryMiddleware 中新增 fn inject_user_profile(&self, ctx: &mut MiddlewareContext, profile: &UserProfile) { // 只注入与当前话题相关的属性 let relevant = self.filter_by_relevance(profile, &ctx.user_input); if relevant.is_empty() { return; } // 格式化为简洁摘要,不超过 100 tokens let summary = format_user_profile_summary(&relevant); ctx.system_prompt.push_str(&summary); } ``` **关键约束:** 注入内容不超过 100 tokens,只注入与当前话题相关的属性。 ### 与管家路由器的协作(外部依赖) 当管家路由器接通后: - ButlerRouterMiddleware 可读取 UserProfile.industry 和 role - 路由时考虑用户背景 - 本设计只提供数据接口,路由逻辑由另一个会话处理 ### 迁移策略 新增 `user_profiles` 表,通过 `schema.rs` 的 `MIGRATIONS` 数组递增版本。初始版本包含 CREATE TABLE + 默认 "default_user" 行。 ```rust // 在 schema.rs MIGRATIONS 数组新增 ("CREATE TABLE IF NOT EXISTS user_profiles (...)", "DROP TABLE IF EXISTS user_profiles") ``` ### 错误处理 - UserProfileStore 读写失败 → `log::warn!` + 返回 None,不阻塞对话 - UserProfiler 聚合失败 → 保留上次有效画像,不覆盖 - Profile 注入失败 → MemoryMiddleware 降级到无 profile 注入模式 - 所有操作遵循:非关键路径错误不阻塞主流程 ### 测试计划 | 测试目标 | 文件位置 | 覆盖场景 | |----------|---------|---------| | UserProfileStore | `user_profile_store.rs` 内联 | CRUD 往返、upsert 去重、JSON 字段序列化 | | UserProfiler 聚合 | `user_profiler.rs` 内联 | 分类正确性、去重、衰减、空输入 | | Profile 注入 | MemoryMiddleware 测试扩展 | 相关性过滤、100 token 限制、空 profile | | 迁移 | schema 测试 | 新建 + 升级路径 | ### 数据库 Schema ```sql CREATE TABLE IF NOT EXISTS user_profiles ( user_id TEXT PRIMARY KEY, industry TEXT, role TEXT, expertise_level TEXT, -- 'Beginner' | 'Intermediate' | 'Expert' communication_style TEXT, -- 'Concise' | 'Detailed' | 'Formal' | 'Casual' preferred_language TEXT DEFAULT 'zh-CN', recent_topics TEXT, -- JSON array active_pain_points TEXT, -- JSON array preferred_tools TEXT, -- JSON array confidence REAL DEFAULT 0.0, updated_at TEXT NOT NULL ); ``` ### 文件清单 | 文件 | 用途 | 预估行数 | |------|------|---------| | `crates/zclaw-memory/src/user_profile_store.rs` | UserProfile 结构体 + SQLite CRUD | ~200 | | `desktop/src-tauri/src/intelligence/user_profiler.rs` | 聚合逻辑 | ~180 | | 改动 `MemoryMiddleware` | profile 注入(相关性过滤) | ~80 | | 改动 `intelligence_hooks.rs` | post-extraction 触发 UserProfiler | ~30 | | 改动 `crates/zclaw-memory/src/lib.rs` | 导出新模块 | ~5 | **预估:~495 行新增/修改** --- ## Section 3: 自然语言 Cron ### 目标 用户说"每天早上9点提醒我查房" → 系统解析为 `0 9 * * *` → 自动创建定时任务。 ### 数据流 ``` 用户消息(含时间意图) ↓ 意图分类(ButlerRouter / 正则预检) ↓ 检测到"定时/提醒"意图 NlScheduleParser(新增,位于 zclaw-runtime) ↓ 解析为 ParsedSchedule ScheduleConfirmDialog(新增) ↓ 用户确认 "每天早上9点 → 0 9 * * *" SchedulerService(已有,位于 zclaw-kernel) ↓ 创建定时任务 TriggerManager(已有) ↓ 到时触发 Hand 执行(已有) ``` ### 解析策略(三层 fallback) **Layer 1: 正则模式匹配(覆盖 80% 常见场景)** | 模式 | 示例 | Cron | |------|------|------| | 每天 + 时间 | 每天早上9点 | `0 9 * * *` | | 每周N + 时间 | 每周一上午10点 | `0 10 * * 1` | | 工作日 + 时间 | 工作日下午3点 | `0 15 * * 1-5` | | 每N小时 | 每2小时 | `0 */2 * * *` | | 每月N号 | 每月1号 | `0 0 1 * *` | | 相对时间 | 明天下午3点 | 一次性 ISO | **Layer 2: LLM 辅助解析(覆盖模糊/复杂表述)** - 使用 Haiku(~50 tokens 输入,~20 tokens 输出) - 处理如"下个月开始每周二和周四提醒我" **Layer 3: 交互澄清(无法确定时)** - "我理解您想设置定时任务,请确认:..." ### 数据结构 ```rust // 新增文件:crates/zclaw-runtime/src/nl_schedule.rs // 放在 runtime 层因为这是纯文本→cron工具,不依赖 kernel 协调 use zclaw_types::AgentId; struct ParsedSchedule { cron_expression: String, // "0 9 * * *" natural_description: String, // "每天早上9点" confidence: f32, task_description: String, // "查房提醒" task_target: TaskTarget, } /// 定时任务目标 enum TaskTarget { Agent(AgentId), // 触发指定 agent Hand(String), // 触发指定 hand(工具名) Workflow(String), // 触发指定 workflow(名称) } enum ScheduleParseResult { Exact(ParsedSchedule), // 高置信度,直接确认 Ambiguous(Vec), // 多种理解,需选择 Unclear, // 需要澄清 } ``` ### 确认流程 1. 用户说"每天早上9点提醒我查房" 2. 解析为 `{ cron: "0 9 * * *", desc: "查房提醒" }` 3. 系统回复:"好的,我为您设置了:**每天早上 9:00** 提醒查房。确认吗?" 4. 用户确认 → 调用已有 `SchedulerService.create_trigger()` 5. 用户修正 → 重新解析或手动编辑 ### 迁移策略 不需要新数据库表。NlScheduleParser 是纯计算工具,输出通过现有 `SchedulerService` + `TriggerManager` 存储。 ### 错误处理 - 正则匹配失败 → 尝试 Layer 2 LLM 解析 - LLM 解析失败 → 返回 `ScheduleParseResult::Unclear`,触发交互澄清 - 定时任务创建失败 → 向用户报告错误,建议手动设置 - 所有错误不阻塞对话流程 ### 测试计划 | 测试目标 | 文件位置 | 覆盖场景 | |----------|---------|---------| | 正则解析 | `nl_schedule.rs` 内联 | 10+ 中文时间表述模式、边界值、无效输入 | | LLM fallback | mock 测试 | LLM 返回无效 cron 时的容错 | | ParsedSchedule | 单元测试 | 序列化、字段完整性 | | TaskTarget 枚举 | 单元测试 | 各变体匹配现有类型 | | 确认流程 | 集成测试 | 完整 parse → confirm → create 链路 | ### 文件清单 | 文件 | 用途 | 预估行数 | |------|------|---------| | `crates/zclaw-runtime/src/nl_schedule.rs` | NlScheduleParser + 中文模式库 | ~300 | | 改动 `intelligence_hooks.rs` | 检测定时意图并触发解析 | ~40 | | 改动 desktop store + component | 确认对话框交互 | ~150 | | 改动 `crates/zclaw-kernel/src/scheduler.rs` | 接受 cron 字符串输入 | ~20 | **预估:~510 行新增/修改** --- ## Section 4: 轨迹压缩 ### 目标 记录完整的工具调用链(用户请求 → 意图分类 → 技能选择 → 执行步骤 → 结果 → 用户满意度),压缩为结构化 JSON,作为未来 RL/改进的基础数据。 ### 数据流 ``` 用户请求 ↓ AgentLoop(已有) ↓ 每步通过中间件记录 TrajectoryRecorderMiddleware(新增,实现 AgentMiddleware trait) ↓ 异步写入 trajectory_events 表 ↓ 会话结束时 TrajectoryCompressor(新增) ↓ 压缩为结构化 JSON compressed_trajectories 表 ↓ 可选 导出为 RL 训练数据格式 ``` ### 关键设计决策:TrajectoryRecorder 作为中间件 TrajectoryRecorder 实现 `AgentMiddleware` trait(来自 `zclaw-runtime`),利用现有中间件钩子: - `before_completion` → 记录 `UserRequest` 步骤 - `after_tool_call` → 记录 `ToolExecution` 步骤 - `after_completion` → 记录 `LlmGeneration` 步骤 + 会话结束时触发压缩 **为什么不用自定义 AgentLoop hook:** - 现有中间件系统已提供所有需要的钩子点 - `MiddlewareContext` 已暴露 `agent_id`、`session_id`、`user_input`、`input_tokens`、`output_tokens` - 符合 Pipeline Closure 原则:不引入新架构层 优先级设置:600-799 范围(遥测类别),确保在业务中间件之后运行。注意现有 `token_calibration` 中间件已占用优先级 700,推荐使用 650。 ### 数据结构 ```rust // 新增文件:crates/zclaw-memory/src/trajectory_store.rs use zclaw_types::{AgentId, SessionId}; use uuid::Uuid; /// 单条轨迹事件(细粒度,按步骤记录) struct TrajectoryEvent { id: TrajectoryId, session_id: SessionId, agent_id: AgentId, step_index: usize, step_type: TrajectoryStepType, input_summary: String, // ≤200 字 output_summary: String, // ≤200 字 duration_ms: u64, timestamp: DateTime, } enum TrajectoryStepType { UserRequest, // 用户原始请求 IntentClassification, // 意图分类结果 SkillSelection, // 选择了哪个技能 ToolExecution, // 工具调用 LlmGeneration, // LLM 生成 UserFeedback, // 用户反馈 } /// 压缩后的完整轨迹(会话结束时生成) struct CompressedTrajectory { id: TrajectoryId, session_id: SessionId, agent_id: AgentId, request_type: String, // "data_report" "policy_query" tools_used: Vec, // ["researcher", "collector"] outcome: CompletionStatus, // Success | Partial | Failed | Abandoned total_steps: usize, total_duration_ms: u64, total_tokens: u32, execution_chain: String, // JSON: [{step, tool, result_summary}] satisfaction_signal: Option, created_at: DateTime, } enum SatisfactionSignal { Positive, // "谢谢""很好""解决了" Negative, // "不对""没用""还是不行" Neutral, // 无明显信号 } ``` ### 记录策略 **低开销原则:** 轨迹记录不能影响正常对话性能。 1. **事件记录:** 每步只存 `step_type + input_summary(≤200字) + output_summary(≤200字)` 2. **异步写入:** 通过 `tokio::spawn` 异步写入 SQLite,不阻塞主流程 3. **压缩触发:** 会话结束时(compactor flush 或 session close),异步压缩 4. **保留策略:** 压缩后删除原始事件(保留 7 天),压缩轨迹保留 90 天 ### 压缩算法 ```rust fn compress(events: Vec) -> CompressedTrajectory { // 1. 提取关键步骤(跳过中间重试/错误恢复) // 2. 合并连续相同类型的步骤 // 3. 生成 execution_chain JSON // 4. 推断 outcome(最后一步是否成功 + 用户反馈信号) // 5. 统计 token 用量和耗时 } ``` ### 与自我改进闭环的协作 当 ExperienceExtractor 运行时: - 查询 `compressed_trajectories` 找到类似场景的历史轨迹 - 评估"这个方案上次用了几步?成功率多少?" - 为经验提取提供数据支撑 ### 未来 RL 扩展(本次不实施) - `execution_chain` 可直接转换为 Atropos/GEPA 训练格式 - `satisfaction_signal` 可作为 reward signal - RL 训练管道不在本次范围内 ### 迁移策略 通过 `schema.rs` 的 `MIGRATIONS` 数组递增版本(使用 `&[&str]` 扁平数组格式,与现有代码一致),新增 `trajectory_events` 和 `compressed_trajectories` 两张表。 ```rust // 在 schema.rs MIGRATIONS 数组新增(扁平 &str 数组,无 down migration) &[ "CREATE TABLE IF NOT EXISTS trajectory_events ( id TEXT PRIMARY KEY, session_id TEXT NOT NULL, ... ); CREATE TABLE IF NOT EXISTS compressed_trajectories ( ... ); CREATE INDEX IF NOT EXISTS idx_trajectory_session ON trajectory_events(session_id);", ] ``` ### 错误处理 - TrajectoryRecorder 异步写入失败 → `log::warn!`,不重试,丢弃单条事件 - TrajectoryCompressor 压缩失败 → `log::warn!`,原始事件保留 7 天后自动清理 - 压缩轨迹查询失败 → ExperienceExtractor 降级到无历史数据模式 - 所有操作:非关键路径错误不阻塞对话 ### 测试计划 | 测试目标 | 文件位置 | 覆盖场景 | |----------|---------|---------| | TrajectoryStore CRUD | `trajectory_store.rs` 内联 | 插入/查询/删除、session 过滤 | | 压缩算法 | `trajectory_compressor.rs` 内联 | 正常压缩、空事件、单步事件、合并去重 | | TrajectoryRecorderMiddleware | 中间件测试 | before/after 钩子记录、空输入跳过 | | 保留策略 | 集成测试 | 7 天清理、90 天清理 | | 满意度检测 | 单元测试 | 正/负/中性关键词匹配 | ### 数据库 Schema ```sql CREATE TABLE IF NOT EXISTS trajectory_events ( id TEXT PRIMARY KEY, session_id TEXT NOT NULL, agent_id TEXT NOT NULL, step_index INTEGER NOT NULL, step_type TEXT NOT NULL, input_summary TEXT, output_summary TEXT, duration_ms INTEGER DEFAULT 0, timestamp TEXT NOT NULL ); CREATE INDEX idx_trajectory_session ON trajectory_events(session_id); CREATE TABLE IF NOT EXISTS compressed_trajectories ( id TEXT PRIMARY KEY, session_id TEXT NOT NULL, agent_id TEXT NOT NULL, request_type TEXT NOT NULL, tools_used TEXT, -- JSON array outcome TEXT NOT NULL, -- 'Success'|'Partial'|'Failed'|'Abandoned' total_steps INTEGER DEFAULT 0, total_duration_ms INTEGER DEFAULT 0, total_tokens INTEGER DEFAULT 0, execution_chain TEXT NOT NULL, -- JSON satisfaction_signal TEXT, -- 'Positive'|'Negative'|'Neutral'|NULL created_at TEXT NOT NULL ); CREATE INDEX idx_ct_request_type ON compressed_trajectories(request_type); CREATE INDEX idx_ct_outcome ON compressed_trajectories(outcome); ``` ### 文件清单 | 文件 | 用途 | 预估行数 | |------|------|---------| | `crates/zclaw-memory/src/trajectory_store.rs` | TrajectoryEvent + CompressedTrajectory + SQLite CRUD | ~250 | | `crates/zclaw-runtime/src/middleware/trajectory_recorder.rs` | AgentMiddleware 实现 | ~150 | | `desktop/src-tauri/src/intelligence/trajectory_compressor.rs` | 压缩算法 | ~120 | | 改动 `crates/zclaw-memory/src/lib.rs` | 导出新模块 | ~5 | | 改动 `crates/zclaw-kernel/src/kernel/mod.rs` | 注册中间件(priority 650) | ~10 | **预估:~535 行新增/修改** --- ## 总览 ### 代码量汇总 | 理念 | 新增 | 修改 | 总计 | 优先级 | |------|------|------|------|--------| | 自我改进闭环 | ~400 | ~155 | ~555 | P1 | | 用户建模 | ~380 | ~115 | ~495 | P2 | | 自然语言 Cron | ~320 | ~190 | ~510 | P3 | | 轨迹压缩 | ~525 | ~15 | ~540 | P4 | | **总计** | **~1625** | **~475** | **~2100** | — | ### 实施顺序和依赖关系 ``` Section 1 (自我改进闭环) ← 立即开始 ↓ Section 2 (用户建模) ← 可与 Section 1 并行,无强依赖 ↓ Section 3 (NL Cron) ← 依赖 Section 2 的 UserProfile(可选)+ 管家路由器(外部) ↓ Section 4 (轨迹压缩) ← 可与 Section 1-3 并行,无依赖 ``` Section 1 和 2 可以并行开发。Section 3 建议在管家路由器接通后实施。Section 4 完全独立。 ### 外部依赖 - 管家路由器(ButlerRouterMiddleware + SemanticSkillRouter 接通)— 另一个会话推进 - 痛点数据持久化(内存 → SQLite)— 已在 pre-release strategy 中规划 ### intelligence_hooks.rs 管理 当前 `intelligence_hooks.rs` 约 281 行。本设计新增约 120 行钩子代码(Section 1: ~50, Section 2: ~30, Section 3: ~40)。 如果文件超过 400 行,应拆分为 `hooks/` 子模块: - `hooks/pain.rs` — 痛点相关钩子 - `hooks/profile.rs` — 用户画像钩子 - `hooks/schedule.rs` — 定时任务意图检测 - `hooks/mod.rs` — 统一注册 ### 验证方式 每个 Section 完成后的验证步骤: 1. **自我改进闭环:** 人工模拟痛点对话 → 验证自动生成方案 → 验证经验提取 → 验证经验复用注入 2. **用户建模:** 多轮对话 → 检查 UserProfile 各字段是否正确聚合 → 验证注入内容相关性 3. **NL Cron:** 测试 10+ 种中文时间表述 → 验证 cron 输出 → 验证定时任务创建 4. **轨迹压缩:** 完整对话流程 → 检查 trajectory_events 记录 → 验证压缩结果 → 检查异步写入无阻塞 ### 验证命令 ```bash # Rust 编译检查 cargo check --workspace --exclude zclaw-saas # Rust 测试 cargo test --workspace --exclude zclaw-saas # TypeScript 类型检查 cd desktop && pnpm tsc --noEmit # 前端测试 cd desktop && pnpm vitest run ```