# Open Canvas 模式需求拆解文档 ## 1. 文档目标 本文档用于指导 DeerFlow 在现有架构中新增一个 `open-canvas` 风格的 Canvas 模式。 目标不是直接照搬 `langchain-ai/open-canvas` 的 Next.js + LangGraph.js 实现,而是在当前项目技术栈内完成一套等价能力的实现: - 前端:基于 `React 19 + Vite + react-router-dom` - 后端:基于 `Python + FastAPI + LangGraph` - 模型层:支持云模型与本地模型自由配置 - 状态层:支持结构化 artifact、版本历史、局部改写、快速动作、画布编辑 本文档重点是把需求拆成“可实现、可排期、可验收”的阶段性任务。 --- ## 2. 最终目标 ### 2.1 用户视角目标 用户进入一个新的 Canvas 工作模式后,可以获得与 open-canvas 接近的体验: - 左侧是聊天区,右侧是 Canvas 编辑区 - 可以从空白文本或代码模板快速开始 - 可以通过聊天让 AI 生成一份结构化 artifact - 可以对 artifact 整体重写,也可以对选中的局部内容进行改写 - artifact 支持版本历史切换 - artifact 支持文本和代码两种主要类型 - 支持快速动作,例如扩写、压缩、改风格、改语气、加注释、修 bug、换语言 - 支持启用 Web 搜索增强 - 支持切换模型 - 支持使用本地模型,例如 Ollama 或 OpenAI-compatible 本地服务 ### 2.2 工程视角目标 新增的 Canvas 模式需要满足以下工程原则: - 不破坏现有 DeerFlow 工作区 - 不影响现有基于 `artifacts: string[]` 的文件产物功能 - 可逐阶段上线 - 前后端状态协议清晰 - 可兼容现有 LangGraph 线程、消息流、认证和模型接口 --- ## 3. 范围定义 ### 3.1 本次需求包含 - 前端新增 `open-canvas` 专用目录 - 在 [PageRoutes.tsx](../src/pages/PageRoutes.tsx) 中引入新的 Canvas 路由 - 前端新增 Canvas 页面、上下文、组件、状态管理 - 后端新增 Canvas 专用线程状态字段 - 后端新增 Canvas Agent 图或在现有 Agent 体系中新增 Canvas 模式分支 - 模型配置统一为 DeerFlow 后端配置驱动 - 支持本地大模型配置与模型列表动态下发 - 支持结构化 artifact 的保存、读取、更新、版本切换 ### 3.2 本次需求不包含 - 一次性复刻 open-canvas 全部 UI 细节 - 完整照搬 Supabase 鉴权体系 - 直接复用 open-canvas 的 Next.js API Route - 直接运行 open-canvas 的 LangGraph.js 后端 - 首阶段就实现所有快捷动作、所有富文本效果、所有搜索增强能力 ### 3.3 迁移原则 - 借鉴 open-canvas 的能力模型,不直接迁移其运行时架构 - 前端尽量复用其交互设计和数据结构 - 后端以 Python 实现同等能力 - 配置以 DeerFlow 为真源,不以 open-canvas 的 TS 文件为真源 --- ## 4. 总体设计思路 ### 4.1 前端设计思路 在现有 `frontend-web/src` 下新增一个专用目录,例如: ```text src/ open-canvas/ pages/ routes/ components/ contexts/ hooks/ types/ api/ utils/ constants/ ``` 建议将 Canvas 模式作为一个独立的页面子系统接入,而不是把现有工作区页面强行改造成 Canvas。 建议路由形式: - `/canvas` - `/canvas/:threadId` 也可以挂在现有页面布局下,例如: - `/workspace/canvas` - `/workspace/canvas/:threadId` 推荐优先采用独立一级功能路由: - 逻辑更清晰 - 状态隔离更容易 - 不容易污染现有 `workspace` 功能 ### 4.2 后端设计思路 后端不建议直接改造现有通用 Agent 去同时承担全部 Canvas 行为,而是建议采用以下两种方案之一: #### 方案 A:新增独立 Canvas Assistant - 新增 `canvas_agent` - 使用单独的 LangGraph 状态定义 - 前端调用时通过 `assistant_id=canvas_agent` 优点: - 与现有 `lead_agent` 隔离 - 风险更低 - 更容易对齐 open-canvas 的图结构 缺点: - 会产生一套新的 Agent 图维护成本 #### 方案 B:在现有 Lead Agent 中增加 Canvas 模式分支 - 在 thread metadata 或 configurable 中增加 `ui_mode=canvas` - Agent 根据模式进入 Canvas 路径 优点: - 统一入口 缺点: - 会显著增加现有 Agent 复杂度 - 容易影响现有聊天和文件产物模式 推荐先做方案 A。 ### 4.3 模型配置设计思路 模型配置统一以 DeerFlow 后端 `config.yaml` 为真源。 前端不维护固定模型常量列表,而是通过 `/api/models` 获取模型能力元数据。 为了实现 open-canvas 风格体验,需要后端模型接口至少返回: - `name` - `display_name` - `provider` - `supports_thinking` - `supports_reasoning_effort` - `supports_vision` - `supports_tool_calling` - `supports_artifact_editing` - `supports_code_editing` - `temperature_range` - `max_tokens_range` - `base_url_source` 或 provider 标识 - `is_local` --- ## 5. 与当前项目的关键差异 ### 5.1 当前 DeerFlow 现状 当前 DeerFlow 线程状态中的 artifact 主要是文件路径列表: - `artifacts: string[]` 这更接近“生成文件产物”的工作模式。 前端当前 artifact 面板也主要是: - 文件列表 - 文件详情 - 文件下载/预览 ### 5.2 open-canvas 的关键能力 open-canvas 的核心不是“生成文件”,而是“维护一个结构化的当前文档对象”: - 一个 conversation 对应一个主 artifact - artifact 具有类型、标题、内容、版本 - 用户可以选中部分内容让 AI 改写 - 每次改写都会生成新版本 ### 5.3 需要新增的核心能力 为支持 Canvas 模式,需要在 DeerFlow 中新增一套结构化 artifact 状态: - 当前 artifact - 当前版本索引 - 历史版本列表 - 选区信息 - 当前编辑模式 - 快速动作状态 - Web 搜索结果状态 --- ## 6. 分阶段实施方案 以下为推荐的 8 个阶段,每个阶段都可单独开发、联调和验收。 --- ## 7. 阶段一:前端路由与目录骨架 ### 7.1 目标 在不影响现有页面的前提下,建立 Canvas 模式的前端骨架。 ### 7.2 需求 - 新增 `src/open-canvas/` 目录 - 新增 Canvas 页面路由 - 将路由接入 [PageRoutes.tsx](../src/pages/PageRoutes.tsx) - 提供 Canvas 首页和 Canvas Thread 页 - 支持空状态展示 ### 7.3 建议目录 ```text src/open-canvas/ api/ threads.ts runs.ts models.ts components/ layout/ chat/ canvas/ artifacts/ quick-actions/ selectors/ contexts/ CanvasThreadContext.tsx CanvasGraphContext.tsx CanvasUIContext.tsx hooks/ useCanvasThread.ts useCanvasStream.ts useCanvasArtifact.ts pages/ CanvasHomePage.tsx CanvasThreadPage.tsx routes/ OpenCanvasRoutes.tsx types/ artifact.ts thread.ts model.ts utils/ artifact.ts selection.ts stream.ts constants/ index.ts ``` ### 7.4 路由建议 - 在 `PageRoutes.tsx` 中新增 `canvas/*` - 在 `src/open-canvas/routes/OpenCanvasRoutes.tsx` 中维护子路由 建议形式: ```text /canvas /canvas/:threadId ``` ### 7.5 验收标准 - 能访问 Canvas 首页 - 能访问指定 thread 的 Canvas 页面 - 不影响现有 `workspace/*` 与 `strategy/*` - 页面有独立布局骨架 --- ## 8. 阶段二:前端 Canvas 布局与交互容器 ### 8.1 目标 先做出“左聊天、右画布”的基础容器,不接真实 AI 改写逻辑。 ### 8.2 需求 - 左侧聊天区 - 右侧画布区 - 支持面板拖拽或折叠 - 初始空状态 - 支持“快速开始”: - 新建空白文本 artifact - 新建代码 artifact ### 8.3 组件拆分建议 - `CanvasShell` - `CanvasSidebar` - `CanvasChatPanel` - `CanvasArtifactPanel` - `CanvasEmptyState` - `QuickStartActions` ### 8.4 快速开始能力 用户进入空线程时可以选择: - 开始写文章 - 开始写代码 - 从模板开始 首版模板可只做最小集: - 空白文档 - HTML 模板 - React 组件模板 - Python 脚本模板 ### 8.5 验收标准 - 页面可稳定展示双栏布局 - 快速开始能创建前端本地 artifact 状态 - 代码和文本可分别进入不同渲染器 --- ## 9. 阶段三:结构化 Artifact 数据模型 ### 9.1 目标 定义 DeerFlow 的 Canvas Artifact 协议,作为前后端统一契约。 ### 9.2 核心要求 需要支持以下能力: - 文本 artifact - 代码 artifact - 标题 - 当前版本索引 - 版本历史 - 当前选中版本切换 - 后续支持局部高亮编辑 ### 9.3 建议数据结构 ```ts type CanvasArtifact = { currentIndex: number; contents: Array; }; type CanvasArtifactText = { index: number; type: "text"; title: string; fullMarkdown: string; }; type CanvasArtifactCode = { index: number; type: "code"; title: string; language: string; code: string; }; ``` ### 9.4 线程状态建议新增字段 前端与后端需共同支持: - `artifact` - `highlighted_text` - `highlighted_code` - `canvas_mode` - `web_search_enabled` - `web_search_results` - `quick_action_id` ### 9.5 与现有 `artifacts: string[]` 的关系 建议保留现有 `artifacts: string[]` 不动。 新增字段: - `artifact` 用于 Canvas 主文档 - `artifacts` 继续用于文件产物 这样可以兼容未来“Canvas 生成网页文件、导出文件、保存文件”的场景。 ### 9.6 验收标准 - 前端类型定义完成 - 后端状态字段设计完成 - 确认与现有线程状态兼容 --- ## 10. 阶段四:后端线程状态与 API 扩展 ### 10.1 目标 让后端线程状态可以安全存储和返回 Canvas Artifact。 ### 10.2 需求 - 扩展 Python `ThreadState` - 扩展状态序列化逻辑 - 确保 `/api/threads/*` 返回结构化 `artifact` - 确保 LangGraph 流中可带上 `artifact` 更新 ### 10.3 后端改造点 建议关注以下模块: - `packages/harness/deerflow/agents/thread_state.py` - 线程 state serializer - `app/gateway/routers/threads.py` - 流事件适配层 ### 10.4 注意事项 - 旧线程没有 `artifact` 字段时必须兼容 - 状态更新不能破坏现有消息结构 - 必须确保 JSON 可序列化 ### 10.5 验收标准 - 新建线程可写入 `artifact` - 读取线程时可返回 `artifact` - 不影响现有线程读取 - 前端能从线程 state 中恢复 Canvas 内容 --- ## 11. 阶段五:Canvas 专用 Agent 图 ### 11.1 目标 实现与 open-canvas 类似的 AI 路由能力。 ### 11.2 推荐方案 新增 `canvas_agent`,单独维护图逻辑。 ### 11.3 节点拆分建议 首版建议至少拆成这些节点: - `route_user_intent` - `reply_general_input` - `generate_artifact` - `rewrite_artifact` - `update_highlighted_text` - `update_highlighted_code` - `generate_followup` 二期可加: - `rewrite_artifact_theme` - `rewrite_code_theme` - `change_length` - `change_reading_level` - `translate_artifact` - `add_comments` - `add_logs` - `fix_bugs` - `port_language` - `web_search_enrich` ### 11.4 路由逻辑要求 系统需要能判断: - 用户是在闲聊 - 用户要新生成 artifact - 用户要整体重写当前 artifact - 用户要局部修改当前 artifact - 用户要执行某个快捷动作 ### 11.5 状态输入要求 节点需要读取: - 当前消息历史 - 当前 artifact - 当前选区 - 当前模型配置 - Web 搜索开关 ### 11.6 输出要求 节点输出必须能更新: - `messages` - `artifact` - `web_search_results` - `followup` ### 11.7 验收标准 - 能根据输入创建新 artifact - 能根据输入整体改写 artifact - 能保留版本历史 - 能在改写后返回自然语言 followup --- ## 12. 阶段六:前端流式同步与版本管理 ### 12.1 目标 让前端能像 open-canvas 一样在流式过程中更新画布与聊天。 ### 12.2 需求 - 复用现有 LangGraph stream client - 在 Canvas 模式中解析 `artifact` 更新 - 支持流式文本更新 - 支持版本切换 - 支持断线后恢复线程状态 ### 12.3 前端状态层建议 - `CanvasThreadContext`:线程基础信息 - `CanvasGraphContext`:消息、artifact、streaming 状态 - `CanvasUIContext`:面板、编辑态、选中态 ### 12.4 关键能力 - 当前版本切换 - 新版本创建后自动定位到最新版本 - 手动编辑内容后保存 - 流结束后线程状态持久化 ### 12.5 验收标准 - 发送消息时聊天和画布可同步更新 - 版本数会增加 - 切换历史版本稳定 - 刷新页面后线程状态能恢复 --- ## 13. 阶段七:局部选区改写 ### 13.1 目标 实现 Canvas 模式最关键的差异化能力之一:选中局部内容进行 AI 改写。 ### 13.2 文本选区需求 - 支持在 Markdown 文本中选择一段文本 - 记录选区位置与原始文本 - 用户发出修改请求后,仅重写该选区 - 将选区结果合并为新版本 artifact ### 13.3 代码选区需求 - 支持在代码编辑器中选择一段代码 - 记录 start/end index 或行列信息 - AI 只返回替换片段 - 前端或后端负责将新片段拼接回完整代码 ### 13.4 实现建议 首版建议: - 文本:前端记录纯文本字符位置 - 代码:使用 CodeMirror selection 信息 不建议首版就做复杂块级富文本局部编辑。 ### 13.5 风险 - Markdown 渲染态与源码态位置映射复杂 - 富文本块级位置难维护 - 流式更新中选区同步容易错位 ### 13.6 首版折中方案 首版文本只基于 `fullMarkdown` 纯文本改写,不做 BlockNote 富文本块定位。 ### 13.7 验收标准 - 文本局部改写成功 - 代码局部改写成功 - 原内容未改动部分保持不变 - 新版本正确入历史 --- ## 14. 阶段八:快捷动作系统 ### 14.1 目标 实现 open-canvas 风格的快捷动作体系。 ### 14.2 首批推荐动作 文本类: - 扩写 - 精简 - 改正式语气 - 改口语语气 - 改阅读难度 - 翻译 代码类: - 加注释 - 加日志 - 修复 bug - 优化代码 - 转换语言 ### 14.3 设计方式 快捷动作不要直接写死在 UI,建议配置化: - `id` - `label` - `type` - `applicable_to` - `prompt_template` ### 14.4 后端设计 快捷动作可通过: - 前端传 `quick_action_id` - 后端路由节点根据动作 id 选择 prompt ### 14.5 验收标准 - 文本动作可执行 - 代码动作可执行 - 结果进入新版本 - 不同动作提示词可扩展 --- ## 15. 阶段九:模型配置统一与本地模型支持 ### 15.1 目标 让 Canvas 模式支持和主系统统一的模型选择,并且能自由配置本地大模型。 ### 15.2 原则 - 后端 `config.yaml` 为真源 - 前端只展示后端暴露的模型信息 - 不维护一份脱离后端的前端常量模型表 ### 15.3 本地模型支持范围 建议优先支持两类: - `Ollama` - OpenAI-compatible 本地服务 - LM Studio - vLLM - LocalAI - one-api 风格代理 ### 15.4 后端配置建议 后端模型配置应至少支持: - `name` - `display_name` - `use` - `model` - `api_key` - `base_url` - `supports_vision` - `supports_thinking` - `supports_tool_calling` - `is_local` - `canvas_capabilities` ### 15.5 Canvas 模式额外要求 由于不是所有模型都适合 Canvas 改写任务,建议增加能力标识: - `supports_canvas_generation` - `supports_canvas_rewrite` - `supports_canvas_code_edit` - `supports_streaming_text` - `supports_streaming_tool_calls` ### 15.6 与 open-canvas 的关系 可以借鉴其命名习惯和能力分层,但不建议直接依赖其 `packages/shared/src/models.ts` 作为配置源。 ### 15.7 验收标准 - 前端模型选择器可显示后端返回模型 - 可切换本地模型 - Canvas 模式能用本地模型生成和改写 --- ## 16. 阶段十:Web 搜索增强 ### 16.1 目标 实现类似 open-canvas 的可选 Web 搜索增强。 ### 16.2 需求 - UI 提供 Web 搜索开关 - 后端在需要时走搜索节点 - 搜索结果写入线程状态 - 结果可在画布旁侧栏展示 ### 16.3 首版建议 只做: - 开关 - 搜索结果列表 - 搜索结果用于生成 artifact 暂不做复杂网页抓取编辑链路。 ### 16.4 验收标准 - 打开搜索后可返回搜索结果 - 搜索结果可参与 artifact 生成 - 结果展示不阻塞主画布 --- ## 17. 阶段十一:持久化、导出与文件产物联动 ### 17.1 目标 让 Canvas 文档与 DeerFlow 原有文件能力协同。 ### 17.2 需求 - artifact 持久化在线程 state 中 - 可手动导出为文件 - 可生成真实 HTML/Markdown/代码文件到现有 outputs - Canvas artifact 与 `artifacts: string[]` 可双向关联 ### 17.3 推荐能力 - 导出 Markdown - 导出代码文件 - 另存为 artifact file - 从 artifact file 回填到 Canvas ### 17.4 验收标准 - 当前版本可导出 - 导出文件可在现有文件面板查看 - 文件型 artifact 和 Canvas artifact 能共存 --- ## 18. 推荐开发顺序 建议严格按以下顺序推进: 1. 路由和目录骨架 2. Canvas 页面布局 3. 前端 artifact 数据模型 4. 后端线程状态扩展 5. 新建 Canvas Agent 图 6. 前后端流式同步 7. 整体生成与整体改写 8. 局部选区改写 9. 快捷动作 10. 本地模型支持完善 11. Web 搜索增强 12. 导出与文件联动 不要先做局部改写和快捷动作,否则前面的状态与路由契约不稳定,返工会很多。 --- ## 19. 里程碑定义 ### M1:页面可进入 - 路由接通 - 双栏布局完成 - 本地 mock artifact 可渲染 ### M2:后端状态打通 - 线程可保存结构化 artifact - 页面刷新后能恢复 ### M3:AI 生成可用 - 可新建文本/代码 artifact - 可整体改写 - 可产生版本历史 ### M4:核心体验可用 - 选区改写可用 - 快捷动作可用 - 模型切换可用 ### M5:增强能力完整 - 本地模型支持完善 - Web 搜索增强 - 导出和文件联动 --- ## 20. 风险与难点 ### 20.1 最大难点 - 结构化 artifact 状态从无到有 - 局部选区改写的精确性 - 流式状态与版本管理的一致性 - 不破坏现有 DeerFlow 文件型 artifact 体系 ### 20.2 技术风险 - 线程 state JSON 结构过大 - 大模型对局部改写指令遵循不稳定 - 本地模型 tool calling 与流式能力差异大 - 文本渲染态与源码态位置映射复杂 ### 20.3 规避建议 - 首版只支持 Markdown 源码态编辑,不做复杂富文本编辑 - 首版只支持文本和代码两种 artifact 类型 - 首版先做整体生成和整体改写,再做局部改写 - 本地模型先支持“能生成、能重写”的最小能力,不强求与顶级闭源模型完全同效 --- ## 21. 验收总清单 ### 21.1 前端 - 有独立 Canvas 路由 - 有专用目录和模块边界 - 双栏布局可用 - 文本和代码两类 artifact 可渲染 - 历史版本可切换 - 选区改写可交互 - 快捷动作可触发 - 模型可切换 ### 21.2 后端 - 线程状态支持 `artifact` - 新增 `canvas_agent` 或等价模式 - 生成、重写、局部改写可用 - 流式返回稳定 - 模型列表接口支持 Canvas 能力元数据 ### 21.3 本地模型 - 可配置 Ollama - 可配置 OpenAI-compatible 本地服务 - 前端可见并可切换 - 至少能完成文本生成和整体改写 --- ## 22. 推荐首版最小可交付范围 如果要控制风险,建议首版只交付以下内容: - 新增 `canvas/*` 路由 - 双栏布局 - 结构化 `artifact` - `canvas_agent` - 文本/代码 artifact 新建 - 整体生成 - 整体改写 - 历史版本切换 - 后端模型动态加载 - Ollama 或本地 OpenAI-compatible 至少一种可用 先不要把以下内容放进首版强制目标: - 富文本块级精确编辑 - 全量快捷动作 - 复杂 Web 搜索增强 - 多 artifact 并行管理 --- ## 23. 后续实施建议 建议下一步基于本文档继续输出两份落地文档: ### 23.1 前端实施清单 逐文件列出: - 要新建哪些文件 - 哪些组件可复用 - 哪些页面要接入路由 - 哪些状态要从现有 hooks 抽离 ### 23.2 后端实施清单 逐模块列出: - 要改哪些 Python 文件 - 新增哪些状态字段 - 新增哪些 Agent 节点 - 哪些 API 需要扩展 --- ## 24. 结论 这个需求很大,但完全可拆。 正确做法不是“先抄 UI”,而是按下面的主线推进: - 先建前端 Canvas 子系统 - 再建结构化 artifact 状态 - 再建 Canvas Agent 图 - 再补局部改写和快捷动作 - 最后统一本地模型能力 只要按本文档阶段推进,这个需求是可以落地的,而且能和你现在的 DeerFlow 架构保持长期兼容。