Files
zclaw_openfang/docs/plans/2026-03-16-openviking-local-deployment.md
iven 0d4fa96b82
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
refactor: 统一项目名称从OpenFang到ZCLAW
重构所有代码和文档中的项目名称,将OpenFang统一更新为ZCLAW。包括:
- 配置文件中的项目名称
- 代码注释和文档引用
- 环境变量和路径
- 类型定义和接口名称
- 测试用例和模拟数据

同时优化部分代码结构,移除未使用的模块,并更新相关依赖项。
2026-03-27 07:36:03 +08:00

427 lines
16 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.

# ZCLAW OpenViking 深度集成方案
## Context
**背景**ZCLAW 项目基于 ZCLAW 定制开发,目标是结合 ZCLAW、NanoClaw、ZeroClaw 等系统的优点。当前 Agent 智能层已超前完成Phase 1-3 完成, Phase 4 部分完成),但 OpenViking 集成依赖外部 Python 服务,用户安装繁琐。
**问题**:如何深度集成 OpenViking避免 Python 依赖,实现无感安装体验?
**目标**:以 OpenViking Rust CLI (`ov`) 为核心,通过 Tauri sidecar 集成让记忆系统成为原生组件。CLI 缺失的功能再自行开发补充。
---
## 关键决策总结
基于头脑风暴讨论,确定以下技术决策:
| 决策点 | 选择 | 理由 |
|--------|------|------|
| **集成方式** | OpenViking Rust CLI + 自建补充 | 利用成熟工具,减少开发量,缺失功能自行补充 |
| **记忆存储** | CLI 内置 SQLite + sqlite-vec | CLI 已实现,无需重复开发 |
| **Embedding 模型** | doubao-embedding-vision | 中文效果优秀,火山引擎生态 |
| **记忆提取** | LLM 提取 | 对话结束后调用 LLM 分析并提取 |
| **部署方式** | Tauri Sidecar | CLI 作为可执行文件随应用分发 |
---
## Architecture Design
```
┌─────────────────────────────────────────────────────────────────┐
│ ZCLAW Desktop (Tauri + React) │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ React UI Layer │ │
│ │ ┌──────────┐ ┌──────────┐ ┌───────────┐ ┌──────────────┐ │ │
│ │ │ ChatArea │ │MemoryPanel│ │SwarmPanel│ │ SkillMarket │ │ │
│ │ └────┬─────┘ └────┬─────┘ └─────┬─────┘└──────┬───────┘ │ │
│ └───────────┼────────────┼─────────────┼───────────────┼─────┘ │
│ ▼ ▼ ▼ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ TypeScript Integration Layer │ │
│ │ ┌──────────────────────────────────────────────────────┐ │ │
│ │ │ VikingAdapter (已存在,保持兼容) │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────▼─────────────────────────────────┐ │
│ │ Tauri Command Layer (Rust) │ │
│ │ ┌────────────────────────────────────────────────────────┐│ │
│ │ │ SidecarWrapper: 调用 `ov` CLI ││ │
│ │ │ - invoke('viking_add', ...) → ov add ││ │
│ │ │ - invoke('viking_find', ...) → ov find ││ │
│ │ │ - invoke('viking_grep', ...) → ov grep ││ │
│ │ └────────────────────────────────────────────────────────┘│ │
│ │ ┌────────────────────────────────────────────────────────┐│ │
│ │ │ SupplementalModule: CLI 缺失功能补充 ││ │
│ │ │ - SessionExtractor (LLM 记忆提取) ││ │
│ │ │ - EmbeddingService (doubao API 封装) ││ │
│ │ │ - ContextBuilder (L0/L1/L2 分层加载) ││ │
│ │ └────────────────────────────────────────────────────────┘│ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────▼─────────────────────────────────┐ │
│ │ Storage Layer │ │
│ │ ┌──────────────────┐ ┌──────────────────────────────────┐ │ │
│ │ │ OpenViking CLI │ │ AppData (配置) │ │ │
│ │ │ ~/.viking/ │ │ ~/.zclaw/config.toml │ │ │
│ │ │ - SQLite + vec │ │ │ │ │
│ │ │ - 向量索引 │ │ │ │ │
│ │ └──────────────────┘ └──────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```
---
## OpenViking Rust CLI 能力分析
### CLI 已实现功能 (直接使用)
| 命令 | 功能 | 状态 |
|------|------|------|
| `ov add <uri>` | 添加资源到索引 | ✅ 可用 |
| `ov find <query>` | 语义搜索 | ✅ 可用 |
| `ov grep <pattern>` | 正则搜索 | ✅ 可用 |
| `ov ls <path>` | 列出资源 | ✅ 可用 |
| `ov tree <path>` | 目录树 | ✅ 可用 |
| `ov chat` | 交互式对话 | ✅ 可用 |
### CLI 缺失功能 (需要自建)
| 功能 | 说明 | 优先级 |
|------|------|--------|
| Session Extraction | 对话后 LLM 提取记忆 | 高 |
| L0/L1/L2 分层加载 | Token 优化上下文构建 | 高 |
| Embedding 批量生成 | doubao API 封装 | 中 |
| 记忆老化/清理 | 低重要性记忆自动清理 | 低 |
| 多 Agent 隔离 | agent_id 维度隔离 | 中 |
---
## Implementation Phases
### Phase 1: Sidecar 集成 (Week 1)
**Goal**: 将 OpenViking CLI 集成为 Tauri sidecar
#### Steps
1. **下载并嵌入 CLI**
```bash
# 将 ov 二进制放入 src-tauri/binaries/
# Windows: ov-x86_64-pc-windows-msvc.exe
# macOS: ov-x86_64-apple-darwin
# Linux: ov-x86_64-unknown-linux-gnu
```
2. **配置 tauri.conf.json**
```json
{
"tauri": {
"bundle": {
"externalBin": ["binaries/ov"]
}
}
}
```
3. **创建 Tauri Commands**
```rust
// src-tauri/src/viking_commands.rs
#[tauri::command]
pub async fn viking_add(uri: String, content: String) -> Result<String, String> {
let sidecar = Command::new_sidecar("ov")
.map_err(|e| e.to_string())?;
let output = sidecar
.args(["add", &uri])
.output()
.await
.map_err(|e| e.to_string())?;
Ok(String::from_utf8_lossy(&output.stdout).to_string())
}
#[tauri::command]
pub async fn viking_find(query: String, limit: usize) -> Result<Vec<FindResult>, String> {
let sidecar = Command::new_sidecar("ov")
.map_err(|e| e.to_string())?;
let output = sidecar
.args(["find", "--json", &query, "--limit", &limit.to_string()])
.output()
.await
.map_err(|e| e.to_string())?;
serde_json::from_slice(&output.stdout)
.map_err(|e| e.to_string())
}
```
#### Files to Create
| File | Purpose |
|------|---------|
| `src-tauri/src/viking_commands.rs` | Tauri 命令封装 |
| `src-tauri/binaries/ov-*` | Sidecar 二进制 |
#### Files to Modify
| File | Changes |
|------|---------|
| `src-tauri/src/lib.rs` | 注册 viking 模块 |
| `src-tauri/tauri.conf.json` | 添加 externalBin 配置 |
| `desktop/src/lib/viking-adapter.ts` | 添加 `invoke()` 调用 |
### Phase 2: TypeScript 适配层 (Week 1-2)
**Goal**: 更新 VikingAdapter 使用 Tauri 命令
#### Key Changes
```typescript
// desktop/src/lib/viking-adapter.ts
import { invoke } from '@tauri-apps/api/tauri';
export class VikingAdapter {
private mode: 'sidecar' | 'remote' = 'sidecar';
async addResource(uri: string, content: string): Promise<void> {
if (this.mode === 'sidecar') {
await invoke('viking_add', { uri, content });
} else {
// Remote fallback
await this.httpClient.addResource(uri, content);
}
}
async find(query: string, options?: FindOptions): Promise<FindResult[]> {
if (this.mode === 'sidecar') {
return await invoke('viking_find', {
query,
limit: options?.limit || 10
});
} else {
return this.httpClient.find(query, options);
}
}
}
```
### Phase 3: 补充模块开发 (Week 2-3)
**Goal**: 实现 CLI 缺失的功能
#### 3.1 Session Extractor
```rust
// src-tauri/src/memory/extractor.rs
pub struct SessionExtractor {
llm_client: LlmClient,
}
impl SessionExtractor {
/// Extract memories from conversation
pub async fn extract(
&self,
messages: Vec<ChatMessage>,
agent_id: &str,
) -> Result<Vec<ExtractedMemory>, Error> {
let prompt = self.build_extraction_prompt(&messages);
let response = self.llm_client.complete(&prompt).await?;
self.parse_extraction(&response, agent_id)
}
}
```
#### 3.2 Context Builder (L0/L1/L2)
```rust
// src-tauri/src/memory/context_builder.rs
pub struct ContextBuilder {
viking: VikingSidecar,
}
impl ContextBuilder {
/// Build layered context for token efficiency
pub async fn build_context(
&self,
query: &str,
agent_id: &str,
max_tokens: usize,
) -> Result<EnhancedContext, Error> {
// L0: Quick scan - top 50 by similarity
let l0_results = self.viking.find(query, 50).await?;
// L1: Load overview for top 10
let l1_items = self.load_overviews(&l0_results[..10]).await?;
// L2: Full content for top 3
let l2_items = self.load_full_content(&l0_results[..3]).await?;
Ok(EnhancedContext { l1_items, l2_items })
}
}
```
#### Files to Create
| File | Purpose |
|------|---------|
| `src-tauri/src/memory/mod.rs` | 模块入口 |
| `src-tauri/src/memory/extractor.rs` | LLM 记忆提取 |
| `src-tauri/src/memory/context_builder.rs` | L0/L1/L2 分层加载 |
| `src-tauri/src/llm/client.rs` | doubao API 客户端 |
### Phase 4: UI 集成 (Week 3-4)
**Goal**: 完善记忆面板 UI
#### Files to Modify
| File | Changes |
|------|---------|
| `desktop/src/components/MemoryPanel.tsx` | 集成 sidecar 模式 |
| `desktop/src/components/RetrievalTrace.tsx` | 显示 L0/L1/L2 检索轨迹 |
| `desktop/src/store/chatStore.ts` | 使用新的 VikingAdapter |
---
## Critical Files
### Existing Files (Reuse)
| File | Path | Purpose |
|------|------|---------|
| VikingAdapter | `desktop/src/lib/viking-adapter.ts` | 保持兼容,添加 sidecar 模式 |
| VikingHttpClient | `desktop/src/lib/viking-client.ts` | 远程模式时使用 |
| AgentMemory | `desktop/src/lib/agent-memory.ts` | 现有记忆接口 |
| MemoryPanel | `desktop/src/components/MemoryPanel.tsx` | 现有 UI |
### New Files (Create)
| File | Path | Purpose |
|------|------|---------|
| VikingCommands | `src-tauri/src/viking_commands.rs` | Sidecar 命令封装 |
| SessionExtractor | `src-tauri/src/memory/extractor.rs` | LLM 提取 (CLI 缺失) |
| ContextBuilder | `src-tauri/src/memory/context_builder.rs` | 分层加载 (CLI 缺失) |
| LlmClient | `src-tauri/src/llm/client.rs` | doubao API 封装 |
---
## Dependencies to Add
```toml
# src-tauri/Cargo.toml
[dependencies]
tauri = { version = "2", features = ["process-command-api"] }
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.11" } # For LLM API calls
serde = { version = "1", features = ["derive"] }
serde_json = "1"
```
---
## Verification Plan
### Unit Tests
```bash
# Run Rust tests
cargo test --manifest-path=src-tauri/Cargo.toml
# Run TypeScript tests
pnpm vitest run tests/desktop/memory*.test.ts
```
### Integration Tests
1. **Sidecar 启动**: CLI 能正确作为 sidecar 运行
2. **Memory Save/Load**: 通过 Tauri 命令保存和检索记忆
3. **Vector Search**: 语义搜索返回相关结果
4. **Session Extraction**: 对话结束后正确提取记忆
5. **Context Building**: L0/L1/L2 分层加载正常工作
6. **UI Integration**: MemoryPanel 正确显示数据
### Manual Testing
1. 启动应用,验证 CLI sidecar 自动启动
2. 发送消息,检查记忆是否保存
3. 发送新消息,验证 Agent 能回忆之前的信息
4. 测试记忆搜索功能
5. 验证无 Python 依赖
---
## Migration Path
### From Current State
```
Current: Target:
viking-client.ts ─────────────► Tauri Command
(HTTP to Python server) (Sidecar wrapper)
viking-adapter.ts ──────────────► Dual mode: sidecar + remote fallback
```
### Data Compatibility
- OpenViking CLI 使用 `~/.viking/` 目录存储数据
- 与 Python Server 版本数据格式兼容
- 可无缝迁移现有数据
---
## Success Criteria
- [ ] OpenViking CLI 作为 sidecar 正确运行
- [ ] Tauri 命令可调用 CLI 功能
- [ ] 记忆保存和检索功能正常
- [ ] 语义搜索返回相关结果
- [ ] LLM 记忆提取正常工作 (自建模块)
- [ ] L0/L1/L2 分层加载正常工作 (自建模块)
- [ ] MemoryPanel UI 正确显示
- [ ] 所有测试通过
- [ ] **无需 Python 依赖**
---
## Risks and Mitigations
| Risk | Mitigation |
|------|------------|
| CLI 二进制兼容性 | 提供多平台预编译版本 |
| CLI 功能不足 | 自建补充模块填补空白 |
| Embedding API 限流 | 实现本地缓存 |
| LLM 提取失败 | 保留规则提取作为 fallback |
| Sidecar 启动失败 | 优雅降级到远程模式 |
---
## Timeline
| Week | Phase | Deliverables |
|------|-------|--------------|
| 1 | Sidecar 集成 | CLI 嵌入 + Tauri 命令 + TypeScript 适配 |
| 2 | 补充模块 | SessionExtractor + ContextBuilder |
| 3 | LLM 集成 | doubao API 客户端 + 提取逻辑 |
| 4 | UI 集成 | MemoryPanel + RetrievalTrace |
| 5 | 测试完善 | 集成测试 + 文档 |
---
## 开发策略总结
1. **Phase 1**: 直接集成 OpenViking Rust CLI 作为 sidecar
2. **Phase 2**: 检测 CLI 功能覆盖度
3. **Phase 3**: 自行开发 CLI 缺失的功能 (Session Extraction, Context Builder)
4. **Phase 4**: UI 完善和测试
**核心原则**: 最大化利用现有成熟工具,最小化自建代码量,只在必要时补充缺失功能。