deerflow-code/frontend-web/docs/ai-writing-对话驱动改造方案.md
2026-09-07 18:24:55 +08:00

25 KiB
Raw Blame History

AI 写作「对话驱动 + 意图解析」改造方案

目标:在不动现有 AI 写作页面的前提下,新建一个「对话驱动」的写作工作台。 去掉素材收集 / 大纲规划 / 作家写作 / 编辑审核各阶段分散的输入框/表单, 用底部一个统一的智能输入框接管全流程交互;该输入框具备强意图解析能力, 能准确识别用户意图(重新搜索、加素材、加关键词、重写大纲、按要求改大纲、改写作、 改编辑、提编辑意见、对写作内容提问……),并在素材不足时自动回退去重新检索素材。

本文只做方案与实现指引,不含代码改动。落地时按第 9 节的路线图分阶段推进。


1. 现状梳理(改造的地基)

现有 AI 写作是一套独立的 LangGraph 子系统(不是 lead_agent),前后端都已成型。

1.1 后端:ai_writing graph

  • 图工厂:offline-backend-20260512/backend/packages/harness/deerflow/agents/ai_writing/graph.py
  • 状态:.../agents/ai_writing/state.py(AIWritingState + UserInterventionPayload)
  • 注册:offline-backend-20260512/backend/langgraph.json → assistant_id = "ai_writing"
  • 执行:与 lead agent 共用 RunManager + StreamBridge + checkpointer(app/gateway/services.py 里 assistant_id=="ai_writing" 分发到 make_ai_writing_graph)

节点拓扑(实际):

sample_analyzer → intent_parser → researcher
  → [cond] pause_material | writer_draft
  → writer_outline → pause_outline
  → writer_draft → [cond] pause_section_help | pause_draft | END
  → editor → [cond] pause_draft | pause_review
  → pause_review → END | writer_draft

四个「阶段大脑」节点:

阶段 节点 文件
素材收集 researcher nodes/researcher.py
大纲规划 writer_outline nodes/writer_outline.py
作家写作 writer_draft nodes/writer_draft.py
编辑审核 editor nodes/editor.py

五个暂停点(interrupt(),靠 Command(resume=payload) 续跑):

pause_point 语义 可用 action(现有)
material_confirm 素材确认 confirm / re_search / supplement_search / enable_skill_search
outline_confirm 大纲确认 confirm / re_outline
draft_confirm 草稿确认 to_editor / finalize / user_revise / custom_revise
review_confirm 编辑打回确认 accept_review / force_finalize
section_help 素材不足求助 supplement / loose / delete

resume 载荷字段(UserInterventionPayload):action、approved_material_ids、 extra_keywords、user_query(自然语言补充检索)、edited_outline、outline_feedback、 user_revision_notes、override_verdict、selected_issue_indices、section_decisions。 关键点:现有协议已经支持「自然语言 + 结构化 action」,这是对话改造的核心可复用资产。

REST(业务元数据,非图执行):app/gateway/routers/ai_writing.py,前缀 /api/ai-writing (sessions CRUD、transcript 保存、article-types、后台挂起 /background + /progress 等)。

持久化:ai_writing_sessions 表(transcript 为 PortableLongText)

  • ai_writing_article_types(deerflow/persistence/...)。

配置:config.yaml → ai_writing(keyword_model、rank_model、max_materials、 use_builtin_agents.{researcher,outliner,writer,editor} 等)。

1.2 前端:open-canvas 子系统

  • 主页面:frontend-web/src/open-canvas/pages/AIWritingPage.tsx
  • 路由:/page/canvas/ai-writing、/page/workspace/ai-writing
  • 状态机:contexts/AIWritingContext.tsx(useReducer + LangGraph useStream)
  • 事件翻译/reducer:hooks/useAIWritingStream.ts
  • 类型:types/ai-writing.ts(WritingStatus、ProgressEvent、UserInterventionPayload、AIWritingRequest…)
  • 流式:LangGraph useStream,assistantId: 'ai_writing',streamMode: ['values','updates','custom','messages-tuple']
  • 要去掉的输入 UI(改造重点):
    • 启动表单 components/ai-writing/AIWritingForm.tsx + WritingFormContext
    • 阶段暂停输入 components/ai-writing/InterventionCard.tsx(素材/大纲/草稿/审核四套内嵌表单)
  • 已存在的对话原型:components/ai-writing/WritingSetupChat.tsx (用 useThreadStream 起一条 lead_agent 线程 + setup_writing 工具审批卡回填表单)—— 这是「对话 → 结构化配置」的现成范式,可借鉴但不直接复用(它只管启动前配置)。

1.3 结论

  • 状态机、流式、暂停/续跑协议、持久化都可复用,无需重写引擎。
  • 改造本质 = 把「分散表单」换成「一个对话输入框 + 意图路由层」, 再把意图映射回现有的 action + payload(大部分场景), 少量新意图(如「对内容提问」「素材不足自动重搜」)需要新增协议/节点。

2. 目标与范围

2.1 必须满足

  1. 新页面/新路由,旧页面零改动(用户要求「初始的不用动」)。
  2. 底部单一对话输入框控制所有阶段交互,移除各阶段独立输入框。
  3. 强意图解析:准确识别用户自然语言意图并路由到正确动作,覆盖全流程 + 更多。
  4. 用户给修改意见后,若现有素材不足以满足要求 → 自动/建议重新检索素材再继续。
  5. 保留右侧草稿实时预览(可编辑)与时间线/进度展示。

2.2 明确不做(本期)

  • 不改旧 AIWritingPage 及其表单/干预卡组件。
  • 不替换底层 ai_writing graph 的四个阶段大脑逻辑(只加意图层与少量新协议)。
  • 不引入新的状态管理库(继续 useReducer + useStream)。

3. 核心设计

3.1 总体思路:三层结构

┌─────────────────────────────────────────────────────────┐
│  对话 UI 层(新)                                          │
│  - 左:消息流(用户消息 + AI 阶段产物卡片 + 进度)          │
│  - 底:统一智能输入框(唯一交互入口)                       │
│  - 右:草稿实时预览(复用 AIWritingDraftPanel)            │
└───────────────┬─────────────────────────────────────────┘
                │ 用户自然语言
                ▼
┌─────────────────────────────────────────────────────────┐
│  意图解析层(新,核心)                                    │
│  - 输入:用户文本 + 当前 WritingStatus + 上下文快照        │
│  - 输出:{ intent, action, payload, needResearch, ... }   │
└───────────────┬─────────────────────────────────────────┘
                │ 结构化 action + payload
                ▼
┌─────────────────────────────────────────────────────────┐
│  执行层(复用现有)                                        │
│  - 空闲态:startWriting(AIWritingRequest)                  │
│  - 暂停态:submitIntervention(UserInterventionPayload)     │
│  - 运行中:stream.stop() → 续跑 / 新命令                    │
│  - 提问态:旁路问答(不改写作状态)                        │
└─────────────────────────────────────────────────────────┘

设计原则:意图解析层是「翻译官」——把自由文本翻译成现有执行层已经懂的指令。 能复用 action + payload 的绝不新造协议;只有现有协议表达不了的才扩展。

3.2 意图分类体系(覆盖用户全流程 + 更多)

按「意图类别 → 触发时机(当前 status)→ 映射到的执行」组织。这是意图解析引擎的目标 schema。

A. 启动类(status = idle)

意图 说明 映射
start_writing 用户描述要写什么 解析成 AIWritingRequest → startWriting()
start_with_outline 用户自带大纲 AIWritingRequest.userOutline
start_imitate 样文仿写 writingModeType=imitate + 样文

B. 素材类(status ≈ awaiting_material_confirm / 运行中)

意图 用户说法示例 映射
confirm_materials 「素材可以,继续」 material_confirm + confirm(可带勾选 ids)
research_again 「重新搜索素材」 material_confirm + re_search
add_material / add_keyword 「补充关于 X 的素材」「加个关键词 Y」 material_confirm + supplement_search,user_query=X/Y
use_skill_search 「用 XX 技能查」 material_confirm + enable_skill_search,user_query=技能/来源
select_materials 「只用第 1、3 条」 confirm + approved_material_ids 子集
drop_materials 「去掉第 2 条」 同上,反选后 approved_material_ids

C. 大纲类(status ≈ awaiting_outline_confirm)

意图 示例 映射
confirm_outline 「大纲 OK」 outline_confirm + confirm
reoutline 「重写大纲」 outline_confirm + re_outline(outline_feedback 可空)
revise_outline 「第二章拆成两节」「调整顺序」 re_outline + outline_feedback=自然语言
edit_outline_manually 用户直接给出新大纲文本 解析成 edited_outline

D. 写作/草稿类(status ≈ awaiting_draft_confirm / writing_draft)

意图 示例 映射
to_editor 「交给编辑审核」 draft_confirm + to_editor
finalize 「就这样定稿」 draft_confirm + finalize
revise_draft 「第三段太啰嗦,精简」「补个案例」 draft_confirm + user_revise,user_revision_notes=意见
rewrite_section 「重写第二章」 user_revise + 定位信息(章节)写进 notes
change_tone/style 「更口语一点」 user_revise + notes

E. 编辑审核类(status ≈ awaiting_review_confirm)

意图 示例 映射
accept_review 「按编辑意见改」 review_confirm + accept_review(可带 selected_issue_indices)
partial_accept_review 「只接受第 1、2 条意见」 accept_review + selected_issue_indices
force_finalize 「不改了,强制定稿」 review_confirm + force_finalize
add_review_opinion 「你再补一条:检查数据准确性」 追加自定义审核意见(见 5.3 扩展)

F. 素材不足求助类(status = awaiting_section_help)

意图 映射
section_supplement section_help + supplement(去重搜)
section_loose section_help + loose(放宽续写)
section_delete section_help + delete

G. 问答类(新,任意 status,旁路,不改写作状态)

意图 示例 映射
ask_about_content 「第二章讲了啥?」「为什么用这个论点?」 旁路问答(见 5.4)
ask_meta 「现在进行到哪一步?」「用了哪些素材?」 读当前 state 直接回答,不走图

H. 控制类(新/半新)

意图 映射
undo/back 回退到上一暂停点(依赖 checkpoint 回滚,见 8.4)
restart_stage 重跑当前阶段
run_background 挂起后台自动跑 → POST /sessions/{id}/background
cancel stream.stop()
unknown/clarify 无法判定 → 反问澄清(对话追问,不误触发)

覆盖「甚至更多」:G(问答)、H(控制)、以及 D/E 里「素材不足自动回退重搜」都是超出原表单能力的新增。

3.3 「素材不足自动重搜」的判定与回退(用户强调的重点)

触发场景:用户在大纲/草稿/审核阶段提出修改意见,但意见需要的信息现有素材里没有。

判定放在意图解析层输出一个 needResearch: boolean + researchQuery,判定来源二选一(推荐组合):

  1. 意图解析 LLM 直接判断:把「当前素材摘要(keywords + 每条 title/来源)」喂给意图解析 prompt,让它判断「用户这条意见能否用现有素材满足」。不能 → needResearch=true 并给出检索词。
  2. 执行阶段兜底:writer_draft 严格模式本就有 blocked_sections → pause_section_help, 这是已有的素材不足闸门;对话层把它翻译成「素材不足,是否重新检索?」的对话追问。

回退动作:needResearch=true 时,先走 material_confirm + supplement_search(或新的 「带目标的重搜」协议,见 8.3)补素材,补完自动继续用户原本的修改意图(需要在对话层 记住「pending 修改意图」,重搜结束后再提交)。


4. 意图解析引擎:方案对比与推荐

方案 做法 优点 缺点
A. 后端 LLM 意图节点(推荐) 新增 /api/ai-writing/intent/parse(或图内新节点),后端用 LLM 把 {text, status, contextSnapshot} → 结构化意图 JSON 能吃到完整 state(素材/大纲/草稿);可判 needResearch;prompt/模型集中可控;离线内网可用配置模型 多一次网络往返(可接受,交互本就等待)
B. 前端调模型接口分类 前端直接调现有 /api/models 聊天做分类 少一层后端改动 前端难拿全后端 state 快照;prompt 分散;鉴权/模型选择复杂
C. 规则 + LLM 混合 常见短句走关键词规则快路径,兜底 LLM 快、省 token 规则易漏、维护成本高;中文表达多样命中率低

推荐 A(后端 LLM 意图节点),并在其上叠加 C 的快路径做优化(如「确认/继续/定稿」等 高频短句先走轻量规则,未命中再调 LLM)。理由:

  • 意图判定需要当前写作上下文(尤其 needResearch 判定),后端天然持有 state/checkpoint。
  • 与现有「配置助手 setup_writing」一脉相承,模型选择/离线部署策略统一。
  • 输出 schema 稳定,前端只消费结构化结果,UI 简单。

4.1 意图解析输出契约(建议)

{
  "intent": "revise_draft",          // 见第 3.2 分类
  "pausePoint": "draft_confirm",     // 若需 resume;否则 null
  "action": "user_revise",           // 映射到现有 action;新意图可为新值
  "payload": {                        // 直接可喂 submitIntervention 的字段
    "userRevisionNotes": "第三段精简,并补一个 2024 年的案例"
  },
  "needResearch": true,               // 素材是否不足
  "researchQuery": "2024 行业案例",   // needResearch 时的检索意图
  "answer": null,                     // 问答类意图的直接回答(旁路)
  "confidence": 0.86,
  "clarify": null                     // 低置信时的反问话术
}

前端拿到后:

  • answer 非空 → 直接在对话流渲染回答(问答旁路,不动写作状态)。
  • clarify 非空或 confidence 低 → 渲染反问,等用户澄清(防误触发)。
  • needResearch=true → 先重搜,缓存 payload 为 pending,重搜完再提交。
  • 否则 → submitIntervention({action, ...payload}) 或 startWriting(...)。

5. 前端改造方案

5.1 新页面与路由

  • 新目录:frontend-web/src/open-canvas/pages/AIWritingChatPage.tsx(或 conversational/ 子目录)。
  • 新路由:/page/canvas/ai-writing-chat(在 OpenCanvasRoutes.tsx 注册;旧路由保留)。
  • 侧边栏:sidebar-menu.ts 加一个入口(如「AI 写作(对话版)」),或先不加、内部灰度。

5.2 复用 vs 新建

复用(尽量不改) 新建
AIWritingContext / useAIWritingStream(状态机 + 流式) 统一对话输入框组件 WritingChatComposer
AIWritingDraftPanel(右侧草稿预览) 消息流容器 WritingChatThread(渲染阶段产物为消息卡片)
types/ai-writing.ts(按需扩展) 意图解析客户端 api/ai-writing-intent.ts
ProgressEvent 事件模型 阶段产物 → 消息卡片的适配器 progressToMessage.ts
会话持久化 REST 「pending 意图」暂存逻辑(重搜后续跑)

不复用:AIWritingForm / WritingFormContext / InterventionCard(这三个就是要去掉的表单)。

5.3 交互流程(对话版)

  1. 空闲:用户在底部输入「写一篇关于 X 的深度分析,2000 字」→ 意图解析 start_writing → 组装 AIWritingRequest → startWriting()。
  2. 运行中:ProgressEvent(research_progress/outline_chunk/draft_chunk…) → 适配成消息流里的进度卡片/流式卡片(复用现有流式视图组件的展示部分)。
  3. 到达暂停点:不再弹 InterventionCard,而是在消息流里展示阶段产物卡片 (素材列表 / 大纲 / 草稿 / 审核结果)+ 一句提示「你可以说:确认继续 / 补充素材 / 改大纲…」。 用户下一句自然语言 → 意图解析 → submitIntervention。
  4. 问答:任意时刻用户提问 → 旁路回答,不打断写作状态。
  5. 素材不足:意图解析 needResearch 或后端 section_help → 对话追问「素材不足,帮你重搜?」 → 确认后重搜 → 自动续跑 pending 意图。

5.4 问答旁路(新能力)

「对写作内容提问」不应改写作 state。两种实现:

  • 轻量(推荐先做):意图解析节点直接带回 answer(后端能读 state,一次调用出答案)。
  • 完整:新起一条只读问答线程(lead_agent,context 注入当前草稿/大纲作为背景), 类似 WritingSetupChat 的 useThreadStream 模式,但只读不回填。

6. 后端改造方案

6.1 意图解析入口(二选一)

  • 方案 A1(推荐,独立 REST):app/gateway/routers/ai_writing.py 新增 POST /api/ai-writing/sessions/{id}/intent,入参 {text},后端读该 session 的 checkpoint state(素材/大纲/草稿摘要)+ 用 ai_writing 配置模型解析,返回第 4.1 的契约。
    • 好处:不改图拓扑;前端拿到结果后再决定调 startWriting/submitIntervention。
  • 方案 A2(图内节点):在图里加 conversation_router 节点。改动大、状态耦合高,不推荐首期。

6.2 意图解析 prompt

新增 agents/ai_writing/prompts/intent_router_prompts.py(或复用/扩展 intent_parser.py):

  • 输入:用户文本、current_status、素材摘要(keywords + 每条 title/source)、大纲纲要、 草稿字数/章节标题、审核意见列表。
  • 输出:严格 JSON(第 4.1 契约)。要求模型只在证据充分时给高 confidence, 否则给 clarify(防误触发是硬指标)。

6.3 「带目标的重搜」协议扩展(可选增强)

现有 supplement_search 用 user_query 追加检索。为支持「改稿意见 → 缺素材 → 重搜 → 自动续跑」, 建议在 material_confirm 的 resume 里新增可选字段 resume_intent(重搜完成后要自动执行的原始意图)。

  • 前端也可纯前端实现(重搜完成事件回来后再自动提交缓存的 pending payload),首期优先前端实现,避免动后端协议。

6.4 追加自定义审核意见(add_review_opinion)

editor/pause_review 目前只接受「接受/强制定稿」。要支持「你再补一条审核意见」, 需在 review_confirm resume 里接受 extra_review_notes,editor 或 writer_draft 修订时并入。首期可先降级为 user_revise + notes(把用户的审核诉求当作改稿意见), 完整版再扩协议。

6.5 不需要改的部分

  • 四个阶段大脑节点(researcher/writer_outline/writer_draft/editor)逻辑不动。
  • 五个暂停点、checkpoint、StreamBridge、持久化不动。

7. 数据流时序(改稿 + 素材不足自动重搜)

用户: "第三段补个2024年的行业案例"
  │
  ▼ POST /api/ai-writing/sessions/{id}/intent  { text }
后端: 读 state(素材摘要) + LLM 解析
  │  返回 { intent:revise_draft, action:user_revise,
  │         payload:{userRevisionNotes:...},
  │         needResearch:true, researchQuery:"2024 行业案例" }
  ▼
前端: needResearch=true → 缓存 pending=payload
  │  对话追问/直接执行: submitIntervention(material_confirm, supplement_search, user_query="2024 行业案例")
  ▼ LangGraph resume → researcher 补素材 → materials_ready
前端: 收到新素材 → 自动提交 pending
  │  submitIntervention(draft_confirm, user_revise, userRevisionNotes=...)
  ▼ writer_draft 用新素材改稿 → draft_chunk... → draft_ready → pause_draft
前端: 消息流展示新草稿 + "已按你的意见改写并补充了案例"

8. 关键实现细节与坑

  1. 暂停态识别:对话层必须知道「现在停在哪个 pause_point」才能正确映射 action。 AIWritingContext 已有 currentPause/status,直接读。
  2. 防误触发:低置信意图一律走 clarify 反问,绝不猜着执行(尤其 finalize/re_search 这种代价大的)。
  3. pending 意图队列:素材不足重搜是「先插一段、再回原意图」,需要一个小状态机记住 pending, 并处理「重搜后用户又改主意」的情况(重搜完成前允许覆盖 pending)。
  4. 回退/undo(H 类):依赖 checkpoint 回滚,runtime/runs/worker.py 有 rollback 概念, 首期可不做或只做「重跑当前阶段」。
  5. 问答旁路不污染 transcript:问答消息可标记 kind:'qa',与写作进度事件区分持久化。
  6. 流式产物→消息卡片:复用现有 OutlineStreamingView/DraftStreamingPreview 等的展示部分, 套进消息气泡即可,不必重写渲染。
  7. 离线内网:意图解析模型走 config.yaml → ai_writing 里的配置模型;检索仍走技能/内网 ES, 不联网(与现有并行席位「禁 web_search」的离线策略一致)。

9. 分阶段实施路线图

阶段 0 — 骨架(不含意图)

  • 新路由 + 新页面 AIWritingChatPage,复用 AIWritingContext/useStream/DraftPanel。
  • 底部对话框先只做「空闲 start_writing + 暂停点固定按钮」跑通端到端(相当于把干预卡换成消息)。

阶段 1 — 意图解析(核心)

  • 后端 POST /sessions/{id}/intent + intent prompt,返回第 4.1 契约。
  • 前端接入:自然语言 → 意图 → startWriting/submitIntervention,覆盖 A~F 类意图。
  • 加高频短句规则快路径 + 低置信 clarify 反问。

阶段 2 — 问答旁路 + 素材不足自动重搜

  • G 类问答(先用 intent 节点直接带 answer)。
  • needResearch + pending 意图机制(前端实现重搜后自动续跑)。

阶段 3 — 增强协议(按需)

  • add_review_opinion 扩 review_confirm 协议、resume_intent 后端化、undo/回退。

阶段 4 — 打磨

  • 消息卡片视觉、历史回看(复用 transcript)、后台挂起入口、灰度到侧边栏。

10. 关键文件清单(落地时对照)

新增(前端)

  • open-canvas/pages/AIWritingChatPage.tsx — 新页面
  • open-canvas/components/ai-writing-chat/WritingChatComposer.tsx — 统一输入框
  • open-canvas/components/ai-writing-chat/WritingChatThread.tsx — 消息流
  • open-canvas/components/ai-writing-chat/progressToMessage.ts — 事件→消息适配
  • open-canvas/api/ai-writing-intent.ts — 意图解析客户端
  • 路由注册:open-canvas/OpenCanvasRoutes.tsx(+ 可选 sidebar-menu.ts)

新增(后端)

  • app/gateway/routers/ai_writing.py — 加 POST /sessions/{id}/intent
  • agents/ai_writing/prompts/intent_router_prompts.py — 意图 prompt
  • (阶段 3)state.py / nodes/* — 扩 review_confirm、resume_intent

复用(尽量不改)

  • open-canvas/contexts/AIWritingContext.tsx、hooks/useAIWritingStream.ts
  • open-canvas/components/ai-writing/AIWritingDraftPanel.tsx 及各流式展示组件
  • open-canvas/types/ai-writing.ts(按需扩字段)
  • agents/ai_writing/graph.py、四个阶段节点、五个暂停点

不动

  • 旧 open-canvas/pages/AIWritingPage.tsx 及 AIWritingForm/WritingFormContext/InterventionCard

11. 待确认

  1. 意图解析引擎是否采用推荐的方案 A(后端 LLM 节点)?
  2. 新页面是独立入口(侧边栏新增)还是先内部灰度(仅直链)?
  3. 「素材不足自动重搜」首期是否接受前端实现 pending 续跑(不动后端 resume 协议)?
  4. 问答旁路首期是否接受意图节点直接带答案(不新起只读线程)?

以上默认按「A / 内部灰度 / 前端 pending / 意图节点带答案」推进,如需调整请指出。