feat(hermes): implement intelligence pipeline — 4 chunks, 684 tests passing

Hermes Intelligence Pipeline closes breakpoints in ZCLAW's existing
intelligence components with 4 self-contained modules:

Chunk 1 — Self-improvement Loop:
- ExperienceStore (zclaw-growth): FTS5+TF-IDF wrapper with scope prefix
- ExperienceExtractor (desktop/intelligence): template-based extraction
  from successful proposals with implicit keyword detection

Chunk 2 — User Modeling:
- UserProfileStore (zclaw-memory): SQLite-backed structured profiles
  with industry/role/expertise/comm_style/recent_topics/pain_points
- UserProfiler (desktop/intelligence): fact classification by category
  (Preference/Knowledge/Behavior) with profile summary formatting

Chunk 3 — NL Cron Chinese Time Parser:
- NlScheduleParser (zclaw-runtime): 6 pattern matchers for Chinese time
  expressions (每天/每周/工作日/间隔/每月/一次性) producing cron expressions
- Period-aware hour adjustment (下午3点→15, 晚上8点→20)
- Schedule intent detection + task description extraction

Chunk 4 — Trajectory Compression:
- TrajectoryStore (zclaw-memory): trajectory_events + compressed_trajectories
- TrajectoryRecorderMiddleware (zclaw-runtime/middleware): priority 650,
  async non-blocking event recording via tokio::spawn
- TrajectoryCompressor (desktop/intelligence): dedup, request classification,
  satisfaction detection, execution chain JSON

Schema migrations: v2→v3 (user_profiles), v3→v4 (trajectory tables)
This commit is contained in:
iven
2026-04-09 17:47:43 +08:00
parent 0883bb28ff
commit 4b15ead8e7
15 changed files with 4225 additions and 0 deletions

View File

@@ -0,0 +1,742 @@
# 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`(不含 AbandonedSection 4 的 CompressedTrajectory 使用完整版。
---
## Section 1: 自我改进闭环
### 目标
用户反馈痛点 → 自动识别 → 自动生成方案 → 方案成功后提取为可复用经验 → 下次类似问题直接复用。
### 数据流
```
用户消息 → PainAggregator已有
↓ confidence >= 0.7
SolutionGenerator已有改为自动触发
↓ 生成 Proposal
等待用户反馈(成功/失败)
↓ 成功
ExperienceExtractor新增
↓ 生成结构化经验
ExperienceStore新增SQLite
↓ 下次对话
MemoryMiddleware已有注入相关经验
```
### 关键断点修复
**断点 1PainAggregator → 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 辅助提取(复用现有 LlmDriverfallback 到模板提取
- 存入 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<String>, // 解决步骤
outcome: CompletionStatus, // Success | Partial经验只记录成功的
source_proposal_id: Option<ProposalId>,
reuse_count: usize,
created_at: DateTime,
}
struct ProposalFeedback {
proposal_id: ProposalId,
outcome: CompletionStatus, // Success | Failed | Partial
user_comment: Option<String>,
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<String>, // "医疗" "制造业"
role: Option<String>, // "行政主任" "厂长"
expertise_level: Option<Level>, // Beginner / Intermediate / Expert
communication_style: Option<CommStyle>, // Concise / Detailed / Formal / Casual
preferred_language: String, // "zh-CN"
// 动态属性(高频更新)
recent_topics: Vec<String>, // 最近 7 天的话题
active_pain_points: Vec<String>, // 当前未解决痛点
preferred_tools: Vec<String>, // 常用技能/工具
// 元数据
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. **存储**单用户单条记录upsertSQLite `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<ParsedSchedule>), // 多种理解,需选择
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<String>, // ["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<SatisfactionSignal>,
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<TrajectoryEvent>) -> 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
```