issue #118 v2 完整闭环。 ## 多轮对话 - QaSessionState 加 messages: Vec<QaChatMessage> + panel_visible flag。 - Cmd+Shift+/ 现在 toggle 浮窗可见性(不再启动录音);浮窗可见时 rightOption 路由到 QA recording,不可见时仍是主听写。open_qa_panel / close_qa_panel 分离。 - 第一轮 user message 嵌选区原文(# 选区原文 / # 我的问题),之后只送提问。 - 前端 QaPanel 渲染气泡列表(user 蓝色靠右 / assistant 灰色 markdown 靠左)。 ## 流式输出 - chat_completion_history → chat_completion_history_streaming:开 stream:true + SSE chunk 解析,on_delta 回调把每 chunk emit 成 qa:state{kind:"answer_delta"}。 - 前端 streamingAnswer state + StreamingAssistantBubble(带蓝色闪烁 caret)。 - answer 事件落定后清空 buffer,最终 messages 接管。 ## macOS 浮窗修复(v1 一直存在的雷) - capabilities/default.json 加 "qa" 到 windows 数组。否则前端 listen("qa:state") 被 Tauri 权限拦截,浮窗永远收不到事件。 - show_qa_window 用 NSWindow.orderFrontRegardless 替代 window.show() (后者在 macOS 走 makeKeyAndOrderFront 抢 frontmost)。这样 capture_selection 的 AX read / Cmd+C fallback 能稳定从原 app 读到选区。 - 所有 ObjC msg_send 必须 wrap 进 app.run_on_main_thread —— macOS 26 对 NSWindow 主线程要求是硬断言(违反直接 SIGTRAP)。 - NSWindow.movableByWindowBackground=YES:浮窗任意空白处可拖。 - QA hotkey 注册在主线程:global-hotkey crate 在 macOS 用 Carbon RegisterEventHotKey,事件回调要靠主 run loop dispatch。 ## 胶囊状态同步 - QA 录音 / 转写 / 思考 同步推 capsule:state,让用户在底部胶囊也看到状态。 - schedule_capsule_idle 同时检查 dictation 和 QA 都 Idle 才隐藏,避免旧 dictation Done timer 把 QA 的胶囊误关。 - open_qa_panel 进入时先 emit Idle 清掉 dictation 残留 message + insertedChars。 ## 设置页 - SelectionAsk 独立成一级 tab;预设减到 4 个 cmd+shift+ 系列(Option 跟主听写 共用,不放进 QA hotkey)。 - howto / hotkey / privacy 文案重写,反映 v2 的「先开浮窗、再 Option 录音」流程。 - prefs 默认 qaHotkey = cmd+shift+;。 ## 后续路线图 - docs/qa-reasoning-roadmap.md:思考能力 v2.2 设计稿(C 路线 reasoner model 切换 + reasoning_content delta + 折叠思考块)。
76 lines
3.7 KiB
Markdown
76 lines
3.7 KiB
Markdown
# 划词追问:思考能力(Reasoning)路线图
|
||
|
||
> 创建于 2026-05-01。流式输出(v2.1)已完成,**思考能力(v2.2)暂未实施**——这份文档是后续迭代的设计稿。
|
||
>
|
||
> 关联:issue #118 v2、PR #119、`openless-all/app/src-tauri/src/polish.rs`、`openless-all/app/src/pages/SelectionAsk.tsx`。
|
||
|
||
## 背景与决策
|
||
|
||
用户提出:"QA 应该让 LLM 进行思考后再回复,并且可以设置思考强度"。
|
||
|
||
讨论了 3 条路径:
|
||
|
||
| 方案 | 实现 | 优 | 劣 |
|
||
|---|---|---|---|
|
||
| A | prompt-engineered(system prompt 加 `<thinking>` 块要求) | 0 配置改动;现 model 即可 | 思考质量受小模型限制;不可控 |
|
||
| B | OpenAI 标准 `reasoning_effort: low/medium/high` 字段 | 标准化 | DeepSeek-v4-flash 不识别该字段 |
|
||
| **C** | **切换 reasoner 模型(deepseek-r1 / o1 / claude extended thinking)** | **真**思考;可视化推理过程 | 用户得多配一个 model;UI 复杂度高 |
|
||
|
||
**结论**:选 C。A/B 在当前 provider 下等于无效。
|
||
|
||
## 实施分解
|
||
|
||
### 后端
|
||
|
||
1. **凭据存储**:`CredentialAccount` 加两条
|
||
- `ArkReasonerModelId`(如 `deepseek-r1`、`doubao-seed-1.6-thinking`)
|
||
- 复用现有 `ArkApiKey` / `ArkEndpoint`(同一 provider 不同 model)
|
||
|
||
2. **prefs**:`Preferences` 加字段
|
||
- `qa_reasoning_effort: ReasoningEffort` 枚举 `Off | Low | Medium | High`
|
||
- 默认 `Off`(与现行为一致)
|
||
|
||
3. **`answer_chat_streaming` 重载**:根据 effort 决定走 chat 还是 reasoner endpoint
|
||
- `Off`:走 v2.1 现路径(chat 模型 + stream)
|
||
- `Low/Medium/High`:走 reasoner 模型;强度通过 system prompt hint 调("简短思考即可" / "详细思考" / "深度推理多角度")
|
||
- SSE 解析时同时收 `delta.content` + `delta.reasoning_content`,两者通过不同事件 emit:
|
||
- `qa:state {kind:"reasoning_delta", chunk}`
|
||
- `qa:state {kind:"answer_delta", chunk}` (已存在)
|
||
|
||
4. **answer_chat 拼装最终 message** 时,`reasoning_content` 不写入 `messages` 数组(只显示用,不进上下文)。多轮提问只把最终答案带回上下文。
|
||
|
||
### 前端
|
||
|
||
1. **SelectionAsk.tsx** 新增配置块:
|
||
- 「思考强度」下拉:关闭 / 浅 / 中 / 深
|
||
- 「思考模型」输入框(model id;默认 `deepseek-r1`)
|
||
- i18n:zh-CN / en
|
||
|
||
2. **QaPanel.tsx** 新增「思考过程」可折叠区块:
|
||
- 在 user 气泡下方、最终 assistant 气泡上方
|
||
- 默认折叠,标题 `思考中…` / `思考过程(X 字)`,点击展开
|
||
- 流式期间:实时拼接 `reasoning_delta`,气泡有打字 caret
|
||
- 答案完成:折叠收起;用户随时可点开看推理
|
||
|
||
3. **types.ts**:`QaStateKind` 加 `'reasoning_delta'`;payload 加 `reasoning_chunk?: string`
|
||
|
||
### 边界与风险
|
||
|
||
- **Provider 兼容性**:火山 Ark 的 deepseek-r1 / doubao-thinking 都返回 `reasoning_content`;OpenAI o1 通过 thinking blocks(不是 reasoning_content),需要单独 adapter
|
||
- **Token 成本**:reasoner 模型 token 价格高 5-10x;用户开「深度」就是真烧钱,UI 应该有提示
|
||
- **延迟**:reasoner 首 token 可能 > 5s(思考阶段无 content 输出)。要在 UI 上区分「思考中」(reasoning streaming)vs「答题中」(content streaming),避免用户以为卡了
|
||
|
||
## 工作量估算
|
||
|
||
- 后端 reasoner 通路 + SSE 双流解析:~2h
|
||
- 前端折叠思考区块 + 打字 caret + 状态切换:~1.5h
|
||
- prefs / SelectionAsk 配置 UI + i18n:~0.5h
|
||
- 端到端测试(三档强度 × 单/多轮 × 错误回退):~1h
|
||
- **总计**:~5h
|
||
|
||
## 实施先决条件
|
||
|
||
1. 用户配置好一个 reasoner model(deepseek-r1 / doubao-thinking-pro 等)
|
||
2. 后端凭据 vault 写入对应 model id
|
||
3. v2.1 流式输出已稳定(已完成 ✅)
|