Files
deerflow-code/frontend-web/docs/openCanvas-backend-checklist.md
2026-05-15 10:42:44 +08:00

1032 lines
19 KiB
Markdown

# Open Canvas 后端实施清单
## 1. 文档目标
本文档是 [openCanvas.md](./openCanvas.md) 的后端落地版清单。
目标是把 Canvas 模式在当前 DeerFlow 后端中的实施工作拆成可以直接排期和执行的任务,覆盖:
- 线程状态扩展
- `canvas_agent` 设计
- LangGraph 节点拆分
- Gateway API 扩展
- 流式输出契约
- 模型配置与本地模型支持
- 结构化 artifact 的持久化
- 测试与验收顺序
本文档默认前端会新增独立的 Canvas 子系统,并通过现有 LangGraph 线程和 Gateway API 与后端通信。
---
## 2. 实施原则
### 2.1 总原则
- 不破坏现有 `lead_agent`
- 不破坏现有 `artifacts: list[str]` 文件产物体系
- 优先增量扩展,不做推倒重构
- 先打通状态和协议,再实现复杂 AI 行为
- 先支持文本/代码双类型,再逐步扩展快捷动作
### 2.2 推荐路线
推荐采用“新增独立 `canvas_agent`”方案,而不是把所有 Canvas 行为塞进现有 `lead_agent`。
推荐原因:
- 风险更低
- 图逻辑更清晰
- 更容易对齐 open-canvas 的状态结构
- 不影响现有 DeerFlow 普通聊天与文件产物模式
### 2.3 后端目标边界
本次后端实施重点是:
- 新增 Canvas 专用线程状态字段
- 新增 Canvas Agent 图
- 新增前端需要的模型能力元数据
- 支持结构化 artifact 在线程状态中读写
本次不要求:
- 完整复刻 open-canvas 的所有 TS 图结构
- 完整复刻 Supabase 相关逻辑
- 把所有模型 provider 完全抽象成统一能力中台
---
## 3. 现有后端基础能力盘点
当前 DeerFlow 后端已经具备非常好的基础设施:
- LangGraph 线程与流式交互
- FastAPI Gateway
- 模型动态配置
- 本地线程状态管理
- Sandbox/工具体系
- 上传与文件 artifact 访问
- Memory 与标题生成
因此 Canvas 模式并不是“从 0 开始做 Agent 平台”,而是“在现有平台上新增一类结构化创作模式”。
---
## 4. 目标代码落点
建议优先关注以下目录:
```text
offline-backend-20260512/backend/
app/gateway/
routers/
deps.py
app.py
packages/harness/deerflow/
agents/
factory.py
thread_state.py
lead_agent/
middlewares/
runtime/
config/
tools/
```
建议为 Canvas 新增或扩展以下区域:
```text
packages/harness/deerflow/
agents/
canvas_agent/
__init__.py
agent.py
prompt.py
state.py
nodes/
route_user_intent.py
generate_artifact.py
rewrite_artifact.py
update_highlighted_text.py
update_highlighted_code.py
generate_followup.py
quick_actions.py
web_search.py
```
如果不想把节点拆得太细,首版也可以把部分逻辑先收在 `agent.py` 里,但建议至少把 `state.py` 和 `prompt.py` 独立出来。
---
## 5. 开发阶段总览
后端建议分为 11 个阶段:
1. 线程状态扩展
2. 结构化 artifact 协议定义
3. `canvas_agent` 接入到 Agent 工厂
4. Canvas 图的最小节点实现
5. Gateway/线程接口兼容
6. 流式状态输出适配
7. 模型能力元数据扩展
8. 本地模型兼容与配置统一
9. 快捷动作与局部改写
10. Web 搜索增强
11. 测试、回归、验收
---
## 6. 阶段一:线程状态扩展
### 6.1 任务目标
让 DeerFlow 的线程状态能原生保存 Canvas 所需的结构化信息。
### 6.2 任务清单
- 扩展 [thread_state.py](../../offline-backend-20260512/backend/packages/harness/deerflow/agents/thread_state.py)
- 定义 Canvas 相关 TypedDict 或 dataclass 结构
- 确保状态字段可序列化
- 不影响现有 `messages/title/artifacts/todos` 逻辑
### 6.3 建议新增字段
在现有 `ThreadState` 上新增:
- `artifact`
- `highlighted_text`
- `highlighted_code`
- `canvas_mode`
- `quick_action_id`
- `web_search_enabled`
- `web_search_results`
### 6.4 建议数据形态
可先采用 JSON-safe dict 结构,而不是在状态层引入过重的复杂对象。
建议:
```python
class CanvasArtifactText(TypedDict):
index: int
type: Literal["text"]
title: str
fullMarkdown: str
class CanvasArtifactCode(TypedDict):
index: int
type: Literal["code"]
title: str
language: str
code: str
class CanvasArtifact(TypedDict):
currentIndex: int
contents: list[CanvasArtifactText | CanvasArtifactCode]
```
### 6.5 与现有 `artifacts` 的关系
必须保留现有:
- `artifacts: list[str]`
新增:
- `artifact: dict | None`
含义区分:
- `artifacts` 表示文件型产物列表
- `artifact` 表示 Canvas 当前主文档
### 6.6 验收标准
- 旧线程无 `artifact` 时不报错
- 新线程可写入 `artifact`
- 线程状态能被 FastAPI 和 LangGraph 正确序列化
---
## 7. 阶段二:结构化 Artifact 协议定义
### 7.1 任务目标
统一前后端对 Canvas artifact 的字段约定。
### 7.2 任务清单
- 在后端建立一份明确的 artifact 协议定义
- 明确字段命名、类型、兼容策略
- 明确版本管理规则
### 7.3 协议要求
必须支持:
- 文本 artifact
- 代码 artifact
- 标题
- 当前版本索引
- 历史版本列表
- 后续支持局部改写
### 7.4 版本规则
- 每次 AI 整体生成,生成 `contents[0]`
- 每次 AI 重写,追加一个新版本
- `currentIndex` 指向当前版本
- 历史版本默认只保留在线程状态中,不额外落库
### 7.5 建议约束
- `index` 从 1 开始
- `currentIndex` 必须落在 `contents` 范围内
- `type` 只允许 `"text"` 或 `"code"`
### 7.6 验收标准
- 前后端字段完全一致
- 状态协议有明确默认值和边界规则
---
## 8. 阶段三:接入 `canvas_agent`
### 8.1 任务目标
在现有 Agent 体系中注册一个独立的 Canvas Agent。
### 8.2 任务清单
- 新建 `packages/harness/deerflow/agents/canvas_agent/`
- 新建 `agent.py`
- 新建 `prompt.py`
- 新建 `state.py`
- 修改 [factory.py](../../offline-backend-20260512/backend/packages/harness/deerflow/agents/factory.py)
### 8.3 注册方式建议
建议将 `canvas_agent` 作为一个显式 assistant id 暴露给 LangGraph 运行时。
前端调用时:
- `assistant_id=canvas_agent`
### 8.4 Agent 设计原则
- Canvas Agent 不负责 DeerFlow 全部工具生态
- 首版专注于:
- 生成文档
- 重写文档
- 局部改写
- 跟进回复
### 8.5 工具策略
首版建议:
- 不强依赖 shell/sandbox
- 不强依赖 present_files
- 先把生成与改写链路做好
后续可以根据需要接入文件导出能力。
### 8.6 验收标准
- `canvas_agent` 可被识别
- 前端能以 assistant id 调用它
- 不影响 `lead_agent`
---
## 9. 阶段四:Canvas 状态与图定义
### 9.1 任务目标
为 Canvas Agent 定义清晰、最小但可扩展的状态结构。
### 9.2 任务清单
- 新建 `canvas_agent/state.py`
- 定义图状态
- 约束与 `ThreadState` 的映射方式
### 9.3 建议状态字段
- `messages`
- `_messages` 或等价内部消息
- `artifact`
- `highlighted_text`
- `highlighted_code`
- `quick_action_id`
- `web_search_enabled`
- `web_search_results`
- `next`
### 9.4 状态设计建议
优先复用 LangGraph 原生消息 reducer。
对结构化字段,尽量采用:
- 可整体替换
- 易序列化
- 无 Python 特殊对象依赖
### 9.5 验收标准
- 状态能驱动 Canvas 节点运行
- 状态可被序列化回线程
---
## 10. 阶段五:Canvas 图最小节点闭环
### 10.1 任务目标
先实现最小闭环,不要一开始就追求 open-canvas 全量功能。
### 10.2 首版最小节点
建议至少实现:
- `route_user_intent`
- `reply_general_input`
- `generate_artifact`
- `rewrite_artifact`
- `generate_followup`
### 10.3 节点职责
#### `route_user_intent`
判断用户当前意图:
- 普通聊天
- 新建 artifact
- 重写当前 artifact
#### `reply_general_input`
仅返回普通消息,不更新 artifact。
#### `generate_artifact`
根据用户需求生成第一版 artifact。
#### `rewrite_artifact`
根据当前 artifact 和用户请求生成新版本。
#### `generate_followup`
在 artifact 更新后补一条自然语言消息。
### 10.4 输出要求
必须至少更新:
- `messages`
- `artifact`
### 10.5 验收标准
- 无 artifact 时能生成新 artifact
- 有 artifact 时能整体重写
- 重写后版本数增加
---
## 11. 阶段六:Prompt 设计与模型调用封装
### 11.1 任务目标
把 Canvas 模式的 prompt 和模型调用逻辑集中管理。
### 11.2 任务清单
- 在 `canvas_agent/prompt.py` 中集中定义 prompt 常量
- 在 `canvas_agent/agent.py` 或节点工具模块中封装模型调用
### 11.3 最少需要的 prompt
- 新建 artifact prompt
- 整体重写 artifact prompt
- 路由判断 prompt
- followup prompt
### 11.4 设计建议
提示词必须显式约束:
- 输出完整文档还是局部片段
- 是否允许修改类型
- 是否允许修改标题
- 对文本和代码的输出格式要求
### 11.5 模型调用封装建议
不要在每个节点里重复拼模型配置。
建议提供统一函数:
- `get_canvas_model(...)`
- `invoke_canvas_model(...)`
### 11.6 验收标准
- prompt 集中管理
- 节点中模型调用逻辑可复用
---
## 12. 阶段七:Gateway 线程接口兼容
### 12.1 任务目标
让前端读取线程状态时能拿到结构化 `artifact`。
### 12.2 任务清单
- 检查 [threads.py](../../offline-backend-20260512/backend/app/gateway/routers/threads.py)
- 扩展线程 state 响应的 `values`
- 确保 `artifact` 字段会被安全返回
### 12.3 要求
- `GET /api/threads/{id}`
- 线程历史
- 状态读取接口
都要兼容 `artifact`
### 12.4 注意事项
- 历史 checkpoint 可能没有 `artifact`
- 旧线程必须兼容
- 结构化字段不能被错误裁剪
### 12.5 验收标准
- 前端取线程时能拿到 `artifact`
- 刷新页面后 Canvas 内容能恢复
---
## 13. 阶段八:流式输出适配
### 13.1 任务目标
让 Canvas 模式的 artifact 能通过 LangGraph 流实时更新。
### 13.2 任务清单
- 检查运行时序列化逻辑
- 确保 `artifact` 在流事件中可见
- 明确前端消费 `values` 还是 `updates`
### 13.3 输出建议
首版允许采用较简单策略:
- 每次节点完成后输出完整 `artifact`
不强制首版做精细的 token 级 artifact 局部流。
### 13.4 原因
完整对象覆盖更新:
- 容易实现
- 容易调试
- 前后端一致性更好
### 13.5 二期方向
后续再考虑:
- 局部 chunk 更新
- 文本与代码差异化流式拼接
### 13.6 验收标准
- 前端发送请求时,artifact 能跟随 run 更新
- 流结束后状态与线程最终值一致
---
## 14. 阶段九:模型接口扩展
### 14.1 任务目标
让前端能拿到适合 Canvas 模式的模型能力信息。
### 14.2 任务清单
- 扩展 [models.py](../../offline-backend-20260512/backend/app/gateway/routers/models.py)
- 扩展模型响应结构
### 14.3 现有字段之外建议新增
- `provider`
- `supports_vision`
- `supports_tool_calling`
- `supports_canvas_generation`
- `supports_canvas_rewrite`
- `supports_canvas_code_edit`
- `supports_streaming_text`
- `supports_streaming_tool_calls`
- `is_local`
- `base_url`
### 14.4 注意事项
不是所有字段都必须从配置文件显式写出。
可以采用:
- 配置直出
- provider 推断
- 默认值补齐
### 14.5 验收标准
- 前端模型选择器能获取足够元数据
- 本地模型和云模型能区分
---
## 15. 阶段十:本地模型支持与配置统一
### 15.1 任务目标
支持像 open-canvas 一样自由配置本地模型,但配置真源在 DeerFlow。
### 15.2 原则
- 以 `config.yaml` 为唯一真源
- 前端不依赖 open-canvas 的 TS 模型表
- 后端负责把配置转换成前端可消费的能力描述
### 15.3 首批支持范围
推荐先支持:
- Ollama
- OpenAI-compatible 本地服务
例如:
- LM Studio
- vLLM
- LocalAI
- One API/OpenAI 兼容代理
### 15.4 配置要求
建议模型配置支持以下字段:
- `name`
- `display_name`
- `use`
- `model`
- `api_key`
- `base_url`
- `supports_vision`
- `supports_thinking`
- `supports_reasoning_effort`
- `supports_tool_calling`
- `is_local`
### 15.5 Canvas 额外能力字段
建议再增加:
- `supports_canvas_generation`
- `supports_canvas_rewrite`
- `supports_canvas_code_edit`
### 15.6 验收标准
- 配置本地模型后 `/api/models` 可见
- `canvas_agent` 可调用本地模型
- 至少文本生成和整体改写可用
---
## 16. 阶段十一:整体重写节点完善
### 16.1 任务目标
让已有 artifact 能被稳定整体重写并产生新版本。
### 16.2 任务清单
- 实现 `rewrite_artifact`
- 明确文本与代码两种重写路径
- 维护标题和类型变更规则
### 16.3 规则建议
- 默认保持当前类型
- 用户明确要求时才允许改类型
- 默认保持标题
- 用户明确换主题时可更新标题
### 16.4 结果写入规则
- 新版本追加到 `contents`
- `currentIndex` 指向新版本
### 16.5 验收标准
- 文本 artifact 整体重写正常
- 代码 artifact 整体重写正常
- 历史版本保留
---
## 17. 阶段十二:局部改写节点
### 17.1 任务目标
支持文本和代码的局部选区修改。
### 17.2 任务清单
- 新增 `update_highlighted_text.py`
- 新增 `update_highlighted_code.py`
- 在状态中消费选区信息
### 17.3 文本局部改写要求
输入:
- 当前 `fullMarkdown`
- 选区起止
- 选中原文
- 用户修改指令
输出:
- 只返回替换片段或返回完整合并后文本
### 17.4 首版建议
首版优先采用“后端返回完整合并后文本”策略。
原因:
- 前端逻辑更轻
- 状态更一致
### 17.5 代码局部改写要求
输入:
- 当前代码全文
- 选区代码片段
- 选区边界
- 用户修改指令
输出:
- 新的完整代码文本
### 17.6 验收标准
- 文本局部改写成功
- 代码局部改写成功
- 未选中区域不被误改
---
## 18. 阶段十三:快捷动作节点
### 18.1 任务目标
支持前端动作栏触发不同的重写行为。
### 18.2 任务清单
- 新增 `quick_actions.py`
- 定义动作 id 到 prompt 的映射
- 在路由节点中识别 `quick_action_id`
### 18.3 首版动作建议
文本:
- `expand`
- `shorten`
- `formalize`
- `casualize`
代码:
- `add_comments`
- `add_logs`
- `fix_bugs`
### 18.4 实现建议
动作不要散落在各节点里硬编码。
建议集中成映射表:
- `action_id -> prompt builder`
### 18.5 验收标准
- 指定动作可触发不同结果
- 动作执行后生成新版本
---
## 19. 阶段十四:Web 搜索增强
### 19.1 任务目标
支持 Canvas 模式在需要时引入搜索结果。
### 19.2 任务清单
- 新增 `web_search.py`
- 消费 `web_search_enabled`
- 将搜索结果写入 `web_search_results`
### 19.3 首版策略
首版只做:
- 打开开关后,生成/重写前先搜索
- 把结果摘要注入 prompt
先不做复杂页面抓取多轮链路。
### 19.4 验收标准
- 开关打开时能引入搜索结果
- 结果可回传前端展示
---
## 20. 阶段十五:线程创建与 metadata 策略
### 20.1 任务目标
让 Canvas 线程在创建和恢复时保留必要上下文。
### 20.2 任务清单
- 约定前端创建 Canvas thread 时写入 metadata
- 后端在 thread search / get 中保留这些 metadata
### 20.3 推荐 metadata
- `ui_mode: "canvas"`
- `agent_id: "canvas_agent"`
- `model_name`
- `canvas_type` 可选
### 20.4 验收标准
- Canvas thread 与普通 thread 可区分
- 恢复线程时前端可据 metadata 恢复 UI
---
## 21. 阶段十六:Gateway 扩展接口评估
### 21.1 任务目标
判断是否需要新增 Canvas 专用 REST API。
### 21.2 原则
能复用现有线程状态与 LangGraph 流,就不要新增太多新接口。
### 21.3 可以先不新增的接口
- Canvas artifact 专用 CRUD
- Canvas 快捷动作专用接口
这些都可以先通过:
- 线程 state
- runs.stream
完成。
### 21.4 可能需要新增的接口
二期如果需要,可增加:
- `GET /api/canvas/models`
- `POST /api/canvas/export`
- `POST /api/canvas/convert-to-file`
### 21.5 验收标准
- 首版尽量少增接口
- 协议尽量复用现有线程与 run 模型
---
## 22. 阶段十七:持久化与导出联动
### 22.1 任务目标
让 Canvas 文档能和现有文件 artifact 体系联动。
### 22.2 任务清单
- 规划导出接口
- 规划 artifact 转文件逻辑
- 规划从 Canvas 生成 outputs 文件
### 22.3 推荐能力
- 保存为 `.md`
- 保存为代码文件
- 将导出文件加入现有 `artifacts: list[str]`
### 22.4 首版建议
这部分不是最早阶段必须做的。
建议等核心 Canvas 生成与重写稳定后再接。
### 22.5 验收标准
- 导出文件能出现在现有 artifact 文件体系中
---
## 23. 测试清单
### 23.1 单元测试建议
优先覆盖:
- artifact 协议校验
- 版本追加逻辑
- 标题/类型变更规则
- 文本局部改写拼接逻辑
- 代码局部改写拼接逻辑
### 23.2 集成测试建议
应覆盖:
- 创建 Canvas thread
- 首次生成 artifact
- 整体重写
- 局部改写
- 模型切换
- 本地模型调用
### 23.3 回归测试重点
重点检查现有功能未被破坏:
- 普通 `lead_agent` 对话
- 文件型 `artifacts`
- uploads
- memory
- scheduled tasks
### 23.4 验收标准
- Canvas 新功能通过
- 现有 DeerFlow 核心路径无回归
---
## 24. 推荐开发顺序
强烈建议按以下顺序推进:
1. 线程状态扩展
2. artifact 协议定稿
3. `canvas_agent` 注册
4. 最小图闭环
5. 线程读取与流式返回
6. 模型接口扩展
7. 整体生成与整体改写
8. 局部改写
9. 快捷动作
10. 本地模型增强
11. Web 搜索增强
12. 导出联动
不要一开始就做:
- 快捷动作全集
- 局部 token 级流式 artifact 更新
- 复杂导出体系
---
## 25. 多人协作拆分建议
### A 组:状态与线程
- `thread_state.py`
- 线程协议
- Gateway 线程兼容
### B 组:Canvas Agent 图
- `canvas_agent`
- prompt
- route/generate/rewrite/followup
### C 组:模型与配置
- `/api/models`
- 本地模型配置
- provider 兼容
### D 组:增强能力
- 局部改写
- 快捷动作
- Web 搜索
---
## 26. 首版最小可交付范围
后端首版建议只交付这些:
- 扩展线程状态支持 `artifact`
- 新增 `canvas_agent`
- 支持文本/代码 artifact 首次生成
- 支持整体重写
- 支持版本历史
- 扩展 `/api/models` 返回 Canvas 能力元数据
- 支持至少一种本地模型接入
首版先不强制:
- 局部高亮改写
- 全量快捷动作
- 搜索增强
- 导出文件联动
---
## 27. 总验收标准
### 27.1 功能层
- 无 artifact 时可生成新文档
- 有 artifact 时可整体重写
- 版本历史可保留
- 前端刷新后可恢复
### 27.2 协议层
- `artifact` 字段稳定
- 流式与最终线程状态一致
- 模型能力字段可用于前端判断
### 27.3 兼容层
- 不破坏 `lead_agent`
- 不破坏现有 `artifacts: list[str]`
- 不破坏现有 Gateway 核心接口
---
## 28. 下一步建议
完成本文档后,建议继续补两份工程文档:
### 28.1 Canvas 状态协议文档
明确:
- `artifact`
- `highlighted_text`
- `highlighted_code`
- `quick_action_id`
- `web_search_results`
的最终 JSON 格式。
### 28.2 Canvas Agent 节点接口文档
逐节点定义:
- 输入字段
- 输出字段
- prompt 责任
- 错误处理
这样进入实际编码时会更顺畅。