Files
zclaw_openfang/wiki/chat.md
iven 9a313e3c92
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
docs(wiki): 回复效率+建议并行化优化 wiki 同步
- middleware.md: 分波并行执行设计决策 + parallel_safe 标注 + 不变量 + 执行流
- chat.md: suggestion prefetch + 解耦 memory + prompt 重写
- log.md: 追加变更记录
- CLAUDE.md: §13 架构快照 + 最近变更
2026-04-23 23:45:28 +08:00

156 lines
6.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.

---
title: 聊天系统
updated: 2026-04-23
status: active
tags: [module, chat, stream]
---
# 聊天系统
> 从 [[index]] 导航。关联模块: [[routing]] [[saas]] [[butler]]
## 1. 设计决策
| 决策 | 原因 |
|------|------|
| 3 种 ChatStream 实现 | 覆盖 3 种运行环境: KernelClient(Tauri) / SaaSRelay(浏览器) / GatewayClient(外部进程) |
| 5 Store 拆分 | 原 908 行 ChatStore → stream/conversation/message/chat/artifact单一职责 |
| 5 分钟超时守护 | 防止流挂起: kernel-chat.ts:76超时自动 cancelStream |
| 统一回调接口 | 3 种实现共享 `{ onDelta, onThinkingDelta, onTool, onHand, onComplete, onError }` |
| LLM 动态建议 | 替换硬编码关键词匹配,用 LLM 生成个性化建议1深入追问+1实用行动+1管家关怀4路并行预取智能上下文 |
### ChatStream 实现
| 环境 | 实现 | 传输 |
|------|------|------|
| Tauri + SaaS (主路径) | KernelClient + relay | Tauri Event → SaaS Token Pool → LLM |
| Tauri 本地 | KernelClient | Tauri Event → Kernel → LLM 直连 |
| 浏览器端 | SaaSRelayGatewayClient | HTTP SSE → SaaS → LLM |
| 外部 Gateway | GatewayClient | WebSocket |
## 2. 关键文件 + 数据流
### 核心文件
| 文件 | 职责 |
|------|------|
| `desktop/src/store/chat/streamStore.ts` | 流式消息编排、发送、取消、LLM 动态建议生成 |
| `desktop/src/store/chat/conversationStore.ts` | 会话管理、当前模型、sessionKey |
| `desktop/src/store/chat/messageStore.ts` | 消息持久化 (IndexedDB) |
| `desktop/src/lib/kernel-chat.ts` | KernelClient ChatStream (Tauri) |
| `desktop/src/lib/suggestion-context.ts` | 4路并行智能上下文拉取 (用户画像/痛点/经验/技能匹配) |
| `desktop/src/lib/cold-start-mapper.ts` | 冷启动配置映射 (行业检测/命名/个性/技能) |
| `desktop/src/components/ChatArea.tsx` | 聊天区域 UI |
| `desktop/src/components/ai/SuggestionChips.tsx` | 动态建议芯片展示 |
| `crates/zclaw-runtime/src/loop_runner.rs` | Rust 主聊天循环 + 中间件链 |
### 发送消息流
```
用户输入 → ChatPanel.tsx
→ streamStore.sendMessage(content)
→ effectiveSessionKey = conversationStore.sessionKey || uuid()
→ effectiveAgentId = resolveGatewayAgentId(currentAgent)
→ getClient().chatStream(content, callbacks, { sessionKey, agentId, chatMode })
→ [KernelClient] Tauri invoke('agent_chat_stream')
→ Kernel → loop_runner → 14层中间件 → LLM Driver
→ Tauri Event emit('chat-response-delta')
→ onDelta → streamStore 追加 delta → UI 渲染
→ onComplete → conversationStore 持久化 → messageStore 写 IndexedDB
→ [SaaSRelay] POST /api/v1/relay/chat/completions → SSE
→ [GatewayClient] WebSocket send → onmessage
→ 5 分钟超时守护 (kernel-chat.ts:76)
```
### 集成契约
| 方向 | 模块 | 接口 | 说明 |
|------|------|------|------|
| Calls -> | routing | `getClient()` | 确定走哪条 ChatStream |
| Calls -> | middleware | Through loop_runner | 14 层 runtime 中间件链 |
| Called by <- | UI | ChatPanel.tsx | 用户发送消息取消流式 |
| Emits -> | streamStore | Tauri Event `chat-response-delta` | 流式增量更新 |
## 3. 代码逻辑
### Store 拆分 (5 Store)
| Store | 文件 | 职责 |
|-------|------|------|
| streamStore | `store/chat/streamStore.ts` | 流式编排、发送、取消 |
| conversationStore | `store/chat/conversationStore.ts` | 会话管理、当前模型 |
| messageStore | `store/chat/messageStore.ts` | 消息持久化 (IndexedDB) |
| chatStore | `store/chat/chatStore.ts` | 聊天通用状态 |
| artifactStore | `store/chat/artifactStore.ts` | 聊天产物/附件 |
### 流式事件类型
`agent_chat_stream` Tauri Event emit 的 tagged union:
`Delta` / `ThinkingDelta` / `ToolStart` / `ToolEnd` / `HandStart` / `HandEnd` / `SubtaskStatus` / `IterationStart` / `Complete` / `Error`
### 模型切换
```
UI 选择模型 → conversationStore.currentModel = newModel
→ 下次 sendMessage → getClient() 读取 currentModel
→ SaaS 模式: relay 白名单验证 → 可用则切换
→ 本地模式: 直接使用用户配置的模型
```
### 不变量
- sessionKey 在会话内必须一致 (UUID 生成一次,持久化 IndexedDB)
- cancelStream 设置原子标志位,与 onDelta 回调无竞态
- 3 种 ChatStream 共享同一套回调接口,上层代码无需感知实现差异
- 消息持久化走 messageStore → IndexedDB与流式渲染解耦
- 动态建议 4 路并行预取 (userProfile/painPoints/experiences/skillMatch)500ms 超时降级为空串
- 建议生成与 memory extraction 解耦 — 不等 memory LLM 调用完成即启动建议
### LLM 动态建议
```
sendMessage → isStreaming=true + _activeSuggestionContextPrefetch = fetchSuggestionContext(...)
→ 流式响应中 prefetch 在后台执行
onComplete → createCompleteHandler
→ generateLLMSuggestions(prefetchedContext) — 立即启动不等 memory
→ prompt: 1 深入追问 + 1 实用行动 + 1 管家关怀
→ memory/reflection 后台独立运行 (Promise.all)
→ SuggestionChips 渲染
```
### Tauri 命令
| 命令 | 说明 |
|------|------|
| `agent_chat_stream` | 流式聊天 (主路径) |
| `agent_chat` | 非流式聊天 |
| `cancel_stream` | 取消当前流式响应 |
| `classroom_chat` | 课堂场景对话 |
## 4. 活跃问题 + 注意事项
| 问题 | 状态 | 说明 |
|------|------|------|
| B-CHAT-07 混合域截断 | P2 Open | 跨域消息时可能截断上下文 |
| SSE Token 统计为 0 | ✅ 已修复 | SseUsageCapture stream_done flag |
| Tauri invoke 参数名 | ✅ 已修复 (f6c5dd2) | camelCase 格式 |
| Provider Key 解密 | ✅ 已修复 (b69dc61) | warn+skip + heal |
**注意事项:**
- 辅助 LLM 调用 (记忆摘要/提取、管家路由) 复用 `kernel_init` 的 model+base_url与聊天同链路
- 课堂聊天是独立 Tauri 命令 (`classroom_chat`),不走 `agent_chat_stream`
- Agent tab 已移除 — 跨会话身份由 soul.md 接管,不再通过 RightPanel 管理
## 5. 变更日志
| 日期 | 变更 |
|------|------|
| 04-23 | 建议 prefetch: sendMessage 时启动 context 预取,流结束后立即消费,不等 memory extraction |
| 04-23 | 建议 prompt 重写: 1深入追问+1实用行动+1管家关怀上下文窗口 6→20 条 |
| 04-23 | 身份信号: detectAgentNameSuggestion 前端即时检测 + RightPanel 监听 Tauri 事件刷新名称 |
| 04-23 | Agent tab 移除: RightPanel 清理 ~280 行 dead code身份由 soul.md 接管 |
| 04-23 | 澄清问题卡片 UX 优化: 去悬空引用 + 默认展开 |
| 04-22 | Wiki 重写: 5 节模板,增加集成契约和不变量 |
| 04-21 | 上一轮更新 |