# OpenMAIC 深度分析报告 > **来源**: https://github.com/THU-MAIC/OpenMAIC > **本地路径**: G:\edu\OpenMAIC > **分析日期**: 2026-03-22 (初版) / 2026-03-26 (深度分析) > **许可证**: AGPL-3.0 ## 1. 项目概述 ### 1.1 项目定位 **OpenMAIC** (Open Multi-Agent Interactive Classroom) 是由清华大学 MAIC 团队开发的开源 AI 互动课堂平台。它能够将任何主题或文档转化为丰富的互动学习体验,核心特点是**多智能体协作**驱动的教育场景生成。 - **在线演示**: https://open.maic.chat/ - **学术论文**: 发表于 JCST'26 (Journal of Computer Science and Technology) ### 1.2 主要功能和特性 | 功能模块 | 描述 | |---------|------| | **一键课堂生成** | 输入主题或上传文档,自动生成完整课堂 | | **多智能体课堂** | AI 老师和 AI 同学实时授课、讨论、互动 | | **丰富场景类型** | 幻灯片、测验、HTML 交互式模拟、项目制学习 (PBL) | | **白板 & 语音** | 智能体实时绘制图表、书写公式、语音讲解 | | **导出功能** | 支持导出 `.pptx` 幻灯片或交互式 `.html` 网页 | | **OpenClaw 集成** | 可从飞书、Slack、Telegram 等聊天应用中直接生成课堂 | ### 1.3 目标用户群体 - **教育工作者**: 快速创建互动课程内容 - **学生**: 获得沉浸式、个性化的学习体验 - **企业培训**: 自动化培训材料生成 - **内容创作者**: 将文档转化为互动演示 --- ## 2. 技术架构 ### 2.1 项目结构 ``` OpenMAIC/ ├── app/ # Next.js App Router │ ├── api/ # 服务端 API 路由 (~18 个端点) │ │ ├── generate/ # 场景生成流水线 │ │ ├── generate-classroom/ # 异步课堂生成提交与轮询 │ │ ├── chat/ # 多智能体讨论 (SSE 流式传输) │ │ ├── pbl/ # 项目制学习端点 │ │ └── ... # quiz-grade, parse-pdf, web-search 等 │ ├── classroom/[id]/ # 课堂回放页面 │ └── page.tsx # 首页 ├── lib/ # 核心业务逻辑 │ ├── generation/ # 两阶段课堂生成流水线 │ ├── orchestration/ # LangGraph 多智能体编排 │ ├── playback/ # 回放状态机 │ ├── action/ # 动作执行引擎 │ ├── ai/ # LLM 服务商抽象层 │ ├── api/ # Stage API 门面 │ ├── store/ # Zustand 状态管理 │ └── types/ # TypeScript 类型定义 ├── components/ # React UI 组件 │ ├── slide-renderer/ # Canvas 幻灯片编辑器 │ ├── scene-renderers/ # Quiz/Interactive/PBL 场景渲染器 │ ├── generation/ # 课堂生成工具栏 │ ├── chat/ # 聊天区域和会话管理 │ ├── settings/ # 设置面板 │ ├── whiteboard/ # SVG 白板绘图 │ ├── agent/ # 智能体头像、配置 │ └── ui/ # 基础 UI 组件 (shadcn/ui) ├── packages/ # 工作区子包 │ ├── pptxgenjs/ # 定制化 PowerPoint 生成 │ └── mathml2omml/ # MathML → Office Math 转换 └── skills/openmaic/ # OpenClaw Skill 定义 ``` ### 2.2 技术栈 | 层级 | 技术 | |------|------| | **前端框架** | Next.js 16 + React 19 | | **状态管理** | Zustand 5 | | **样式方案** | Tailwind CSS 4 | | **LLM SDK** | Vercel AI SDK + LangGraph | | **类型系统** | TypeScript 5 | | **Canvas 渲染** | @napi-rs/canvas | | **幻灯片渲染** | 基于 PPTist 的 Canvas 引擎 | | **存储** | IndexedDB (Dexie) | | **富文本编辑** | ProseMirror | ### 2.3 核心模块和组件 #### A. 生成流水线 (`lib/generation/`) **两阶段生成架构**: 1. **大纲生成** (Stage 1): 分析用户输入,生成结构化课堂大纲 2. **场景生成** (Stage 2): 每个大纲条目生成为丰富的场景 ``` 用户输入 → 大纲生成器 → 场景生成器 → 完整课堂 ↓ ↓ SceneOutline[] Scene[] (含 Actions) ``` #### B. 多智能体编排 (`lib/orchestration/`) **LangGraph 状态机拓扑**: ``` START → director ──(end)──→ END │ └─(next)→ agent_generate ──→ director (loop) ``` **Director 策略**: - **单智能体**: 纯代码逻辑,无 LLM 调用 - **多智能体**: LLM 决定下一个发言的智能体 #### C. 回放引擎 (`lib/playback/engine.ts`) **状态机**: ``` start() pause() idle ──────────────────→ playing ──────────────→ paused ▲ ▲ │ │ │ resume() │ │ └───────────────────────┘ │ │ handleEndDiscussion() │ confirmDiscussion() │ / handleUserInterrupt() │ │ │ ▼ pause() └──────────────────────── live ──────────────→ paused ``` #### D. 动作引擎 (`lib/action/engine.ts`) **支持 28+ 种动作类型**: | 类别 | 动作 | |------|------| | **视觉特效** (Fire-and-forget) | `spotlight`, `laser` | | **语音** | `speech` (带 TTS) | | **白板** | `wb_open`, `wb_close`, `wb_draw_text`, `wb_draw_shape`, `wb_draw_chart`, `wb_draw_latex`, `wb_draw_table`, `wb_draw_line`, `wb_clear`, `wb_delete` | | **视频** | `play_video` | | **讨论** | `discussion` | ### 2.4 数据流和通信机制 **核心数据流**: ``` 用户操作 → React UI → Zustand Store → Next.js API → LangGraph → LLM ↓ ↓ SSE Stream ← StatelessEvent ← Agent Response ``` **SSE 事件类型** (`StatelessEvent`): - `agent_start` / `agent_end`: 智能体开始/结束 - `text_delta`: 文本增量 - `action`: 动作执行 - `thinking`: 思考状态 - `cue_user`: 提示用户发言 - `done` / `error`: 完成/错误 --- ## 3. 核心能力 ### 3.1 Agent 架构设计 **智能体配置结构** (`AgentConfig`): ```typescript interface AgentConfig { id: string; // 唯一 ID name: string; // 显示名称 role: string; // 角色: teacher, assistant, student persona: string; // 完整系统提示词 avatar: string; // 头像 URL 或 emoji color: string; // UI 主题色 allowedActions: string[]; // 允许的动作类型 priority: number; // Director 选择优先级 (1-10) isDefault: boolean; // 是否默认模板 isGenerated?: boolean; // 是否由 LLM 生成 } ``` **默认智能体**: | ID | 名称 | 角色 | 优先级 | |----|------|------|--------| | default-1 | AI teacher | teacher | 10 | | default-2 | AI助教 | assistant | 7 | | default-3 | 显眼包 | student | 4 | | default-4 | 好奇宝宝 | student | 5 | | default-5 | 笔记员 | student | 5 | | default-6 | 思考者 | student | 6 | **角色-动作映射**: ```typescript const ROLE_ACTIONS = { teacher: [...SLIDE_ACTIONS, ...WHITEBOARD_ACTIONS], // 全部能力 assistant: [...WHITEBOARD_ACTIONS], // 仅白板 student: [...WHITEBOARD_ACTIONS], // 仅白板 }; ``` ### 3.2 工具/能力系统 **动作执行架构**: ```typescript class ActionEngine { async execute(action: Action): Promise { // 1. 自动打开白板 (如果需要) // 2. 根据动作类型执行 switch (action.type) { case 'spotlight': // Fire-and-forget case 'laser': case 'speech': // 同步等待 TTS case 'wb_*': // 同步等待渲染 } } } ``` **结构化输出格式** (LLM 生成): ```json [ {"type": "action", "name": "spotlight", "params": {"elementId": "img_1"}}, {"type": "text", "content": "Hello students..."}, {"type": "action", "name": "wb_draw_text", "params": {...}} ] ``` ### 3.3 记忆/上下文管理 **无状态架构设计**: - 后端完全无状态,所有状态由客户端维护 - 每次请求携带完整上下文 (`StatelessChatRequest`) **DirectorState (跨轮次传递)**: ```typescript interface DirectorState { turnCount: number; // 当前轮次 agentResponses: AgentTurnSummary[]; // 智能体响应历史 whiteboardLedger: WhiteboardActionRecord[]; // 白板操作记录 } ``` **存储层**: - **IndexedDB** (Dexie): 课堂数据、大纲、生成的智能体 - **localStorage**: 智能体注册表、用户配置 - **持久化策略**: Zustand persist middleware + debounce 保存 ### 3.4 多模态支持 | 模态 | 实现 | |------|------| | **文本** | 流式生成 + SSE | | **语音** | Azure TTS / 浏览器 TTS | | **图像** | 多服务商 (Kling, Qwen, Seedance 等) | | **视频** | Kling, Veo, Seedance | | **LaTeX** | KaTeX 渲染 | | **图表** | ECharts | --- ## 4. 代码质量评估 ### 4.1 代码组织方式 **优点**: - 清晰的模块划分 - 类型集中管理 (`lib/types/`) - API 门面模式 (`lib/api/stage-api.ts`) - 关注点分离 (生成/播放/动作) **文件规模**: - 核心文件 200-800 行 - 最大文件 `director-graph.ts` 约 450 行 ### 4.2 测试覆盖 **未发现测试文件** - 这是项目的明显短板。建议添加: - 单元测试: 生成流水线、动作解析 - 集成测试: API 端点 - E2E 测试: 课堂生成流程 ### 4.3 文档完善度 **优点**: - 详细的 README (中英双语) - 内联注释丰富 - SKILL.md 示例展示了 Skill 系统用法 **不足**: - 缺少 API 文档 - 缺少架构图 (除 README 中的文字描述) - 无贡献指南细节 ### 4.4 可扩展性设计 **良好实践**: - **Provider 抽象**: 统一的 LLM 服务商接口 - **Action 插件化**: 易于添加新动作类型 - **Scene 类型扩展**: 支持 slide/quiz/interactive/pbl - **Agent 注册表**: 支持动态添加智能体 **扩展点**: ```typescript // 添加新 Provider PROVIDERS['new-provider'] = { ... }; // 添加新 Action 类型 type Action = ... | NewAction; // 添加新 Scene 类型 type SceneContent = ... | NewContent; ``` --- ## 5. 与 ZCLAW 的整合分析 ### 5.1 可复用的组件 | 组件 | 来源路径 | ZCLAW 适用场景 | |------|---------|---------------| | **LLM Provider 抽象** | `lib/ai/providers.ts` | 统一多模型支持 | | **结构化输出解析** | `lib/orchestration/stateless-generate.ts` | Tool Call 解析 | | **Action 系统** | `lib/types/action.ts` + `lib/action/engine.ts` | Agent 能力定义 | | **智能体注册表** | `lib/orchestration/registry/` | Agent 配置管理 | | **Zustand Store 模式** | `lib/store/` | 状态管理参考 | | **SKILL.md 格式** | `skills/openmaic/SKILL.md` | Skill 系统设计 | ### 5.2 架构参考价值 #### A. 无状态后端设计 OpenMAIC 的无状态架构非常适合 ZCLAW 参考: ```typescript // StatelessChatRequest - 所有状态由客户端传递 interface StatelessChatRequest { messages: UIMessage[]; // 对话历史 storeState: { ... }; // 应用状态 config: { agentIds, ... }; // 智能体配置 directorState?: DirectorState; // 跨轮次状态 } ``` ZCLAW 可采用类似模式,避免服务端状态管理复杂性。 #### B. LangGraph 多智能体编排 ```typescript // Director Graph - 智能体调度状态机 const graph = new StateGraph(OrchestratorState) .addNode('director', directorNode) .addNode('agent_generate', agentGenerateNode) .addEdge(START, 'director') .addConditionalEdges('director', directorCondition, {...}) .addEdge('agent_generate', 'director'); ``` ZCLAW 的多 Agent 协作可参考此模式。 #### C. Action 执行引擎 ```typescript // 统一的动作执行入口 class ActionEngine { async execute(action: Action): Promise { // Fire-and-forget vs Synchronous } } ``` ZCLAW 的 Hands 系统可采用类似架构。 ### 5.3 潜在的整合方式 #### 方式 1: 作为 ZCLAW 的 Skill OpenMAIC 可作为 ZCLAW 的一个 Skill 集成: ```markdown # skills/openmaic/SKILL.md --- name: openmaic description: 生成互动课堂 --- ``` 用户可通过 ZCLAW 调用 OpenMAIC 的课堂生成能力。 #### 方式 2: 共享组件库 抽取共享组件: - `zclaw-shared-types`: Action 类型、Provider 接口 - `zclaw-action-engine`: 通用动作执行引擎 - `zclaw-llm-adapter`: LLM 服务商适配器 #### 方式 3: 架构借鉴 | OpenMAIC 特性 | ZCLAW 对应 | |--------------|-----------| | Director Graph | zclaw-kernel 调度器 | | Agent Registry | Agent 分身管理 | | Action Engine | Hands 能力系统 | | Stage/Scene | 会话/任务管理 | ### 5.4 需要适配的部分 | 差异点 | OpenMAIC | ZCLAW | 适配建议 | |--------|----------|-------|---------| | **运行时** | Next.js (服务端) | Tauri (桌面端) | 重构为 Rust 调用 | | **状态存储** | IndexedDB | SQLite | 保持数据结构,换存储后端 | | **通信协议** | SSE over HTTP | gRPC / Tauri Commands | 适配流式响应 | | **UI 框架** | React + Next.js | React + Tauri | 组件可复用 | | **部署模式** | Web / Vercel | 桌面应用 | 需本地 LLM 支持 | --- ## 6. 总结与建议 ### 6.1 OpenMAIC 的优势 1. **成熟的多智能体编排**: LangGraph 状态机设计精良 2. **丰富的场景类型**: 幻灯片、测验、交互、PBL 全覆盖 3. **完善的多模态支持**: 文本、语音、图像、视频、白板 4. **无状态架构**: 易于扩展和维护 5. **学术论文支撑**: 有理论基础 ### 6.2 OpenMAIC 的不足 1. **缺少测试**: 无单元测试、集成测试 2. **Web-only**: 无桌面端支持 3. **依赖外部服务**: 需要多个 API Key 4. **文档分散**: 缺少集中式 API 文档 ### 6.3 对 ZCLAW 的建议 1. **借鉴无状态设计**: 将状态管理收敛到客户端 2. **采用 Action 系统模式**: 统一 Hands 能力接口 3. **参考 LangGraph 编排**: 实现多 Agent 协作 4. **复用 Provider 抽象**: 统一 LLM 服务商管理 5. **保持桌面端优势**: OpenMAIC 的 Web 限制是 ZCLAW 的机会 --- ## 7. 关键代码参考 ### 7.1 Provider 抽象接口 ```typescript // lib/ai/providers.ts export type ProviderId = 'openai' | 'anthropic' | 'google' | ...; export const PROVIDERS: Record = { openai: { name: 'OpenAI', models: ['gpt-4o', 'gpt-4o-mini', ...], defaultModel: 'gpt-4o-mini', }, // ... }; ``` ### 7.2 Action 类型定义 ```typescript // lib/types/action.ts export type Action = | SpotlightAction | LaserAction | SpeechAction | WhiteboardAction | VideoAction | DiscussionAction; export interface ActionBase { type: string; id?: string; } ``` ### 7.3 Agent 配置结构 ```typescript // lib/types/agent.ts export interface AgentConfig { id: string; name: string; role: 'teacher' | 'assistant' | 'student'; persona: string; avatar: string; color: string; allowedActions: string[]; priority: number; isDefault: boolean; } ``` --- ## 8. AGPL-3.0 许可证风险分析 ### 8.1 风险评估 | 风险点 | 影响 | 严重程度 | |--------|------|----------| | **Copyleft 传染** | 整合代码可能要求 ZCLAW 也开源 | 🔴 高 | | **网络条款** | AGPL-3.0 的网络使用条款比 GPL 更严格 | 🔴 高 | | **商业影响** | 可能影响 ZCLAW 的商业化能力 | 🔴 高 | ### 8.2 决策 ❌ **不直接整合 OpenMAIC 代码** ✅ **仅借鉴架构思想和设计模式** --- ## 9. 基于 ZCLAW 现有能力的实现方案 ### 9.1 ZCLAW 已有能力对照 | OpenMAIC 功能 | ZCLAW 对应 | 成熟度 | |---------------|------------|--------| | 多 Agent 编排 (Director Graph) | A2A 协议 + Kernel Registry | 框架完成 | | Agent 角色配置 | Skills + Agent 分身 | 完成 | | 动作执行引擎 (28+ Actions) | Hands 能力系统 | 完成 | | 工作流编排 | Trigger + EventBus | 基础完成 | | 状态管理 | MemoryStore (SQLite) | 完成 | | 外部集成 | Channels | 框架完成 | ### 9.2 实现路径 1. **完善 A2A 通信** - 实现 `crates/zclaw-protocols/src/a2a.rs` 中的 TODO 2. **扩展 Hands** - 添加 whiteboard/slideshow/speech/quiz 能力 3. **创建 Skill** - classroom-generator 课堂生成技能 4. **工作流增强** - DAG 编排、条件分支、并行执行 ### 9.3 需要新增的文件 ``` hands/whiteboard.HAND.toml # 白板能力 hands/slideshow.HAND.toml # 幻灯片能力 hands/speech.HAND.toml # 语音能力 hands/quiz.HAND.toml # 测验能力 skills/classroom-generator/SKILL.md # 课堂生成 ``` --- ## 10. 后续行动项 - [ ] 完善 A2A 协议实现(消息路由、能力发现) - [ ] 创建教育类 Hands(whiteboard、slideshow、speech、quiz) - [ ] 开发 classroom-generator Skill - [ ] 增强工作流编排能力(DAG、条件分支) --- ## 11. 深度架构分析 (2026-03-26 补充) ### 11.1 Director Graph 核心实现 **文件**: `lib/orchestration/director-graph.ts` #### 11.1.1 状态定义 ```typescript const OrchestratorState = Annotation.Root({ // 输入 (图入口时设置一次) messages: Annotation[]>, storeState: Annotation<{ stage: Stage | null; scenes: Scene[]; currentSceneId: string | null; mode: StageMode; whiteboardOpen: boolean; }>, availableAgentIds: Annotation, maxTurns: Annotation, languageModel: Annotation, triggerAgentId: Annotation, agentConfigOverrides: Annotation>, // 可变 (节点更新) currentAgentId: Annotation, turnCount: Annotation, agentResponses: Annotation({ reducer: (prev, update) => [...prev, ...update], default: () => [], }), whiteboardLedger: Annotation({ reducer: (prev, update) => [...prev, ...update], default: () => [], }), shouldEnd: Annotation, totalActions: Annotation, }); ``` #### 11.1.2 Director 节点核心逻辑 ```typescript async function directorNode(state, config) { const write = config.writer as (chunk: StatelessEvent) => void; const isSingleAgent = state.availableAgentIds.length <= 1; // Turn limit check if (state.turnCount >= state.maxTurns) { return { shouldEnd: true }; } // 单 Agent: 纯代码逻辑,无 LLM 调用 if (isSingleAgent) { const agentId = state.availableAgentIds[0] || 'default-1'; if (state.turnCount === 0) { write({ type: 'thinking', data: { stage: 'agent_loading', agentId } }); return { currentAgentId: agentId, shouldEnd: false }; } write({ type: 'cue_user', data: { fromAgentId: agentId } }); return { shouldEnd: true }; } // 多 Agent: 快速路径 - 触发 Agent if (state.turnCount === 0 && state.triggerAgentId) { const triggerId = state.triggerAgentId; if (state.availableAgentIds.includes(triggerId)) { write({ type: 'thinking', data: { stage: 'agent_loading', agentId: triggerId } }); return { currentAgentId: triggerId, shouldEnd: false }; } } // 多 Agent: LLM 决策 write({ type: 'thinking', data: { stage: 'director' } }); const prompt = buildDirectorPrompt(agents, conversationSummary, ...); const result = await adapter._generate([new SystemMessage(prompt), ...]); const decision = parseDirectorDecision(result.generations[0]?.text || ''); if (decision.nextAgentId === 'USER') { write({ type: 'cue_user', data: { fromAgentId: state.currentAgentId } }); return { shouldEnd: true }; } write({ type: 'thinking', data: { stage: 'agent_loading', agentId: decision.nextAgentId } }); return { currentAgentId: decision.nextAgentId, shouldEnd: false }; } ``` ### 11.2 StreamBuffer 节奏控制 **文件**: `lib/buffer/stream-buffer.ts` #### 11.2.1 设计目的 位于 SSE 流和 React 状态之间的统一内容展示节奏控制层: - 固定速率 tick 循环逐字显示文本 - 按顺序触发 Action 回调 - 避免 LLM 流式输出和前端打字机的双重效果 #### 11.2.2 缓冲项类型 ```typescript type BufferItem = | { kind: 'agent_start'; messageId: string; agentId: string; agentName: string; avatar?: string; color?: string } | { kind: 'agent_end'; messageId: string; agentId: string } | { kind: 'text'; messageId: string; agentId: string; partId: string; text: string; sealed: boolean } | { kind: 'action'; messageId: string; actionId: string; actionName: string; params: Record; agentId: string } | { kind: 'thinking'; stage: string; agentId?: string } | { kind: 'cue_user'; fromAgentId?: string; prompt?: string } | { kind: 'done'; totalActions: number; totalAgents: number; directorState?: DirectorState } | { kind: 'error'; message: string }; ``` #### 11.2.3 回调接口 ```typescript interface StreamBufferCallbacks { onAgentStart(data: AgentStartItem): void; onAgentEnd(data: AgentEndItem): void; onTextReveal(messageId: string, partId: string, revealedText: string, isComplete: boolean): void; onActionReady(messageId: string, data: ActionItem): void; onLiveSpeech(text: string | null, agentId: string | null): void; // Roundtable 实时语音 onSpeechProgress(ratio: number | null): void; // 播放进度 onThinking(data: { stage: string; agentId?: string } | null): void; onCueUser(fromAgentId?: string, prompt?: string): void; onDone(data: { totalActions: number; totalAgents: number; directorState?: DirectorState }): void; onError(message: string): void; } ``` #### 11.2.4 Tick 循环核心逻辑 ```typescript private tick(): void { if (this._paused || this._disposed) return; const item = this.items[this.readIndex]; if (!item) return; switch (item.kind) { case 'text': { // 逐字显示 this.charCursor = Math.min(this.charCursor + this.charsPerTick, item.text.length); const revealed = item.text.slice(0, this.charCursor); const fullyRevealed = this.charCursor >= item.text.length; const isComplete = fullyRevealed && item.sealed; this.cb.onTextReveal(item.messageId, item.partId, revealed, isComplete); this.cb.onLiveSpeech(revealed, this.currentAgentId); this.cb.onSpeechProgress(item.text.length > 0 ? this.charCursor / item.text.length : 1); if (isComplete) { this.readIndex++; this.charCursor = 0; this.advanceNonText(); // 处理后续非文本项 } break; } case 'action': { this.cb.onActionReady(item.messageId, item); this.readIndex++; // Action 后延迟,让动画有时间播放 if (this.actionDelayTicks > 0) { this._dwellTicksRemaining = this.actionDelayTicks; } break; } // ... 其他类型 } } ``` #### 11.2.5 配置选项 ```typescript interface StreamBufferOptions { tickMs?: number; // Tick 间隔,默认 30ms charsPerTick?: number; // 每 tick 显示字符数,默认 1 postTextDelayMs?: number; // 文本完成后延迟 actionDelayMs?: number; // Action 后延迟 } ``` ### 11.3 Action 引擎详细实现 **文件**: `lib/action/engine.ts` #### 11.3.1 执行模式 | 模式 | 动作 | 行为 | |------|------|------| | **Fire-and-forget** | spotlight, laser | 立即返回,不等待 | | **Synchronous** | speech, wb_*, play_video, discussion | 返回 Promise,等待完成 | #### 11.3.2 核心执行流程 ```typescript export class ActionEngine { private stageStore: StageStore; private audioPlayer: AudioPlayer | null; private effectTimer: ReturnType | null = null; async execute(action: Action): Promise { // 自动打开白板 if (action.type.startsWith('wb_') && action.type !== 'wb_open' && action.type !== 'wb_close') { await this.ensureWhiteboardOpen(); } switch (action.type) { case 'spotlight': this.executeSpotlight(action); return; // Fire-and-forget case 'speech': return this.executeSpeech(action); // Synchronous // ... 其他 } } // 视觉特效自动清除 private scheduleEffectClear(): void { if (this.effectTimer) clearTimeout(this.effectTimer); this.effectTimer = setTimeout(() => { useCanvasStore.getState().clearAllEffects(); }, 5000); // 5 秒后自动清除 } } ``` #### 11.3.3 白板动作实现 ```typescript private async executeWbDrawText(action: WbDrawTextAction): Promise { const wb = this.stageAPI.whiteboard.get(); if (!wb.success || !wb.data) return; this.stageAPI.whiteboard.addElement({ id: action.elementId || '', type: 'text', content: action.content, left: action.x, top: action.y, width: action.width ?? 400, height: action.height ?? 100, defaultColor: action.color ?? '#333333', }, wb.data.id); await delay(800); // 等待淡入动画 } ``` ### 11.4 设置状态管理 **文件**: `lib/store/settings.ts` #### 11.4.1 状态结构 ```typescript interface SettingsState { // 模型选择 providerId: ProviderId; modelId: string; providersConfig: ProvidersConfig; // TTS/ASR 设置 ttsProviderId: TTSProviderId; ttsVoice: string; ttsSpeed: number; asrProviderId: ASRProviderId; asrLanguage: string; ttsProvidersConfig: Record; asrProvidersConfig: Record; // 媒体生成 imageProviderId: ImageProviderId; imageModelId: string; videoProviderId: VideoProviderId; videoModelId: string; imageGenerationEnabled: boolean; videoGenerationEnabled: boolean; // Web Search webSearchProviderId: WebSearchProviderId; webSearchProvidersConfig: Record; // Agent 设置 selectedAgentIds: string[]; maxTurns: string; agentMode: 'preset' | 'auto'; autoAgentCount: number; // 播放控制 ttsMuted: boolean; ttsVolume: number; autoPlayLecture: boolean; playbackSpeed: PlaybackSpeed; // 布局 sidebarCollapsed: boolean; chatAreaCollapsed: boolean; chatAreaWidth: number; } ``` #### 11.4.2 持久化与迁移 ```typescript export const useSettingsStore = create()( persist( (set) => ({ /* state and actions */ }), { name: 'settings-storage', version: 2, migrate: (persistedState, version) => { // 版本迁移逻辑 if (version === 0) { /* ... */ } if (version < 2) { /* ... */ } return state; }, merge: (persistedState, currentState) => { // 合并内置 Provider 配置 const merged = { ...currentState, ...persistedState }; ensureBuiltInProviders(merged); return merged; }, }, ), ); ``` #### 11.4.3 服务器配置合并 ```typescript fetchServerProviders: async () => { const res = await fetch('/api/server-providers'); const data = await res.json(); set((state) => { // 重置所有服务器标记 // 合并服务器配置 // 自动选择/启用 (仅首次) return { /* updated state */ }; }); } ``` ### 11.5 无状态请求设计 **文件**: `lib/types/chat.ts` ```typescript interface StatelessChatRequest { // 对话历史 (客户端维护) messages: UIMessage[]; // 当前应用状态 storeState: { stage: Stage | null; scenes: Scene[]; currentSceneId: string | null; mode: StageMode; whiteboardOpen: boolean; }; // Agent 配置 config: { agentIds: string[]; sessionType?: 'qa' | 'discussion'; discussionTopic?: string; triggerAgentId?: string; agentConfigs?: Array<{...}>; // 动态生成的 Agent }; // 跨轮次状态 (Director) directorState?: DirectorState; // 用户配置 userProfile?: { nickname?: string; bio?: string }; // API 凭证 apiKey: string; baseUrl?: string; model?: string; } ``` ### 11.6 SSE 事件类型完整定义 ```typescript type StatelessEvent = | { type: 'agent_start'; data: { messageId, agentId, agentName, agentAvatar?, agentColor? } } | { type: 'agent_end'; data: { messageId, agentId } } | { type: 'text_delta'; data: { content, messageId? } } | { type: 'action'; data: { actionId, actionName, params, agentId, messageId? } } | { type: 'thinking'; data: { stage: 'director' | 'agent_loading'; agentId? } } | { type: 'cue_user'; data: { fromAgentId?, prompt? } } | { type: 'done'; data: { totalActions, totalAgents, agentHadContent?, directorState? } } | { type: 'error'; data: { message } }; ``` --- ## 12. 对 ZCLAW 的关键借鉴点 ### 12.1 StreamBuffer 节奏控制 **问题**: ZCLAW 目前可能存在 LLM 流式输出和前端打字机的双重效果 **解决方案**: 1. 引入类似 StreamBuffer 的中间层 2. 统一 Chat 和 Agent 回复的内容展示节奏 3. 支持暂停/恢复/刷新 ### 12.2 Director 快速路径优化 **问题**: 每次都需要 LLM 决策下一个 Agent **解决方案**: 1. 单 Agent 场景跳过 LLM 调用 2. 触发 Agent 场景直接调度 3. 仅多 Agent 复杂场景使用 LLM 决策 ### 12.3 无状态设计 **问题**: ZCLAW 服务端 Session 管理复杂 **解决方案**: 1. 考虑将部分状态迁移到客户端 2. 服务端只做生成,不维护会话状态 3. 每次请求携带完整上下文 ### 12.4 Action 引擎统一执行 **问题**: ZCLAW Hands 系统执行逻辑分散 **解决方案**: 1. 创建统一的 ActionEngine 类 2. 区分 Fire-and-forget 和 Synchronous 模式 3. 自动处理前置条件 (如白板自动打开) ### 12.5 设置版本迁移 **问题**: ZCLAW 配置更新时需要清理缓存 **解决方案**: 1. 实现 Zustand persist 的 migrate 函数 2. 支持 merge 函数合并新默认值 3. 保持用户配置不丢失