508 lines
33 KiB
Markdown
508 lines
33 KiB
Markdown
# 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 as `assistant_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` + LangGraph `useStream`,`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 必须满足
|
||
|
||
1. **复制式新增**:新目录 / 新路由 / 新侧边栏入口,**旧页面、旧路由、旧组件零改动**(「初始的不用动」)。
|
||
2. 页面**底部单一多行智能输入框**接管全流程交互;四个阶段干预卡里的**输入框全部移除**。
|
||
3. **保留确认按钮**:每个阶段到达暂停点时,消息流里仍渲染**产物卡 + 原来的确认/动作按钮**
|
||
(素材「确认素材」、大纲「确认大纲」、草稿「让编辑审核 / 确认定稿」、审核「按编辑意见修改 / 强制定稿」、
|
||
素材不足的三选一按钮)。用户**点按钮**或**在底部输入框发自然语言意图**二选一均可推进。
|
||
4. **强意图理解**:把用户自由文本准确路由到正确动作,**覆盖现有全部交互 + 更多**(见 3.2)。
|
||
5. **阶段作用域**:意图解析必须知道「当前停在哪个专家阶段」,把同一句话按当前阶段翻译成对应 action。
|
||
6. **素材不足自动回退重搜**:修改意见需要的信息现有素材没有时,先重搜补素材、补完自动继续原意图。
|
||
7. **拿不准就协助**:低置信意图**不猜着执行**,走澄清追问(clarify)或用户协助。
|
||
8. 保留右侧草稿实时预览(可编辑)与时间线 / 进度展示。
|
||
|
||
### 2.2 明确不做(本期)
|
||
|
||
- 不改旧 `AIWritingPage` 及其 `AIWritingForm` / `InterventionCard`(这两个是要在**副本**里改的)。
|
||
- 不替换 `ai_writing` graph 四个阶段大脑逻辑,不动五个暂停点 / 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 「素材不足自动重搜」判定与回退(用户强调点)
|
||
|
||
触发:用户在**大纲/草稿/审核**阶段提出修改意见,但意见需要的信息现有素材里没有。
|
||
|
||
判定来源(组合):
|
||
1. **意图节点直接判**:把「素材摘要(keywords + 每条 title/source)」喂给意图 prompt,让它判断
|
||
「这条意见能否用现有素材满足」;不能 → `needResearch=true` + `researchQuery`。
|
||
2. **执行阶段兜底**:`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 意图解析输出契约
|
||
|
||
```jsonc
|
||
{
|
||
"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 // 低置信时的反问话术(非空则不执行、只追问)
|
||
}
|
||
```
|
||
|
||
前端消费顺序:
|
||
1. `answer` 非空 → 对话流渲染回答(问答旁路,不动写作状态)。
|
||
2. `clarify` 非空 **或** `confidence < 阈值(建议 0.6)` → 渲染反问气泡,等用户澄清(**防误触发**)。
|
||
3. `needResearch=true` → 缓存 `pendingIntent=payload`,先重搜,收到新素材后自动提交。
|
||
4. 否则 → `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 交互流程(对话版)串起来
|
||
|
||
1. **空闲**:底部输入「写一篇关于 X 的深度分析,2000 字」→ 意图 `start_writing` → 组 `AIWritingRequest`
|
||
→ `startWriting()`。(缺关键字段时先 `clarify` 追问字数/读者/类型。)
|
||
2. **运行中**:进度/流式卡渲染。
|
||
3. **到暂停点**:渲染产物卡 + 按钮 + 一句提示「你可以点上面的按钮,或直接说:确认继续 / 补充素材 / 改大纲…」。
|
||
- **点按钮** → 直接 `submitIntervention`(旧逻辑)。
|
||
- **发文字** → `resolveIntent(text, status, pausePoint)`(先快路径、后后端)→ 按 4.3 消费。
|
||
4. **问答**:任意时刻提问 → 旁路 `answer`,不打断写作。
|
||
5. **素材不足**:`needResearch` 或 `section_help` → 追问/执行「重搜 → 自动续跑 pending 意图」。
|
||
6. **拿不准**:`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_confirm` resume 增字段 `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. 关键实现细节与坑
|
||
|
||
1. **阶段作用域**:`resolveIntent` 必须带 `state.currentPause?.pausePoint` + `state.status`——
|
||
同一句「重新来」在 material 是重搜、在 outline 是重写大纲。`AIWritingContext` 已有这两个字段,直接读。
|
||
2. **确认按钮零改动**:新卡的按钮 `onClick` 原样调 `submitIntervention(payload)`,与旧卡逐字一致,
|
||
风险最低;**只删输入框**。
|
||
3. **防误触发**:低置信(<0.6)或 `clarify` 非空一律追问;`finalize`/`force_finalize`/`re_search`
|
||
即使命中也要求高置信,否则澄清。绝不盲目定稿/覆盖重搜。
|
||
4. **pending 意图队列**:素材不足是「先插重搜、再回原意图」,用 5.6 的小状态机;重搜完成前允许覆盖 pending。
|
||
5. **问答不污染 transcript**:问答/澄清消息在前端标记 `kind:'qa'|'clarify'`,与写作进度事件区分(
|
||
`AIWritingContext` 的 transcript 只存 progressEvents/completedInterventions,问答气泡是纯前端消息,
|
||
默认不入 transcript,避免历史回看错乱)。
|
||
6. **流式产物→消息卡**:复用 `OutlineStreamingView`/`DraftGeneratingView`/`ReviewStreamingView`/
|
||
`SkillStepsCard` 的**展示部分**,套进消息容器,不重写渲染。
|
||
7. **右侧草稿预览**:`AIWritingDraftPanel` + `DraftSync` 原样复用(`DraftSync` 依据 status/markdown
|
||
同步右侧画布)。
|
||
8. **离线内网**:意图模型走 `config.yaml → ai_writing` 配置模型;检索仍走技能/内网 ES,不联网。
|
||
9. **模型选择透传**:`submitIntervention` 的 resume 已把 `state.request?.modelName` 一并回传(见
|
||
`AIWritingContext`),新页面沿用即可。
|
||
10. **旧页面隔离验证**:改完后回归旧 `/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}/intent`
|
||
- `agents/ai_writing/prompts/intent_router_prompts.py` — 意图 prompt
|
||
- `tests/test_ai_writing_intent.py` — 意图接口单测(TDD 强制)
|
||
|
||
### 复用(不改)
|
||
- `open-canvas/contexts/AIWritingContext.tsx`、`hooks/useAIWritingStream.ts`
|
||
- `open-canvas/components/ai-writing/{AIWritingDraftPanel,DraftSync,MaterialsCard,OutlineCard,ReviewCard,SkillStepsCard,OutlineStreamingView,DraftGeneratingView,ReviewStreamingView}.tsx`
|
||
- `agents/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. 待确认(默认取值已给出,可直接推进)
|
||
|
||
1. 意图引擎:**后端 LLM 节点(方案 A)+ 前端短句快路径** —— 默认采用。
|
||
2. `AIWritingContext` / `useAIWritingStream`:**复用**(不物理复制)——默认采用;需绝对隔离可改为复制。
|
||
3. 新页面入口:**侧边栏新增「AI写作(对话版)」** —— 默认加;若要先灰度可只留直链。
|
||
4. 「素材不足自动重搜」:**首期前端 pending 续跑**(不动后端 resume 协议)——默认采用。
|
||
5. 问答旁路:**首期意图节点直接带 `answer`** —— 默认采用。
|
||
|
||
> 以上默认按「A + 复用引擎 + 侧边栏入口 + 前端 pending + 意图节点带答案」推进,如需调整请指出。
|