Files
zclaw_openfang/docs/superpowers/specs/2026-04-09-hermes-intelligence-pipeline-design.md
iven 4b15ead8e7 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)
2026-04-09 17:47:43 +08:00

743 lines
26 KiB
Markdown
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.

# 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
```