20 KiB
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 中引入新的 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 下新增一个专用目录,例如:
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 风格体验,需要后端模型接口至少返回:
namedisplay_nameprovidersupports_thinkingsupports_reasoning_effortsupports_visionsupports_tool_callingsupports_artifact_editingsupports_code_editingtemperature_rangemax_tokens_rangebase_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
- 提供 Canvas 首页和 Canvas Thread 页
- 支持空状态展示
7.3 建议目录
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中维护子路由
建议形式:
/canvas
/canvas/:threadId
7.5 验收标准
- 能访问 Canvas 首页
- 能访问指定 thread 的 Canvas 页面
- 不影响现有
workspace/*与strategy/* - 页面有独立布局骨架
8. 阶段二:前端 Canvas 布局与交互容器
8.1 目标
先做出“左聊天、右画布”的基础容器,不接真实 AI 改写逻辑。
8.2 需求
- 左侧聊天区
- 右侧画布区
- 支持面板拖拽或折叠
- 初始空状态
- 支持“快速开始”:
- 新建空白文本 artifact
- 新建代码 artifact
8.3 组件拆分建议
CanvasShellCanvasSidebarCanvasChatPanelCanvasArtifactPanelCanvasEmptyStateQuickStartActions
8.4 快速开始能力
用户进入空线程时可以选择:
- 开始写文章
- 开始写代码
- 从模板开始
首版模板可只做最小集:
- 空白文档
- HTML 模板
- React 组件模板
- Python 脚本模板
8.5 验收标准
- 页面可稳定展示双栏布局
- 快速开始能创建前端本地 artifact 状态
- 代码和文本可分别进入不同渲染器
9. 阶段三:结构化 Artifact 数据模型
9.1 目标
定义 DeerFlow 的 Canvas Artifact 协议,作为前后端统一契约。
9.2 核心要求
需要支持以下能力:
- 文本 artifact
- 代码 artifact
- 标题
- 当前版本索引
- 版本历史
- 当前选中版本切换
- 后续支持局部高亮编辑
9.3 建议数据结构
type CanvasArtifact = {
currentIndex: number;
contents: Array<CanvasArtifactText | CanvasArtifactCode>;
};
type CanvasArtifactText = {
index: number;
type: "text";
title: string;
fullMarkdown: string;
};
type CanvasArtifactCode = {
index: number;
type: "code";
title: string;
language: string;
code: string;
};
9.4 线程状态建议新增字段
前端与后端需共同支持:
artifacthighlighted_texthighlighted_codecanvas_modeweb_search_enabledweb_search_resultsquick_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_intentreply_general_inputgenerate_artifactrewrite_artifactupdate_highlighted_textupdate_highlighted_codegenerate_followup
二期可加:
rewrite_artifact_themerewrite_code_themechange_lengthchange_reading_leveltranslate_artifactadd_commentsadd_logsfix_bugsport_languageweb_search_enrich
11.4 路由逻辑要求
系统需要能判断:
- 用户是在闲聊
- 用户要新生成 artifact
- 用户要整体重写当前 artifact
- 用户要局部修改当前 artifact
- 用户要执行某个快捷动作
11.5 状态输入要求
节点需要读取:
- 当前消息历史
- 当前 artifact
- 当前选区
- 当前模型配置
- Web 搜索开关
11.6 输出要求
节点输出必须能更新:
messagesartifactweb_search_resultsfollowup
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,建议配置化:
idlabeltypeapplicable_toprompt_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 后端配置建议
后端模型配置应至少支持:
namedisplay_nameusemodelapi_keybase_urlsupports_visionsupports_thinkingsupports_tool_callingis_localcanvas_capabilities
15.5 Canvas 模式额外要求
由于不是所有模型都适合 Canvas 改写任务,建议增加能力标识:
supports_canvas_generationsupports_canvas_rewritesupports_canvas_code_editsupports_streaming_textsupports_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. 推荐开发顺序
建议严格按以下顺序推进:
- 路由和目录骨架
- Canvas 页面布局
- 前端 artifact 数据模型
- 后端线程状态扩展
- 新建 Canvas Agent 图
- 前后端流式同步
- 整体生成与整体改写
- 局部选区改写
- 快捷动作
- 本地模型支持完善
- Web 搜索增强
- 导出与文件联动
不要先做局部改写和快捷动作,否则前面的状态与路由契约不稳定,返工会很多。
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 架构保持长期兼容。