fix(presentation): 修复 presentation 模块类型错误和语法问题
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- 创建 types.ts 定义完整的类型系统 - 重写 DocumentRenderer.tsx 修复语法错误 - 重写 QuizRenderer.tsx 修复语法错误 - 重写 PresentationContainer.tsx 添加类型守卫 - 重写 TypeSwitcher.tsx 修复类型引用 - 更新 index.ts 移除不存在的 ChartRenderer 导出 审计结果: - 类型检查: 通过 - 单元测试: 222 passed - 构建: 成功
This commit is contained in:
757
docs/superpowers/specs/2026-03-26-agent-growth-design.md
Normal file
757
docs/superpowers/specs/2026-03-26-agent-growth-design.md
Normal file
@@ -0,0 +1,757 @@
|
||||
# ZCLAW Agent 成长功能设计规格
|
||||
|
||||
> **版本**: 1.0
|
||||
> **日期**: 2026-03-26
|
||||
> **状态**: 已批准
|
||||
> **作者**: Claude + 用户协作设计
|
||||
|
||||
---
|
||||
|
||||
## 一、概述
|
||||
|
||||
### 1.1 背景
|
||||
|
||||
ZCLAW 当前的学习系统存在**前后端分离问题**:
|
||||
- 前端有完整的学习逻辑 (`active-learning.ts`, `memory-extractor.ts`)
|
||||
- 但这些学习结果存储在 localStorage/IndexedDB
|
||||
- 后端执行系统 (Rust) 无法获取这些学习结果
|
||||
- 导致 Agent 无法真正"成长"
|
||||
|
||||
### 1.2 目标
|
||||
|
||||
设计并实现完整的 Agent 成长功能,让 Agent 像个人管家一样:
|
||||
- **记住偏好**:用户的沟通风格、回复格式、语言偏好等
|
||||
- **积累知识**:从对话中学习用户相关事实、领域知识、经验教训
|
||||
- **掌握技能**:记录技能/Hand 的使用模式,优化执行效率
|
||||
|
||||
### 1.3 需求决策
|
||||
|
||||
| 维度 | 决策 | 理由 |
|
||||
|------|------|------|
|
||||
| 成长维度 | 偏好 + 知识 + 技能(全部) | 完整的管家式成长体验 |
|
||||
| 整合策略 | 完全后端化,Rust 重写 | 避免前后端数据隔离问题 |
|
||||
| 存储架构 | OpenViking 作为完整记忆层 | 利用现有的 L0/L1/L2 分层 + 语义搜索 |
|
||||
| 学习触发 | 对话后自动 + 用户显式触发 | 平衡自动化和可控性 |
|
||||
| 行为影响 | 智能检索 + Token 预算控制 | 解决长期使用后数据量过大的问题 |
|
||||
|
||||
---
|
||||
|
||||
## 二、系统架构
|
||||
|
||||
### 2.1 整体架构图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ZCLAW Agent 成长系统 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ zclaw-growth (新 Crate) │ │
|
||||
│ │ ────────────────────────────────────────────────────── │ │
|
||||
│ │ • MemoryExtractor - 从对话中提取偏好/知识/经验 │ │
|
||||
│ │ • MemoryRetriever - 语义检索相关记忆 │ │
|
||||
│ │ • PromptInjector - 动态构建 system_prompt │ │
|
||||
│ │ • GrowthTracker - 追踪成长指标和演化 │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ OpenViking (记忆层) │ │
|
||||
│ │ ────────────────────────────────────────────────────── │ │
|
||||
│ │ URI 结构: │ │
|
||||
│ │ • agent://{id}/preferences/{category} - 用户偏好 │ │
|
||||
│ │ • agent://{id}/knowledge/{domain} - 知识积累 │ │
|
||||
│ │ • agent://{id}/experience/{skill} - 技能经验 │ │
|
||||
│ │ • agent://{id}/sessions/{sid} - 对话历史 │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ zclaw-runtime (修改) │ │
|
||||
│ │ ────────────────────────────────────────────────────── │ │
|
||||
│ │ AgentLoop 集成: │ │
|
||||
│ │ 1. 对话前 → MemoryRetriever 检索相关记忆 │ │
|
||||
│ │ 2. 构建请求 → PromptInjector 注入记忆 │ │
|
||||
│ │ 3. 对话后 → MemoryExtractor 提取新记忆 │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 数据流
|
||||
|
||||
```
|
||||
用户输入
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 1. 记忆检索 │
|
||||
│ • 用当前输入查询 OpenViking │
|
||||
│ • 召回 Top-5 相关记忆 │
|
||||
│ • Token 预算控制 (500 tokens) │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 2. Prompt 构建 │
|
||||
│ system_prompt = base + │
|
||||
│ "## 用户偏好\n" + preferences + │
|
||||
│ "## 相关知识\n" + knowledge │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 3. LLM 对话 │
|
||||
│ • 正常的 AgentLoop 执行 │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 4. 记忆提取 (对话后) │
|
||||
│ • 分析对话内容 │
|
||||
│ • 提取偏好/知识/经验 │
|
||||
│ • 写入 OpenViking (L0/L1/L2) │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.3 OpenViking URI 结构
|
||||
|
||||
```
|
||||
agent://{agent_id}/
|
||||
├── preferences/
|
||||
│ ├── communication-style # 沟通风格偏好
|
||||
│ ├── response-format # 回复格式偏好
|
||||
│ ├── language-preference # 语言偏好
|
||||
│ └── topic-interests # 主题兴趣
|
||||
├── knowledge/
|
||||
│ ├── user-facts # 用户相关事实
|
||||
│ ├── domain-knowledge # 领域知识
|
||||
│ └── lessons-learned # 经验教训
|
||||
├── experience/
|
||||
│ ├── skill-{id} # 技能使用经验
|
||||
│ └── hand-{id} # Hand 使用经验
|
||||
└── sessions/
|
||||
└── {session_id}/ # 对话历史
|
||||
├── raw # 原始对话 (L0)
|
||||
├── summary # 摘要 (L1)
|
||||
└── keywords # 关键词 (L2)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、详细设计
|
||||
|
||||
### 3.1 新 Crate 结构
|
||||
|
||||
```
|
||||
crates/zclaw-growth/
|
||||
├── Cargo.toml
|
||||
├── src/
|
||||
│ ├── lib.rs # 入口和公共 API
|
||||
│ ├── extractor.rs # 记忆提取器
|
||||
│ ├── retriever.rs # 记忆检索器
|
||||
│ ├── injector.rs # Prompt 注入器
|
||||
│ ├── tracker.rs # 成长追踪器
|
||||
│ ├── types.rs # 类型定义
|
||||
│ └── viking_adapter.rs # OpenViking 适配器
|
||||
```
|
||||
|
||||
### 3.2 核心类型定义
|
||||
|
||||
```rust
|
||||
// types.rs
|
||||
|
||||
/// 记忆类型
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum MemoryType {
|
||||
Preference, // 偏好
|
||||
Knowledge, // 知识
|
||||
Experience, // 经验
|
||||
Session, // 对话
|
||||
}
|
||||
|
||||
/// 记忆条目
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct MemoryEntry {
|
||||
pub uri: String,
|
||||
pub memory_type: MemoryType,
|
||||
pub content: String,
|
||||
pub keywords: Vec<String>,
|
||||
pub importance: u8, // 1-10
|
||||
pub access_count: u32,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub last_accessed: DateTime<Utc>,
|
||||
}
|
||||
|
||||
/// 提取的记忆
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ExtractedMemory {
|
||||
pub memory_type: MemoryType,
|
||||
pub category: String,
|
||||
pub content: String,
|
||||
pub confidence: f32, // 提取置信度 0.0-1.0
|
||||
pub source_session: SessionId,
|
||||
}
|
||||
|
||||
/// 检索配置
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RetrievalConfig {
|
||||
pub max_tokens: usize, // 总 Token 预算,默认 500
|
||||
pub preference_budget: usize, // 偏好 Token 预算,默认 200
|
||||
pub knowledge_budget: usize, // 知识 Token 预算,默认 200
|
||||
pub experience_budget: usize, // 经验 Token 预算,默认 100
|
||||
pub min_similarity: f32, // 最小相似度阈值,默认 0.7
|
||||
pub max_results: usize, // 最大返回数量,默认 10
|
||||
}
|
||||
|
||||
impl Default for RetrievalConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
max_tokens: 500,
|
||||
preference_budget: 200,
|
||||
knowledge_budget: 200,
|
||||
experience_budget: 100,
|
||||
min_similarity: 0.7,
|
||||
max_results: 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 检索结果
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct RetrievalResult {
|
||||
pub preferences: Vec<MemoryEntry>,
|
||||
pub knowledge: Vec<MemoryEntry>,
|
||||
pub experience: Vec<MemoryEntry>,
|
||||
pub total_tokens: usize,
|
||||
}
|
||||
|
||||
/// 提取配置
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExtractionConfig {
|
||||
pub extract_preferences: bool, // 是否提取偏好,默认 true
|
||||
pub extract_knowledge: bool, // 是否提取知识,默认 true
|
||||
pub extract_experience: bool, // 是否提取经验,默认 true
|
||||
pub min_confidence: f32, // 最小置信度阈值,默认 0.6
|
||||
}
|
||||
|
||||
impl Default for ExtractionConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
extract_preferences: true,
|
||||
extract_knowledge: true,
|
||||
extract_experience: true,
|
||||
min_confidence: 0.6,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 MemoryExtractor 接口
|
||||
|
||||
```rust
|
||||
// extractor.rs
|
||||
|
||||
/// 记忆提取器 - 从对话中提取有价值的记忆
|
||||
pub struct MemoryExtractor {
|
||||
llm_driver: Arc<dyn LlmDriver>,
|
||||
}
|
||||
|
||||
impl MemoryExtractor {
|
||||
pub fn new(llm_driver: Arc<dyn LlmDriver>) -> Self {
|
||||
Self { llm_driver }
|
||||
}
|
||||
|
||||
/// 从对话中提取记忆
|
||||
pub async fn extract(
|
||||
&self,
|
||||
messages: &[Message],
|
||||
config: &ExtractionConfig,
|
||||
) -> Result<Vec<ExtractedMemory>> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
if config.extract_preferences {
|
||||
let prefs = self.extract_preferences(messages).await?;
|
||||
results.extend(prefs);
|
||||
}
|
||||
|
||||
if config.extract_knowledge {
|
||||
let knowledge = self.extract_knowledge(messages).await?;
|
||||
results.extend(knowledge);
|
||||
}
|
||||
|
||||
if config.extract_experience {
|
||||
let experience = self.extract_experience(messages).await?;
|
||||
results.extend(experience);
|
||||
}
|
||||
|
||||
// 过滤低置信度结果
|
||||
results.retain(|m| m.confidence >= config.min_confidence);
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
/// 提取偏好
|
||||
async fn extract_preferences(
|
||||
&self,
|
||||
messages: &[Message],
|
||||
) -> Result<Vec<ExtractedMemory>> {
|
||||
// 使用 LLM 分析对话,提取用户偏好
|
||||
// 例如:用户喜欢简洁的回复、用户偏好中文等
|
||||
// ...
|
||||
}
|
||||
|
||||
/// 提取知识
|
||||
async fn extract_knowledge(
|
||||
&self,
|
||||
messages: &[Message],
|
||||
) -> Result<Vec<ExtractedMemory>> {
|
||||
// 使用 LLM 分析对话,提取有价值的事实和知识
|
||||
// 例如:用户是程序员、用户在做一个 Rust 项目等
|
||||
// ...
|
||||
}
|
||||
|
||||
/// 提取经验
|
||||
async fn extract_experience(
|
||||
&self,
|
||||
messages: &[Message],
|
||||
) -> Result<Vec<ExtractedMemory>> {
|
||||
// 分析对话中的技能/工具使用,提取经验教训
|
||||
// 例如:某个技能执行失败、某个工具效果很好等
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 MemoryRetriever 接口
|
||||
|
||||
```rust
|
||||
// retriever.rs
|
||||
|
||||
/// 记忆检索器 - 从 OpenViking 检索相关记忆
|
||||
pub struct MemoryRetriever {
|
||||
viking: Arc<VikingAdapter>,
|
||||
}
|
||||
|
||||
impl MemoryRetriever {
|
||||
pub fn new(viking: Arc<VikingAdapter>) -> Self {
|
||||
Self { viking }
|
||||
}
|
||||
|
||||
/// 检索与当前输入相关的记忆
|
||||
pub async fn retrieve(
|
||||
&self,
|
||||
agent_id: &AgentId,
|
||||
query: &str,
|
||||
config: &RetrievalConfig,
|
||||
) -> Result<RetrievalResult> {
|
||||
// 1. 检索偏好
|
||||
let preferences = self.retrieve_by_type(
|
||||
agent_id,
|
||||
MemoryType::Preference,
|
||||
query,
|
||||
config.max_results,
|
||||
).await?;
|
||||
|
||||
// 2. 检索知识
|
||||
let knowledge = self.retrieve_by_type(
|
||||
agent_id,
|
||||
MemoryType::Knowledge,
|
||||
query,
|
||||
config.max_results,
|
||||
).await?;
|
||||
|
||||
// 3. 检索经验
|
||||
let experience = self.retrieve_by_type(
|
||||
agent_id,
|
||||
MemoryType::Experience,
|
||||
query,
|
||||
config.max_results / 2,
|
||||
).await?;
|
||||
|
||||
// 4. 计算 Token 使用
|
||||
let total_tokens = self.estimate_tokens(&preferences, &knowledge, &experience);
|
||||
|
||||
Ok(RetrievalResult {
|
||||
preferences,
|
||||
knowledge,
|
||||
experience,
|
||||
total_tokens,
|
||||
})
|
||||
}
|
||||
|
||||
/// 按类型检索
|
||||
async fn retrieve_by_type(
|
||||
&self,
|
||||
agent_id: &AgentId,
|
||||
memory_type: MemoryType,
|
||||
query: &str,
|
||||
limit: usize,
|
||||
) -> Result<Vec<MemoryEntry>> {
|
||||
let scope = format!("agent://{}/{}", agent_id, memory_type_to_scope(&memory_type));
|
||||
|
||||
let results = self.viking.find(query, FindOptions {
|
||||
scope: Some(scope),
|
||||
limit: Some(limit),
|
||||
level: Some("L1"), // 使用摘要级别
|
||||
}).await?;
|
||||
|
||||
// 转换为 MemoryEntry
|
||||
// ...
|
||||
}
|
||||
|
||||
fn estimate_tokens(
|
||||
&self,
|
||||
preferences: &[MemoryEntry],
|
||||
knowledge: &[MemoryEntry],
|
||||
experience: &[MemoryEntry],
|
||||
) -> usize {
|
||||
// 简单估算:约 4 字符 = 1 token
|
||||
let total_chars: usize = preferences.iter()
|
||||
.chain(knowledge.iter())
|
||||
.chain(experience.iter())
|
||||
.map(|m| m.content.len())
|
||||
.sum();
|
||||
total_chars / 4
|
||||
}
|
||||
}
|
||||
|
||||
fn memory_type_to_scope(ty: &MemoryType) -> &'static str {
|
||||
match ty {
|
||||
MemoryType::Preference => "preferences",
|
||||
MemoryType::Knowledge => "knowledge",
|
||||
MemoryType::Experience => "experience",
|
||||
MemoryType::Session => "sessions",
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5 PromptInjector 接口
|
||||
|
||||
```rust
|
||||
// injector.rs
|
||||
|
||||
/// Prompt 注入器 - 将记忆动态注入 system_prompt
|
||||
pub struct PromptInjector {
|
||||
config: RetrievalConfig,
|
||||
}
|
||||
|
||||
impl PromptInjector {
|
||||
pub fn new(config: RetrievalConfig) -> Self {
|
||||
Self { config }
|
||||
}
|
||||
|
||||
/// 构建增强的 system_prompt
|
||||
pub fn inject(
|
||||
&self,
|
||||
base_prompt: &str,
|
||||
memories: &RetrievalResult,
|
||||
) -> String {
|
||||
let mut result = base_prompt.to_string();
|
||||
|
||||
// 注入偏好
|
||||
if !memories.preferences.is_empty() {
|
||||
let prefs_section = self.format_preferences(
|
||||
&memories.preferences,
|
||||
self.config.preference_budget,
|
||||
);
|
||||
result.push_str("\n\n## 用户偏好\n");
|
||||
result.push_str(&prefs_section);
|
||||
}
|
||||
|
||||
// 注入知识
|
||||
if !memories.knowledge.is_empty() {
|
||||
let knowledge_section = self.format_knowledge(
|
||||
&memories.knowledge,
|
||||
self.config.knowledge_budget,
|
||||
);
|
||||
result.push_str("\n\n## 相关知识\n");
|
||||
result.push_str(&knowledge_section);
|
||||
}
|
||||
|
||||
// 注入经验
|
||||
if !memories.experience.is_empty() {
|
||||
let exp_section = self.format_experience(
|
||||
&memories.experience,
|
||||
self.config.experience_budget,
|
||||
);
|
||||
result.push_str("\n\n## 经验参考\n");
|
||||
result.push_str(&exp_section);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn format_preferences(&self, entries: &[MemoryEntry], budget: usize) -> String {
|
||||
let mut result = String::new();
|
||||
let mut used = 0;
|
||||
|
||||
for entry in entries.iter().take(5) { // 最多 5 条偏好
|
||||
let line = format!("- {}\n", entry.content);
|
||||
let line_tokens = line.len() / 4;
|
||||
|
||||
if used + line_tokens > budget {
|
||||
break;
|
||||
}
|
||||
|
||||
result.push_str(&line);
|
||||
used += line_tokens;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn format_knowledge(&self, entries: &[MemoryEntry], budget: usize) -> String {
|
||||
// 类似 format_preferences
|
||||
// ...
|
||||
}
|
||||
|
||||
fn format_experience(&self, entries: &[MemoryEntry], budget: usize) -> String {
|
||||
// 类似 format_preferences
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.6 AgentLoop 集成
|
||||
|
||||
修改 `crates/zclaw-runtime/src/loop_runner.rs`:
|
||||
|
||||
```rust
|
||||
pub struct AgentLoop {
|
||||
agent_id: AgentId,
|
||||
driver: Arc<dyn LlmDriver>,
|
||||
tools: ToolRegistry,
|
||||
memory: Arc<MemoryStore>,
|
||||
model: String,
|
||||
system_prompt: Option<String>,
|
||||
max_tokens: u32,
|
||||
temperature: f32,
|
||||
skill_executor: Option<Arc<dyn SkillExecutor>>,
|
||||
|
||||
// 新增:成长系统
|
||||
memory_retriever: Option<Arc<MemoryRetriever>>,
|
||||
memory_extractor: Option<Arc<MemoryExtractor>>,
|
||||
prompt_injector: Option<PromptInjector>,
|
||||
growth_enabled: bool,
|
||||
}
|
||||
|
||||
impl AgentLoop {
|
||||
pub async fn run(&self, session_id: SessionId, input: String) -> Result<AgentLoopResult> {
|
||||
// 1. 检索相关记忆 (新增)
|
||||
let memories = if self.growth_enabled {
|
||||
if let Some(retriever) = &self.memory_retriever {
|
||||
retriever.retrieve(
|
||||
&self.agent_id,
|
||||
&input,
|
||||
&RetrievalConfig::default(),
|
||||
).await.unwrap_or_default()
|
||||
} else {
|
||||
RetrievalResult::default()
|
||||
}
|
||||
} else {
|
||||
RetrievalResult::default()
|
||||
};
|
||||
|
||||
// 2. 构建增强的 system_prompt (修改)
|
||||
let enhanced_prompt = if self.growth_enabled {
|
||||
if let Some(injector) = &self.prompt_injector {
|
||||
injector.inject(
|
||||
self.system_prompt.as_deref().unwrap_or(""),
|
||||
&memories,
|
||||
)
|
||||
} else {
|
||||
self.system_prompt.clone().unwrap_or_default()
|
||||
}
|
||||
} else {
|
||||
self.system_prompt.clone().unwrap_or_default()
|
||||
};
|
||||
|
||||
// 3. 添加用户消息
|
||||
let user_message = Message::user(input);
|
||||
self.memory.append_message(&session_id, &user_message).await?;
|
||||
|
||||
// 4. 获取完整上下文
|
||||
let mut messages = self.memory.get_messages(&session_id).await?;
|
||||
|
||||
// 5. 执行 LLM 循环 (使用增强的 prompt)
|
||||
let mut iterations = 0;
|
||||
let max_iterations = 10;
|
||||
|
||||
loop {
|
||||
// ... 现有的 LLM 循环逻辑
|
||||
// 使用 enhanced_prompt 作为 system message
|
||||
}
|
||||
|
||||
// 6. 对话结束后提取记忆 (新增)
|
||||
if self.growth_enabled {
|
||||
if let Some(extractor) = &self.memory_extractor {
|
||||
let final_messages = self.memory.get_messages(&session_id).await?;
|
||||
let extracted = extractor.extract(
|
||||
&final_messages,
|
||||
&ExtractionConfig::default(),
|
||||
).await?;
|
||||
|
||||
// 写入 OpenViking
|
||||
for memory in extracted {
|
||||
// 通过 VikingAdapter 写入
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、前端变化
|
||||
|
||||
### 4.1 新增组件
|
||||
|
||||
```typescript
|
||||
// desktop/src/components/GrowthPanel.tsx
|
||||
|
||||
interface GrowthPanelProps {
|
||||
agentId: string;
|
||||
}
|
||||
|
||||
export function GrowthPanel({ agentId }: GrowthPanelProps) {
|
||||
// 功能:
|
||||
// - 显示 Agent 成长指标
|
||||
// - 手动触发学习
|
||||
// - 查看/编辑记忆
|
||||
// - 配置学习参数
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Store 扩展
|
||||
|
||||
```typescript
|
||||
// desktop/src/store/agentStore.ts
|
||||
|
||||
interface AgentState {
|
||||
// ... 现有字段
|
||||
|
||||
// 新增:成长相关
|
||||
growthEnabled: boolean;
|
||||
memoryStats: {
|
||||
totalMemories: number;
|
||||
preferences: number;
|
||||
knowledge: number;
|
||||
experience: number;
|
||||
lastLearningTime: string | null;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Tauri Commands
|
||||
|
||||
```rust
|
||||
// desktop/src-tauri/src/growth_commands.rs
|
||||
|
||||
#[tauri::command]
|
||||
async fn get_memory_stats(agent_id: String) -> Result<MemoryStats, String>;
|
||||
|
||||
#[tauri::command]
|
||||
async fn trigger_learning(agent_id: String, session_id: String) -> Result<Vec<ExtractedMemory>, String>;
|
||||
|
||||
#[tauri::command]
|
||||
async fn get_memories(agent_id: String, memory_type: Option<String>) -> Result<Vec<MemoryEntry>, String>;
|
||||
|
||||
#[tauri::command]
|
||||
async fn delete_memory(agent_id: String, uri: String) -> Result<(), String>;
|
||||
|
||||
#[tauri::command]
|
||||
async fn update_memory(agent_id: String, uri: String, content: String) -> Result<(), String>;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、执行计划
|
||||
|
||||
### 5.1 Phase 1: Crate 骨架 (1-2 天)
|
||||
|
||||
- [ ] 创建 `crates/zclaw-growth/` 目录结构
|
||||
- [ ] 定义 `types.rs` 核心类型
|
||||
- [ ] 设置 `Cargo.toml` 依赖
|
||||
|
||||
### 5.2 Phase 2: 检索系统 (2-3 天)
|
||||
|
||||
- [ ] 实现 `VikingAdapter` 封装
|
||||
- [ ] 实现 `MemoryRetriever`
|
||||
- [ ] 单元测试
|
||||
|
||||
### 5.3 Phase 3: 注入 + 集成 (2-3 天)
|
||||
|
||||
- [ ] 实现 `PromptInjector`
|
||||
- [ ] 修改 `AgentLoop` 集成点
|
||||
- [ ] 集成测试
|
||||
|
||||
### 5.4 Phase 4: 提取系统 (3-4 天)
|
||||
|
||||
- [ ] 实现 `MemoryExtractor`
|
||||
- [ ] 设计 LLM prompt 模板
|
||||
- [ ] 测试提取质量
|
||||
|
||||
### 5.5 Phase 5: 前端 UI (2-3 天)
|
||||
|
||||
- [ ] 实现 `GrowthPanel` 组件
|
||||
- [ ] 扩展 Agent Store
|
||||
- [ ] 添加 Tauri Commands
|
||||
|
||||
### 5.6 Phase 6: 测试 + 优化 (2-3 天)
|
||||
|
||||
- [ ] 端到端测试
|
||||
- [ ] 性能优化
|
||||
- [ ] 文档完善
|
||||
|
||||
**总计**: 约 12-18 天
|
||||
|
||||
---
|
||||
|
||||
## 六、关键文件路径
|
||||
|
||||
### 核心类型
|
||||
- `crates/zclaw-types/src/agent.rs` - AgentConfig
|
||||
- `crates/zclaw-types/src/message.rs` - Message
|
||||
- `crates/zclaw-types/src/id.rs` - AgentId, SessionId
|
||||
|
||||
### 存储层
|
||||
- `crates/zclaw-memory/src/store.rs` - MemoryStore
|
||||
- `crates/zclaw-memory/src/schema.rs` - SQLite Schema
|
||||
|
||||
### 运行时
|
||||
- `crates/zclaw-runtime/src/loop_runner.rs` - AgentLoop
|
||||
|
||||
### OpenViking 集成
|
||||
- `desktop/src/lib/viking-client.ts` - 前端客户端
|
||||
- `desktop/src-tauri/src/viking_commands.rs` - Tauri 命令
|
||||
- `docs/features/03-context-database/00-openviking-integration.md` - 文档
|
||||
|
||||
### 前端学习系统(将被后端化)
|
||||
- `desktop/src/lib/active-learning.ts`
|
||||
- `desktop/src/lib/memory-extractor.ts`
|
||||
- `desktop/src/store/activeLearningStore.ts`
|
||||
|
||||
---
|
||||
|
||||
## 七、风险与缓解
|
||||
|
||||
| 风险 | 影响 | 缓解措施 |
|
||||
|------|------|---------|
|
||||
| OpenViking 不可用 | 高 | 实现 LocalStorageAdapter 降级方案 |
|
||||
| 记忆提取质量低 | 中 | 可配置的置信度阈值 + 人工审核 |
|
||||
| Token 预算超限 | 中 | 严格的 Token 控制和截断 |
|
||||
| 前端学习数据丢失 | 高 | 提供迁移脚本导入旧数据 |
|
||||
|
||||
---
|
||||
|
||||
## 八、新会话执行指南
|
||||
|
||||
在新会话中执行此方案时,请:
|
||||
|
||||
1. **阅读本文档**:`docs/superpowers/specs/2026-03-26-agent-growth-design.md`
|
||||
2. **参考计划文件**:`plans/crispy-spinning-reef.md`(包含更多分析细节)
|
||||
3. **从 Phase 1 开始**:创建 zclaw-growth crate 骨架
|
||||
4. **遵循设计**:严格按照本文档的接口定义实现
|
||||
5. **保持沟通**:如有疑问,与用户确认后再修改设计
|
||||
Reference in New Issue
Block a user