33 KiB
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(make_ai_writing_graph,registered asassistant_id="ai_writing") - 状态:
.../ai_writing/state.py(AIWritingState) - 四个「阶段大脑」节点:
| 阶段 | 节点 | 文件 |
|---|---|---|
| 素材收集 | 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 / enable_skill_search |
outline_confirm |
大纲确认 | confirm / re_outline |
draft_confirm |
草稿确认 | to_editor / finalize / user_revise |
review_confirm |
编辑打回确认 | accept_review / force_finalize |
section_help |
素材不足求助 | section_help(+sectionDecisions) |
- resume 载荷(
UserInterventionPayload,types/ai-writing.ts)字段:action、approvedMaterialIds、userQuery(自然语言补充检索)、editedOutline、outlineFeedback、userRevisionNotes、overrideVerdict、selectedIssueIndices、sectionDecisions。 协议已同时支持「自然语言 + 结构化 action」——这是对话层能复用的关键。
结论:状态机 / 流式 / 暂停·续跑协议 / 持久化都可复用,无需重写引擎。改造本质是 「把分散在干预卡里的输入框,换成一个底部智能输入框 + 意图路由层」,再把意图翻译回现有
action + payload;仅少量新意图(对内容提问、素材不足自动回退重搜、追加审核意见)需新增能力。
1.2 前端 open-canvas 子系统
- 主页面:
frontend-web/src/open-canvas/pages/AIWritingPage.tsx- 路由注册:
open-canvas/routes/OpenCanvasRoutes.tsx(/page/canvas/ai-writing/*)、pages/WorkspaceRoutes.tsx(/page/workspace/ai-writing/*)、pages/NotebookAIWritingPage.tsx
- 路由注册:
- 状态机 + 流式:
contexts/AIWritingContext.tsx(useReducer+ LangGraphuseStream,assistantId:'ai_writing') - 事件翻译 / reducer:
hooks/useAIWritingStream.ts - 类型:
types/ai-writing.ts - 左栏面板:
components/ai-writing/AIWritingPanel.tsx(时间线 + 干预卡 + 状态栏;idle 时挂启动表单) - 要改造的输入 UI(本次重点):
- 干预卡
components/ai-writing/InterventionCard.tsx:内含MaterialConfirmCard(素材:有MaterialsToolbar输入框)、OutlineConfirmCard(大纲:有 feedback textarea)、DraftConfirmCard(草稿:有「修改意见」textarea)、ReviewConfirmCard(审核:有「补充修改指令」textarea)、SectionHelpCard(素材不足:按钮组)。 每张卡里都既有输入框又有确认/动作按钮——本次要去掉输入框、保留按钮。 - 启动表单
components/ai-writing/AIWritingForm.tsx(idle 阶段的配置表单)——本次由底部输入框接管启动。
- 干预卡
- 已存在的对话原型(可借鉴):
components/ai-writing/WritingSetupChat.tsx(useThreadStream起 lead_agent 线程 +setup_writing审批卡回填表单;仅管启动前配置,不直接复用)。 - 底部输入框可直接复用 UI 组件:
@/components/ai-elements/prompt-input(PromptInput/PromptInputTextarea/PromptInputSubmit/PromptInputFooter,见WritingSetupChat)。
2. 目标与范围
2.1 必须满足
- 复制式新增:新目录 / 新路由 / 新侧边栏入口,旧页面、旧路由、旧组件零改动(「初始的不用动」)。
- 页面底部单一多行智能输入框接管全流程交互;四个阶段干预卡里的输入框全部移除。
- 保留确认按钮:每个阶段到达暂停点时,消息流里仍渲染产物卡 + 原来的确认/动作按钮 (素材「确认素材」、大纲「确认大纲」、草稿「让编辑审核 / 确认定稿」、审核「按编辑意见修改 / 强制定稿」、 素材不足的三选一按钮)。用户点按钮或在底部输入框发自然语言意图二选一均可推进。
- 强意图理解:把用户自由文本准确路由到正确动作,覆盖现有全部交互 + 更多(见 3.2)。
- 阶段作用域:意图解析必须知道「当前停在哪个专家阶段」,把同一句话按当前阶段翻译成对应 action。
- 素材不足自动回退重搜:修改意见需要的信息现有素材没有时,先重搜补素材、补完自动继续原意图。
- 拿不准就协助:低置信意图不猜着执行,走澄清追问(clarify)或用户协助。
- 保留右侧草稿实时预览(可编辑)与时间线 / 进度展示。
2.2 明确不做(本期)
- 不改旧
AIWritingPage及其AIWritingForm/InterventionCard(这两个是要在副本里改的)。 - 不替换
ai_writinggraph 四个阶段大脑逻辑,不动五个暂停点 / checkpoint / 持久化。 - 不引新状态管理库(继续
useReducer+useStream)。
2.3 复制策略(关键决策)
「复制一份」= 复制会被大改的表现层组件(页面 + 干预卡 + 面板),复用不改的引擎层:
| 复制(新建副本,大改) | 复用(原样,不改;仅对 types 做追加式扩展) |
|---|---|
新页面 AIWritingChatPage.tsx |
contexts/AIWritingContext.tsx(状态机 + 流式) |
新面板 WritingChatPanel.tsx(消息流 + 底部输入框) |
hooks/useAIWritingStream.ts(事件 → state) |
新消息卡 chat-cards/*(产物卡+确认按钮,无输入框) |
components/ai-writing/AIWritingDraftPanel.tsx(右侧草稿预览) |
新意图客户端 api/ai-writing-intent.ts |
各流式展示子组件(MaterialsCard/OutlineCard/ReviewCard/SkillStepsCard…) |
(可选)新 contexts/WritingChatContext.tsx 包一层「pending 意图 / 澄清态」 |
types/ai-writing.ts(只加字段不改旧字段,保证旧页面不受影响) |
不复用、也不改 的三个「输入框组件」:
AIWritingForm/InterventionCard/WritingFormContext—— 旧页面继续用它们,新页面完全不引用它们。这样「初始的不用动」得到硬保证。为什么复用
AIWritingContext而不复制它?它不含任何输入框 UI,只是「状态机 + 与后端 graph 的 流式桥」,复用它不会改动旧页面的任何呈现(旧页面照常在自己的 Provider 实例里跑)。复用能显著 降低维护成本、避免两套引擎漂移。若要绝对物理隔离,也可整目录复制AIWritingContext+useAIWritingStream到新目录——推荐先复用,仅当后续需要给对话态加大量图内新协议时再分叉。
3. 核心设计
3.1 三层结构
┌──────────────────────────────────────────────────────────────┐
│ 对话 UI 层(新) WritingChatPanel │
│ - 消息流:用户消息 + AI 阶段产物卡(含【保留的确认按钮】)+ 进度 │
│ - 底部:统一多行智能输入框(唯一自由输入入口) │
│ - 右侧:草稿实时预览(复用 AIWritingDraftPanel) │
└───────────────┬──────────────────────────────────────────────┘
│ 用户自然语言(+ 当前 status/pausePoint 上下文)
▼
┌──────────────────────────────────────────────────────────────┐
│ 意图解析层(新,核心) POST /api/ai-writing/sessions/{id}/intent │
│ 输出:{ intent, pausePoint, action, payload, │
│ needResearch, researchQuery, answer, confidence, clarify }│
└───────────────┬──────────────────────────────────────────────┘
│ 结构化 action + payload
▼
┌──────────────────────────────────────────────────────────────┐
│ 执行层(复用现有 AIWritingContext) │
│ idle → startWriting(AIWritingRequest) │
│ 暂停 → submitIntervention(UserInterventionPayload) │
│ 问答 → 旁路回答(不改写作状态) │
│ 素材不足 → 先重搜、缓存 pending、补完自动续跑 │
└──────────────────────────────────────────────────────────────┘
设计原则:意图解析层是「翻译官」——把自由文本翻译成执行层已经懂的指令。能复用
action + payload 的绝不新造协议;确认按钮点击直接走执行层(不经意图层,零延迟、零误判)。
3.2 意图分类体系(覆盖全流程 + 更多)
按「意图 → 触发时机(当前 status/pausePoint)→ 映射执行」组织,即意图解析引擎的目标 schema。 「甚至更多」 = G(问答)、H(控制)、以及 B/C/D/E 里的「素材不足自动回退重搜」。
A. 启动类(status = idle)
| 意图 | 用户说法示例 | 映射 |
|---|---|---|
start_writing |
「写一篇关于新能源出口的深度分析,2000 字」 | 解析成 AIWritingRequest → startWriting() |
start_with_outline |
「按这个大纲写:…」 | AIWritingRequest.userOutline |
start_imitate |
「仿照这篇样文写…」 | writingModeType='imitate' + sampleText |
B. 素材类(pausePoint = material_confirm)
| 意图 | 示例 | 映射 |
|---|---|---|
confirm_materials |
「素材可以,继续 / 下一步」 | {action:'confirm', approvedMaterialIds} |
research_again |
「重新搜索素材」 | {action:'re_search'}(无 userQuery=覆盖式重检) |
add_material/add_keyword |
「再补点关于 X 的素材」「加个关键词 Y」 | {action:'re_search', userQuery:'X/Y'}(追加) |
select_materials |
「只用第 1、3 条」 | {action:'confirm', approvedMaterialIds:[…]} |
drop_materials |
「去掉第 2 条」 | 同上(反选后的子集) |
C. 大纲类(pausePoint = outline_confirm)
| 意图 | 示例 | 映射 |
|---|---|---|
confirm_outline |
「大纲 OK,开始写」 | {action:'confirm'} |
reoutline |
「重写大纲」 | {action:'re_outline'}(feedback 可空) |
revise_outline |
「第二章拆成两节」「调整顺序」 | {action:'re_outline', outlineFeedback:自然语言} |
D. 写作 / 草稿类(pausePoint = draft_confirm)
| 意图 | 示例 | 映射 |
|---|---|---|
to_editor |
「交给编辑审核」 | {action:'to_editor'} |
finalize |
「就这样定稿」 | {action:'finalize'} (高代价:低置信必澄清) |
revise_draft |
「第三段太啰嗦,精简」「补个 2024 案例」 | {action:'user_revise', userRevisionNotes:意见} |
rewrite_section |
「重写第二章」 | user_revise + 章节定位写进 notes |
change_tone/style |
「更口语一点 / 更正式」 | user_revise + notes |
apply_review(若已有审核结果) |
「按编辑意见改」「只接受第 1、2 条」 | {action:'user_revise', selectedIssueIndices:[…]} |
E. 编辑审核类(pausePoint = review_confirm)
| 意图 | 示例 | 映射 |
|---|---|---|
accept_review |
「按编辑意见改」 | {action:'accept_review', selectedIssueIndices} |
partial_accept_review |
「只接受第 1、2 条」 | accept_review + selectedIssueIndices 子集 |
add_review_opinion |
「再补一条:核查数据准确性」 | accept_review + userRevisionNotes(并入补充指令,现协议已支持) |
force_finalize |
「不改了,强制定稿」 | {action:'force_finalize', overrideVerdict:true} (高代价:必澄清) |
F. 素材不足求助类(pausePoint = section_help)
| 意图 | 映射 |
|---|---|
section_supplement |
{action:'section_help', sectionDecisions:[…'supplement']} |
section_loose |
sectionDecisions:[…'loose'] |
section_delete |
sectionDecisions:[…'delete'] |
G. 问答类(新;任意 status;旁路,不改写作状态)
| 意图 | 示例 | 映射 |
|---|---|---|
ask_about_content |
「第二章讲了啥?」「为什么用这个论点?」 | 意图节点直接带回 answer,对话流渲染(见 5.4) |
ask_meta |
「现在到哪步了?」「用了哪些素材?」 | 读当前 state 直接回答,不走图 |
H. 控制类(新 / 半新)
| 意图 | 映射 |
|---|---|
next_step(通用「继续/下一步」) |
按当前 pausePoint 映射到该阶段的默认确认(material/outline→confirm,draft→to_editor…;等价点确认按钮) |
restart_stage |
重跑当前阶段(复用 resumeWriting() 空 command 续跑) |
run_background |
转后台自动跑:suspendAIWritingToBackground() |
cancel |
pauseWriting()(stream.stop()) |
unknown/clarify |
无法判定 → 反问澄清 / 用户协助(防误触发硬指标) |
3.3 「素材不足自动重搜」判定与回退(用户强调点)
触发:用户在大纲/草稿/审核阶段提出修改意见,但意见需要的信息现有素材里没有。
判定来源(组合):
- 意图节点直接判:把「素材摘要(keywords + 每条 title/source)」喂给意图 prompt,让它判断
「这条意见能否用现有素材满足」;不能 →
needResearch=true+researchQuery。 - 执行阶段兜底:
writer_draft严格模式已有blocked_sections→section_help暂停点, 对话层把它翻译成「素材不足,是否重搜?」的追问。
回退动作(首期纯前端实现,不动后端协议):needResearch=true 时,前端把用户的修改
payload 缓存为 pendingIntent,先 submitIntervention({action:'re_search', userQuery:researchQuery})
补素材;监听到新一轮 material_confirm(素材追加完成)后,自动提交 pendingIntent。
需处理「重搜期间用户又改主意」→ 允许覆盖 pending。
4. 意图解析引擎:方案与契约
采用方案 A:后端 LLM 意图节点(独立 REST),叠加高频短句规则快路径优化。
理由:needResearch 判定需要完整写作上下文(素材/大纲/草稿),后端天然持有 checkpoint state;
与 setup_writing 一脉相承,离线模型选择策略统一;输出 schema 稳定、前端只消费。
4.1 后端入口
app/gateway/routers/ai_writing.py 新增:
POST /api/ai-writing/sessions/{session_id}/intent
Body: { text: string, status: string, pausePoint?: string }
Resp: IntentResult(见 4.3)
实现:读该 session 的 checkpoint state(素材摘要 / 大纲纲要 / 草稿字数·章节 / 审核意见)→
用 ai_writing 配置模型(复用 intent_parser.py 同套 create_chat_model + parse_json +
模型容错 _model_fallback)解析 → 返回结构化契约。不改图拓扑。
新增 prompt:agents/ai_writing/prompts/intent_router_prompts.py
- 输入:用户文本、
current_status/pause_point、素材摘要、大纲纲要、草稿字数+章节标题、审核意见列表。 - 输出:严格 JSON(4.3 契约)。硬要求:只在证据充分时给高 confidence,否则给
clarify;finalize/force_finalize/re_search等高代价意图必须高置信才不澄清。
4.2 前端快路径(先跑规则,未命中再调后端)
api/ai-writing-intent.ts 里对当前 pausePoint 做少量确定性短语命中,直接产出 payload,省一次往返:
- 「继续/下一步/确认/可以/ok/好的」→ 当前阶段默认
confirm(draft 阶段=to_editor)。 - 「重新搜索/重搜」(material)→
re_search。「重写大纲」(outline)→re_outline。 - 「定稿/强制定稿」→ 不进快路径(高代价,一律走后端 + 可能澄清)。
- 命中即执行;未命中 → 调后端
intent接口。
4.3 意图解析输出契约
{
"intent": "revise_draft", // 见 3.2 分类
"pausePoint": "draft_confirm", // 需要 resume 时;否则 null
"action": "user_revise", // 映射到现有 action
"payload": { // 直接可喂 submitIntervention 的字段(camelCase)
"userRevisionNotes": "第三段精简,并补一个 2024 年的案例"
},
"needResearch": true, // 素材是否不足
"researchQuery": "2024 行业案例", // needResearch 时的检索意图
"answer": null, // 问答类意图的直接回答(旁路)
"confidence": 0.86,
"clarify": null // 低置信时的反问话术(非空则不执行、只追问)
}
前端消费顺序:
answer非空 → 对话流渲染回答(问答旁路,不动写作状态)。clarify非空 或confidence < 阈值(建议 0.6)→ 渲染反问气泡,等用户澄清(防误触发)。needResearch=true→ 缓存pendingIntent=payload,先重搜,收到新素材后自动提交。- 否则 →
idle走startWriting(...);暂停态走submitIntervention({action, ...payload})。
5. 前端改造方案
5.1 新页面与路由(复制式)
- 新页面:
open-canvas/pages/AIWritingChatPage.tsx(骨架照抄AIWritingPage.tsx的 Provider 包裹与左右分栏;左栏换成WritingChatPanel,右栏仍AIWritingDraftPanel;idle 不再挂AIWritingForm,改由底部输入框启动)。 - 路由注册(新增,不动旧行):
open-canvas/routes/OpenCanvasRoutes.tsx加path="ai-writing-chat/*"。- 侧边栏
core/page-layout/sidebar-menu.ts:在qa-research旁新增{ id:"qa-research-chat", label:"AI写作(对话版)", icon:FileText, path:"/page/canvas/ai-writing-chat" }。 (或先不加、内部灰度直链验证。)
5.2 新面板 WritingChatPanel.tsx(左栏主体)
职责 = 消息流容器 + 底部输入框,替代 AIWritingPanel 里的「时间线 + InterventionCard + 状态栏」。
复用 useAIWriting() 读 state / 调 startWriting / submitIntervention / pauseWriting /
suspendAIWritingToBackground。
消息流渲染(把 ProgressEvent / 阶段产物适配成消息卡,复用现有展示子组件):
- 运行中:
research_progress/outline_chunk/draft_chunk/review_chunk→ 进度 / 流式卡 (复用SkillStepsCard/OutlineStreamingView/DraftGeneratingView/ReviewStreamingView的展示部分)。 - 到达暂停点:渲染 产物卡 + 保留的确认按钮(见 5.3),不再有输入框。
- 用户消息、AI 澄清追问、问答回答:普通气泡。
底部输入框:直接复用 @/components/ai-elements/prompt-input(PromptInput+PromptInputTextarea+
PromptInputSubmit),Enter 发送、Shift+Enter 换行;发送时读当前 state.status/currentPause?.pausePoint
交给意图路由(见 5.5)。运行中(非暂停点)可禁用发送或转「排队/提示当前在生成」。
5.3 新消息卡 chat-cards/*(保留按钮、去掉输入框)
把 InterventionCard.tsx 的五张卡各复制一份到 open-canvas/components/ai-writing-chat/chat-cards/,
删掉其中的 textarea / MaterialsToolbar 输入部分,保留产物展示 + 确认/动作按钮:
| 新卡 | 展示(复用) | 保留的按钮 | 删除的输入 |
|---|---|---|---|
MaterialConfirmChatCard |
MaterialsCard(勾选保留)+ SkillStepsCard |
「确认素材,规划大纲」「重新搜索」 | MaterialsToolbar 的 userQuery 输入框 |
OutlineConfirmChatCard |
OutlineCard(可点标题微调保留) |
「确认大纲,开始写作」 | feedback textarea + 发送 |
DraftConfirmChatCard |
ReviewCard(若有审核,勾选保留) |
「按编辑审核意见修改」「让编辑继续审核」「确认定稿」 | 「修改意见」textarea |
ReviewConfirmChatCard |
ReviewCard(勾选保留) |
「按编辑意见修改」「强制定稿」 | 「补充修改指令」textarea |
SectionHelpChatCard |
章节 + 三选一按钮组 | 三选一 + 「提交并继续」 | (本就无自由输入,原样保留) |
勾选态(素材/审核意见)保留——它是「点按钮」路径的一部分,不算自由输入框。用户想用自然语言 「只用第 1、3 条」也能走底部输入框(意图层产出
approvedMaterialIds/selectedIssueIndices)。 按钮点击 直接调submitIntervention,与旧卡完全一致,零改动风险。
5.4 问答旁路(新能力)
「对写作内容提问」不改写作 state。首期轻量实现:意图节点检出 ask_* 时读 state 直接带回 answer,
前端在消息流渲染为普通 AI 气泡即可(一次调用出答案)。完整版(后续)可另起只读 lead_agent 线程注入
草稿/大纲作背景,类似 WritingSetupChat 的 useThreadStream。
5.5 交互流程(对话版)串起来
- 空闲:底部输入「写一篇关于 X 的深度分析,2000 字」→ 意图
start_writing→ 组AIWritingRequest→startWriting()。(缺关键字段时先clarify追问字数/读者/类型。) - 运行中:进度/流式卡渲染。
- 到暂停点:渲染产物卡 + 按钮 + 一句提示「你可以点上面的按钮,或直接说:确认继续 / 补充素材 / 改大纲…」。
- 点按钮 → 直接
submitIntervention(旧逻辑)。 - 发文字 →
resolveIntent(text, status, pausePoint)(先快路径、后后端)→ 按 4.3 消费。
- 点按钮 → 直接
- 问答:任意时刻提问 → 旁路
answer,不打断写作。 - 素材不足:
needResearch或section_help→ 追问/执行「重搜 → 自动续跑 pending 意图」。 - 拿不准:
clarify/低置信 → 反问气泡,不执行。
5.6 pending 意图 & 澄清态(新增本地状态)
在 WritingChatPanel(或新 WritingChatContext)维护:
pendingIntent: UserInterventionPayload | null—— 素材不足重搜完成后自动提交。awaitingClarify: { originalText: string } | null—— 澄清态,用户下一句与上一句拼接再解析。- pending 生命周期:设置 → 提交
re_search→ 监听 reducer 里新一轮awaiting_material_confirm(state.status从researching回到awaiting_material_confirm)→ 自动submitIntervention(pending)→ 清空。
6. 后端改造方案
6.1 意图解析入口(新增,唯一后端改动主体)
app/gateway/routers/ai_writing.py:新增POST /sessions/{id}/intent(见 4.1)。 读 checkpoint state 用app.state.checkpointer+make_ai_writing_graph().aget_state(...)(参照ai_writing_job_executor.py的读法)取素材/大纲/草稿/审核摘要。agents/ai_writing/prompts/intent_router_prompts.py:新增意图 prompt(见 4.1)。- 复用
nodes/intent_parser.py的模型创建 /parse_json/_model_fallback容错。
6.2 不需要改的部分
- 四个阶段大脑节点、五个暂停点、checkpoint、StreamBridge、持久化、sessions/transcript REST——全不动。
- 「素材不足自动续跑」「问答旁路」首期都在前端 / 意图节点实现,不扩 resume 协议。
6.3 可选增强(阶段 3,按需)
add_review_opinion完整版:review_confirmresume 增字段extra_review_notes(首期已用现有userRevisionNotes降级承载,够用)。resume_intent后端化(把「重搜完自动续跑」搬到后端,减少前端状态机复杂度)。- undo / 回退到上一暂停点(依赖 checkpoint 回滚)。
7. 数据流时序(改稿 + 素材不足自动重搜)
用户(draft_confirm 暂停): "第三段补个2024年的行业案例"
│ 底部输入框 → resolveIntent(text, status='awaiting_draft_confirm', pausePoint='draft_confirm')
▼ POST /api/ai-writing/sessions/{id}/intent { text, status, pausePoint }
后端: 读 state(素材摘要) + LLM 解析
│ 返回 { intent:revise_draft, action:user_revise,
│ payload:{userRevisionNotes:"第三段…补2024案例"},
│ needResearch:true, researchQuery:"2024 行业案例", confidence:0.9 }
▼
前端: needResearch=true → pendingIntent = payload
│ submitIntervention({action:'re_search', userQuery:"2024 行业案例"})
▼ LangGraph resume → researcher 追加素材 → status 回到 awaiting_material_confirm
前端: 监听到新一轮素材确认 → 自动提交 pendingIntent
│ submitIntervention({action:'user_revise', userRevisionNotes:"第三段…补2024案例"})
▼ writer_draft 用新素材改稿 → draft_chunk… → draft_ready → draft_confirm
前端: 消息流展示新草稿卡 + "已按你的意见改写并补充了 2024 案例"
8. 关键实现细节与坑
- 阶段作用域:
resolveIntent必须带state.currentPause?.pausePoint+state.status—— 同一句「重新来」在 material 是重搜、在 outline 是重写大纲。AIWritingContext已有这两个字段,直接读。 - 确认按钮零改动:新卡的按钮
onClick原样调submitIntervention(payload),与旧卡逐字一致, 风险最低;只删输入框。 - 防误触发:低置信(<0.6)或
clarify非空一律追问;finalize/force_finalize/re_search即使命中也要求高置信,否则澄清。绝不盲目定稿/覆盖重搜。 - pending 意图队列:素材不足是「先插重搜、再回原意图」,用 5.6 的小状态机;重搜完成前允许覆盖 pending。
- 问答不污染 transcript:问答/澄清消息在前端标记
kind:'qa'|'clarify',与写作进度事件区分(AIWritingContext的 transcript 只存 progressEvents/completedInterventions,问答气泡是纯前端消息, 默认不入 transcript,避免历史回看错乱)。 - 流式产物→消息卡:复用
OutlineStreamingView/DraftGeneratingView/ReviewStreamingView/SkillStepsCard的展示部分,套进消息容器,不重写渲染。 - 右侧草稿预览:
AIWritingDraftPanel+DraftSync原样复用(DraftSync依据 status/markdown 同步右侧画布)。 - 离线内网:意图模型走
config.yaml → ai_writing配置模型;检索仍走技能/内网 ES,不联网。 - 模型选择透传:
submitIntervention的 resume 已把state.request?.modelName一并回传(见AIWritingContext),新页面沿用即可。 - 旧页面隔离验证:改完后回归旧
/page/canvas/ai-writing与/page/workspace/ai-writing、 笔记本嵌入页,确认零变化(新代码不 import 旧的AIWritingForm/InterventionCard/WritingFormContext)。
9. 分阶段实施路线图
阶段 0 — 骨架(不含意图)
- 复制
AIWritingChatPage+ 注册新路由 + 侧边栏入口;复用AIWritingContext/useStream/DraftPanel。 - 复制五张
chat-cards(删输入框、留按钮);底部输入框先只做 idle 直发start_writing(文本原样当userIntent,其余字段取默认)+ 暂停点靠按钮推进。端到端跑通。
阶段 1 — 意图解析(核心)
- 后端
POST /sessions/{id}/intent+intent_router_prompts.py,返回 4.3 契约。 - 前端
api/ai-writing-intent.ts(快路径 + 后端)接入WritingChatPanel,覆盖 A~F 类意图。 - 低置信
clarify澄清态(5.6)。
阶段 2 — 问答旁路 + 素材不足自动重搜
- G 类问答(意图节点直接带
answer)。 needResearch+ pending 意图机制(前端实现重搜后自动续跑,5.6)。
阶段 3 — 增强(按需)
add_review_opinion扩协议、resume_intent后端化、undo/回退、完整问答只读线程。
阶段 4 — 打磨
- 消息卡视觉、历史回看(transcript)、后台挂起入口、灰度到侧边栏。
10. 关键文件清单(落地对照)
新增(前端)
open-canvas/pages/AIWritingChatPage.tsx— 新页面(复制AIWritingPage骨架改造)open-canvas/components/ai-writing-chat/WritingChatPanel.tsx— 消息流 + 底部输入框open-canvas/components/ai-writing-chat/chat-cards/{MaterialConfirmChatCard,OutlineConfirmChatCard,DraftConfirmChatCard,ReviewConfirmChatCard,SectionHelpChatCard}.tsx— 保留按钮、去掉输入框open-canvas/components/ai-writing-chat/progressToMessage.ts—ProgressEvent→ 消息卡适配open-canvas/api/ai-writing-intent.ts— 意图解析客户端(快路径 +POST …/intent)- (可选)
open-canvas/contexts/WritingChatContext.tsx— pending 意图 / 澄清态
修改(前端,仅追加,不动旧逻辑)
open-canvas/routes/OpenCanvasRoutes.tsx— 加一条ai-writing-chat/*路由core/page-layout/sidebar-menu.ts— 加一个侧边栏入口(可选)open-canvas/types/ai-writing.ts— 仅追加IntentResult等新类型,不改旧字段
新增(后端)
app/gateway/routers/ai_writing.py— 加POST /sessions/{id}/intentagents/ai_writing/prompts/intent_router_prompts.py— 意图 prompttests/test_ai_writing_intent.py— 意图接口单测(TDD 强制)
复用(不改)
open-canvas/contexts/AIWritingContext.tsx、hooks/useAIWritingStream.tsopen-canvas/components/ai-writing/{AIWritingDraftPanel,DraftSync,MaterialsCard,OutlineCard,ReviewCard,SkillStepsCard,OutlineStreamingView,DraftGeneratingView,ReviewStreamingView}.tsxagents/ai_writing/graph.py、四个阶段节点、五个暂停点、nodes/intent_parser.py
绝不动(保证「初始的不用动」)
open-canvas/pages/AIWritingPage.tsx及其引用的components/ai-writing/{AIWritingForm,InterventionCard}.tsx、contexts/WritingFormContext.tsx- 旧路由
/page/canvas/ai-writing、/page/workspace/ai-writing、笔记本嵌入页
11. 待确认(默认取值已给出,可直接推进)
- 意图引擎:后端 LLM 节点(方案 A)+ 前端短句快路径 —— 默认采用。
AIWritingContext/useAIWritingStream:复用(不物理复制)——默认采用;需绝对隔离可改为复制。- 新页面入口:侧边栏新增「AI写作(对话版)」 —— 默认加;若要先灰度可只留直链。
- 「素材不足自动重搜」:首期前端 pending 续跑(不动后端 resume 协议)——默认采用。
- 问答旁路:首期意图节点直接带
answer—— 默认采用。
以上默认按「A + 复用引擎 + 侧边栏入口 + 前端 pending + 意图节点带答案」推进,如需调整请指出。