- feature-checklist: 新增 Admin V2 章节(12项全通过),Speech/Twitter 状态提升, Hands 9/11 可用,安全备注更新 - roadmap: 标记 S1/S3 审批/Hand 为已完成,更新 crate 数量(10), 新增审计/依赖/清理已完成项 - technical-reference: 更新日期至 03-30,crate 数量 10
902 lines
28 KiB
Markdown
902 lines
28 KiB
Markdown
# ZCLAW Kernel 技术参考文档
|
||
|
||
> **文档版本**: v2.2
|
||
> **更新日期**: 2026-03-30
|
||
> **目标**: 为 ZCLAW 内部 Kernel 架构提供技术参考
|
||
|
||
---
|
||
|
||
## 一、项目概述
|
||
|
||
### 1.1 基本信息
|
||
|
||
| 属性 | 值 |
|
||
|------|-----|
|
||
| **项目名称** | ZCLAW |
|
||
| **架构** | 10 个 Rust Crates 模块化设计 |
|
||
| **定位** | AI Agent 桌面客户端 |
|
||
| **许可** | MIT |
|
||
|
||
### 1.2 核心特性
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ ZCLAW 核心特性 │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 🚀 内部 Kernel 架构 │
|
||
│ ├── 无外部进程依赖 │
|
||
│ ├── 单一安装包可运行 │
|
||
│ └── 即时启动 │
|
||
│ │
|
||
│ 🤖 多 LLM Provider 支持 │
|
||
│ ├── Kimi Code (kimi) │
|
||
│ ├── 百炼/通义千问 (qwen) │
|
||
│ ├── DeepSeek (deepseek) │
|
||
│ ├── 智谱 GLM (zhipu) │
|
||
│ ├── OpenAI (openai) │
|
||
│ ├── Anthropic (anthropic) │
|
||
│ └── 本地模型 (local/ollama) │
|
||
│ │
|
||
│ 🔒 UI 配置 │
|
||
│ ├── 无需编辑配置文件 │
|
||
│ ├── "模型与 API"设置页面配置 │
|
||
│ └── 配置存储在 localStorage │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 二、Crate 架构
|
||
|
||
### 2.1 模块结构
|
||
|
||
```
|
||
ZCLAW/
|
||
├── crates/ # Rust Workspace
|
||
│ │
|
||
│ ├── zclaw-types/ # L1: 基础类型(无依赖)
|
||
│ │ ├── AgentId, SessionId, Message
|
||
│ │ ├── Capability, Tool, Event
|
||
│ │ ├── Config, Error
|
||
│ │ └── 共享 trait 定义
|
||
│ │
|
||
│ ├── zclaw-memory/ # L2: 存储层(依赖 types)
|
||
│ │ ├── KV Store(Agent 配置、状态)
|
||
│ │ ├── Session Manager(对话历史)
|
||
│ │ ├── Semantic Search(向量搜索)
|
||
│ │ └── SQLite 持久化
|
||
│ │
|
||
│ ├── zclaw-runtime/ # L3: 运行时(依赖types, memory)
|
||
│ │ ├── LLM Drivers(Anthropic, OpenAI, Gemini, Local)
|
||
│ │ ├── Tool Runner(23 个内置工具)
|
||
│ │ ├── Agent Loop(消息循环、流式处理)
|
||
│ │ ├── Loop Guard(防循环)
|
||
│ │ └── Session Compactor(上下文压缩)
|
||
│ │
|
||
│ ├── zclaw-kernel/ # L4: 核心协调(依赖所有下层)
|
||
│ │ ├── Agent Registry(注册、生命周期)
|
||
│ │ ├── Scheduler(配额、调度)
|
||
│ │ ├── Capability Manager(权限)
|
||
│ │ ├── Event Bus(事件发布)
|
||
│ │ ├── Workflow Engine(工作流)
|
||
│ │ ├── Trigger Engine(触发器)
|
||
│ │ └── Supervisor(健康监控)
|
||
│ │
|
||
│ ├── zclaw-skills/ # 技能系统
|
||
│ │ ├── Skill Loader(TOML/SKILL.md 解析)
|
||
│ │ ├── Skill Runner(Python/WASM/PromptOnly)
|
||
│ │ └── Bundled Skills(内置技能)
|
||
│ │
|
||
│ ├── zclaw-hands/ # Hands 自主能力
|
||
│ │ ├── Hand/Trigger trait 定义
|
||
│ │ ├── HandRegistry/TriggerRegistry 实现
|
||
│ │ ├── Browser Hand
|
||
│ │ ├── Collector Hand
|
||
│ │ ├── Researcher Hand
|
||
│ │ └── 其他 Hands
|
||
│ │
|
||
│ └── zclaw-protocols/ # 协议支持
|
||
│ ├── MCP Client/Server
|
||
│ └── A2A Protocol
|
||
│
|
||
├── desktop/
|
||
│ ├── src-tauri/ # Tauri 应用
|
||
│ │ ├── src/
|
||
│ │ │ ├── lib.rs # 主入口,Kernel 初始化
|
||
│ │ │ ├── kernel_commands.rs # Tauri 命令封装
|
||
│ │ │ └── state.rs # 应用状态
|
||
│ │ └── Cargo.toml # 依赖内部 crates
|
||
│ └── src/ # React 前端
|
||
│
|
||
└── Cargo.toml # Workspace 定义
|
||
```
|
||
|
||
### 2.2 依赖关系
|
||
|
||
```
|
||
zclaw-types (无依赖)
|
||
↑
|
||
zclaw-memory (→ types)
|
||
↑
|
||
zclaw-runtime (→ types, memory)
|
||
↑
|
||
zclaw-kernel (→ types, memory, runtime)
|
||
↑
|
||
desktop/src-tauri (→ kernel, skills, hands, channels, protocols)
|
||
```
|
||
|
||
---
|
||
|
||
## 三、zclaw-types
|
||
|
||
### 3.1 核心 ID 类型
|
||
|
||
```rust
|
||
pub struct AgentId(Uuid);
|
||
pub struct SessionId(Uuid);
|
||
pub struct ToolId(String);
|
||
```
|
||
|
||
### 3.2 消息类型
|
||
|
||
```rust
|
||
pub enum Message {
|
||
User { content: String },
|
||
Assistant { content: String, thinking: Option<String> },
|
||
ToolUse { tool: ToolId, input: Value },
|
||
ToolResult { tool: ToolId, output: Value, error: bool },
|
||
}
|
||
```
|
||
|
||
### 3.3 Agent 配置
|
||
|
||
```rust
|
||
pub struct AgentConfig {
|
||
pub id: AgentId,
|
||
pub name: String,
|
||
pub model: ModelConfig,
|
||
pub system_prompt: String,
|
||
pub capabilities: Vec<Capability>,
|
||
pub tools: Vec<ToolId>,
|
||
}
|
||
|
||
pub struct ModelConfig {
|
||
pub provider: String,
|
||
pub model: String,
|
||
pub api_key_env: Option<String>,
|
||
pub base_url: Option<String>,
|
||
}
|
||
```
|
||
|
||
### 3.4 统一错误类型
|
||
|
||
```rust
|
||
pub enum ZclawError {
|
||
NotFound(String),
|
||
PermissionDenied(String),
|
||
LlmError(String),
|
||
ToolError(String),
|
||
StorageError(String),
|
||
ConfigError(String),
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 四、zclaw-memory
|
||
|
||
### 4.1 MemoryStore
|
||
|
||
```rust
|
||
pub struct MemoryStore {
|
||
db: Arc<Mutex<Connection>>,
|
||
}
|
||
|
||
impl MemoryStore {
|
||
// Agent 配置持久化
|
||
pub async fn save_agent(&self, agent: &AgentConfig) -> Result<()>;
|
||
pub async fn load_agent(&self, id: &AgentId) -> Result<Option<AgentConfig>>;
|
||
pub async fn list_agents(&self) -> Result<Vec<AgentConfig>>;
|
||
|
||
// 会话管理
|
||
pub async fn create_session(&self, agent_id: &AgentId) -> Result<SessionId>;
|
||
pub async fn get_session(&self, id: &SessionId) -> Result<Option<Session>>;
|
||
pub async fn append_message(&self, session: &SessionId, msg: Message) -> Result<()>;
|
||
|
||
// KV 存储
|
||
pub async fn store(&self, agent: &AgentId, key: &str, value: &Value) -> Result<()>;
|
||
pub async fn recall(&self, agent: &AgentId, key: &str) -> Result<Option<Value>>;
|
||
|
||
// 语义搜索
|
||
pub async fn embed(&self, text: &str) -> Result<Vec<f32>>;
|
||
pub async fn search_similar(&self, query: &str, limit: usize) -> Result<Vec<MemoryEntry>>;
|
||
}
|
||
```
|
||
|
||
### 4.2 数据库 Schema
|
||
|
||
```sql
|
||
-- Agent 配置表
|
||
CREATE TABLE agents (
|
||
id TEXT PRIMARY KEY,
|
||
name TEXT NOT NULL,
|
||
config JSON NOT NULL,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
-- 会话表
|
||
CREATE TABLE sessions (
|
||
id TEXT PRIMARY KEY,
|
||
agent_id TEXT NOT NULL,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (agent_id) REFERENCES agents(id)
|
||
);
|
||
|
||
-- 消息表
|
||
CREATE TABLE messages (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
session_id TEXT NOT NULL,
|
||
role TEXT NOT NULL,
|
||
content TEXT NOT NULL,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
FOREIGN KEY (session_id) REFERENCES sessions(id)
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 五、zclaw-runtime
|
||
|
||
### 5.1 LLM Driver Trait
|
||
|
||
```rust
|
||
#[async_trait]
|
||
pub trait LlmDriver: Send + Sync {
|
||
async fn complete(&self, req: CompletionRequest) -> Result<CompletionResponse>;
|
||
async fn stream(&self, req: CompletionRequest) -> Result<mpsc::Receiver<StreamEvent>>;
|
||
}
|
||
```
|
||
|
||
### 5.2 Driver 实现
|
||
|
||
```rust
|
||
// Anthropic Claude
|
||
pub struct AnthropicDriver {
|
||
api_key: SecretString,
|
||
}
|
||
|
||
// OpenAI 兼容(支持 Kimi, Qwen, DeepSeek, Zhipu 等)
|
||
pub struct OpenAiDriver {
|
||
api_key: SecretString,
|
||
base_url: String,
|
||
}
|
||
|
||
impl OpenAiDriver {
|
||
pub fn with_base_url(api_key: SecretString, base_url: String) -> Self {
|
||
Self { api_key, base_url }
|
||
}
|
||
}
|
||
|
||
// Google Gemini
|
||
pub struct GeminiDriver {
|
||
api_key: SecretString,
|
||
}
|
||
|
||
// 本地模型(Ollama/LMStudio)
|
||
pub struct LocalDriver {
|
||
base_url: String,
|
||
}
|
||
```
|
||
|
||
### 5.3 Agent Loop
|
||
|
||
```rust
|
||
pub struct AgentLoop {
|
||
driver: Arc<dyn LlmDriver>,
|
||
tools: Vec<Tool>,
|
||
memory: Arc<MemoryStore>,
|
||
loop_guard: LoopGuard,
|
||
// 模型配置(2026-03-22 添加)
|
||
model: String,
|
||
system_prompt: Option<String>,
|
||
max_tokens: u32,
|
||
temperature: f32,
|
||
}
|
||
|
||
impl AgentLoop {
|
||
pub fn new(...) -> Self;
|
||
pub fn with_model(self, model: impl Into<String>) -> Self;
|
||
pub fn with_system_prompt(self, prompt: impl Into<String>) -> Self;
|
||
pub fn with_max_tokens(self, max_tokens: u32) -> Self;
|
||
pub fn with_temperature(self, temperature: f32) -> Self;
|
||
|
||
pub async fn run(&self, session: SessionId, input: String) -> Result<AgentLoopResult>;
|
||
pub async fn run_streaming(&self, session: SessionId, input: String)
|
||
-> Result<mpsc::Receiver<LoopEvent>>;
|
||
}
|
||
```
|
||
|
||
**重要**: `AgentLoop` 必须通过 builder 方法配置模型,否则将使用默认值。`run()` 方法会从 `CompletionResponse.content` 中提取 `ContentBlock::Text` 作为响应内容。
|
||
|
||
---
|
||
|
||
## 六、zclaw-kernel
|
||
|
||
### 6.1 Kernel 主结构
|
||
|
||
```rust
|
||
pub struct Kernel {
|
||
registry: AgentRegistry,
|
||
scheduler: Scheduler,
|
||
capabilities: CapabilityManager,
|
||
events: EventBus,
|
||
workflows: WorkflowEngine,
|
||
triggers: TriggerEngine,
|
||
supervisor: Supervisor,
|
||
memory: Arc<MemoryStore>,
|
||
config: KernelConfig,
|
||
}
|
||
```
|
||
|
||
### 6.2 Kernel 方法
|
||
|
||
```rust
|
||
impl Kernel {
|
||
/// 启动 Kernel
|
||
pub async fn boot(config: KernelConfig) -> Result<Self>;
|
||
|
||
/// 关闭 Kernel
|
||
pub async fn shutdown(self) -> Result<()>;
|
||
|
||
// Agent 生命周期
|
||
pub async fn spawn_agent(&self, config: AgentConfig) -> Result<AgentId>;
|
||
pub async fn kill_agent(&self, id: &AgentId) -> Result<()>;
|
||
pub fn list_agents(&self) -> Vec<AgentInfo>;
|
||
pub fn get_agent(&self, id: &AgentId) -> Option<AgentInfo>;
|
||
|
||
// 消息处理
|
||
pub async fn send_message(&self, agent: &AgentId, msg: String)
|
||
-> Result<MessageResponse>;
|
||
pub async fn send_message_stream(&self, agent: &AgentId, msg: String)
|
||
-> Result<mpsc::Receiver<StreamEvent>>;
|
||
}
|
||
|
||
// send_message 实现:从 AgentConfig 获取模型配置传递给 AgentLoop
|
||
// 优先级:agent_config.model > kernel_config.default_model
|
||
```
|
||
|
||
**消息处理流程**:
|
||
|
||
```
|
||
send_message(agent_id, message)
|
||
│
|
||
├── 获取 AgentConfig: registry.get(agent_id)
|
||
│
|
||
├── 确定模型:
|
||
│ if !agent_config.model.model.is_empty():
|
||
│ model = agent_config.model.model
|
||
│ else:
|
||
│ model = kernel_config.default_model
|
||
│
|
||
├── 创建 AgentLoop (使用 builder 模式):
|
||
│ AgentLoop::new(...)
|
||
│ .with_model(model)
|
||
│ .with_max_tokens(agent_config.max_tokens || kernel_config.max_tokens)
|
||
│ .with_temperature(agent_config.temperature || kernel_config.temperature)
|
||
│ .with_system_prompt(agent_config.system_prompt) // 可选
|
||
│
|
||
└── 运行: loop_runner.run(session_id, message)
|
||
│
|
||
├── 调用 LLM: driver.complete(request)
|
||
│
|
||
└── 提取响应: 从 ContentBlock::Text 获取内容
|
||
```
|
||
|
||
// 工作流
|
||
pub async fn run_workflow(&self, workflow_id: &str, input: Value) -> Result<Value>;
|
||
|
||
// 事件
|
||
pub fn subscribe(&self) -> broadcast::Receiver<Event>;
|
||
}
|
||
```
|
||
|
||
### 6.3 KernelConfig
|
||
|
||
```rust
|
||
pub struct KernelConfig {
|
||
// 数据库
|
||
pub database_url: String,
|
||
|
||
// 默认 Provider 和模型
|
||
pub default_provider: String,
|
||
pub default_model: String,
|
||
|
||
// API Keys(从 UI 传入)
|
||
pub anthropic_api_key: Option<String>,
|
||
pub openai_api_key: Option<String>,
|
||
pub gemini_api_key: Option<String>,
|
||
pub kimi_api_key: Option<String>,
|
||
pub qwen_api_key: Option<String>,
|
||
pub deepseek_api_key: Option<String>,
|
||
pub zhipu_api_key: Option<String>,
|
||
|
||
// Base URLs
|
||
pub kimi_base_url: String,
|
||
pub qwen_base_url: String,
|
||
pub deepseek_base_url: String,
|
||
pub zhipu_base_url: String,
|
||
pub local_base_url: Option<String>,
|
||
|
||
// 生成参数
|
||
pub max_tokens: u32,
|
||
pub temperature: f32,
|
||
}
|
||
```
|
||
|
||
### 6.4 create_driver 方法
|
||
|
||
```rust
|
||
impl KernelConfig {
|
||
pub fn create_driver(&self) -> Result<Arc<dyn LlmDriver>> {
|
||
match self.default_provider.as_str() {
|
||
"anthropic" => {
|
||
let key = self.anthropic_api_key.clone()
|
||
.ok_or_else(|| ZclawError::ConfigError("ANTHROPIC_API_KEY not set".into()))?;
|
||
Ok(Arc::new(AnthropicDriver::new(SecretString::new(key))))
|
||
}
|
||
"kimi" => {
|
||
let key = self.kimi_api_key.clone()
|
||
.ok_or_else(|| ZclawError::ConfigError("KIMI_API_KEY not set".into()))?;
|
||
Ok(Arc::new(OpenAiDriver::with_base_url(
|
||
SecretString::new(key),
|
||
self.kimi_base_url.clone(),
|
||
)))
|
||
}
|
||
"qwen" => {
|
||
let key = self.qwen_api_key.clone()
|
||
.ok_or_else(|| ZclawError::ConfigError("QWEN_API_KEY not set".into()))?;
|
||
Ok(Arc::new(OpenAiDriver::with_base_url(
|
||
SecretString::new(key),
|
||
self.qwen_base_url.clone(),
|
||
)))
|
||
}
|
||
"deepseek" => {
|
||
let key = self.deepseek_api_key.clone()
|
||
.ok_or_else(|| ZclawError::ConfigError("DEEPSEEK_API_KEY not set".into()))?;
|
||
Ok(Arc::new(OpenAiDriver::with_base_url(
|
||
SecretString::new(key),
|
||
self.deepseek_base_url.clone(),
|
||
)))
|
||
}
|
||
"zhipu" => {
|
||
let key = self.zhipu_api_key.clone()
|
||
.ok_or_else(|| ZclawError::ConfigError("ZHIPU_API_KEY not set".into()))?;
|
||
Ok(Arc::new(OpenAiDriver::with_base_url(
|
||
SecretString::new(key),
|
||
self.zhipu_base_url.clone(),
|
||
)))
|
||
}
|
||
"openai" => {
|
||
let key = self.openai_api_key.clone()
|
||
.ok_or_else(|| ZclawError::ConfigError("OPENAI_API_KEY not set".into()))?;
|
||
Ok(Arc::new(OpenAiDriver::new(SecretString::new(key))))
|
||
}
|
||
"gemini" => {
|
||
let key = self.gemini_api_key.clone()
|
||
.ok_or_else(|| ZclawError::ConfigError("GEMINI_API_KEY not set".into()))?;
|
||
Ok(Arc::new(GeminiDriver::new(SecretString::new(key))))
|
||
}
|
||
"local" | "ollama" => {
|
||
let base_url = self.local_base_url.clone()
|
||
.unwrap_or_else(|| "http://localhost:11434/v1".to_string());
|
||
Ok(Arc::new(LocalDriver::new(base_url)))
|
||
}
|
||
_ => Err(ZclawError::ConfigError(
|
||
format!("Unknown provider: {}", self.default_provider)
|
||
)),
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 6.5 自我进化系统
|
||
|
||
ZCLAW 内置自我进化能力,通过四个核心组件实现:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 自我进化数据流 │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ 对话 ──► 记忆存储 ──► 反思引擎 ──► 提案生成 ──► 用户审批 │
|
||
│ │ │
|
||
│ ▼ │
|
||
│ 心跳引擎 (定期检查) │
|
||
│ │ │
|
||
│ ▼ │
|
||
│ 人格改进 / 学习机会 / 任务积压 │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
**核心文件**:
|
||
|
||
| 组件 | 后端文件 | 前端文件 |
|
||
|------|----------|----------|
|
||
| 心跳引擎 | `intelligence/heartbeat.rs` | `intelligence-client.ts` |
|
||
| 反思引擎 | `intelligence/reflection.rs` | `intelligence-client.ts` |
|
||
| 身份管理 | `intelligence/identity.rs` | `intelligence-client.ts` |
|
||
| 记忆存储 | `memory/persistent.rs` | `intelligence-client.ts` |
|
||
|
||
**心跳检查函数**:
|
||
|
||
```rust
|
||
// heartbeat.rs
|
||
fn check_pending_tasks(agent_id: &str) -> Option<HeartbeatAlert>; // 任务积压
|
||
fn check_memory_health(agent_id: &str) -> Option<HeartbeatAlert>; // 存储健康
|
||
fn check_correction_patterns(agent_id: &str) -> Vec<HeartbeatAlert>; // 纠正模式
|
||
fn check_learning_opportunities(agent_id: &str) -> Option<HeartbeatAlert>; // 学习机会
|
||
fn check_idle_greeting(agent_id: &str) -> Option<HeartbeatAlert>; // 空闲问候
|
||
```
|
||
|
||
**关键注意事项**:
|
||
|
||
1. **DateTime 类型转换**: `chrono::DateTime::parse_from_rfc3339()` 返回 `DateTime<FixedOffset>`,需要转换为 `DateTime<Utc>` 才能与 `chrono::Utc::now()` 计算时间差:
|
||
```rust
|
||
let last_time = chrono::DateTime::parse_from_rfc3339(×tamp)
|
||
.ok()?
|
||
.with_timezone(&chrono::Utc); // 必须转换时区
|
||
```
|
||
|
||
2. **API 参数命名**: 前端调用 Tauri 命令时使用 snake_case 参数名:
|
||
```typescript
|
||
await invoke('heartbeat_update_memory_stats', {
|
||
agent_id: agentId, // 不是 agentId
|
||
task_count: taskCount, // 不是 taskCount
|
||
// ...
|
||
});
|
||
```
|
||
|
||
3. **MemoryStats 类型**: 后端使用 `total_entries`,前端转换为 `totalEntries`
|
||
|
||
---
|
||
|
||
## 七、Tauri 集成
|
||
|
||
### 7.1 命令封装
|
||
|
||
```rust
|
||
// desktop/src-tauri/src/kernel_commands.rs
|
||
|
||
/// Kernel 状态包装器
|
||
pub type KernelState = Arc<Mutex<Option<Kernel>>>;
|
||
|
||
/// 初始化 Kernel
|
||
#[tauri::command]
|
||
pub async fn kernel_init(
|
||
state: State<'_, KernelState>,
|
||
config_request: Option<KernelConfigRequest>,
|
||
) -> Result<KernelStatusResponse, String> {
|
||
// ...
|
||
}
|
||
|
||
/// 创建 Agent
|
||
#[tauri::command]
|
||
pub async fn agent_create(
|
||
state: State<'_, KernelState>,
|
||
request: CreateAgentRequest,
|
||
) -> Result<CreateAgentResponse, String> {
|
||
// ...
|
||
}
|
||
|
||
/// 发送消息
|
||
#[tauri::command]
|
||
pub async fn agent_chat(
|
||
state: State<'_, KernelState>,
|
||
request: ChatRequest,
|
||
) -> Result<ChatResponse, String> {
|
||
// ...
|
||
}
|
||
```
|
||
|
||
### 7.2 lib.rs 注册
|
||
|
||
```rust
|
||
// desktop/src-tauri/src/lib.rs
|
||
|
||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||
pub fn run() {
|
||
tauri::Builder::default()
|
||
.setup(|app| {
|
||
app.manage(kernel_commands::create_kernel_state());
|
||
Ok(())
|
||
})
|
||
.invoke_handler(tauri::generate_handler![
|
||
kernel_commands::kernel_init,
|
||
kernel_commands::kernel_status,
|
||
kernel_commands::kernel_shutdown,
|
||
kernel_commands::agent_create,
|
||
kernel_commands::agent_list,
|
||
kernel_commands::agent_get,
|
||
kernel_commands::agent_delete,
|
||
kernel_commands::agent_chat,
|
||
])
|
||
.run(tauri::generate_context!())
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 八、前端集成
|
||
|
||
### 8.1 KernelClient
|
||
|
||
```typescript
|
||
// desktop/src/lib/kernel-client.ts
|
||
|
||
export class KernelClient {
|
||
private config: KernelConfig = {};
|
||
private defaultAgentId: string = '';
|
||
|
||
setConfig(config: KernelConfig): void {
|
||
this.config = config;
|
||
}
|
||
|
||
async connect(): Promise<void> {
|
||
if (!this.config.provider || !this.config.model || !this.config.apiKey) {
|
||
throw new Error('请先在"模型与 API"设置页面配置模型');
|
||
}
|
||
|
||
const status = await invoke<KernelStatus>('kernel_init', {
|
||
configRequest: {
|
||
provider: this.config.provider,
|
||
model: this.config.model,
|
||
apiKey: this.config.apiKey,
|
||
baseUrl: this.config.baseUrl || null,
|
||
},
|
||
});
|
||
|
||
// 创建默认 Agent
|
||
const agents = await this.listAgents();
|
||
if (agents.length === 0) {
|
||
const agent = await this.createAgent({
|
||
name: 'Default Agent',
|
||
provider: this.config.provider,
|
||
model: this.config.model,
|
||
});
|
||
this.defaultAgentId = agent.id;
|
||
}
|
||
}
|
||
|
||
async chat(message: string, opts?: ChatOptions): Promise<ChatResponse> {
|
||
return invoke<ChatResponse>('agent_chat', {
|
||
request: {
|
||
agentId: opts?.agentId || this.defaultAgentId,
|
||
message,
|
||
},
|
||
});
|
||
}
|
||
}
|
||
```
|
||
|
||
### 8.2 ConnectionStore
|
||
|
||
```typescript
|
||
// desktop/src/store/connectionStore.ts
|
||
|
||
connect: async (url?: string, token?: string) => {
|
||
const useInternalKernel = isTauriRuntime();
|
||
|
||
if (useInternalKernel) {
|
||
const kernelClient = getKernelClient();
|
||
const modelConfig = getDefaultModelConfig();
|
||
|
||
if (!modelConfig) {
|
||
throw new Error('请先在"模型与 API"设置页面添加自定义模型配置');
|
||
}
|
||
|
||
kernelClient.setConfig({
|
||
provider: modelConfig.provider,
|
||
model: modelConfig.model,
|
||
apiKey: modelConfig.apiKey,
|
||
baseUrl: modelConfig.baseUrl,
|
||
});
|
||
|
||
await kernelClient.connect();
|
||
set({ client: kernelClient, gatewayVersion: '0.2.0-internal' });
|
||
return;
|
||
}
|
||
|
||
// 非 Tauri 环境...
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 九、支持的 Provider
|
||
|
||
### 9.1 Provider 列表
|
||
|
||
| Provider | Driver | Base URL | API 协议 |
|
||
|----------|--------|----------|----------|
|
||
| kimi | OpenAiDriver | `https://api.kimi.com/coding/v1` | OpenAI 兼容 |
|
||
| qwen | OpenAiDriver | `https://dashscope.aliyuncs.com/compatible-mode/v1` | OpenAI 兼容 |
|
||
| deepseek | OpenAiDriver | `https://api.deepseek.com/v1` | OpenAI 兼容 |
|
||
| zhipu | OpenAiDriver | `https://open.bigmodel.cn/api/paas/v4` | OpenAI 兼容 |
|
||
| openai | OpenAiDriver | `https://api.openai.com/v1` | OpenAI |
|
||
| anthropic | AnthropicDriver | `https://api.anthropic.com` | Anthropic |
|
||
| gemini | GeminiDriver | `https://generativelanguage.googleapis.com` | Gemini |
|
||
| local | LocalDriver | `http://localhost:11434/v1` | OpenAI 兼容 |
|
||
|
||
### 9.2 配置示例
|
||
|
||
```typescript
|
||
// Kimi Code 配置
|
||
{
|
||
provider: 'kimi',
|
||
model: 'kimi-k2-turbo',
|
||
apiKey: 'your-kimi-api-key',
|
||
baseUrl: 'https://api.kimi.com/coding/v1'
|
||
}
|
||
|
||
// 百炼 Qwen 配置
|
||
{
|
||
provider: 'qwen',
|
||
model: 'qwen-plus',
|
||
apiKey: 'your-qwen-api-key',
|
||
baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1'
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 十、开发命令
|
||
|
||
### 10.1 构建命令
|
||
|
||
```bash
|
||
# 构建所有 crates
|
||
cargo build
|
||
|
||
# 构建生产版本
|
||
cargo build --release
|
||
|
||
# 运行测试
|
||
cargo test
|
||
|
||
# 启动开发环境
|
||
pnpm start:dev
|
||
```
|
||
|
||
### 10.2 常用命令
|
||
|
||
```bash
|
||
# 安装依赖
|
||
pnpm install
|
||
|
||
# 类型检查
|
||
pnpm tsc --noEmit
|
||
|
||
# 运行测试
|
||
pnpm vitest run
|
||
|
||
# E2E 测试
|
||
pnpm test:e2e
|
||
```
|
||
|
||
---
|
||
|
||
## 十一、Skill 系统架构
|
||
|
||
### 11.1 概述
|
||
|
||
Skill 系统是 ZCLAW 的可扩展技能框架,允许通过 `SKILL.md` 或 `skill.toml` 文件定义和加载技能。
|
||
|
||
### 11.2 核心组件
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ Skill 系统架构 │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ zclaw-skills/ │
|
||
│ ├── SkillManifest # 技能元数据 │
|
||
│ ├── SkillContext # 执行上下文 (agent_id, session_id) │
|
||
│ ├── SkillResult # 执行结果 │
|
||
│ ├── SkillRegistry # 技能注册表 │
|
||
│ ├── SkillLoader # SKILL.md/skill.toml 解析 │
|
||
│ └── SkillRunner # 执行器 (PromptOnly/Shell) │
|
||
│ │
|
||
│ zclaw-runtime/ │
|
||
│ ├── ExecuteSkillTool # execute_skill 工具 │
|
||
│ ├── SkillExecutor # 技能执行 trait │
|
||
│ └── ToolContext # 包含 skill_executor │
|
||
│ │
|
||
│ zclaw-kernel/ │
|
||
│ ├── KernelSkillExecutor # SkillExecutor 实现 │
|
||
│ └── default_skills_dir # 默认 ./skills 目录 │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 11.3 数据流
|
||
|
||
```
|
||
LLM 调用 execute_skill 工具
|
||
↓
|
||
AgentLoop.execute_tool()
|
||
↓
|
||
ExecuteSkillTool.execute()
|
||
↓
|
||
ToolContext.skill_executor.execute_skill()
|
||
↓
|
||
KernelSkillExecutor.execute_skill()
|
||
↓
|
||
SkillRegistry.execute()
|
||
↓
|
||
返回结果给 LLM
|
||
```
|
||
|
||
### 11.4 Tauri 命令
|
||
|
||
| 命令 | 说明 |
|
||
|------|------|
|
||
| `skill_list` | 列出所有已加载的技能 |
|
||
| `skill_execute` | 执行指定技能 |
|
||
| `skill_refresh` | 刷新技能目录 |
|
||
|
||
### 11.5 前端集成
|
||
|
||
```typescript
|
||
// 从后端加载技能列表
|
||
const skills = await invoke('skill_list');
|
||
|
||
// 执行技能
|
||
const result = await invoke('skill_execute', {
|
||
id: 'skill-id',
|
||
context: { agentId: '...', sessionId: '...', workingDir: null },
|
||
input: { ... }
|
||
});
|
||
```
|
||
|
||
### 11.6 技能发现
|
||
|
||
1. Kernel 启动时扫描 `./skills` 目录
|
||
2. 查找 `SKILL.md` 或 `skill.toml` 文件
|
||
3. 解析 frontmatter 元数据
|
||
4. 注册到 SkillRegistry
|
||
|
||
### 11.7 已知限制
|
||
|
||
| 限制 | 说明 |
|
||
|------|------|
|
||
| Python/WASM 模式 | 未实现,回退到 PromptOnly |
|
||
| Frontmatter 解析 | 仅支持简单 `key: value` 格式 |
|
||
| 模式字符串 | `"PromptOnly"` 而非 `"prompt_only"` |
|
||
|
||
---
|
||
|
||
## 十二、参考资料
|
||
|
||
### 12.1 相关文档
|
||
|
||
- [快速启动指南](../quick-start.md)
|
||
- [模型配置指南](./configuration.md)
|
||
- [通信层文档](../features/00-architecture/01-communication-layer.md)
|
||
- [后端集成文档](../features/06-tauri-backend/00-backend-integration.md)
|
||
|
||
### 12.2 架构演进
|
||
|
||
| 版本 | 架构 | 说明 |
|
||
|------|------|------|
|
||
| v1.x | 外部 ZCLAW | 需要启动独立后端进程 |
|
||
| v2.0 | 内部 Kernel | Kernel 集成在 Tauri 中,无需外部进程 |
|
||
| v2.1 | Skill 工具执行 | 完整的 execute_skill 工具链路 |
|
||
|
||
---
|
||
|
||
*文档版本: v2.1 | 更新日期: 2026-03-24*
|