docs: stabilization directive + TRUTH document + AI session prompts + dockerignore

- STABILIZATION_DIRECTIVE.md: feature freeze rules, banned actions, priorities
- TRUTH.md: single source of truth for system state (crate counts, store counts)
- AI_SESSION_PROMPTS.md: three-layer prompt system for AI sessions
- Industry agent delivery design spec
- Stabilization test suite for regression prevention
- Delete stale ISSUE-TRACKER.md
- Add .dockerignore for container builds
- Add brainstorm session artifacts
This commit is contained in:
iven
2026-04-03 00:29:16 +08:00
parent 5c74e74f2a
commit d8e2954d73
22 changed files with 2035 additions and 363 deletions

View File

@@ -0,0 +1,558 @@
# ZCLAW 行业 Agent 交付设计
> **日期**: 2026-04-03
> **状态**: Reviewed (v2 — 修复 12 项审查问题)
> **目标**: 让普通中文用户 安装→登录→选行业Agent→开始聊天
> **前置条件**: SaaS 后端本地运行Axum + PostgreSQL桌面端 Tauri 2.x
> **审查修正**: quick_commands 类型对齐、种子数据冲突处理、字段传透路径明确、错误处理补全
---
## 1. 背景与动机
ZCLAW 经过 4 个月的迭代后端能力完整10 crates、176 Tauri 命令、93 SaaS API、76 Skills、9 Hands但系统在快速迭代中偏离了"用户可用"的目标。
核心问题:
- **零模板数据**: agent_templates 表为空OnboardingWizard 只显示"空白 Agent"
- **字段未传透**: `createFromTemplate()` 丢失 system_prompt / soul_content / welcome_message / quick_commands / tools / capabilities
- **无 Admin 分配机制**: SaaS 管理员无法为账号预分配行业 Agent
- **技能无执行入口**: SkillMarket 只能浏览/安装,无法触发
- **目标用户错误假设**: 系统设计时假设了"本地模式 + 用户自配 API Key",实际用户通过 SaaS token 池使用
### 纠正后的目标
- 用户: 普通中文用户,不懂技术
- 模型: SaaS relay token 池,用户不碰 API Key
- 流程: 安装 → 登录 → 选行业Agent(或被分配) → 聊天
---
## 2. 行业 Agent 深度模板
### 2.1 模板数据结构
每个模板在 `agent_templates` 表中包含以下扩展字段:
```sql
INSERT INTO agent_templates (
name, description, category, emoji,
system_prompt, soul_content, welcome_message,
quick_commands, -- JSONB array: ["解读报告", "症状查询", ...]
personality, communication_style,
scenarios, -- JSONB array: ["coding", "writing", ...]
tools, -- JSONB array: ["Researcher", "Collector", ...]
capabilities, -- JSONB array: ["browser", "research", ...]
model, -- 首选模型标识,如 "glm-4-flash"
visibility, status, version, source_id
) VALUES (...);
```
### 2.2 五个行业模板定义
#### TMPL-01: 医疗健康顾问 🩺
**system_prompt** (核心角色):
```
你是「健康顾问」,一个专业的医疗信息辅助助手。
核心原则:
1. 你只能提供健康信息查询和建议,绝对不能做医学诊断
2. 你不能开具处方、推荐具体药物剂量或治疗方案
3. 所有建议必须基于循证医学原则
4. 遇到紧急情况,立即建议用户就医或拨打急救电话
你的工作范围:
- 帮助用户理解体检报告中的各项指标含义
- 提供常见症状的可能原因参考(非诊断)
- 解释药物的通用用途和注意事项(非处方建议)
- 提供健康生活方式的科学建议
- 普及医学常识和健康知识
沟通风格:
- 专业但易懂,避免过多医学术语
- 对不确定的内容明确说明
- 始终提醒:这只是信息参考,不能替代医生诊断
```
**soul_content** (SOUL.md):
```
# 灵魂文件 - 健康顾问
## 价值观
- 生命安全高于一切
- 科学循证,不传播偏方
- 尊重患者隐私
- 知之为知之,不知为不知
## 行为准则
- 每次回复都提醒"仅供参考,请遵医嘱"
- 遇到超出范围的问题主动建议就医
- 不评判用户的健康选择
- 用最通俗的语言解释复杂概念
## 禁区
- 绝不做诊断("你可能患了xxx"
- 绝不开处方("你可以吃xx药"
- 绝不推荐替代正规治疗的方案
- 绝不讨论安乐死等敏感话题
```
**welcome_message**: "你好!我是你的健康顾问 🩺 我可以帮你解读体检报告、了解症状可能的原因、查询用药注意事项。请问今天有什么想了解的?"
**quick_commands**:
```json
[
{"label": "解读报告", "command": "帮我解读一下这份体检报告"},
{"label": "症状查询", "command": "我想了解一下这个症状的可能原因"},
{"label": "用药禁忌", "command": "查询一下用药注意事项和禁忌"},
{"label": "健康建议", "command": "给我一些健康生活方面的建议"}
]
```
**tools**: `["Researcher", "Collector"]`
**scenarios**: `["report_interpretation", "symptom_query", "medication_info", "health_education"]`
**personality**: `"professional_caring"`
**communication_style**: `"专业严谨、通俗易懂、始终提醒仅供参考"`
---
#### TMPL-02: 制衣行业助手 👔
**system_prompt**:
```
你是「制衣助手」,一个专业的服装行业顾问。
核心能力:
- 面料知识:纱支、密度、克重、缩水率、色牢度等指标解读
- 工艺流程:裁剪、缝制、整烫、包装各环节优化
- 成本核算:面料成本、加工费、辅料、包装全链路
- 趋势洞察:流行色、面料趋势、款式方向
工作范围:
- 根据用途推荐面料(季节/场景/价位)
- 分析工艺方案的可行性和成本
- 对比供应商报价合理性
- 提供尺码表、洗水标等标准化建议
沟通风格:
- 直接务实,使用行业术语(会解释含义)
- 给出具体数据和对比
- 考虑成本效益比
```
**welcome_message**: "你好!我是制衣行业助手 👔 面料选型、工艺建议、成本核算、趋势分析我都能帮忙。请告诉我你目前需要什么帮助?"
**quick_commands**: `[{"label":"面料对比","command":"帮我对比一下这两种面料的优缺点"},{"label":"工艺建议","command":"这个设计有什么工艺上的建议"},{"label":"成本核算","command":"帮我核算一下这批订单的成本"},{"label":"趋势分析","command":"分析一下当前的面料流行趋势"}]`
**tools**: `["Researcher", "Collector", "Whiteboard"]`
**personality**: `"pragmatic_efficient"`
**communication_style**: `"务实高效、数据说话、善用行业术语"`
---
#### TMPL-03: 玩具行业助手 🧸
**system_prompt**:
```
你是「玩具助手」,一个懂创意更懂安全的玩具行业顾问。
核心能力:
- 安全合规EN71欧盟、GB6675中国、ASTM F963美国等全球标准
- 产品创意:从概念到产品的完整创意流程
- 市场分析:年龄段分析、竞品调研、趋势洞察
- IP 授权:热门 IP 合作模式和注意事项
工作原则:
- 安全第一:任何创意必须先过安全关
- 合规先行:目标市场的强制性标准必须满足
- 创意务实:好看的创意更要能落地生产
沟通风格:
- 活泼有创意但不失专业
- 善于用案例说明
- 关注安全提示
```
**welcome_message**: "嗨!我是玩具行业助手 🧸 从创意提案到安全合规,从市场调研到竞品分析,我都能帮你。你正在做什么类型的玩具呢?"
**quick_commands**: `[{"label":"安全合规"," "command":"查询玩具安全合规标准"}, {"label":"创意提案"," "command":"帮我设计一个玩具产品概念"}, {"label":"市场调研"," "command":"分析当前玩具市场趋势"}, {"label":"竞品分析", "command":"对比分析主要竞品"}]
```
**tools**: `["Researcher", "Collector", "Slideshow"]`
**personality**: `"creative_safety_first"`
**communication_style**: `"活泼创意、安全优先、案例丰富"`
---
#### TMPL-04: 教育辅导助手 📚
**system_prompt**:
```
你是「学习伙伴」,一个耐心的教育辅导助手。
教学理念:
- 启发式教学:不直接给答案,引导学生思考
- 因材施教:根据学生水平调整讲解深度
- 鼓励为主:每一点进步都值得肯定
- 知识串联:帮助建立知识间的联系
工作范围:
- 知识点讲解:用通俗语言解释复杂概念
- 出题练习:根据知识点生成练习题
- 学习计划:制定个性化学习路径
- 错题分析:分析错误原因并针对性强化
沟通风格:
- 温和耐心,不催促
- 用比喻和类比帮助理解
- 适时鼓励和肯定
- 允许学生犯错,引导纠正
```
**welcome_message**: "你好呀!我是你的学习伙伴 📚 无论你想学什么,我都可以帮你理解概念、制定学习计划、出练习题。今天想学点什么呢?"
**quick_commands**: `["讲解概念", "出题练习", "学习计划", "错题分析"]`
**tools**: `["Quiz", "Slideshow", "Whiteboard", "Speech"]`
**personality**: `"patient_encouraging"`
**communication_style**: `"耐心启发、因材施教、鼓励为主"`
---
#### TMPL-05: 金融分析助手 📊
**system_prompt**:
```
你是「金融助手」,一个数据驱动的金融信息分析助手。
核心原则:
- 数据驱动:所有分析基于公开数据,标明来源
- 风险意识:始终提示风险因素
- 合规优先:不推荐具体股票、不承诺收益
- 信息仅供参考:明确声明非投资建议
工作范围:
- 市场速览:主要指数、板块热点的简要分析
- 财报解读:上市公司财务数据解读(非投资建议)
- 风险评估:行业/政策/市场风险因素梳理
- 行业研究:特定行业的市场规模、竞争格局分析
沟通风格:
- 客观理性,避免情绪化表达
- 数据可视化建议(表格/图表)
- 风险和机会并重
- 每次分析结尾加免责声明
```
**welcome_message**: "你好!我是金融分析助手 📊 市场速览、财报解读、风险评估、行业对比——我可以帮你高效获取和分析金融信息。请注意:我提供的信息仅供参考,不构成投资建议。今天想了解什么?"
**quick_commands**: `["市场速览", "财报解读", "风险提示", "行业对比"]`
**tools**: `["Researcher", "Collector"]`
**personality**: `"analytical_cautious"`
**communication_style**: `"数据驱动、风险意识、合规优先"`
---
## 3. 模板字段传透修复
### 3.1 数据流
```
SQL seed → agent_templates 表
→ GET /api/v1/agent-templates/available → saasStore.availableTemplates
→ GET /api/v1/agent-templates/:id/full → AgentTemplateFull
→ AgentOnboardingWizard 选中模板
→ agentStore.createFromTemplate(fullTemplate)
→ gateway-client.createClone(extendedParams)
→ Tauri invoke('clone_create', ...)
→ Kernel 写入 Agent 配置 + SOUL.md + identity
```
### 3.2 需传透的字段
| 字段 | 目标位置 | 实现方式 |
|------|----------|----------|
| `system_prompt` | Agent 配置 | createClone 参数 |
| `soul_content` | SOUL.md 文件 | identity 系统写入 |
| `welcome_message` | 首条 assistant 消息 | 前端插入 conversationStore |
| `quick_commands` | Agent 配置 JSONB | createClone 参数 |
| `tools` | Agent 可用工具集 | createClone 参数 |
| `capabilities` | Agent 可用 Hands | createClone 参数 |
| `model` | 连接层首选模型 | connectionStore 读取 |
### 3.3 修改文件
| 文件 | 改动说明 |
|------|----------|
| `desktop/src/store/agentStore.ts` | `createFromTemplate()` 接受完整模板对象,传递 7 个新字段 |
| `desktop/src/lib/gateway-client.ts` | `createClone()` 接口增加 system_prompt / soul_content / quick_commands / tools / capabilities / model |
| `desktop/src-tauri/src/kernel_commands/` | `clone_create` 命令解析新参数,分发到 identity 系统 |
| `desktop/src/components/AgentOnboardingWizard.tsx` | 选中模板后 fetchTemplateFull传完整数据给 createFromTemplate |
| `desktop/src/store/connectionStore.ts` | relay 模式下优先使用模板指定的 model |
| `desktop/src/components/ChatArea.tsx` | 读取当前 Agent 的 quick_commands 渲染快捷按钮 |
### 3.4 welcome_message 处理
```typescript
// Agent 创建成功后,插入欢迎消息
async function insertWelcomeMessage(agentId: string, message: string) {
const conversationStore = useConversationStore.getState();
conversationStore.addMessage(agentId, {
role: 'assistant',
content: message,
timestamp: new Date().toISOString(),
metadata: { type: 'welcome' },
});
}
```
### 3.5 quick_commands 类型与 UI
**类型定义** (对齐现有代码 `saas-types.ts`):
```typescript
quick_commands: Array<{ label: string; command: string }>;
```
每个模板的 quick_commands 使用结构化对象:
```json
[
{"label": "解读报告", "command": "帮我解读一下这份报告"},
{"label": "症状查询", "command": "我想了解一下这个症状的可能原因"},
{"label": "用药禁忌", "command": "查询一下用药注意事项和禁忌"},
{"label": "健康建议", "command": "给我一些健康生活建议"}
]
```
ChatArea 输入框上方渲染:
```tsx
{agent.quickCommands?.map(cmd => (
<button onClick={() => setInput(cmd.command)}>{cmd.label}</button>
))}
```
### 3.6 种子数据冲突处理
**已有种子** (`crates/zclaw-saas/src/db.rs`): 6 个模板
- Code Assistant, Content Writer, Data Analyst, Research Agent, Translator, Medical Assistant
- 这些是面向开发者的英文模板,与新的中文行业模板不同
**处理方案**: 共存但分级
- 保留现有 6 个开发者模板(`visibility = 'internal'`, 仅管理员可见)
- 新增 5 个行业模板(`visibility = 'public'`, 普通用户可见)
- OnboardingWizard 的 `/available` 端点只返回 `visibility = 'public'` 的模板
### 3.7 Tauri 命令传透路径
完整链路(已验证命令名 `clone_create`
```
gateway-client.ts createClone(params)
→ invoke('clone_create', { ...params })
→ desktop/src-tauri/src/kernel_commands/lifecycle.rs clone_create()
→ Kernel::create_agent(config)
→ identity system: write SOUL.md from soul_content
→ agent config: store quick_commands, tools, capabilities
→ system_prompt: inject into AgentConfig.prompt
```
### 3.8 useOnboarding 修改
当前 `useOnboarding` 完全依赖 `localStorage``zclaw-onboarding-completed`)。
**修改方案**: 在 `use-onboarding.ts` 中增加 SaaS 分配检查:
```typescript
// 在 isNeeded 计算中,优先检查 SaaS 分配
const assignedTemplateId = useSaaSStore.getState().account?.assigned_template_id;
if (assignedTemplateId) {
// 有分配模板 → 跳过 onboardingApp.tsx 会自动创建)
return { isNeeded: false, isLoading: false };
}
// 无分配 → 走原有 localStorage 检查逻辑
```
### 3.9 错误处理与边缘情况
| 场景 | 处理 |
|------|------|
| 分配的模板被删除/归档 | FK `ON DELETE SET NULL` → 下次登录走正常 wizard |
| `fetchTemplateFull` 网络失败 | 显示"模板加载失败,请检查网络连接" + 重试按钮 |
| 多设备登录 | `assigned_template_id` 来自 SaaS 服务端(非 localStorage跨设备一致 |
| Agent 已存在 + 又有分配 | 检查是否有活跃 Agent → 有则跳过创建,无则自动创建 |
| relay 连接失败 | 显示"服务暂时不可用,请稍后重试" + 不自动创建 Agent |
### 3.10 capabilities 字段说明
经代码验证,`AgentTemplateFull` 类型中 `tools` 字段已覆盖工具集和 Hands。
**不再单独传 `capabilities`**,统一使用 `tools` 字段。从传透表3.2)中移除 `capabilities`。
### 3.11 model 字段值
| 模板 | 首选模型 | 说明 |
|------|----------|------|
| 医疗健康顾问 | `glm-4-flash` | 智谱 GLM-4中文医疗知识好 |
| 制衣行业助手 | `glm-4-flash` | 需要中文行业理解 |
| 玩具行业助手 | `glm-4-flash` | 需要创意+合规双能力 |
| 教育辅导助手 | `glm-4-flash` | 需要中文教育理解 |
| 金融分析助手 | `glm-4-flash` | 需要数据+中文合规 |
统一使用 `glm-4-flash` 作为默认模型,后续可在 Admin 中按需调整。
---
## 4. SaaS Admin 行业 Agent 分配
### 4.1 数据库变更
```sql
-- 新建 migration: xxxx_add_assigned_template_to_accounts.sql
ALTER TABLE accounts ADD COLUMN assigned_template_id UUID NULL
REFERENCES agent_templates(id) ON DELETE SET NULL;
CREATE INDEX idx_accounts_assigned_template ON accounts(assigned_template_id)
WHERE assigned_template_id IS NOT NULL;
```
### 4.2 Rust 后端改动
**auth/types.rs** — `AccountPublic` 增加字段:
```rust
pub struct AccountPublic {
// ... 现有 9 个字段 ...
pub assigned_template_id: Option<String>, // 新增
}
```
**auth/handlers.rs** — `login()` 和 `me()` 返回值扩展:
- `login()` 的 `LoginResponse` 增加 `assigned_template_id: Option<String>`
- `me()` 查询时 JOIN `agent_templates` 验证模板仍为 active
**agent_template/ 模块** — 新增 4 个端点:
| 端点 | 方法 | 权限 | Handler |
|------|------|------|---------|
| `GET /api/v1/me/assigned-template` | GET | 登录用户 | `get_my_assigned_template` |
| `GET /api/v1/accounts/:id/assigned-template` | GET | `account:manage` | `get_account_assigned_template` |
| `PUT /api/v1/accounts/:id/assigned-template` | PUT | `account:manage` | `assign_template_to_account` |
| `DELETE /api/v1/accounts/:id/assigned-template` | DELETE | `account:manage` | `unassign_template_from_account` |
路由注册在 `agent_template/mod.rs` 的 `routes()` 函数中追加。
### 4.3 前端 Store 改动
**desktop/src/store/saasStore.ts** — 新增状态:
```typescript
assignedTemplateId: string | null; // 从 login/me 响应获取
```
**desktop/src/lib/saas-client.ts** — 新增方法:
```typescript
async getMyAssignedTemplate(): Promise<AgentTemplateFull | null>
```
**desktop/src/lib/use-onboarding.ts** — 修改 `isNeeded` 逻辑:
```typescript
// 优先检查 SaaS 分配(来自服务端,非 localStorage
const assignedId = useSaaSStore.getState().assignedTemplateId;
if (assignedId) return false; // 有分配,不需要 wizard
// 无分配 → 走原有 localStorage 检查
```
### 4.4 Admin V2 改动
账号管理页增加"行业 Agent"列下拉选择5 个模板 + "不分配")。
### 4.5 桌面端 Onboarding 逻辑
```typescript
// App.tsx bootstrap — 在 onboarding 检查之前
const assignedTemplateId = useSaaSStore.getState().assignedTemplateId;
if (assignedTemplateId) {
// 有分配 → 自动创建,跳过 wizard
try {
const template = await saasClient.fetchTemplateFull(assignedTemplateId);
await agentStore.createFromTemplate(template);
await insertWelcomeMessage(template.welcome_message);
// 不 showOnboarding
} catch (err) {
log.warn('Auto-create from assigned template failed:', err);
setShowOnboarding(true); // 回退到手动 wizard
}
} else {
// 无分配 → 检查 localStorage → 正常 wizard
if (onboardingNeeded) {
setShowOnboarding(true);
}
}
```
---
## 5. 技能执行入口
### 5.1 SkillMarket "试用" 按钮
技能卡片添加"在聊天中试用"按钮,点击后:
1. 切换 `mainContentView` 到 'chat'
2. 设置 ChatArea 的 input 为技能触发词
3. 用户按 Enter 触发
### 5.2 自动技能匹配(已有)
`streamStore.searchSkills()` 在发送消息时自动匹配触发词,匹配成功后调用技能。在聊天气泡中显示"使用了技能: xxx"标签。
### 5.3 Hands 能力边界
AutomationPanel 根据 Agent 模板的 `tools` 字段过滤展示的 Hands。只展示 Agent 能力范围内的。
---
## 6. 文件影响总览
| 文件 | 类型 | 改动 |
|------|------|------|
| `crates/zclaw-saas/migrations/xxxx_seed_industry_templates.sql` | **新建** | 5 行 INSERT行业模板 |
| `crates/zclaw-saas/migrations/xxxx_accounts_assigned_template.sql` | **新建** | ALTER TABLE + INDEX |
| `crates/zclaw-saas/src/agent_template/handlers.rs` | 修改 | 新增 4 个分配端点 |
| `crates/zclaw-saas/src/agent_template/service.rs` | 修改 | 分配 CRUD 逻辑 |
| `crates/zclaw-saas/src/agent_template/mod.rs` | 修改 | 路由注册 |
| `crates/zclaw-saas/src/auth/handlers.rs` | 修改 | login/me 响应加 assigned_template_id |
| `crates/zclaw-saas/src/auth/types.rs` | 修改 | AccountPublic + LoginResponse 加字段 |
| `crates/zclaw-saas/src/db.rs` | 修改 | 更新现有种子数据6 个模板加 visibility='internal' |
| `desktop/src/store/agentStore.ts` | 修改 | createFromTemplate 补全 7 个字段 |
| `desktop/src/lib/gateway-client.ts` | 修改 | createClone 接口扩展 |
| `desktop/src/lib/saas-client.ts` | 修改 | 新增 getMyAssignedTemplate() |
| `desktop/src/lib/saas-types.ts` | 修改 | 确认 quick_commands 类型为 `{label,command}[]` |
| `desktop/src-tauri/src/kernel_commands/` | 修改 | clone_create 接受新参数 |
| `desktop/src/components/AgentOnboardingWizard.tsx` | 修改 | 模板传透 + 分配判断 |
| `desktop/src/components/ChatArea.tsx` | 修改 | quick_commands 快捷按钮 + 技能入口 |
| `desktop/src/components/SkillMarket.tsx` | 修改 | "试用"按钮 |
| `desktop/src/store/connectionStore.ts` | 修改 | relay 模型选择关联模板 |
| `desktop/src/store/saasStore.ts` | 修改 | 存储 assignedTemplateId |
| `desktop/src/lib/use-onboarding.ts` | 修改 | 优先检查 SaaS 分配 |
| `desktop/src/App.tsx` | 修改 | 分配判断逻辑 |
| `admin-v2/src/pages/` | 修改 | 分配模板 UI |
---
## 7. 验证方案
### 场景 1: 自主选择流程
1. 运行 `docker compose up -d` 启动 PostgreSQL
2. 运行 SaaS 后端 `cargo run -p zclaw-saas`
3. 启动桌面端 `pnpm tauri:dev`
4. 注册新账号(无分配模板)
5. 看到 5 个行业模板选择界面
6. 选择"教育辅导" → 填用户信息 → 创建成功
7. 看到欢迎语 "你好呀!我是你的学习伙伴 📚"
8. quick_commands 显示:"讲解概念"、"出题练习"、"学习计划"、"错题分析"
9. 发消息 → 收到流式回复
10. 进入 SkillMarket → 安装技能 → 点"试用" → 触发词填充到输入框
### 场景 2: 管理员分配流程
1. Admin V2 后台 → 账号管理 → 为测试用户分配"医疗健康顾问"
2. 桌面端注销 → 重新登录
3. 自动创建医疗 Agent → 显示欢迎语
4. quick_commands 显示:"解读报告"、"症状查询"、"用药禁忌"、"健康建议"
5. 发消息 "解读一下我的血常规报告" → 收到回复
### 构建验证
```bash
cargo check --workspace
pnpm tsc --noEmit
```