Files
zclaw_openfang/plans/whimsical-humming-kite.md
iven 3ff08faa56 release(v0.2.0): streaming, MCP protocol, Browser Hand, security enhancements
## Major Features

### Streaming Response System
- Implement LlmDriver trait with `stream()` method returning async Stream
- Add SSE parsing for Anthropic and OpenAI API streaming
- Integrate Tauri event system for frontend streaming (`stream:chunk` events)
- Add StreamChunk types: Delta, ToolStart, ToolEnd, Complete, Error

### MCP Protocol Implementation
- Add MCP JSON-RPC 2.0 types (mcp_types.rs)
- Implement stdio-based MCP transport (mcp_transport.rs)
- Support tool discovery, execution, and resource operations

### Browser Hand Implementation
- Complete browser automation with Playwright-style actions
- Support Navigate, Click, Type, Scrape, Screenshot, Wait actions
- Add educational Hands: Whiteboard, Slideshow, Speech, Quiz

### Security Enhancements
- Implement command whitelist/blacklist for shell_exec tool
- Add SSRF protection with private IP blocking
- Create security.toml configuration file

## Test Improvements
- Fix test import paths (security-utils, setup)
- Fix vi.mock hoisting issues with vi.hoisted()
- Update test expectations for validateUrl and sanitizeFilename
- Add getUnsupportedLocalGatewayStatus mock

## Documentation Updates
- Update architecture documentation
- Improve configuration reference
- Add quick-start guide updates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 03:24:24 +08:00

165 lines
4.7 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.

# 修复 LLM API 404 错误
## 问题描述
用户在对话时收到错误:
```
Chat failed: LLM error: API error 404 Not Found: {"error":{"message":"The requested resource was not found","type":"resource_not_found_error"}}
```
## 根因分析
### 1. 模型别名未被解析(主要原因)
**数据流问题:**
- 前端 `chatStore.ts:194` 默认模型是 `'glm-5'`
- 配置文件 `config.toml:131` 定义了别名映射 `"glm-5" = "zhipu/glm-4-plus"`
- **但是后端 `kernel.rs` 没有解析这个别名**,直接把 `'glm-5'` 发送给API
- 智谱API不认识 `'glm-5'`返回404
### 2. 模型ID格式问题
配置文件使用带provider前缀的格式 `"zhipu/glm-4-plus"`,但:
- 智谱API只认识 `"glm-4-plus"`(不带前缀)
- `openai.rs:140` 直接传递模型ID不做任何处理
### 3. 多处配置不一致
| 位置 | 默认Provider | 默认Model |
|------|-------------|-----------|
| `config.rs:84-88` | `"qwen"` | `"qwen-plus"` |
| `config.toml:115-116` | `"zhipu"` | `"glm-4-plus"` |
| `chatStore.ts:194` | - | `'glm-5'` (别名) |
| `loop_runner.rs:38` | - | `"claude-sonnet-4-20250514"` (硬编码) |
### 4. Kimi Base URL错误
`config.rs:92` 使用 `https://api.kimi.com/coding/v1`,正确应该是 `https://api.moonshot.cn/v1`
## 修复方案
### 修复1: 在Kernel中添加模型别名解析
**文件**: `crates/zclaw-kernel/src/kernel.rs`
`send_message``send_message_stream` 方法中,解析模型别名:
```rust
// 在 send_message 方法中约第119行
// 添加模型别名解析函数
fn resolve_model_alias(model: &str, aliases: &HashMap<String, String>) -> String {
aliases.get(model).map(|s| s.as_str()).unwrap_or(model).to_string()
}
// 然后在确定模型后,检查是否是别名
let model = resolve_model_alias(model, &self.config.model_aliases);
```
### 修复2: 在KernelConfig中添加模型别名配置
**文件**: `crates/zclaw-kernel/src/config.rs`
1. 添加模型别名字段:
```rust
/// Model aliases (e.g., "glm-5" -> "zhipu/glm-4-plus")
#[serde(default)]
pub model_aliases: HashMap<String, String>,
```
2. 修正Kimi Base URL
```rust
fn default_kimi_base_url() -> String {
"https://api.moonshot.cn/v1".to_string() // 修正
}
```
### 修复3: 在OpenAIDriver中规范化模型ID
**文件**: `crates/zclaw-runtime/src/driver/openai.rs`
`build_api_request` 方法中去除provider前缀
```rust
fn normalize_model_id(model: &str) -> String {
// 如果模型ID包含 "/",取最后一部分
// 例如 "zhipu/glm-4-plus" -> "glm-4-plus"
if model.contains('/') {
model.split('/').last().unwrap_or(model).to_string()
} else {
model.to_string()
}
}
```
### 修复4: 统一默认配置
**文件**: `crates/zclaw-kernel/src/config.rs`
将默认provider和model改为与config.toml一致
```rust
fn default_provider() -> String {
"zhipu".to_string()
}
fn default_model() -> String {
"glm-4-plus".to_string()
}
```
### 修复5: 移除loop_runner.rs中的硬编码默认值
**文件**: `crates/zclaw-runtime/src/loop_runner.rs`
第38行的硬编码模型应该移除使用传入的配置
```rust
// 移除硬编码,改为空字符串或从配置获取
model: String::new(), // 必须通过 with_model() 设置
```
## 关键文件
| 文件 | 修改内容 |
|------|----------|
| [config.rs](crates/zclaw-kernel/src/config.rs) | 添加model_aliases字段、修正Kimi URL、统一默认配置 |
| [kernel.rs](crates/zclaw-kernel/src/kernel.rs) | 添加模型别名解析逻辑 |
| [openai.rs](crates/zclaw-runtime/src/driver/openai.rs) | 添加模型ID规范化去除provider前缀 |
| [loop_runner.rs](crates/zclaw-runtime/src/loop_runner.rs) | 移除硬编码默认模型 |
## 问题场景确认
用户使用**智谱 GLM** 模型时遇到404错误
- 前端默认 `currentModel: 'glm-5'`
- 配置别名 `"glm-5" = "zhipu/glm-4-plus"`
- 后端未解析别名,直接发送 `'glm-5'` 给API
- 智谱API返回404
## 验证步骤
1. **单元测试**
```bash
cargo test -p zclaw-kernel --lib config::tests
cargo test -p zclaw-runtime --lib driver::openai::tests
```
2. **集成测试**
```bash
cargo test -p zclaw-kernel
```
3. **手动验证智谱GLM**
- 启动桌面应用:`pnpm start:dev`
- 在"模型与API"设置中配置智谱API Key
- 选择 `glm-5` 或 `glm-4-plus` 模型
- 发送消息验证不再出现404错误
- 检查日志确认:
- 模型别名 `'glm-5'` 被解析为 `'zhipu/glm-4-plus'`
- provider前缀被去除发送给API的是 `'glm-4-plus'`
## 实现顺序
1. **config.rs** - 添加model_aliases字段和修正Kimi URL
2. **openai.rs** - 添加模型ID规范化函数
3. **kernel.rs** - 添加别名解析逻辑
4. **loop_runner.rs** - 移除硬编码
5. **测试验证**