# ZCLAW Admin V2 与 Desktop 系统定位设计 > 日期: 2026-03-30 > 状态: Draft > 范围: Admin V2 定位 + Desktop 集成 + Token Pool + Agent 模板 ## 1. 系统定位 ### 1.1 Admin V2 — 资源管理与配置中心 **目标用户**: 系统管理员、运营人员 **核心职责**: 1. **账号管理** — 用户 CRUD、角色权限、LLM 路由模式配置 2. **Token 池管理** — 多提供商多密钥的统一池化管理,解决 Coding Plan 套餐的时段限额和资源浪费问题 3. **行业 Agent 模板** — 预调教好的行业 Agent 人设(含 soul.md、system_prompt、工具集),供 Desktop 首次使用时获取 4. **系统监控** — 用量统计、日志审计、配置管理 ### 1.2 Desktop (Agent 会话端) — 终端用户界面 **目标用户**: 终端用户(AI Agent 操作者) **核心职责**: 1. **智能对话** — 流式响应、多模型切换、上下文管理 2. **Agent 管理** — 创建、配置、切换 Agent(支持从 SaaS 模板初始化) 3. **自主能力** — Hands 触发、工作流编排、技能调用 4. **智能成长** — Agent 通过对话逐步成长,记忆、反思、身份演化 ### 1.3 数据流 ``` Admin V2 (配置) → SaaS API → PostgreSQL ↓ Desktop (登录) → SaaS API → 拉取 AccountProfile { llm_routing, available_templates } ↓ ┌─────────┴──────────┐ │ │ relay 模式 local 模式 │ │ SaaS Relay Tauri Kernel │ │ Key Pool 旋转 本地 API Key │ │ LLM Provider LLM Provider ``` --- ## 2. 账号级 LLM 路由 ### 2.1 背景 国内 LLM 厂商推出 Coding Plan 套餐,但套餐有时段使用量限额。每个 Desktop 客户端各自配置 API Key 会造成资源浪费。在 Admin 端搭建 Token 池,多账号共享密钥资源,成本更优。 ### 2.2 数据层 `accounts` 表新增: ```sql ALTER TABLE accounts ADD COLUMN llm_routing TEXT NOT NULL DEFAULT 'local' CHECK (llm_routing IN ('relay', 'local')); COMMENT ON COLUMN accounts.llm_routing IS 'LLM路由模式: relay=SaaS中转, local=本地直连'; ``` 默认值 `local`,保持向后兼容。 ### 2.3 API 层 **登录响应扩展**: `POST /api/v1/auth/login` 和 `GET /api/v1/auth/me` 返回值增加: ```typescript { token: string; refresh_token: string; account: { id: string; username: string; role: string; llm_routing: 'relay' | 'local'; // 新增 // ... 现有字段 } } ``` **Admin 端账号管理**: `PATCH /api/v1/accounts/:id` 请求体支持 `llm_routing` 字段更新,仅 `account:admin` 权限可修改。 ### 2.4 Desktop 行为 `saasStore` 登录成功后读取 `account.llm_routing`,写入 `connectionStore`: - `'relay'` → 使用 `SaaSClient.chatCompletion()` 走 SaaS Relay,无需启动本地 Kernel - `'local'` → 使用 `KernelClient` 走本地 Tauri Kernel 路由模式在登录时确定,会话期间不变。切换需要管理员修改 + 用户重新登录。 --- ## 3. Token Pool / Key Pool 管理 ### 3.1 现状 后端 Key Pool 已完整实现: - `select_best_key()`: 优先级排序 + RPM/TPM 滑窗检查 - `mark_key_429()`: 429 自动冷却 + `Retry-After` 支持 - `record_key_usage()`: 分钟粒度用量记录 - SSRF 防护、加密存储、降级回退 Admin UI 为只读(仅显示密钥列表),缺少添加/切换/删除操作。 ### 3.2 Admin UI 补全 Providers 页面 Key Pool Modal 升级为完整管理: | 操作 | 交互 | 说明 | |------|------|------| | 添加密钥 | 点击"添加"按钮 → 弹出表单 | 字段: label, key_value, priority, max_rpm(可选), max_tpm(可选) | | 启用/禁用 | 切换 Switch 组件 | 调用 `PUT /providers/:id/keys/:keyId/toggle` | | 删除密钥 | 点击删除 → Popconfirm 确认 | 调用 `DELETE /providers/:id/keys/:keyId` | | 状态展示 | 表格列 | 每个密钥显示: 状态、priority、RPM/TPM 配额、当前窗口用量、总用量 | 前端使用 `providerService.addKey()`, `providerService.toggleKey()`, `providerService.deleteKey()` — 这些 service 方法已定义但未使用,直接接入即可。 ### 3.3 缺陷修复 | 缺陷 | 修复方案 | 优先级 | |------|---------|--------| | `key_usage_window` 无清理 | Scheduler 增加定时任务,清理 >24h 的窗口记录 | P1 | | 同优先级无负载分散 | `select_best_key()` 加入"最近最少使用"次排序 | P2 | | `quota_reset_interval` 未使用 | 移除字段或实现按 interval 重置配额逻辑 | P3 | --- ## 4. 行业 Agent 模板系统 ### 4.1 背景 通过预设行业 Agent 模板(如医疗行业),预先调教好完整的 Agent 人设。Desktop 端首次使用时从 SaaS 获取完整模板配置,之后 Agent 由用户对话驱动逐步成长,不再与模板同步。 ### 4.2 数据层 — 扩展 agent_templates ```sql ALTER TABLE agent_templates ADD COLUMN soul_content TEXT; ALTER TABLE agent_templates ADD COLUMN scenarios TEXT NOT NULL DEFAULT '[]'; ALTER TABLE agent_templates ADD COLUMN welcome_message TEXT; ALTER TABLE agent_templates ADD COLUMN quick_commands TEXT NOT NULL DEFAULT '[]'; ALTER TABLE agent_templates ADD COLUMN personality TEXT; ALTER TABLE agent_templates ADD COLUMN communication_style TEXT; ALTER TABLE agent_templates ADD COLUMN emoji TEXT; ALTER TABLE agent_templates ADD COLUMN version INTEGER NOT NULL DEFAULT 1; ALTER TABLE agent_templates ADD COLUMN source_id TEXT UNIQUE; ``` 字段说明: | 字段 | 类型 | 说明 | |------|------|------| | `soul_content` | TEXT | SOUL.md 人格配置全文 (Markdown) | | `scenarios` | JSON | 场景标签数组,如 `["临床辅助", "文献检索"]` | | `welcome_message` | TEXT | 首次问候语 | | `quick_commands` | JSON | 快捷指令数组 `[{label, prompt}]` | | `personality` | TEXT | 人格预设: professional/friendly/creative/concise | | `communication_style` | TEXT | 沟通风格描述文本 | | `emoji` | TEXT | Agent 图标 | | `version` | INT | 模板版本号,用于新用户获取最新版 | | `source_id` | TEXT | 模板唯一标识,用于 Desktop 去重 | ### 4.3 种子模板示例 — 医疗行业 ```typescript { name: "医疗助手", source_id: "medical-assistant-v1", category: "healthcare", description: "医疗行业专业 AI 助手,熟悉临床流程、医学文献和诊疗规范", emoji: "🏥", personality: "professional", system_prompt: "你是一位专业的医疗AI助手,具备以下能力:\n1. 临床辅助诊断建议\n2. 医学文献检索与解读\n3. 用药参考与相互作用检查\n4. 诊疗规范查询\n\n注意: 你的建议仅供参考,不能替代专业医生诊断。", soul_content: `# SOUL.md ## 人格特质 - 专业严谨,使用准确的医学术语 - 耐心细致,对每个问题都给予充分解答 - 保守审慎,涉及诊断和用药建议时始终提示"仅供参考" - 持续学习,关注最新医学研究进展 ## 沟通风格 - 使用专业但易懂的语言 - 适当使用类比解释复杂医学概念 - 对不确定的内容明确标注置信度 - 主动提醒风险和注意事项 ## 边界 - 不做明确诊断,只提供参考意见 - 不推荐处方药的具体用法用量 - 遇到紧急情况建议立即就医 `, scenarios: ["临床辅助", "文献检索", "诊断建议", "用药参考", "病历整理"], welcome_message: "你好!我是你的医疗AI助手。我可以帮你检索文献、解读检查报告、提供诊疗参考意见。请注意,我的建议仅供参考,不能替代专业医生的诊断。有什么我可以帮你的吗?", quick_commands: [ { label: "文献检索", prompt: "请帮我检索关于 {topic} 的最新医学文献" }, { label: "用药查询", prompt: "请查询 {drug} 的药理作用、适应症和注意事项" }, { label: "检查解读", prompt: "请帮我解读以下检查报告: {report}" }, { label: "诊疗参考", prompt: "关于 {symptom} 的诊疗参考方案" } ], model: "claude-sonnet-4-6", tools: ["browser", "researcher", "collector"], temperature: 0.3, max_tokens: 4096, communication_style: "使用专业但易懂的语言,适当使用类比,对不确定内容标注置信度" } ``` ### 4.4 API 层 **新增端点**: | 端点 | 方法 | 权限 | 说明 | |------|------|------|------| | `/api/v1/agent-templates/available` | GET | 任何已认证 | 返回可浏览模板列表 (id, name, category, emoji, description, source_id) | | `/api/v1/agent-templates/:id/full` | GET | 任何已认证 | 返回完整模板 (含 soul_content, welcome_message, quick_commands 等) | **现有端点扩展**: `POST /api/v1/agent-templates` 和 `POST /api/v1/agent-templates/:id` (update) 请求体支持所有新增字段。 ### 4.5 Desktop 消费流程 ``` 1. 登录成功 → saasStore 调用 GET /agent-templates/available → 缓存模板列表到 saasStore.availableTemplates 2. 用户创建 Agent(首次 / 新建) → AgentOnboardingWizard 增加 Step 0: 选择行业模板 → 展示 Grid 卡片(emoji + 名称 + 分类 + 描述) → 两个入口: "空白 Agent" / "从模板创建" 3. 选择模板后 → 调用 GET /agent-templates/:id/full 获取完整配置 → 映射到 Desktop Clone + Kernel Agent: | SaaS 字段 | Desktop 目标 | |---------------------|-------------------------------------| | name | Clone.name | | emoji | Clone.emoji | | personality | Clone.personality | | scenarios | Clone.scenarios | | communication_style | Clone.communicationStyle | | model | Clone.model | | system_prompt | → Kernel agent system_prompt | | soul_content | → identity.updateFile('soul', ...) | | welcome_message | → 首条消息展示 | | quick_commands | → 本地缓存,快捷指令面板 | | temperature | → Kernel agent config | | max_tokens | → Kernel agent config | | tools | → Kernel agent tools | 4. 创建完成 → Agent 在本地成长 → 不再与 SaaS 模板同步 → 模板更新仅影响新用户 ``` --- ## 5. Admin V2 UI 变更汇总 ### 5.1 Accounts 页面 - 编辑 Modal 增加 "LLM 路由模式" 字段 - 下拉选项: "SaaS 中转 (Token 池)" / "本地直连" - 表格增加路由模式列 ### 5.2 Providers 页面 - Key Pool Modal 从只读升级为完整管理 - 增加 "添加密钥" 按钮 → 表单 (label, key, priority, RPM, TPM) - 密钥行增加启用/禁用 Switch 和删除按钮 - 增加用量统计展示 ### 5.3 Agent Templates 页面 - 创建/编辑 Modal 增加新字段: emoji, personality, soul_content (大文本编辑器), scenarios (多选标签), welcome_message, quick_commands (动态列表), communication_style - 列表增加 emoji 列和 category 筛选 - 预览功能: 展示模板效果(模拟 Agent 外观) --- ## 6. Desktop 端变更汇总 ### 6.1 saasStore - 登录响应增加 `llm_routing` 解析 - 新增 `fetchAvailableTemplates()` 方法 - 新增 `availableTemplates` 状态 ### 6.2 connectionStore - `connect()` 根据账号 `llm_routing` 选择路径 - relay 模式: 使用 `SaaSClient.chatCompletion()` - local 模式: 保持现有 `KernelClient` 逻辑 ### 6.3 AgentOnboardingWizard - 新增 Step 0: 行业模板选择 - 模板 Grid 展示 (从 saasStore.availableTemplates 渲染) - 选择模板后预填后续步骤默认值 ### 6.4 agentStore - 新增 `createFromTemplate(template)` 方法 - 映射模板字段到 Clone + Kernel Agent --- ## 7. 文件变更清单 ### SaaS 后端 (Rust) | 文件 | 变更 | |------|------| | `crates/zclaw-saas/migrations/20260331000001_accounts_llm_routing.sql` | 新增: accounts 加 llm_routing 字段 | | `crates/zclaw-saas/migrations/20260331000002_agent_templates_extensions.sql` | 新增: agent_templates 加 soul_content 等 9 个扩展字段 | | `crates/zclaw-saas/src/account/types.rs` | UpdateAccountRequest 增加 llm_routing 字段 | | `crates/zclaw-saas/src/account/service.rs` | update_account SQL 增加 llm_routing 列 | | `crates/zclaw-saas/src/account/handlers.rs` | update_account 支持 llm_routing | | `crates/zclaw-saas/src/auth/types.rs` | AccountPublic 增加 llm_routing 字段 | | `crates/zclaw-saas/src/auth/handlers.rs` | login/register/me 响应增加 llm_routing (4 个构建点) | | `crates/zclaw-saas/src/agent_template/types.rs` | 扩展 Create/Update/Info 类型 + 9 个新字段 | | `crates/zclaw-saas/src/agent_template/service.rs` | 支持 soul_content 等新字段 (考虑重构为 sqlx::FromRow) | | `crates/zclaw-saas/src/agent_template/mod.rs` | 新增 /available 和 /:id/full 路由 | | `crates/zclaw-saas/src/relay/key_pool.rs` | select_best_key 加入 LRU 次排序 | | `crates/zclaw-saas/src/scheduler.rs` | 新增 key_usage_window 清理任务 | | `crates/zclaw-saas/src/db.rs` | 扩展种子模板数据 | ### Admin V2 (TypeScript) | 文件 | 变更 | |------|------| | `admin-v2/src/pages/Accounts.tsx` | 编辑 Modal 增加 LLM 路由模式字段 | | `admin-v2/src/pages/Providers.tsx` | Key Pool Modal 升级为完整管理 | | `admin-v2/src/pages/AgentTemplates.tsx` | 创建/编辑 Modal 增加扩展字段 | | `admin-v2/src/services/providers.ts` | 接入已有的 addKey/toggleKey/deleteKey | | `admin-v2/src/services/agent-templates.ts` | 新增 getFull 方法 | | `admin-v2/src/types/index.ts` | 扩展 AccountPublic 和 AgentTemplate 类型定义 | ### Desktop (TypeScript) | 文件 | 变更 | |------|------| | `desktop/src/store/saasStore.ts` | 增加 llm_routing 解析 + fetchAvailableTemplates + availableTemplates 状态 | | `desktop/src/store/connectionStore.ts` | connect() 按 llm_routing 覆盖 localStorage connectionMode | | `desktop/src/store/agentStore.ts` | 新增 createFromTemplate() + Clone 接口增加 source_template_id | | `desktop/src/components/AgentOnboardingWizard.tsx` | 新增 Step 0: 模板选择 | | `desktop/src/lib/saas-client.ts` | SaaSAccountInfo 增加 llm_routing; 新增 fetchAvailableTemplates + fetchTemplateFull | --- ## 8. 关键设计决策说明 ### 8.1 llm_routing 优先级规则 Desktop 端 `connectionStore.connect()` 的路由决策逻辑: ``` 1. 读取 saasStore.account.llm_routing (Admin 配置) 2. 如果 llm_routing === 'relay' → 强制使用 SaaSClient,忽略 localStorage connectionMode 3. 如果 llm_routing === 'local' → 使用 KernelClient 4. llm_routing 优先级 > localStorage connectionMode ``` 管理员对路由模式有最终控制权。用户无法通过修改 localStorage 绕过 Admin 配置。 ### 8.2 模板获取失败降级 登录时模板获取 (`GET /agent-templates/available`) 失败时: - 不阻塞登录流程 - saasStore.availableTemplates 设为空数组 - AgentOnboardingWizard Step 0 显示"模板加载失败"提示 + "空白 Agent"入口 - 模板功能降级为不可用,不影响核心聊天 ### 8.3 模板引用不可用工具 模板指定 `tools: ["browser", "researcher"]` 但 Desktop 端某工具不可用时: - 创建 Agent 时静默跳过不可用的工具 - Agent 创建后仍可正常使用,只是缺少该工具能力 - 在 Agent 详情中标注"部分工具不可用" ### 8.4 source_id 唯一约束 使用部分索引替代列级 UNIQUE 约束,允许 NULL 值: ```sql CREATE UNIQUE INDEX idx_agent_templates_source_id ON agent_templates(source_id) WHERE source_id IS NOT NULL; ``` --- ## 9. 不在范围内 以下事项本次设计不涉及: - AccountTier / 订阅等级体系 - 实时配置推送 (WebSocket) - 模板市场 / 用户自定义模板上传 - Token 池计费 / 用量配额限制 - Desktop 端路由模式用户自选 (由 Admin 统一管控)