docs: add setup guides and error notification component
- Add OpenFang Kernel configuration guide (docs/setup/OPENFANG-SETUP.md) - Add Chinese models configuration guide (docs/setup/chinese-models.md) - Add quick start guide (docs/quick-start.md) - Add quick start scripts for Windows and Linux/macOS - Add ErrorNotification component for centralized error display These additions help users: - Quickly set up development environment - Configure OpenFang backend correctly - Configure Chinese LLM providers (GLM, Qwen, Kimi, MiniMax) - See error notifications in a consistent UI Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
271
desktop/src/components/ErrorNotification.tsx
Normal file
271
desktop/src/components/ErrorNotification.tsx
Normal file
@@ -0,0 +1,271 @@
|
||||
/**
|
||||
* ErrorNotification Component
|
||||
*
|
||||
* Displays error notifications as toast-style messages.
|
||||
* Integrates with the centralized error handling system.
|
||||
*/
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import {
|
||||
X,
|
||||
AlertCircle,
|
||||
AlertTriangle,
|
||||
Info,
|
||||
Bug,
|
||||
WifiOff,
|
||||
ShieldAlert,
|
||||
Clock,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
getUndismissedErrors,
|
||||
dismissError,
|
||||
dismissAll,
|
||||
type StoredError,
|
||||
} from '../lib/error-handling';
|
||||
import {
|
||||
ErrorCategory,
|
||||
ErrorSeverity,
|
||||
formatErrorForToast,
|
||||
} from '../lib/error-types';
|
||||
|
||||
interface ErrorNotificationProps {
|
||||
/** Maximum number of visible notifications */
|
||||
maxVisible?: number;
|
||||
/** Position on screen */
|
||||
position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
|
||||
/** Auto dismiss timeout in ms (0 = no auto dismiss) */
|
||||
autoDismissMs?: number;
|
||||
/** Additional CSS classes */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const categoryIcons: Record<ErrorCategory, typeof AlertCircle> = {
|
||||
network: WifiOff,
|
||||
authentication: ShieldAlert,
|
||||
authorization: ShieldAlert,
|
||||
validation: AlertTriangle,
|
||||
configuration: AlertTriangle,
|
||||
internal: Bug,
|
||||
external: AlertCircle,
|
||||
timeout: Clock,
|
||||
unknown: AlertCircle,
|
||||
};
|
||||
|
||||
const severityColors: Record<ErrorSeverity, {
|
||||
bg: string;
|
||||
border: string;
|
||||
text: string;
|
||||
icon: string;
|
||||
}> = {
|
||||
critical: {
|
||||
bg: 'bg-red-50 dark:bg-red-900/20',
|
||||
border: 'border-red-200 dark:border-red-800',
|
||||
text: 'text-red-800 dark:text-red-200',
|
||||
icon: 'text-red-500',
|
||||
},
|
||||
high: {
|
||||
bg: 'bg-orange-50 dark:bg-orange-900/20',
|
||||
border: 'border-orange-200 dark:border-orange-800',
|
||||
text: 'text-orange-800 dark:text-orange-200',
|
||||
icon: 'text-orange-500',
|
||||
},
|
||||
medium: {
|
||||
bg: 'bg-yellow-50 dark:bg-yellow-900/20',
|
||||
border: 'border-yellow-200 dark:border-yellow-800',
|
||||
text: 'text-yellow-800 dark:text-yellow-200',
|
||||
icon: 'text-yellow-500',
|
||||
},
|
||||
low: {
|
||||
bg: 'bg-blue-50 dark:bg-blue-900/20',
|
||||
border: 'border-blue-200 dark:border-blue-800',
|
||||
text: 'text-blue-800 dark:text-blue-200',
|
||||
icon: 'text-blue-500',
|
||||
},
|
||||
};
|
||||
|
||||
function ErrorItem({
|
||||
error,
|
||||
onDismiss,
|
||||
autoDismissMs,
|
||||
}: {
|
||||
error: StoredError;
|
||||
onDismiss: (id: string) => void;
|
||||
autoDismissMs: number;
|
||||
}) {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const Icon = categoryIcons[error.category] || AlertCircle;
|
||||
const colors = severityColors[error.severity] || severityColors.medium;
|
||||
const { title, message } = formatErrorForToast(error);
|
||||
|
||||
// Auto dismiss
|
||||
useEffect(() => {
|
||||
if (autoDismissMs > 0 && error.severity !== 'critical') {
|
||||
const timer = setTimeout(() => {
|
||||
onDismiss(error.id);
|
||||
}, autoDismissMs);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [autoDismissMs, error.id, error.severity, onDismiss]);
|
||||
|
||||
const hasDetails = error.stack || error.context;
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 300, scale: 0.9 }}
|
||||
animate={{ opacity: 1, x: 0, scale: 1 }}
|
||||
exit={{ opacity: 0, x: 300, scale: 0.9 }}
|
||||
className={`
|
||||
${colors.bg} ${colors.border} ${colors.text}
|
||||
border rounded-lg shadow-lg p-4 min-w-[320px] max-w-[420px]
|
||||
`}
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<Icon className={`w-5 h-5 mt-0.5 flex-shrink-0 ${colors.icon}`} />
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<h4 className="font-medium text-sm">{title}</h4>
|
||||
<button
|
||||
onClick={() => onDismiss(error.id)}
|
||||
className="p-1 rounded hover:bg-black/10 dark:hover:bg-white/10 flex-shrink-0"
|
||||
>
|
||||
<X className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-sm mt-1 opacity-90">{message}</p>
|
||||
|
||||
{hasDetails && (
|
||||
<button
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
className="flex items-center gap-1 text-xs mt-2 opacity-70 hover:opacity-100"
|
||||
>
|
||||
{expanded ? (
|
||||
<>
|
||||
<ChevronUp className="w-3 h-3" />
|
||||
隐藏详情
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ChevronDown className="w-3 h-3" />
|
||||
显示详情
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
|
||||
{expanded && hasDetails && (
|
||||
<motion.div
|
||||
initial={{ height: 0, opacity: 0 }}
|
||||
animate={{ height: 'auto', opacity: 1 }}
|
||||
exit={{ height: 0, opacity: 0 }}
|
||||
className="mt-2 p-2 bg-black/5 dark:bg-white/5 rounded text-xs font-mono overflow-auto max-h-32"
|
||||
>
|
||||
{error.context && (
|
||||
<div className="mb-1">
|
||||
<span className="opacity-70">Context: </span>
|
||||
{JSON.stringify(error.context, null, 2)}
|
||||
</div>
|
||||
)}
|
||||
{error.stack && (
|
||||
<pre className="whitespace-pre-wrap opacity-70">{error.stack}</pre>
|
||||
)}
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-2 mt-2 text-xs opacity-60">
|
||||
<span>{error.category}</span>
|
||||
<span>•</span>
|
||||
<span>{new Date(error.timestamp).toLocaleTimeString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ErrorNotification({
|
||||
maxVisible = 3,
|
||||
position = 'top-right',
|
||||
autoDismissMs = 10000,
|
||||
className = '',
|
||||
}: ErrorNotificationProps) {
|
||||
const [errors, setErrors] = useState<StoredError[]>([]);
|
||||
|
||||
// Poll for new errors
|
||||
useEffect(() => {
|
||||
const updateErrors = () => {
|
||||
setErrors(getUndismissedErrors().slice(0, maxVisible));
|
||||
};
|
||||
|
||||
updateErrors();
|
||||
const interval = setInterval(updateErrors, 1000);
|
||||
return () => clearInterval(interval);
|
||||
}, [maxVisible]);
|
||||
|
||||
const handleDismiss = useCallback((id: string) => {
|
||||
dismissError(id);
|
||||
setErrors(prev => prev.filter(e => e.id !== id));
|
||||
}, []);
|
||||
|
||||
const handleDismissAll = useCallback(() => {
|
||||
dismissAll();
|
||||
setErrors([]);
|
||||
}, []);
|
||||
|
||||
const positionClasses: Record<string, string> = {
|
||||
'top-right': 'top-4 right-4',
|
||||
'top-left': 'top-4 left-4',
|
||||
'bottom-right': 'bottom-4 right-4',
|
||||
'bottom-left': 'bottom-4 left-4',
|
||||
};
|
||||
|
||||
if (errors.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`fixed ${positionClasses[position]} z-50 flex flex-col gap-2 ${className}`}
|
||||
>
|
||||
<AnimatePresence mode="popLayout">
|
||||
{errors.map(error => (
|
||||
<ErrorItem
|
||||
key={error.id}
|
||||
error={error}
|
||||
onDismiss={handleDismiss}
|
||||
autoDismissMs={autoDismissMs}
|
||||
/>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
|
||||
{errors.length > 1 && (
|
||||
<motion.button
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
onClick={handleDismissAll}
|
||||
className="text-xs text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 text-center py-1"
|
||||
>
|
||||
清除全部 ({errors.length})
|
||||
</motion.button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* ErrorNotificationProvider - Include at app root
|
||||
*/
|
||||
export function ErrorNotificationProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
<ErrorNotification />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ErrorNotification;
|
||||
233
docs/quick-start.md
Normal file
233
docs/quick-start.md
Normal file
@@ -0,0 +1,233 @@
|
||||
# ZCLAW 快速启动指南
|
||||
|
||||
> 5 分钟内启动 ZCLAW 开发环境
|
||||
|
||||
---
|
||||
|
||||
## 前置要求
|
||||
|
||||
| 工具 | 最低版本 | 检查命令 |
|
||||
|------|----------|----------|
|
||||
| Node.js | 18.x | `node -v` |
|
||||
| pnpm | 8.x | `pnpm -v` |
|
||||
| Rust | 1.70+ | `rustc --version` |
|
||||
| OpenFang | - | `openfang --version` |
|
||||
|
||||
---
|
||||
|
||||
## 快速启动
|
||||
|
||||
### Windows 用户
|
||||
|
||||
```powershell
|
||||
# 在项目根目录执行
|
||||
.\scripts\quick-start-dev.ps1
|
||||
```
|
||||
|
||||
### Linux/macOS 用户
|
||||
|
||||
```bash
|
||||
# 在项目根目录执行
|
||||
./scripts/quick-start.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 手动启动步骤
|
||||
|
||||
### 1. 安装依赖
|
||||
|
||||
```bash
|
||||
# 根目录依赖
|
||||
pnpm install
|
||||
|
||||
# 桌面端依赖
|
||||
cd desktop && pnpm install && cd ..
|
||||
```
|
||||
|
||||
### 2. 启动 OpenFang 后端
|
||||
|
||||
```bash
|
||||
# 方法 A: 使用 CLI
|
||||
openfang start
|
||||
|
||||
# 方法 B: 使用 pnpm 脚本
|
||||
pnpm gateway:start
|
||||
```
|
||||
|
||||
验证后端运行:
|
||||
```bash
|
||||
curl http://127.0.0.1:50051/api/health
|
||||
# 应返回: {"status":"ok"}
|
||||
```
|
||||
|
||||
### 3. 启动开发环境
|
||||
|
||||
```bash
|
||||
# 方法 A: 一键启动(推荐)
|
||||
pnpm start:dev
|
||||
|
||||
# 方法 B: 仅启动桌面端(需要后端已运行)
|
||||
pnpm desktop
|
||||
|
||||
# 方法 C: 分开启动
|
||||
# 终端 1 - 启动 Gateway
|
||||
pnpm dev
|
||||
|
||||
# 终端 2 - 启动桌面端
|
||||
pnpm desktop
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 测试环境启动
|
||||
|
||||
### 单元测试
|
||||
|
||||
```bash
|
||||
# 运行所有单元测试
|
||||
pnpm test
|
||||
|
||||
# 监听模式
|
||||
pnpm test:watch
|
||||
|
||||
# 桌面端测试
|
||||
cd desktop && pnpm test
|
||||
```
|
||||
|
||||
### E2E 测试
|
||||
|
||||
```bash
|
||||
# 运行 E2E 测试
|
||||
pnpm test:e2e
|
||||
|
||||
# 带界面运行
|
||||
cd desktop && pnpm test:e2e:ui
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 开发端口说明
|
||||
|
||||
| 服务 | 端口 | 说明 |
|
||||
|------|------|------|
|
||||
| OpenFang 后端 | 50051 | API 和 WebSocket 服务 |
|
||||
| Vite 开发服务器 | 1420 | 前端热重载 |
|
||||
| Tauri 窗口 | - | 桌面应用窗口 |
|
||||
|
||||
---
|
||||
|
||||
## 常见问题排查
|
||||
|
||||
### Q1: 端口被占用
|
||||
|
||||
**症状**: `Port 1420 is already in use` 或 `Port 50051 is already in use`
|
||||
|
||||
**解决**:
|
||||
```powershell
|
||||
# Windows - 查找并终止进程
|
||||
netstat -ano | findstr "1420"
|
||||
taskkill /PID <PID> /F
|
||||
|
||||
# Linux/macOS
|
||||
lsof -i :1420
|
||||
kill -9 <PID>
|
||||
```
|
||||
|
||||
### Q2: 后端连接失败
|
||||
|
||||
**症状**: `Network Error` 或 `Connection refused`
|
||||
|
||||
**排查步骤**:
|
||||
```bash
|
||||
# 1. 检查后端是否运行
|
||||
curl http://127.0.0.1:50051/api/health
|
||||
|
||||
# 2. 检查端口监听
|
||||
netstat -ano | findstr "50051"
|
||||
|
||||
# 3. 重启后端
|
||||
openfang restart
|
||||
```
|
||||
|
||||
### Q3: API Key 未配置
|
||||
|
||||
**症状**: `Missing API key: No LLM provider configured`
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
# 编辑配置文件
|
||||
# Windows: %USERPROFILE%\.openfang\.env
|
||||
# Linux/macOS: ~/.openfang/.env
|
||||
|
||||
# 添加 API Key
|
||||
echo "ZHIPU_API_KEY=your_key" >> ~/.openfang/.env
|
||||
|
||||
# 重启后端
|
||||
openfang restart
|
||||
```
|
||||
|
||||
### Q4: Tauri 编译失败
|
||||
|
||||
**症状**: Rust 编译错误
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
# 更新 Rust
|
||||
rustup update
|
||||
|
||||
# 清理并重新构建
|
||||
cd desktop/src-tauri
|
||||
cargo clean
|
||||
cargo build
|
||||
```
|
||||
|
||||
### Q5: 依赖安装失败
|
||||
|
||||
**症状**: pnpm install 报错
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
# 清理缓存
|
||||
pnpm store prune
|
||||
|
||||
# 删除 node_modules 重新安装
|
||||
rm -rf node_modules desktop/node_modules
|
||||
pnpm install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 验证清单
|
||||
|
||||
启动成功后,验证以下功能:
|
||||
|
||||
- [ ] 后端健康检查通过: `curl http://127.0.0.1:50051/api/health`
|
||||
- [ ] 桌面端窗口正常显示
|
||||
- [ ] 可以发送消息并获得响应
|
||||
- [ ] 可以切换 Agent
|
||||
- [ ] 可以查看设置页面
|
||||
|
||||
---
|
||||
|
||||
## 停止服务
|
||||
|
||||
```bash
|
||||
# 停止所有服务
|
||||
pnpm start:stop
|
||||
|
||||
# 或手动停止
|
||||
# Ctrl+C 终止运行中的进程
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [完整开发文档](./DEVELOPMENT.md)
|
||||
- [故障排查指南](./knowledge-base/troubleshooting.md)
|
||||
- [配置说明](./knowledge-base/configuration.md)
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2026-03-21
|
||||
512
docs/setup/OPENFANG-SETUP.md
Normal file
512
docs/setup/OPENFANG-SETUP.md
Normal file
@@ -0,0 +1,512 @@
|
||||
# OpenFang Kernel 配置指南
|
||||
|
||||
> 本文档帮助你正确配置 OpenFang Kernel,作为 ZCLAW 的后端执行引擎。
|
||||
|
||||
## 概述
|
||||
|
||||
OpenFang 是一个用 Rust 构建的生产级 Agent 操作系统(Agent Operating System)。与传统的聊天机器人框架不同,OpenFang 采用"主动执行"范式:Agent 能够按计划自主唤醒、完成任务并报告结果,而无需用户持续提示。
|
||||
|
||||
### 核心特性
|
||||
|
||||
- **高性能**:冷启动 < 200ms,空闲内存 ~40MB
|
||||
- **Hands 机制**:7 个预构建的自主能力包,即插即用
|
||||
- **40+ 渠道适配器**:支持 Telegram、Discord、飞书、钉钉等
|
||||
- **27+ LLM 提供商**:包括中文模型(智谱、通义千问、Kimi、MiniMax)
|
||||
- **16 层安全防护**:WASM 沙箱、Merkle 审计追踪、Ed25519 签名等
|
||||
|
||||
---
|
||||
|
||||
## 前置要求
|
||||
|
||||
### 系统要求
|
||||
|
||||
| 要求 | 最低配置 | 推荐配置 |
|
||||
|------|----------|----------|
|
||||
| **操作系统** | Windows 10 / macOS 10.15 / Linux | Windows 11 / macOS 13+ / Ubuntu 22.04+ |
|
||||
| **CPU 架构** | x86_64 或 ARM64 | x86_64 |
|
||||
| **内存** | 64MB | 256MB+ |
|
||||
| **磁盘空间** | 100MB | 500MB+ |
|
||||
|
||||
### 依赖项
|
||||
|
||||
OpenFang 是一个独立的单二进制文件(~32MB),无外部依赖。但以下工具可能对某些功能必要:
|
||||
|
||||
- **FFmpeg**:视频处理 Hand (Clip) 需要
|
||||
- **yt-dlp**:YouTube 视频下载需要
|
||||
|
||||
---
|
||||
|
||||
## 安装步骤
|
||||
|
||||
### 方式一:官方安装脚本(推荐)
|
||||
|
||||
#### Windows
|
||||
|
||||
```powershell
|
||||
# 使用 PowerShell
|
||||
iwr -useb https://openfang.sh/install.ps1 | iex
|
||||
```
|
||||
|
||||
#### macOS / Linux
|
||||
|
||||
```bash
|
||||
curl -fsSL https://openfang.sh/install.sh | bash
|
||||
```
|
||||
|
||||
### 方式二:手动下载
|
||||
|
||||
1. 访问 [GitHub Releases](https://github.com/RightNow-AI/openfang/releases)
|
||||
2. 下载对应平台的二进制文件
|
||||
3. 将文件放入 PATH 目录
|
||||
|
||||
#### Windows
|
||||
|
||||
```powershell
|
||||
# 下载后移动到用户目录
|
||||
move openfang.exe C:\Users\<你的用户名>\.local\bin\
|
||||
```
|
||||
|
||||
#### macOS / Linux
|
||||
|
||||
```bash
|
||||
chmod +x openfang
|
||||
sudo mv openfang /usr/local/bin/
|
||||
```
|
||||
|
||||
### 方式三:从源码编译
|
||||
|
||||
```bash
|
||||
git clone https://github.com/RightNow-AI/openfang.git
|
||||
cd openfang
|
||||
cargo build --release
|
||||
# 编译产物位于 target/release/openfang
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置说明
|
||||
|
||||
### 1. 初始化配置
|
||||
|
||||
首次使用需要初始化配置文件:
|
||||
|
||||
```bash
|
||||
openfang init
|
||||
```
|
||||
|
||||
这将在 `~/.openfang/` 目录下创建以下结构:
|
||||
|
||||
```
|
||||
~/.openfang/
|
||||
├── config.toml # 主配置文件
|
||||
├── openfang.db # SQLite 数据库
|
||||
├── data/ # 数据目录
|
||||
│ ├── agents/ # Agent 配置
|
||||
│ ├── skills/ # 自定义技能
|
||||
│ └── hands/ # Hand 配置
|
||||
└── logs/ # 日志文件
|
||||
```
|
||||
|
||||
### 2. 配置文件结构
|
||||
|
||||
编辑 `~/.openfang/config.toml`:
|
||||
|
||||
```toml
|
||||
# OpenFang 主配置文件
|
||||
|
||||
[general]
|
||||
# 默认语言
|
||||
language = "zh-CN"
|
||||
# 日志级别: trace, debug, info, warn, error
|
||||
log_level = "info"
|
||||
# 数据目录
|
||||
data_dir = "~/.openfang/data"
|
||||
|
||||
[model]
|
||||
# 默认模型提供商
|
||||
provider = "zhipu"
|
||||
# 默认模型
|
||||
model = "glm-4-flash"
|
||||
# API Key 环境变量名(不直接写 Key)
|
||||
api_key_env = "ZHIPU_API_KEY"
|
||||
# 可选:自定义 API 端点
|
||||
# base_url = "https://open.bigmodel.cn/api/paas/v4"
|
||||
|
||||
[api]
|
||||
# API 服务端口
|
||||
port = 50051
|
||||
# 绑定地址(0.0.0.0 允许外部访问)
|
||||
bind = "127.0.0.1"
|
||||
# 启用 OpenAI 兼容 API
|
||||
openai_compat = true
|
||||
|
||||
[security]
|
||||
# 启用能力门控
|
||||
capability_gates = true
|
||||
# 启用审计追踪
|
||||
audit_trail = true
|
||||
# 启用 WASM 沙箱
|
||||
wasm_sandbox = true
|
||||
|
||||
[memory]
|
||||
# 会话保留天数
|
||||
session_retention_days = 30
|
||||
# 向量嵌入模型
|
||||
embedding_model = "text-embedding-3-small"
|
||||
```
|
||||
|
||||
### 3. 配置 API Key
|
||||
|
||||
**重要**:永远不要在配置文件中直接写入 API Key,使用环境变量:
|
||||
|
||||
#### Windows (PowerShell)
|
||||
|
||||
```powershell
|
||||
# 临时设置(当前会话)
|
||||
$env:ZHIPU_API_KEY = "your-api-key-here"
|
||||
$env:DASHSCOPE_API_KEY = "your-dashscope-key" # 通义千问
|
||||
$env:MOONSHOT_API_KEY = "your-moonshot-key" # Kimi
|
||||
|
||||
# 永久设置(写入配置文件)
|
||||
[Environment]::SetEnvironmentVariable("ZHIPU_API_KEY", "your-api-key", "User")
|
||||
```
|
||||
|
||||
#### macOS / Linux
|
||||
|
||||
```bash
|
||||
# 临时设置(当前会话)
|
||||
export ZHIPU_API_KEY="your-api-key-here"
|
||||
export DASHSCOPE_API_KEY="your-dashscope-key"
|
||||
export MOONSHOT_API_KEY="your-moonshot-key"
|
||||
|
||||
# 永久设置(写入 shell 配置文件)
|
||||
echo 'export ZHIPU_API_KEY="your-api-key"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
### 4. 配置中文模型
|
||||
|
||||
在 `config.toml` 中配置中文模型提供商:
|
||||
|
||||
```toml
|
||||
# 智谱 GLM
|
||||
[model.zhipu]
|
||||
provider = "zhipu"
|
||||
model = "glm-4-flash"
|
||||
api_key_env = "ZHIPU_API_KEY"
|
||||
base_url = "https://open.bigmodel.cn/api/paas/v4"
|
||||
|
||||
# 通义千问
|
||||
[model.qwen]
|
||||
provider = "openai-compat"
|
||||
model = "qwen-turbo"
|
||||
api_key_env = "DASHSCOPE_API_KEY"
|
||||
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||
|
||||
# Kimi (Moonshot)
|
||||
[model.kimi]
|
||||
provider = "openai-compat"
|
||||
model = "moonshot-v1-8k"
|
||||
api_key_env = "MOONSHOT_API_KEY"
|
||||
base_url = "https://api.moonshot.cn/v1"
|
||||
|
||||
# MiniMax
|
||||
[model.minimax]
|
||||
provider = "openai-compat"
|
||||
model = "abab6.5-chat"
|
||||
api_key_env = "MINIMAX_API_KEY"
|
||||
base_url = "https://api.minimax.chat/v1"
|
||||
```
|
||||
|
||||
### 5. 启动服务
|
||||
|
||||
#### 前台运行(调试用)
|
||||
|
||||
```bash
|
||||
openfang start
|
||||
```
|
||||
|
||||
#### 后台守护进程
|
||||
|
||||
```bash
|
||||
# 启动守护进程
|
||||
openfang daemon start
|
||||
|
||||
# 查看状态
|
||||
openfang status
|
||||
|
||||
# 停止守护进程
|
||||
openfang daemon stop
|
||||
```
|
||||
|
||||
#### 检查健康状态
|
||||
|
||||
```bash
|
||||
openfang doctor
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 与 ZCLAW 集成
|
||||
|
||||
### 配置 ZCLAW 连接 OpenFang
|
||||
|
||||
编辑 ZCLAW 配置文件 `~/.zclaw/config.toml`:
|
||||
|
||||
```toml
|
||||
[gateway]
|
||||
# OpenFang API 端点
|
||||
endpoint = "http://127.0.0.1:50051"
|
||||
# WebSocket 端点
|
||||
ws_endpoint = "ws://127.0.0.1:50051/ws"
|
||||
# 连接超时(秒)
|
||||
timeout = 30
|
||||
|
||||
[model]
|
||||
# 使用 OpenFang 的模型路由
|
||||
use_gateway_routing = true
|
||||
```
|
||||
|
||||
### 验证连接
|
||||
|
||||
```bash
|
||||
# 启动 OpenFang
|
||||
openfang start
|
||||
|
||||
# 在另一个终端启动 ZCLAW
|
||||
cd desktop && pnpm tauri dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 端口被占用
|
||||
|
||||
**错误信息**:`Address already in use: 0.0.0.0:50051`
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```bash
|
||||
# 查找占用端口的进程
|
||||
# Windows
|
||||
netstat -ano | findstr :50051
|
||||
|
||||
# macOS / Linux
|
||||
lsof -i :50051
|
||||
|
||||
# 修改配置文件中的端口
|
||||
[api]
|
||||
port = 50052
|
||||
```
|
||||
|
||||
### 2. API Key 无效
|
||||
|
||||
**错误信息**:`Authentication failed` 或 `Invalid API key`
|
||||
|
||||
**排查步骤**:
|
||||
|
||||
1. 确认环境变量已设置:
|
||||
```bash
|
||||
# Windows
|
||||
echo $env:ZHIPU_API_KEY
|
||||
|
||||
# macOS / Linux
|
||||
echo $ZHIPU_API_KEY
|
||||
```
|
||||
|
||||
2. 确认 API Key 格式正确(无多余空格或引号)
|
||||
|
||||
3. 确认 API Key 未过期
|
||||
|
||||
### 3. 内存不足
|
||||
|
||||
**错误信息**:`Out of memory` 或系统卡顿
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 关闭不必要的服务
|
||||
2. 降低并发 Agent 数量
|
||||
3. 增加系统交换空间
|
||||
|
||||
### 4. 模型调用失败
|
||||
|
||||
**错误信息**:`Model not found` 或 `Provider error`
|
||||
|
||||
**排查步骤**:
|
||||
|
||||
1. 检查模型名称是否正确
|
||||
2. 确认 API 端点可访问
|
||||
3. 检查网络连接和代理设置
|
||||
|
||||
```bash
|
||||
# 测试 API 连通性
|
||||
curl -I https://open.bigmodel.cn/api/paas/v4/models
|
||||
```
|
||||
|
||||
### 5. 中文乱码
|
||||
|
||||
**解决方案**:
|
||||
|
||||
确保系统 locale 设置正确:
|
||||
|
||||
```bash
|
||||
# Windows
|
||||
chcp 65001
|
||||
|
||||
# macOS / Linux
|
||||
export LANG=zh_CN.UTF-8
|
||||
```
|
||||
|
||||
### 6. 从 OpenClaw 迁移
|
||||
|
||||
如果你之前使用 OpenClaw,可以使用迁移工具:
|
||||
|
||||
```bash
|
||||
# 迁移所有内容:代理、记忆、技能、配置
|
||||
openfang migrate --from openclaw
|
||||
|
||||
# 从特定路径迁移
|
||||
openfang migrate --from openclaw --path ~/.openclaw
|
||||
|
||||
# 先试运行查看变更
|
||||
openfang migrate --from openclaw --dry-run
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 进阶配置
|
||||
|
||||
### 配置 Hands
|
||||
|
||||
Hands 是 OpenFang 的核心创新,每个 Hand 是一个预构建的自主能力包:
|
||||
|
||||
```toml
|
||||
# ~/.openfang/data/hands/researcher.toml
|
||||
|
||||
[hand]
|
||||
name = "researcher"
|
||||
description = "深度研究助手"
|
||||
enabled = true
|
||||
|
||||
[hand.schedule]
|
||||
# 执行模式:continuous, periodic, manual
|
||||
mode = "manual"
|
||||
# 定时执行(cron 表达式)
|
||||
# cron = "0 9 * * *" # 每天早上 9 点
|
||||
|
||||
[hand.config]
|
||||
# 最大搜索深度
|
||||
max_depth = 5
|
||||
# 输出格式
|
||||
output_format = "markdown"
|
||||
# 引用格式
|
||||
citation_style = "apa"
|
||||
```
|
||||
|
||||
### 配置 MCP 服务器
|
||||
|
||||
```toml
|
||||
# ~/.openfang/config.toml
|
||||
|
||||
[[mcp_servers]]
|
||||
name = "filesystem"
|
||||
command = "mcp-filesystem"
|
||||
args = ["--root", "/path/to/allowed/dir"]
|
||||
|
||||
[[mcp_servers]]
|
||||
name = "postgres"
|
||||
command = "mcp-postgres"
|
||||
env = { DATABASE_URL = "postgresql://localhost/mydb" }
|
||||
```
|
||||
|
||||
### 配置渠道适配器
|
||||
|
||||
```toml
|
||||
# ~/.openfang/config.toml
|
||||
|
||||
[[channels]]
|
||||
type = "feishu"
|
||||
enabled = true
|
||||
|
||||
[channels.config]
|
||||
app_id = "cli_xxx"
|
||||
app_secret_env = "FEISHU_APP_SECRET"
|
||||
# 加密密钥(可选)
|
||||
encrypt_key_env = "FEISHU_ENCRYPT_KEY"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 性能调优
|
||||
|
||||
### 内存优化
|
||||
|
||||
```toml
|
||||
[memory]
|
||||
# 会话压缩阈值(token 数)
|
||||
compaction_threshold = 80000
|
||||
# 保留最近消息数
|
||||
keep_recent = 20
|
||||
# 向量嵌入缓存大小
|
||||
embedding_cache_size = 1000
|
||||
```
|
||||
|
||||
### 并发优化
|
||||
|
||||
```toml
|
||||
[runtime]
|
||||
# 最大并发工具调用
|
||||
max_concurrent_tools = 10
|
||||
# 工具执行超时(秒)
|
||||
tool_timeout = 60
|
||||
# Agent 循环最大迭代
|
||||
max_iterations = 50
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 日志与监控
|
||||
|
||||
### 查看日志
|
||||
|
||||
```bash
|
||||
# 实时日志
|
||||
openfang logs -f
|
||||
|
||||
# 按级别过滤
|
||||
openfang logs --level error
|
||||
|
||||
# 按时间范围
|
||||
openfang logs --since "2024-01-01" --until "2024-01-02"
|
||||
```
|
||||
|
||||
### 监控指标
|
||||
|
||||
```bash
|
||||
# 系统状态
|
||||
openfang status
|
||||
|
||||
# 详细健康检查
|
||||
openfang doctor --verbose
|
||||
|
||||
# 使用统计
|
||||
openfang usage --daily
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关链接
|
||||
|
||||
- [OpenFang 官方文档](https://openfang.sh/)
|
||||
- [GitHub 仓库](https://github.com/RightNow-AI/openfang)
|
||||
- [中文模型配置](./chinese-models.md)
|
||||
- [ZCLAW 主文档](../../README.md)
|
||||
|
||||
---
|
||||
|
||||
## 获取帮助
|
||||
|
||||
- **命令行帮助**:`openfang --help` 或 `openfang <command> --help`
|
||||
- **GitHub Issues**:https://github.com/RightNow-AI/openfang/issues
|
||||
- **社区讨论**:https://deepseek.club/t/topic/996
|
||||
472
docs/setup/chinese-models.md
Normal file
472
docs/setup/chinese-models.md
Normal file
@@ -0,0 +1,472 @@
|
||||
# 中文模型配置指南
|
||||
|
||||
> 本文档详细介绍 OpenFang Kernel 支持的中文大语言模型,以及如何获取和配置 API Key。
|
||||
|
||||
---
|
||||
|
||||
## 支持的中文模型
|
||||
|
||||
OpenFang 通过 OpenAI 兼容 API 支持所有主流中文模型提供商:
|
||||
|
||||
| 提供商 | 模型系列 | 特点 | 定价 |
|
||||
|--------|----------|------|------|
|
||||
| **智谱 AI** | GLM-4 | 国产领先,多模态支持 | 免费 + 付费 |
|
||||
| **阿里云** | 通义千问 (Qwen) | 性价比高,企业级 | 按量计费 |
|
||||
| **月之暗面** | Kimi | 长上下文(200K) | 按量计费 |
|
||||
| **MiniMax** | 海螺 AI | 语音能力强 | 按量计费 |
|
||||
| **百度** | 文心一言 | 企业应用广泛 | 按量计费 |
|
||||
| **DeepSeek** | DeepSeek | 编程能力强,低价 | 极低价格 |
|
||||
| **百川智能** | Baichuan | 中文优化 | 按量计费 |
|
||||
| **上海 AI Lab** | 书生浦语 | 开源模型 | 免费 |
|
||||
|
||||
---
|
||||
|
||||
## 1. 智谱 GLM
|
||||
|
||||
### 模型列表
|
||||
|
||||
| 模型 | 上下文 | 特点 | 适用场景 |
|
||||
|------|--------|------|----------|
|
||||
| `glm-4-flash` | 128K | 快速响应,免费额度 | 日常对话、快速问答 |
|
||||
| `glm-4` | 128K | 旗舰模型 | 复杂任务、推理 |
|
||||
| `glm-4-plus` | 128K | 增强版 | 专业应用 |
|
||||
| `glm-4-air` | 128K | 轻量版 | 简单任务 |
|
||||
| `glm-4v` | 8K | 多模态(图像理解) | 图像分析 |
|
||||
| `glm-4-long` | 1M | 超长上下文 | 长文档处理 |
|
||||
|
||||
### API Key 获取
|
||||
|
||||
1. 访问 [智谱开放平台](https://open.bigmodel.cn/)
|
||||
2. 注册/登录账号
|
||||
3. 进入「API Keys」页面
|
||||
4. 点击「创建 API Key」
|
||||
|
||||
**免费额度**:新用户赠送 1000 万 tokens
|
||||
|
||||
### 配置示例
|
||||
|
||||
```toml
|
||||
[model.zhipu]
|
||||
provider = "zhipu"
|
||||
model = "glm-4-flash"
|
||||
api_key_env = "ZHIPU_API_KEY"
|
||||
base_url = "https://open.bigmodel.cn/api/paas/v4"
|
||||
```
|
||||
|
||||
```bash
|
||||
# 设置环境变量
|
||||
export ZHIPU_API_KEY="your-zhipu-api-key"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 通义千问 (Qwen)
|
||||
|
||||
### 模型列表
|
||||
|
||||
| 模型 | 上下文 | 特点 | 适用场景 |
|
||||
|------|--------|------|----------|
|
||||
| `qwen-turbo` | 8K | 快速版 | 快速问答 |
|
||||
| `qwen-plus` | 32K | 增强版 | 复杂任务 |
|
||||
| `qwen-max` | 32K | 旗舰版 | 高质量输出 |
|
||||
| `qwen-max-longcontext` | 200K | 长上下文 | 长文档 |
|
||||
| `qwen-vl-plus` | 8K | 多模态 | 图像理解 |
|
||||
| `qwen-vl-max` | 8K | 多模态增强 | 高精度图像 |
|
||||
|
||||
### API Key 获取
|
||||
|
||||
1. 访问 [阿里云百炼](https://dashscope.console.aliyun.com/)
|
||||
2. 登录阿里云账号
|
||||
3. 开通「灵积模型服务」
|
||||
4. 获取 API Key
|
||||
|
||||
**免费额度**:部分模型有免费试用
|
||||
|
||||
### 配置示例
|
||||
|
||||
```toml
|
||||
[model.qwen]
|
||||
provider = "openai-compat"
|
||||
model = "qwen-turbo"
|
||||
api_key_env = "DASHSCOPE_API_KEY"
|
||||
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||
```
|
||||
|
||||
```bash
|
||||
# 设置环境变量
|
||||
export DASHSCOPE_API_KEY="your-dashscope-api-key"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Kimi (Moonshot)
|
||||
|
||||
### 模型列表
|
||||
|
||||
| 模型 | 上下文 | 特点 | 适用场景 |
|
||||
|------|--------|------|----------|
|
||||
| `moonshot-v1-8k` | 8K | 基础版 | 日常对话 |
|
||||
| `moonshot-v1-32k` | 32K | 长上下文 | 中等文档 |
|
||||
| `moonshot-v1-128k` | 128K | 超长上下文 | 长文档分析 |
|
||||
|
||||
### API Key 获取
|
||||
|
||||
1. 访问 [Moonshot AI 开放平台](https://platform.moonshot.cn/)
|
||||
2. 注册/登录账号
|
||||
3. 进入「API Key 管理」
|
||||
4. 创建新的 API Key
|
||||
|
||||
**免费额度**:新用户赠送 15 元体验金
|
||||
|
||||
### 配置示例
|
||||
|
||||
```toml
|
||||
[model.kimi]
|
||||
provider = "openai-compat"
|
||||
model = "moonshot-v1-8k"
|
||||
api_key_env = "MOONSHOT_API_KEY"
|
||||
base_url = "https://api.moonshot.cn/v1"
|
||||
```
|
||||
|
||||
```bash
|
||||
# 设置环境变量
|
||||
export MOONSHOT_API_KEY="your-moonshot-api-key"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. MiniMax
|
||||
|
||||
### 模型列表
|
||||
|
||||
| 模型 | 上下文 | 特点 | 适用场景 |
|
||||
|------|--------|------|----------|
|
||||
| `abab6.5-chat` | 8K | 旗舰对话 | 通用对话 |
|
||||
| `abab6.5s-chat` | 8K | 快速版 | 快速响应 |
|
||||
| `abab6.5g-chat` | 8K | 通用版 | 平衡场景 |
|
||||
| `abab5.5-chat` | 16K | 经典版 | 日常使用 |
|
||||
| `abab5.5s-chat` | 16K | 轻量版 | 简单任务 |
|
||||
|
||||
### API Key 获取
|
||||
|
||||
1. 访问 [MiniMax 开放平台](https://www.minimaxi.com/)
|
||||
2. 注册/登录账号
|
||||
3. 进入「账户管理」->「API Key」
|
||||
4. 创建 API Key
|
||||
|
||||
**注意**:MiniMax 需要同时配置 Group ID
|
||||
|
||||
### 配置示例
|
||||
|
||||
```toml
|
||||
[model.minimax]
|
||||
provider = "openai-compat"
|
||||
model = "abab6.5-chat"
|
||||
api_key_env = "MINIMAX_API_KEY"
|
||||
base_url = "https://api.minimax.chat/v1"
|
||||
|
||||
[model.minimax.headers]
|
||||
# MiniMax 需要 Group ID
|
||||
"x-minimax-group-id" = "your-group-id"
|
||||
```
|
||||
|
||||
```bash
|
||||
# 设置环境变量
|
||||
export MINIMAX_API_KEY="your-minimax-api-key"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. DeepSeek
|
||||
|
||||
### 模型列表
|
||||
|
||||
| 模型 | 上下文 | 特点 | 适用场景 |
|
||||
|------|--------|------|----------|
|
||||
| `deepseek-chat` | 64K | 通用对话 | 日常使用 |
|
||||
| `deepseek-coder` | 16K | 代码专精 | 编程任务 |
|
||||
| `deepseek-reasoner` | 64K | 深度推理 | 复杂推理 |
|
||||
|
||||
### API Key 获取
|
||||
|
||||
1. 访问 [DeepSeek 开放平台](https://platform.deepseek.com/)
|
||||
2. 注册/登录账号
|
||||
3. 进入「API Keys」页面
|
||||
4. 创建 API Key
|
||||
|
||||
**定价优势**:极低价格,性价比高
|
||||
|
||||
### 配置示例
|
||||
|
||||
```toml
|
||||
[model.deepseek]
|
||||
provider = "openai-compat"
|
||||
model = "deepseek-chat"
|
||||
api_key_env = "DEEPSEEK_API_KEY"
|
||||
base_url = "https://api.deepseek.com"
|
||||
```
|
||||
|
||||
```bash
|
||||
# 设置环境变量
|
||||
export DEEPSEEK_API_KEY="your-deepseek-api-key"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 百度文心一言
|
||||
|
||||
### 模型列表
|
||||
|
||||
| 模型 | 上下文 | 特点 | 适用场景 |
|
||||
|------|--------|------|----------|
|
||||
| `ernie-4.0-8k` | 8K | 旗舰版 | 复杂任务 |
|
||||
| `ernie-3.5-8k` | 8K | 标准版 | 日常使用 |
|
||||
| `ernie-speed-8k` | 8K | 快速版 | 快速响应 |
|
||||
| `ernie-lite-8k` | 8K | 轻量版 | 简单任务 |
|
||||
|
||||
### API Key 获取
|
||||
|
||||
1. 访问 [百度智能云千帆平台](https://console.bce.baidu.com/qianfan/)
|
||||
2. 登录百度账号
|
||||
3. 创建应用,获取 API Key 和 Secret Key
|
||||
|
||||
**注意**:文心一言使用 access_token 认证,需要额外处理
|
||||
|
||||
### 配置示例
|
||||
|
||||
```toml
|
||||
[model.wenxin]
|
||||
provider = "openai-compat"
|
||||
model = "ernie-4.0-8k"
|
||||
api_key_env = "WENXIN_ACCESS_TOKEN"
|
||||
base_url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 百川智能
|
||||
|
||||
### 模型列表
|
||||
|
||||
| 模型 | 上下文 | 特点 | 适用场景 |
|
||||
|------|--------|------|----------|
|
||||
| `Baichuan4` | 128K | 旗舰版 | 复杂任务 |
|
||||
| `Baichuan3-Turbo` | 32K | 快速版 | 日常使用 |
|
||||
| `Baichuan3-Turbo-128k` | 128K | 长上下文 | 长文档 |
|
||||
|
||||
### API Key 获取
|
||||
|
||||
1. 访问 [百川智能开放平台](https://platform.baichuan-ai.com/)
|
||||
2. 注册/登录账号
|
||||
3. 获取 API Key
|
||||
|
||||
### 配置示例
|
||||
|
||||
```toml
|
||||
[model.baichuan]
|
||||
provider = "openai-compat"
|
||||
model = "Baichuan4"
|
||||
api_key_env = "BAICHUAN_API_KEY"
|
||||
base_url = "https://api.baichuan-ai.com/v1"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 本地模型 (Ollama)
|
||||
|
||||
如果你想在本地运行开源中文模型:
|
||||
|
||||
### 支持的开源模型
|
||||
|
||||
| 模型 | 参数量 | 内存需求 | 特点 |
|
||||
|------|--------|----------|------|
|
||||
| `qwen2:7b` | 7B | 8GB | 通用对话 |
|
||||
| `qwen2:14b` | 14B | 16GB | 高质量输出 |
|
||||
| `glm4:9b` | 9B | 12GB | 智谱开源版 |
|
||||
| `deepseek-coder:6.7b` | 6.7B | 8GB | 代码专精 |
|
||||
|
||||
### 安装 Ollama
|
||||
|
||||
```bash
|
||||
# macOS / Linux
|
||||
curl -fsSL https://ollama.com/install.sh | sh
|
||||
|
||||
# Windows
|
||||
# 访问 https://ollama.com/download 下载安装包
|
||||
```
|
||||
|
||||
### 下载模型
|
||||
|
||||
```bash
|
||||
# 下载通义千问
|
||||
ollama pull qwen2:7b
|
||||
|
||||
# 下载 GLM4
|
||||
ollama pull glm4:9b
|
||||
```
|
||||
|
||||
### 配置示例
|
||||
|
||||
```toml
|
||||
[model.ollama]
|
||||
provider = "openai-compat"
|
||||
model = "qwen2:7b"
|
||||
base_url = "http://localhost:11434/v1"
|
||||
# 本地模型无需 API Key
|
||||
api_key_env = ""
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 多模型配置
|
||||
|
||||
OpenFang 支持同时配置多个模型,并自动路由:
|
||||
|
||||
```toml
|
||||
# ~/.openfang/config.toml
|
||||
|
||||
[model]
|
||||
# 默认模型
|
||||
provider = "zhipu"
|
||||
model = "glm-4-flash"
|
||||
|
||||
# 备选模型
|
||||
[[model.alternates]]
|
||||
name = "coding"
|
||||
provider = "deepseek"
|
||||
model = "deepseek-coder"
|
||||
api_key_env = "DEEPSEEK_API_KEY"
|
||||
|
||||
[[model.alternates]]
|
||||
name = "long-context"
|
||||
provider = "kimi"
|
||||
model = "moonshot-v1-128k"
|
||||
api_key_env = "MOONSHOT_API_KEY"
|
||||
|
||||
[[model.alternates]]
|
||||
name = "local"
|
||||
provider = "openai-compat"
|
||||
model = "qwen2:7b"
|
||||
base_url = "http://localhost:11434/v1"
|
||||
|
||||
# 模型路由规则
|
||||
[model.routing]
|
||||
# 编程任务使用 DeepSeek Coder
|
||||
coding = ["deepseek-coder", "glm-4"]
|
||||
# 长文档使用 Kimi
|
||||
long_context = ["moonshot-v1-128k", "glm-4-long"]
|
||||
# 快速响应使用 Flash 或本地模型
|
||||
fast = ["glm-4-flash", "qwen2:7b"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 价格对比
|
||||
|
||||
| 模型 | 输入价格 (元/百万 tokens) | 输出价格 (元/百万 tokens) |
|
||||
|------|---------------------------|---------------------------|
|
||||
| GLM-4-Flash | 免费 | 免费 |
|
||||
| GLM-4 | 100 | 100 |
|
||||
| 通义千问-Turbo | 2 | 6 |
|
||||
| 通义千问-Max | 40 | 120 |
|
||||
| Kimi-8K | 12 | 12 |
|
||||
| DeepSeek-Chat | 1 | 2 |
|
||||
| DeepSeek-Coder | 1 | 2 |
|
||||
|
||||
*价格仅供参考,以官方最新公告为准*
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 模型选择建议
|
||||
|
||||
| 场景 | 推荐模型 | 理由 |
|
||||
|------|----------|------|
|
||||
| 日常对话 | GLM-4-Flash | 免费且速度快 |
|
||||
| 编程任务 | DeepSeek-Coder | 专业代码能力 |
|
||||
| 长文档分析 | Kimi-128K | 超长上下文 |
|
||||
| 复杂推理 | GLM-4 / Qwen-Max | 高质量输出 |
|
||||
| 离线使用 | Ollama + Qwen2 | 本地运行 |
|
||||
|
||||
### 2. API Key 安全
|
||||
|
||||
- 永远不要在代码或配置文件中硬编码 API Key
|
||||
- 使用环境变量存储敏感信息
|
||||
- 定期轮换 API Key
|
||||
- 为不同项目使用不同的 API Key
|
||||
- 设置 API Key 使用额度限制
|
||||
|
||||
### 3. 成本控制
|
||||
|
||||
```toml
|
||||
[metering]
|
||||
# 每日最大花费(美元)
|
||||
daily_budget = 5.0
|
||||
# 每个 Agent 每小时最大 tokens
|
||||
hourly_token_limit = 100000
|
||||
# 超限行为:reject(拒绝)或 downgrade(降级)
|
||||
on_limit = "downgrade"
|
||||
# 降级到的模型
|
||||
fallback_model = "glm-4-flash"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 如何测试 API Key 是否有效?
|
||||
|
||||
```bash
|
||||
# 使用 curl 测试智谱 API
|
||||
curl -X POST https://open.bigmodel.cn/api/paas/v4/chat/completions \
|
||||
-H "Authorization: Bearer $ZHIPU_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"model": "glm-4-flash", "messages": [{"role": "user", "content": "你好"}]}'
|
||||
```
|
||||
|
||||
### Q: 多个模型如何切换?
|
||||
|
||||
在 Agent 配置中指定:
|
||||
|
||||
```toml
|
||||
[agent.my-agent]
|
||||
[model]
|
||||
provider = "deepseek"
|
||||
model = "deepseek-coder"
|
||||
```
|
||||
|
||||
### Q: 如何查看用量?
|
||||
|
||||
```bash
|
||||
# 查看今日用量
|
||||
openfang usage --today
|
||||
|
||||
# 查看本月用量
|
||||
openfang usage --month
|
||||
|
||||
# 按模型分组
|
||||
openfang usage --group-by model
|
||||
```
|
||||
|
||||
### Q: API Key 泄露了怎么办?
|
||||
|
||||
1. 立即在对应平台撤销泄露的 Key
|
||||
2. 生成新的 API Key
|
||||
3. 更新环境变量
|
||||
4. 检查账单是否有异常使用
|
||||
|
||||
---
|
||||
|
||||
## 相关链接
|
||||
|
||||
- [智谱开放平台](https://open.bigmodel.cn/)
|
||||
- [阿里云百炼](https://dashscope.console.aliyun.com/)
|
||||
- [Moonshot 平台](https://platform.moonshot.cn/)
|
||||
- [MiniMax 开放平台](https://www.minimaxi.com/)
|
||||
- [DeepSeek 平台](https://platform.deepseek.com/)
|
||||
- [Ollama 官网](https://ollama.com/)
|
||||
|
||||
---
|
||||
|
||||
*最后更新:2026 年 3 月*
|
||||
225
scripts/quick-start-dev.ps1
Normal file
225
scripts/quick-start-dev.ps1
Normal file
@@ -0,0 +1,225 @@
|
||||
#Requires -Version 5.1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
ZCLAW 开发环境快速启动脚本
|
||||
|
||||
.DESCRIPTION
|
||||
检查依赖、启动后端服务、启动桌面端开发环境
|
||||
|
||||
.PARAMETER SkipBackend
|
||||
跳过后端启动(假设后端已运行)
|
||||
|
||||
.PARAMETER DesktopOnly
|
||||
仅启动桌面端
|
||||
|
||||
.PARAMETER Stop
|
||||
停止所有服务
|
||||
|
||||
.EXAMPLE
|
||||
.\scripts\quick-start-dev.ps1
|
||||
.\scripts\quick-start-dev.ps1 -SkipBackend
|
||||
.\scripts\quick-start-dev.ps1 -Stop
|
||||
#>
|
||||
|
||||
param(
|
||||
[switch]$SkipBackend,
|
||||
[switch]$DesktopOnly,
|
||||
[switch]$Stop
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ProjectRoot = $PSScriptRoot | Split-Path -Parent
|
||||
|
||||
# 颜色输出函数
|
||||
function Write-Step {
|
||||
param([string]$Message)
|
||||
Write-Host "`n[STEP] $Message" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
function Write-Success {
|
||||
param([string]$Message)
|
||||
Write-Host "[OK] $Message" -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Write-Warning {
|
||||
param([string]$Message)
|
||||
Write-Host "[WARN] $Message" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
function Write-Error {
|
||||
param([string]$Message)
|
||||
Write-Host "[ERROR] $Message" -ForegroundColor Red
|
||||
}
|
||||
|
||||
# 停止服务
|
||||
if ($Stop) {
|
||||
Write-Step "停止所有服务..."
|
||||
|
||||
# 停止 OpenFang
|
||||
$openfang = Get-Process -Name "openfang" -ErrorAction SilentlyContinue
|
||||
if ($openfang) {
|
||||
Stop-Process -Name "openfang" -Force -ErrorAction SilentlyContinue
|
||||
Write-Success "OpenFang 已停止"
|
||||
}
|
||||
|
||||
# 停止 Vite
|
||||
$vite = Get-Process -Name "node" -ErrorAction SilentlyContinue | Where-Object { $_.MainWindowTitle -like "*vite*" -or $_.CommandLine -like "*vite*" }
|
||||
if ($vite) {
|
||||
$vite | Stop-Process -Force -ErrorAction SilentlyContinue
|
||||
Write-Success "Vite 进程已停止"
|
||||
}
|
||||
|
||||
# 调用项目的停止脚本
|
||||
$stopScript = Join-Path $ProjectRoot "start-all.ps1"
|
||||
if (Test-Path $stopScript) {
|
||||
& $stopScript -Stop
|
||||
}
|
||||
|
||||
Write-Success "所有服务已停止"
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host " ZCLAW Development Quick Start" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
|
||||
# 1. 检查 Node.js
|
||||
Write-Step "检查 Node.js..."
|
||||
try {
|
||||
$nodeVersion = node -v
|
||||
if ($nodeVersion -match "v(\d+)") {
|
||||
$majorVersion = [int]$Matches[1]
|
||||
if ($majorVersion -lt 18) {
|
||||
Write-Error "Node.js 版本过低: $nodeVersion (需要 18+)"
|
||||
Write-Host "请从 https://nodejs.org 安装最新版本"
|
||||
exit 1
|
||||
}
|
||||
Write-Success "Node.js $nodeVersion"
|
||||
}
|
||||
} catch {
|
||||
Write-Error "未找到 Node.js,请从 https://nodejs.org 安装"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 2. 检查 pnpm
|
||||
Write-Step "检查 pnpm..."
|
||||
try {
|
||||
$pnpmVersion = pnpm -v
|
||||
Write-Success "pnpm $pnpmVersion"
|
||||
} catch {
|
||||
Write-Warning "未找到 pnpm,正在安装..."
|
||||
npm install -g pnpm
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "pnpm 安装失败"
|
||||
exit 1
|
||||
}
|
||||
Write-Success "pnpm 安装完成"
|
||||
}
|
||||
|
||||
# 3. 检查依赖安装
|
||||
Write-Step "检查依赖..."
|
||||
$nodeModules = Join-Path $ProjectRoot "node_modules"
|
||||
$desktopModules = Join-Path $ProjectRoot "desktop\node_modules"
|
||||
|
||||
if (-not (Test-Path $nodeModules)) {
|
||||
Write-Host "安装根目录依赖..."
|
||||
Push-Location $ProjectRoot
|
||||
pnpm install
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
if (-not (Test-Path $desktopModules)) {
|
||||
Write-Host "安装桌面端依赖..."
|
||||
Push-Location (Join-Path $ProjectRoot "desktop")
|
||||
pnpm install
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
Write-Success "依赖已就绪"
|
||||
|
||||
# 4. 检查/启动后端
|
||||
if (-not $SkipBackend -and -not $DesktopOnly) {
|
||||
Write-Step "检查后端服务..."
|
||||
|
||||
$backendRunning = $false
|
||||
try {
|
||||
$response = Invoke-WebRequest -Uri "http://127.0.0.1:50051/api/health" -TimeoutSec 2 -UseBasicParsing -ErrorAction SilentlyContinue
|
||||
if ($response.StatusCode -eq 200) {
|
||||
$backendRunning = $true
|
||||
Write-Success "后端服务已运行"
|
||||
}
|
||||
} catch {
|
||||
# 后端未运行
|
||||
}
|
||||
|
||||
if (-not $backendRunning) {
|
||||
Write-Host "启动 OpenFang 后端..."
|
||||
|
||||
# 尝试多种方式启动
|
||||
$started = $false
|
||||
|
||||
# 方式 1: 使用 openfang CLI
|
||||
try {
|
||||
$openfangCmd = Get-Command "openfang" -ErrorAction SilentlyContinue
|
||||
if ($openfangCmd) {
|
||||
Start-Process -FilePath "openfang" -ArgumentList "start" -NoNewWindow
|
||||
$started = $true
|
||||
}
|
||||
} catch {}
|
||||
|
||||
# 方式 2: 使用 pnpm 脚本
|
||||
if (-not $started) {
|
||||
$startScript = Join-Path $ProjectRoot "start-all.ps1"
|
||||
if (Test-Path $startScript) {
|
||||
Start-Process -FilePath "powershell" -ArgumentList "-ExecutionPolicy", "Bypass", "-File", $startScript -NoNewWindow
|
||||
$started = $true
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $started) {
|
||||
Write-Error "无法启动后端服务"
|
||||
Write-Host "请手动启动 OpenFang:"
|
||||
Write-Host " openfang start"
|
||||
Write-Host " 或运行 start-all.ps1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 等待后端启动
|
||||
Write-Host "等待后端启动..."
|
||||
$retries = 0
|
||||
$maxRetries = 15
|
||||
while ($retries -lt $maxRetries) {
|
||||
Start-Sleep -Seconds 1
|
||||
try {
|
||||
$response = Invoke-WebRequest -Uri "http://127.0.0.1:50051/api/health" -TimeoutSec 2 -UseBasicParsing -ErrorAction SilentlyContinue
|
||||
if ($response.StatusCode -eq 200) {
|
||||
Write-Success "后端服务启动成功"
|
||||
break
|
||||
}
|
||||
} catch {}
|
||||
$retries++
|
||||
Write-Host "." -NoNewline
|
||||
}
|
||||
|
||||
if ($retries -ge $maxRetries) {
|
||||
Write-Error "后端启动超时"
|
||||
Write-Host "请检查 OpenFang 是否正确安装"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 5. 启动开发环境
|
||||
Write-Step "启动开发环境..."
|
||||
|
||||
Push-Location $ProjectRoot
|
||||
|
||||
if ($DesktopOnly) {
|
||||
Write-Host "仅启动桌面端..."
|
||||
pnpm desktop
|
||||
} else {
|
||||
Write-Host "启动完整开发环境..."
|
||||
pnpm start:dev
|
||||
}
|
||||
|
||||
Pop-Location
|
||||
218
scripts/quick-start.sh
Normal file
218
scripts/quick-start.sh
Normal file
@@ -0,0 +1,218 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# ZCLAW Development Quick Start Script
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/quick-start.sh [options]
|
||||
#
|
||||
# Options:
|
||||
# --skip-backend Skip backend startup (assume already running)
|
||||
# --desktop-only Start desktop only
|
||||
# --stop Stop all services
|
||||
# --help Show this help message
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
SKIP_BACKEND=false
|
||||
DESKTOP_ONLY=false
|
||||
STOP_SERVICES=false
|
||||
|
||||
# Parse arguments
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--skip-backend)
|
||||
SKIP_BACKEND=true
|
||||
shift
|
||||
;;
|
||||
--desktop-only)
|
||||
DESKTOP_ONLY=true
|
||||
shift
|
||||
;;
|
||||
--stop)
|
||||
STOP_SERVICES=true
|
||||
shift
|
||||
;;
|
||||
--help)
|
||||
echo "ZCLAW Development Quick Start Script"
|
||||
echo ""
|
||||
echo "Usage: $0 [options]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --skip-backend Skip backend startup"
|
||||
echo " --desktop-only Start desktop only"
|
||||
echo " --stop Stop all services"
|
||||
echo " --help Show this help"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $arg"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Output functions
|
||||
step() {
|
||||
echo -e "\n${CYAN}[STEP]${NC} $1"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "${GREEN}[OK]${NC} $1"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Stop services
|
||||
if [ "$STOP_SERVICES" = true ]; then
|
||||
step "Stopping all services..."
|
||||
|
||||
# Kill OpenFang processes
|
||||
pkill -f "openfang" 2>/dev/null || true
|
||||
|
||||
# Kill Vite processes
|
||||
pkill -f "vite" 2>/dev/null || true
|
||||
|
||||
# Kill Tauri processes
|
||||
pkill -f "tauri" 2>/dev/null || true
|
||||
|
||||
success "All services stopped"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo -e "${CYAN}========================================${NC}"
|
||||
echo -e "${CYAN} ZCLAW Development Quick Start${NC}"
|
||||
echo -e "${CYAN}========================================${NC}"
|
||||
|
||||
# 1. Check Node.js
|
||||
step "Checking Node.js..."
|
||||
if ! command -v node &> /dev/null; then
|
||||
error "Node.js not found"
|
||||
echo "Please install from https://nodejs.org"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NODE_VERSION=$(node -v | sed 's/v//')
|
||||
MAJOR_VERSION=$(echo "$NODE_VERSION" | cut -d. -f1)
|
||||
|
||||
if [ "$MAJOR_VERSION" -lt 18 ]; then
|
||||
error "Node.js version too low: v$NODE_VERSION (requires 18+)"
|
||||
echo "Please upgrade from https://nodejs.org"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
success "Node.js $(node -v)"
|
||||
|
||||
# 2. Check pnpm
|
||||
step "Checking pnpm..."
|
||||
if ! command -v pnpm &> /dev/null; then
|
||||
warn "pnpm not found, installing..."
|
||||
npm install -g pnpm
|
||||
if [ $? -ne 0 ]; then
|
||||
error "Failed to install pnpm"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
success "pnpm $(pnpm -v)"
|
||||
|
||||
# 3. Check and install dependencies
|
||||
step "Checking dependencies..."
|
||||
|
||||
if [ ! -d "$PROJECT_ROOT/node_modules" ]; then
|
||||
echo "Installing root dependencies..."
|
||||
cd "$PROJECT_ROOT"
|
||||
pnpm install
|
||||
fi
|
||||
|
||||
if [ ! -d "$PROJECT_ROOT/desktop/node_modules" ]; then
|
||||
echo "Installing desktop dependencies..."
|
||||
cd "$PROJECT_ROOT/desktop"
|
||||
pnpm install
|
||||
fi
|
||||
|
||||
success "Dependencies ready"
|
||||
|
||||
# 4. Check/Start backend
|
||||
if [ "$SKIP_BACKEND" = false ] && [ "$DESKTOP_ONLY" = false ]; then
|
||||
step "Checking backend service..."
|
||||
|
||||
BACKEND_RUNNING=false
|
||||
|
||||
if curl -s --connect-timeout 2 "http://127.0.0.1:50051/api/health" > /dev/null 2>&1; then
|
||||
BACKEND_RUNNING=true
|
||||
success "Backend service already running"
|
||||
fi
|
||||
|
||||
if [ "$BACKEND_RUNNING" = false ]; then
|
||||
echo "Starting OpenFang backend..."
|
||||
|
||||
STARTED=false
|
||||
|
||||
# Method 1: Use openfang CLI
|
||||
if command -v openfang &> /dev/null; then
|
||||
openfang start &
|
||||
STARTED=true
|
||||
fi
|
||||
|
||||
# Method 2: Use the project's start script
|
||||
if [ "$STARTED" = false ] && [ -f "$PROJECT_ROOT/start-all.sh" ]; then
|
||||
"$PROJECT_ROOT/start-all.sh" &
|
||||
STARTED=true
|
||||
fi
|
||||
|
||||
if [ "$STARTED" = false ]; then
|
||||
error "Cannot start backend service"
|
||||
echo "Please start OpenFang manually:"
|
||||
echo " openfang start"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Wait for backend
|
||||
echo "Waiting for backend to start..."
|
||||
RETRIES=0
|
||||
MAX_RETRIES=15
|
||||
|
||||
while [ $RETRIES -lt $MAX_RETRIES ]; do
|
||||
sleep 1
|
||||
if curl -s --connect-timeout 2 "http://127.0.0.1:50051/api/health" > /dev/null 2>&1; then
|
||||
success "Backend started successfully"
|
||||
break
|
||||
fi
|
||||
RETRIES=$((RETRIES + 1))
|
||||
printf "."
|
||||
done
|
||||
|
||||
if [ $RETRIES -ge $MAX_RETRIES ]; then
|
||||
error "Backend startup timeout"
|
||||
echo "Please check if OpenFang is properly installed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# 5. Start development environment
|
||||
step "Starting development environment..."
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
if [ "$DESKTOP_ONLY" = true ]; then
|
||||
echo "Starting desktop only..."
|
||||
pnpm desktop
|
||||
else
|
||||
echo "Starting full development environment..."
|
||||
pnpm start:dev
|
||||
fi
|
||||
Reference in New Issue
Block a user