文档: 架构方案文档(意图识别论证+多主题愿景/论证+文档物理分类+边界清晰化)
squash合并: - 意图识别层论证(8维度+10业界佐证) - 多主题上下文管理愿景+并存论证+补充论证(多轮agentic) - 架构设计文档物理分类(四子目录+INDEX+命名规范+引用同步+边界清晰化) - 前端架构技术债清单归档
This commit is contained in:
295
docs/02-架构设计/构想审查/aichat交互体验改进方案-2026-06-14.md
Normal file
295
docs/02-架构设计/构想审查/aichat交互体验改进方案-2026-06-14.md
Normal file
@@ -0,0 +1,295 @@
|
||||
# AIChat 交互体验改进方案
|
||||
|
||||
> 创建: 2026-06-14 | 状态: 待讨论
|
||||
> 范围: 消息发送、流式渲染、对话管理、错误恢复、技能/Provider、窗口布局等非授权类交互
|
||||
|
||||
---
|
||||
|
||||
## 一、消息输入与发送
|
||||
|
||||
### 1.1 无法编辑已发送消息
|
||||
|
||||
**现象**:用户发出消息后发现措辞有误,只能重新打一条新消息。无法像 ChatGPT/Claude 那样编辑上一条用户消息并重新生成。
|
||||
|
||||
**根因**:`sendMessage`(useAiSend.ts)push 后的消息是只追加不可变的。前端没有编辑入口,后端 `ai_chat_send` 也没有"替换最后一条 user 消息并重跑"的语义。
|
||||
|
||||
**方案**:
|
||||
- 用户消息气泡 hover 显示"编辑"按钮
|
||||
- 点击后消息内容回填到输入框,用户修改后发送时后端截断该消息之后的所有历史(含 AI 回复),重新跑 agentic loop
|
||||
- 后端新增 `ai_chat_edit` 命令,接收 `message + 截断位置`,替换 messages 数组中对应 user 消息并清掉后续消息,然后走正常 `run_agentic_loop`
|
||||
|
||||
### 1.2 无法重新生成 AI 回复
|
||||
|
||||
**现象**:AI 回答不满意时没有"重新生成"按钮,只能重新措辞追问。
|
||||
|
||||
**根因**:`AiChat.vue` 的 AI 消息气泡上没有任何操作按钮。后端也没有 `ai_regenerate` 命令。
|
||||
|
||||
**方案**:
|
||||
- AI 消息气泡 hover 显示操作栏(复制 | 重新生成)
|
||||
- "重新生成":后端删除最后一条 AI 消息,用倒数第二条 user 消息重新触发 `run_agentic_loop`
|
||||
- 后端新增 `ai_regenerate` 命令
|
||||
|
||||
### 1.3 无法一键复制消息内容
|
||||
|
||||
**现象**:代码或文本只能手动选中复制。流式渲染中选中文字会被后续 delta 打断。
|
||||
|
||||
**根因**:消息气泡上没有复制按钮。
|
||||
|
||||
**方案**:
|
||||
- AI 消息气泡 hover 显示"复制"按钮
|
||||
- 点击后 `navigator.clipboard.writeText(msg.content)`,toast 提示"已复制"
|
||||
- 代码块单独提供"复制代码"按钮(hover 代码块右上角浮出)
|
||||
|
||||
### 1.4 缺少 `@` 实体引用
|
||||
|
||||
**现象**:用户无法在输入时引用某个项目、任务或文件。描述需求时无法精确指定上下文,AI 可能猜错对象。
|
||||
|
||||
**根因**:输入框只有 `/` 技能联想,没有 `@` 实体引用机制。
|
||||
|
||||
**方案**:
|
||||
- 输入框支持 `@` 触发实体联想浮层(复用技能联想的 popover 架构)
|
||||
- 联想源:项目列表、任务列表、最近编辑的文件
|
||||
- 选中后在消息中展开为 `[项目: u-desk]` 等标记文本,后端 system prompt 注入对应实体的上下文摘要
|
||||
|
||||
### 1.5 输入框高度过紧
|
||||
|
||||
**现象**:textarea 最大高度 120px(约 5-6 行),超过后内部滚动。用户写长提示词时看不到全貌。
|
||||
|
||||
**根因**:`autoResize` 中 `Math.min(el.scrollHeight, 120)` 限制太紧。
|
||||
|
||||
**方案**:
|
||||
- 最大高度提升到 200px(约 10 行),超过后再内部滚动
|
||||
- 或改为可拖拽调整高度(底部 resize handle)
|
||||
|
||||
---
|
||||
|
||||
## 二、流式渲染与消息展示
|
||||
|
||||
### 2.1 流式渲染中无法稳定选中文字
|
||||
|
||||
**现象**:AI 正在流式输出时,用户尝试选中已渲染的文字,新的 delta 触发 DOM 更新导致选区丢失。
|
||||
|
||||
**根因**:`renderContent` 在流式时返回 `streamingHtml.value`(rAF 节流重 parse),每次更新都 `v-html` 替换整个 DOM 子树,浏览器选区被清除。
|
||||
|
||||
**方案**:
|
||||
- 方案 A(推荐):检测到用户正在选择文字时(`selectionchange` 事件 + 选区非空且在消息容器内),暂停 rAF 流式 parse,选区结束后恢复
|
||||
- 方案 B:流式渲染时在已完成的块(blockCache 命中的块)上使用独立 DOM 节点不参与 v-html 替换,仅末块动态更新
|
||||
|
||||
### 2.2 代码块无语法高亮、无复制按钮
|
||||
|
||||
**现象**:Markdown 代码块只有纯文本渲染,没有语法高亮,也没有一键复制按钮。
|
||||
|
||||
**根因**:`useMarkdown` composable 配置了 marked + DOMPurify,但没有集成 highlight.js / Prism 等高亮器。
|
||||
|
||||
**方案**:
|
||||
- 集成 highlight.js(体积小、语言全),在 marked renderer 的 `code` 回调中调用 `hljs.highlightAuto` 或按 info string 指定语言
|
||||
- 代码块右上角浮出"复制"按钮(纯前端,hover 显示)
|
||||
- 高亮器按需加载(与 marked 一样后台预热,不阻塞首屏)
|
||||
|
||||
### 2.3 历史消息无分页懒加载
|
||||
|
||||
**现象**:切换对话时 `switchConversation` 一次性加载全部 messages 到 `state.messages`。超长对话可能一次加载几百条消息。
|
||||
|
||||
**根因**:`switchConversation`(useAiConversations.ts)直接 `state.messages = rawMsgs.filter().map()`,无分页。
|
||||
|
||||
**方案**:
|
||||
- 首次加载最近 50 条,滚动到顶部时加载更多(前端 slice + 后端支持 offset/limit 查询 messages)
|
||||
- 或前端全量加载但虚拟滚动只渲染可视区域(见 7.2)
|
||||
|
||||
### 2.4 消息不显示时间戳
|
||||
|
||||
**现象**:消息气泡上不显示发送时间。用户无法判断某条消息是多久前发的。
|
||||
|
||||
**根因**:模板中 AI/用户消息都没有渲染 `msg.timestamp`。
|
||||
|
||||
**方案**:
|
||||
- 消息气泡下方或侧边以极小字号(9px)+ dim 颜色展示相对时间(`formatRelativeZh`)
|
||||
- hover 时 tooltip 展示完整时间
|
||||
|
||||
---
|
||||
|
||||
## 三、对话管理
|
||||
|
||||
### 3.1 对话搜索缺失
|
||||
|
||||
**现象**:侧栏对话列表只能滚动浏览,没有搜索框。对话多了之后找不到特定对话。
|
||||
|
||||
**根因**:侧栏 `.ai-conv-list` 直接渲染 `groupedActive`,上方只有"新建"按钮,没有搜索输入框。
|
||||
|
||||
**方案**:
|
||||
- 侧栏 header 下方增加搜索输入框(实时过滤 `state.conversations`,匹配 title)
|
||||
- 搜索时取消分组,按相关度/时间平铺展示
|
||||
- 支持 `Ctrl+K` 快捷键聚焦搜索框
|
||||
|
||||
### 3.2 对话无法置顶
|
||||
|
||||
**现象**:没有置顶或收藏功能。重要对话会被新对话挤到下面。
|
||||
|
||||
**根因**:对话列表只按 `updated_at` 排序,无 `pinned` 字段。
|
||||
|
||||
**方案**:
|
||||
- `ai_conversations` 表增加 `pinned INTEGER DEFAULT 0`
|
||||
- 排序逻辑改为 `pinned DESC, updated_at DESC`
|
||||
- 侧栏对话项 hover 显示"置顶/取消置顶"按钮(图钉图标)
|
||||
|
||||
### 3.3 对话无法导出
|
||||
|
||||
**现象**:无法将对话导出为 Markdown / JSON / 文本文件。
|
||||
|
||||
**根因**:没有导出 IPC 命令和前端入口。
|
||||
|
||||
**方案**:
|
||||
- 后端新增 `ai_conversation_export(conv_id, format)` 命令,支持 `markdown` / `json` / `txt` 三种格式
|
||||
- 前端侧栏对话项 hover 显示"导出"按钮,或对话操作菜单中提供
|
||||
- Markdown 格式:`## 用户` / `## 助手` 交替,代码块保留围栏
|
||||
|
||||
### 3.4 新建对话强制中断已有生成
|
||||
|
||||
**现象**:用户在 AI 生成中点"新建对话",后端 `ai_conversation_create` 会强制复位 `generating=false` + 置 `stop_flag`,中断当前生成。
|
||||
|
||||
**根因**:`commands.rs ai_conversation_create` 中 `if session.generating` 分支主动结束生成(B-260615-10 设计)。
|
||||
|
||||
**方案**:
|
||||
- 生成中点"新建对话"时弹 ConfirmDialog:"当前对话正在生成,确定要新建对话并中断吗?"
|
||||
- 用户确认后才执行中断+新建;取消则不操作
|
||||
- 或改为不中断:新对话仅切换视图,旧对话后台继续生成(需 AiSession 多实例化支持,属远期方案)
|
||||
|
||||
---
|
||||
|
||||
## 四、错误处理与恢复
|
||||
|
||||
### 4.1 错误气泡无操作入口
|
||||
|
||||
**现象**:错误气泡只显示一行文字(如 `[GLM-4] AI 调用失败(HTTP 401): Unauthorized`),没有"重试"按钮或"去设置"链接。
|
||||
|
||||
**根因**:`AiError` 事件只携带 `error: String`,前端 `handleEvent` push 一条 `isError: true` 的消息气泡,无操作按钮。
|
||||
|
||||
**方案**:
|
||||
- 错误气泡底部增加操作按钮区:
|
||||
- **重试**:取上一条 user 消息重新发送(调 `ai_chat_send`)
|
||||
- **去设置**(仅 401/403/Provider 未配置时显示):跳转到 Settings → AI Tab
|
||||
- 错误消息结构扩展:后端 `AiError` 增加 `error_type: Option<ErrorType>` 枚举(`auth` / `network` / `timeout` / `provider_config` / `unknown`),前端据此决定显示哪些按钮
|
||||
|
||||
### 4.2 流式中断丢失已生成文本
|
||||
|
||||
**现象**:网络波动导致流式中断(idle timeout 或 mid-stream error),已接收的文本被丢弃(`stream_llm` return None → `agentic.rs` emit AiError 并退出),用户看到错误气泡,之前生成的几百字全部丢失。
|
||||
|
||||
**根因**:`stream_llm` 遇到错误时 `return None`,不保留已接收的部分文本。`agentic.rs` 收到 None 后直接结束。
|
||||
|
||||
**方案**:
|
||||
- `stream_llm` mid-stream error 时改为返回 `Some((partial_text, tool_calls, usage))` + 一个 `incomplete: bool` 标志
|
||||
- `agentic.rs` 收到 incomplete=true 时:
|
||||
- 已有文本正常入库(标注 `truncated`)
|
||||
- emit `AiCompleted`(而非 AiError)让前端正常展示已生成内容
|
||||
- 在消息末尾追加系统提示:"⚠ 响应因网络中断不完整"
|
||||
- 前端 AI 消息气泡底部显示"继续生成"按钮(用最后一条 user 消息重新触发,后端识别不完整消息做续写或重跑)
|
||||
|
||||
---
|
||||
|
||||
## 五、技能与 Provider
|
||||
|
||||
### 5.1 Provider 切换零反馈
|
||||
|
||||
**现象**:点击 provider bar 循环切换 provider(`cycleProvider`),切换后只在 bar 上显示名字变化,没有 toast 或动画反馈。
|
||||
|
||||
**根因**:`cycleProvider` 直接调 `store.setProvider`,无 UI 反馈。
|
||||
|
||||
**方案**:
|
||||
- 切换后 toast 提示"已切换到 {providerName}"
|
||||
- provider bar 切换时加 0.15s 淡入动画
|
||||
- bar 上增加 provider 状态指示(model 名称小字展示)
|
||||
|
||||
### 5.2 技能联想不展示参数用法
|
||||
|
||||
**现象**:技能联想浮层显示 name + description + source,但不显示技能的参数格式或示例。选中后 placeholder 里的 `argument_hint` 太短。
|
||||
|
||||
**根因**:浮层设计只展示概要信息,`argument_hint` 仅在选中后作为 placeholder 显示。
|
||||
|
||||
**方案**:
|
||||
- 联想浮层每项增加一行参数提示(`argument_hint` 以等宽字体小字展示)
|
||||
- 选中技能后输入框上方 chip 展示完整的参数格式说明(而非仅 name + description)
|
||||
- 或选中技能后自动在输入框填入模板骨架(如 `/commit `),光标定位到参数位置
|
||||
|
||||
---
|
||||
|
||||
## 六、窗口与布局
|
||||
|
||||
### 6.1 侧栏宽度不可调
|
||||
|
||||
**现象**:侧栏固定 160px,不可拖拽调整宽度。长对话标题被截断。
|
||||
|
||||
**根因**:`.ai-conv-sidebar { width: 160px; min-width: 160px; }` 硬编码。
|
||||
|
||||
**方案**:
|
||||
- 侧栏右边缘增加 2px 拖拽条(`cursor: col-resize`)
|
||||
- 拖拽时实时更新 width,范围 120~280px
|
||||
- 宽度持久化到 `df-ai-ui` 设置(与 sidebarOpen/maximized 同存)
|
||||
|
||||
### 6.2 分离窗口关闭后生成态不同步
|
||||
|
||||
**现象**:分离窗口关闭时,如果正在生成,主窗口虽然 `panelOpen=true` 恢复,但 `state.streaming` / `state.currentText` 可能不同步——如果生成中的对话不是主窗口当前活跃对话,主窗口看不到生成态。
|
||||
|
||||
**根因**:分离窗口关闭走 `closeDetachedWindow`,清了 localStorage 快照,但主窗口的状态依赖事件路由自然恢复。
|
||||
|
||||
**方案**:
|
||||
- 分离窗口关闭时,主窗口检测 `state.generatingConvId` 非空,自动切换到正在生成的对话
|
||||
- 或在主窗口 header 显示"对话 X 正在生成中"提示条,点击切换过去
|
||||
|
||||
---
|
||||
|
||||
## 七、其他交互细节
|
||||
|
||||
### 7.1 无键盘快捷键
|
||||
|
||||
**现象**:除了 Enter 发送 / Shift+Enter 换行,没有其他快捷键。
|
||||
|
||||
**方案**:
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
|--------|------|
|
||||
| `Ctrl+N` | 新建对话 |
|
||||
| `Ctrl+K` | 搜索对话 |
|
||||
| `Ctrl+L` | 清空当前对话 |
|
||||
| `Ctrl+Shift+C` | 复制最后一条 AI 消息 |
|
||||
| `Ctrl+R` | 重新生成最后一条 AI 回复 |
|
||||
| `Esc` | 关闭面板(嵌入模式)/ 关闭窗口(分离模式) |
|
||||
| `Ctrl+B` | 切换侧栏 |
|
||||
|
||||
### 7.2 消息列表无虚拟滚动
|
||||
|
||||
**现象**:消息列表直接 `v-for` 渲染所有消息,长对话几百条消息全量渲染 DOM,滚动卡顿。
|
||||
|
||||
**根因**:没有使用虚拟滚动库。
|
||||
|
||||
**方案**:
|
||||
- 集成 `vue-virtual-scroller` 或自研 IntersectionObserver 懒渲染
|
||||
- 仅渲染可视区域 ±缓冲区的消息节点
|
||||
- 注意:流式渲染的最后一条消息需要始终保持挂载
|
||||
|
||||
### 7.3 空状态无引导
|
||||
|
||||
**现象**:首次打开 AI Chat(有 provider 配置),空状态只显示标题+提示语,没有示例问题或快捷操作。
|
||||
|
||||
**方案**:
|
||||
- 空状态展示 3-4 个示例问题卡片(如"帮我创建一个新项目"、"查看当前任务列表"、"分析这段代码的问题")
|
||||
- 点击卡片自动填入输入框并发送
|
||||
- 无 provider 配置时展示"去配置 AI Provider"引导按钮
|
||||
|
||||
### 7.4 对话标题生成对用户不透明
|
||||
|
||||
**现象**:对话标题由后端 `ensure_conversation_title` 异步生成,侧栏对话从"新对话"突然变成某个标题,没有过渡。
|
||||
|
||||
**方案**:
|
||||
- 标题生成后加 0.3s 淡入动画
|
||||
- 或在标题前加小图标标识"AI 自动生成"(可 hover 查看)
|
||||
|
||||
---
|
||||
|
||||
## 八、落地优先级
|
||||
|
||||
| 批次 | 痛点 | 理由 |
|
||||
|------|------|------|
|
||||
| **第一批** | 2.1 流式选中文字、1.2+1.3 消息操作栏(复制/重新生成)、4.1 错误重试、4.2 断线保文 | 每次对话都会遇到,最高频痛点 |
|
||||
| **第二批** | 2.2 代码高亮+复制、3.1 对话搜索、7.1 键盘快捷键、3.4 新建不中断生成 | 显著提升日常效率 |
|
||||
| **第三批** | 1.1 编辑重发、1.4 `@` 引用、3.3 导出、7.2 虚拟滚动、6.1 侧栏可调 | 按需推进,锦上添花 |
|
||||
| **第四批** | 2.3 分页加载、2.4 时间戳、3.2 置顶、5.1+5.2 技能/Provider 反馈、7.3+7.4 空状态/标题 | 打磨细节 |
|
||||
102
docs/02-架构设计/构想审查/aichat信息密度构想-2026-06-14.md
Normal file
102
docs/02-架构设计/构想审查/aichat信息密度构想-2026-06-14.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# 构想:AI Chat 信息密度优化 — 折叠 + 会话详情面板 — 2026-06-14
|
||||
|
||||
> 性质:功能升级构想(瞬时灵感),未实现。记录作为后期优化参考。
|
||||
|
||||
## 背景
|
||||
|
||||
提高 AI chat 对话区有用信息密度。当前长回复/代码块/历史轮次全展开,信息密度低,关键内容被淹没。两个构想:① 卡片与消息折叠策略;② 会话详情面板组件。
|
||||
|
||||
---
|
||||
|
||||
## 构想一:卡片与消息折叠
|
||||
|
||||
### 当前折叠现状(2026-06-14 探索)
|
||||
|
||||
**已有折叠**:
|
||||
- 工具卡片:卡片级折叠(`ToolCardList.vue` expandedCards)+ read_file 内容级折叠(expandedTools,max-height 180px + 渐隐)+ list_directory max-height 220px + 通用 result max-height 100px。
|
||||
- `shouldKeepOpen`:running/pending_approval/rejected/write_file 保持展开。
|
||||
- auto-collapse(`AiChat.vue:639-667` watch):新内容追加时收起旧已完成/已拒绝卡。
|
||||
- 侧栏归档分组可折叠。
|
||||
|
||||
**未折叠(可优化)**:
|
||||
- AI 消息正文:template `AiChat.vue:191-198` `v-html` 全展开,长 markdown 无截断。
|
||||
- 代码块:markdown `pre code` 无折叠(`:1103-1118` 仅样式)。
|
||||
- 用户消息:`ai-msg-bubble--user` 全展开(`:1058`)。
|
||||
- 同消息多 toolCall:逐卡渲染,无聚合。
|
||||
- 历史 agent 轮次:每轮独立气泡全展开,无折叠。
|
||||
|
||||
### 可折叠优化点
|
||||
|
||||
| 对象 | 当前 | 折叠策略建议 |
|
||||
|------|------|-------------|
|
||||
| AI 消息正文 | 全展开 | >N 行(如 15)截断 + 渐隐 + "展开"(复用 read_file 卡的 max-height + ::after 模式);折叠态显示首行摘要 |
|
||||
| 代码块 | 全展开 | >20 行折叠,显示"展开 N 行";默认显示首尾几行 |
|
||||
| 用户消息 | 全展开 | >5 行折叠为摘要 + "展开" |
|
||||
| 同消息多 toolCall | 逐卡 | ≥3 个聚合成"完成 N 个工具调用 [展开]",展开后逐卡(已有 auto-collapse 配合) |
|
||||
| 历史 agent 轮次 | 每轮全展开 | 非最新轮折叠为单行(轮次标识 + 文本摘要 + 工具数),点击展开 |
|
||||
| 错误消息 | 各自气泡 | 连续多条错误可堆叠折叠 |
|
||||
|
||||
### 设计原则
|
||||
- 折叠态必须有**摘要**(避免光秃秃):AI 消息取首行/工具卡已有 `toolResultSummary`。
|
||||
- 最新/活跃内容默认展开,历史默认折叠(与现有 auto-collapse 一致)。
|
||||
- 流式生成中不折叠(避免重渲染抖动,与 H1 流式重解析问题联动)。
|
||||
- 折叠状态可记忆(同会话内持久,刷新重置)。
|
||||
|
||||
---
|
||||
|
||||
## 构想二:会话详情面板
|
||||
|
||||
> 在 AI Chat 对话面板增加"会话详情"功能组件,聚合展示当前会话的全维度信息。
|
||||
|
||||
### 功能建议
|
||||
|
||||
**1. 当前会话整体信息**
|
||||
- 标题 / provider / model / conversation_id
|
||||
- token 总量(prompt + completion,来自 conversation 表累加字段)
|
||||
- 消息数 / 工具调用数 / 审批数(通过/拒绝/待审)
|
||||
- 创建时间 / 更新时间 / 持续时长
|
||||
|
||||
**2. 历史整体对话**
|
||||
- 侧栏已有对话列表;详情面板补:搜索(标题/内容)、按时间/provider/状态筛选、批量归档/删除、导出(Markdown/JSON)。
|
||||
|
||||
**3. 审计类能力**
|
||||
- 工具执行时间线(来自 `ai_tool_executions` 表:tool_name / arguments / result / status / risk_level / requested_at / executed_at / decided_by)。
|
||||
- 风险分布(Low/Medium/High 统计)、审批通过率。
|
||||
- token 消耗趋势(按轮次/按时间)。
|
||||
- 决策记录跳转(若有 DecisionJournal 关联)。
|
||||
|
||||
**4. 快捷获取某类信息**
|
||||
- 按工具类型筛选(只看 read_file / 只看 create_project)。
|
||||
- 按风险/状态筛选(只看待审批)。
|
||||
- 关键词搜消息全文。
|
||||
- 时间范围筛选。
|
||||
|
||||
### 后端数据支撑(已有,无需新建)
|
||||
|
||||
| 数据 | 来源 |
|
||||
|------|------|
|
||||
| 对话元信息 + token | `conversations` 表(title/model/provider_id/prompt_tokens/completion_tokens/messages),`conversation.rs` 累加 |
|
||||
| 工具执行审计 | `ai_tool_executions` 表,`audit.rs` 写入 + `list_pending` / `find_by_tool_call_id` 查询 |
|
||||
| 消息全文 | `ai_conversation_detail` IPC(已返回 messages JSON) |
|
||||
|
||||
**待补 IPC**:工具执行按 conversation 聚合查询(现有 list_pending / find_by_tool_call_id,需加 by_conversation 全量时间线);token 趋势(按轮次拆分,当前只存总量)。
|
||||
|
||||
### 组件设想
|
||||
- 入口:header 加"详情"按钮,或对话项右键菜单。
|
||||
- 形态:侧滑面板(drawer,不离开对话)/ modal / 独立路由(/ai-detail/:id)。
|
||||
- 结构:Tab 分「概览 / 审计时间线 / 消息检索」。
|
||||
|
||||
---
|
||||
|
||||
## 评估
|
||||
|
||||
| 构想 | 复杂度 | 依赖 | 建议 |
|
||||
|------|--------|------|------|
|
||||
| 折叠策略 | 中 | 纯前端,复用现有 max-height 模式 | 优先做 AI 消息正文 + 代码块折叠,收益最大 |
|
||||
| 会话详情面板 | 中高 | 前端新组件 + 后端补聚合 IPC | 审计时间线最有价值(数据已在),先做概览 + 审计两 tab |
|
||||
|
||||
两者都与信息密度相关:折叠压缩单条信息,详情面板聚合全局信息。可并行推进。
|
||||
|
||||
## 关联
|
||||
- 折叠与 [[devflow-aichat-review-pending]] H1(流式重解析)联动——流式中不折叠,完成后折叠。
|
||||
- 会话详情审计能力复用 audit.rs 已有审计表。
|
||||
299
docs/02-架构设计/构想审查/aichat审查报告-2026-06-14.md
Normal file
299
docs/02-架构设计/构想审查/aichat审查报告-2026-06-14.md
Normal file
@@ -0,0 +1,299 @@
|
||||
# aichat 审查报告 — 2026-06-14
|
||||
|
||||
> 性质:只审查不改代码。本报告汇总本次会话对 devflow AI chat 全链路的核对发现。
|
||||
> 增补:2026-06-14 追加「修复进度」表(AC1/AC2、AR-3、FR-S4、FR-R4、FR-R5 对照 commit 36d68dd / 4b5f096 标已完成),并在 §8 优先级表 AR-3 行内联标注。
|
||||
> 二次增补:2026-06-15 §8 优先级表全表对齐 todo.md AR 编号体系,逐行补 AR-1~AR-11 标签 + 状态勾注(AR-1 退役 / AR-2~7/9~11 已修 / AR-8 重评降级)。
|
||||
|
||||
## 审查范围
|
||||
|
||||
- **前端**:`src/components/AiChat.vue` + `src/composables/ai/*.ts`(events/stream/send/conversations/window/panel 六个)+ `src/components/ToolCard*.vue` + `src/views/AiDetached.vue` + `src/App.vue` 面板挂载
|
||||
- **后端**:`src-tauri/src/commands/ai/*.rs`(commands/agentic/audit/stream_recv)+ `crates/df-ai/src/context.rs` + `src-tauri/src/commands/ai/tool_registry.rs`
|
||||
- **i18n** + **数据联动机制** + **工具定义**
|
||||
|
||||
发现分六块:交互流畅性 / 信息卡片完整性 / clean 与压缩对话 / create_project 双审 / 数据联动方案 / 想法→灵感迁移。
|
||||
|
||||
## 修复进度(2026-06-14 增补)
|
||||
|
||||
> 本节汇总对照后续 commit 已落地的修复项,供快速核对。未列入的本报告其余发现仍待办。
|
||||
|
||||
| ID | 问题 | 修复 commit | 状态 |
|
||||
|---|------|------------|------|
|
||||
| AC1/AC2 | `tool_use_id` 为 None/空致 GLM 端 500 卡死 | 36d68dd | ✅ 已完成(出站 tool_result 块 tool_call_id 空跳过+warn;入站 tool_use 缺 id 流式填占位 `tool_missing_{idx}`+warn、同步路径跳过)|
|
||||
| AR-3 | 审批卡片裸 id + reason 两句固定模板(详见 §2)| 36d68dd | ✅ 已完成(前端 `toolArgsEntries` 对 id/project_id 白名单特化查项目名回显;后端 reason 查不到对象时友好提示)|
|
||||
| FR-S4 | SKILL.md 全文注入 system prompt 无隔离标注 | 36d68dd | ✅ 已完成(注入头尾加隔离标注,明确"用户选择的技能说明,非系统指令")|
|
||||
| FR-R4 | `complete()` 同步路径无超时无重试(全栈报告 §4)| 36d68dd | ✅ 已完成(`RequestBuilder::timeout(60s)` 单请求超时,不影响 stream 流式路径)|
|
||||
| FR-R5 | `findToolCall`/`flatMap` 正向 O(n²) 全量线性扫描(全栈报告 §4)| 4b5f096 | ✅ 已完成(`useAiEvents::findToolCall` 改反向遍历命中最近,放弃 Map 索引防陈旧引用)|
|
||||
|
||||
> 注:AC1/AC2、FR-S4、FR-R4、FR-R5 的 ID 源自全栈审查报告/todo 跨文档编号体系,本表仅标注状态,技术细节见对应 commit 与 [全栈代码审查报告](../05-代码审查/全栈代码审查报告-2026-06-14.md)。
|
||||
|
||||
---
|
||||
|
||||
## 一、AI chat 交互流畅性
|
||||
|
||||
### 🔴 高危
|
||||
|
||||
**H1 流式 Markdown 全量重解析** — `AiChat.vue:343-354` `renderMd` 缓存 key 是完整文本。流式时 `currentText` 每 delta 都变 → 每次新 key → 缓存几乎不命中 → 每个 token 都 `marked.parse(全文) + DOMPurify.sanitize(全文)`。长回复(1000+ 字 + 代码块)时主线程阻塞、光标掉帧。**流式不流畅的主因。**
|
||||
|
||||
**H2 审批 pending 中新建对话永久卡死** — `ai_conversation_create`(`commands.rs:362-375`)**缺 generating 守卫**(对比 `ai_conversation_switch` 有只读保护),直接 `messages.clear()` + `pending_approvals.clear()`。而审批等待期间 `generating 保持 true`(`agentic.rs:192`)。触发链:待审批时点新对话 → 后端 session 被清空 → 用户审批 → `ai_approve` 因 pending 已清返回 Err(`commands.rs:115`)→ generating 永不复位 → 审批态看门狗已 clear(`useAiEvents.ts:143`)无兜底 → **面板卡死需重启**。
|
||||
|
||||
**H3 审批态 stop 无本地兜底** — `stopChat`(`useAiSend.ts:111-113`)只 `await aiApi.stopChat()`,不改 `state.streaming`,依赖后端 `AiCompleted`。审批态 stop 后端确实 emit(`commands.rs:241`),但审批态看门狗已 clear(`useAiEvents.ts:143`),若 `AiCompleted` 竞态丢失 → streaming 永久 true 无兜底 → 卡死。
|
||||
|
||||
### 🟡 中危
|
||||
|
||||
**M1 流式 delta 无节流** — `stream_recv.rs` 逐 chunk `app.emit(AiTextDelta)`,前端同步 `state.currentText += delta`。每 delta:IPC 序列化 + Vue reactive + renderMd 全量解析(叠加 H1)+ scrollToBottom。后端无 50ms 合批,前端无 rAF/throttle。
|
||||
|
||||
**M2 scrollToBottom 高频强制滚** — `AiChat.vue:625-633` watch `currentText` → `onContentChange` → 在底部则 `nextTick(scrollToBottom)`。每 delta 强制 `scrollTop = scrollHeight`,大 DOM 重排掉帧。
|
||||
|
||||
**M3 Low 工具失败语义冲突** — `audit.rs` Low 工具失败 emit `AiError`,但 `process_tool_calls` 返回 `pending_count=0`,`agentic.rs:195` 续下一轮。前端收 AiError 置 streaming=false + 错误气泡,后端 loop 仍跑,后续 delta 继续追加(handleEvent delta 分支不检查 streaming),最终 AiCompleted 又 flushCurrentText 写残留文本 → 一次错误又"完成",状态紊乱。
|
||||
|
||||
**M4 friendlyError 硬编码中文** — `useAiEvents.ts:42-48` 错误提示硬编码中文,绕过 i18n。看门狗超时文案(`useAiStream.ts:29`)同样。en 用户看到中文。
|
||||
|
||||
**M5 分离窗口与主窗口 state 完全隔离** — 独立 webview → 独立 JS realm → 独立 `state` 单例。localStorage 只快照生成态初始文本,不解决双向同步。detach 后两窗口 messages/conversations 各自独立,一边操作另一边看不到。
|
||||
|
||||
**M6 AiChat 卸载不调 stopListener** — `AiChat.vue` 无 `onUnmounted`。面板 v-if 开关销毁重建 AiChat,但 `stopListener`(`useAiEvents.ts:240`)从不调用,Tauri listener 累积泄漏(幂等防住重复注册,但旧 listener 不释放)。
|
||||
|
||||
### 🟢 低危
|
||||
|
||||
**L1 队列续发失败丢消息** — `useAiSend.ts:25-29` `drainQueue` 先 `queue.shift()` 再 `void sendMessage`,IPC 失败时 catch 回滚 streaming + 移除空气泡,但消息已 shift 丢失无回滚入队。理论竞态,正常路径(AiCompleted 时后端 generating 已 false)不撞。
|
||||
|
||||
**L2 生成中切 provider 无守卫** — `AiChat.vue:458-464` `cycleProvider` 生成中可切,当前回复仍用旧 provider(spawn 快照),provider bar 立即显示新名 → 用户误判。
|
||||
|
||||
**L3 handleKeydown Escape 分支冗余** — `AiChat.vue:532-536` 与 `:554-558` 两处 Escape 判断,逻辑可工作但分叉冗余。
|
||||
|
||||
**L4 selectSkill/clearSkill 未 autoResize** — `:409-419` 清空 inputText 不调 autoResize,textarea 可能残留高度。
|
||||
|
||||
**L5 deep watch + JSON.stringify 快照** — `AiChat.vue:639-667` watch messages(deep)每次 `JSON.stringify` 整数组。流式 delta 不触发,工具密集轮次时开销可见。
|
||||
|
||||
---
|
||||
|
||||
## 二、信息卡片完整性(审批/工具卡片)
|
||||
|
||||
> 用户反馈:"只有 1 个 ID,根本不知道审批要做什么"。核对所有 Medium/High 审批工具。
|
||||
|
||||
### 三层缺陷
|
||||
|
||||
**缺陷 1 — 审批 reason 两句固定模板**(`audit.rs:179-182`):
|
||||
```rust
|
||||
let reason = match risk_level {
|
||||
RiskLevel::High => "高风险操作,必须人工批准".to_string(),
|
||||
_ => "创建操作,请确认是否执行".to_string(),
|
||||
};
|
||||
```
|
||||
所有 High 文案相同,所有 Medium 文案相同,**不含操作对象**。
|
||||
|
||||
**缺陷 2 — id/project_id 原样展示**(`ToolCard.vue:149-169` `toolArgsEntries` + `formatArgValue`):字符串直接展示(截断 300),`id`/`project_id` 以裸值出现。
|
||||
|
||||
**缺陷 3 — 完成态 resultSummary 缺 delete/restore/purge 分支**(`ToolCard.vue:272-288`):这三类完成后只显示 header + 裸 JSON `{"deleted":true,"id":"..."}`。
|
||||
|
||||
### 逐工具核对表
|
||||
|
||||
| 工具 | 风险 | args | 裸 id | 审批卡片可见性 |
|
||||
|------|------|------|-------|--------------|
|
||||
| **delete_project** | High | `id` | id | 🔴 "Delete Project" + `id=proj_xxx` + 模板 reason,完全不知删哪个 |
|
||||
| **restore_project** | High | `id` | id | 🔴 同上 |
|
||||
| **purge_project** | High | `id` | id | 🔴 永久删除却不知删啥 |
|
||||
| update_project | Med | `id, field, value` | id | 🟡 改什么可读,对象不可读 |
|
||||
| bind_directory | Med | `id, path` | id | 🟡 path 可读,哪个项目不可读(用户实测反馈) |
|
||||
| create_task | Med | `project_id, title, ...` | project_id | 🟡 title 可读,归哪个项目不可读 |
|
||||
| create_project | Med | `name, description` | 无 | ✅ |
|
||||
| create_idea | Med | `title, ...` | 无 | ✅ |
|
||||
| write_file | Med | `path, content` | 无 | ✅ |
|
||||
| run_workflow | High | `name, dag` | 无 | 🟡 name 可读,dag 庞大 |
|
||||
|
||||
**9 个审批工具:3 个完全不可用,3 个对象不可读,仅 3 个完整。**
|
||||
|
||||
### 修复方向
|
||||
- P0 后端 emit `AiApprovalRequired` 前按工具查对象名拼 reason(如"删除项目「前端重构」(id=xxx),移入回收站")。
|
||||
- P0 前端 `toolArgsEntries` 对 id/project_id 特化(查 store 或后端 args 补 `__label`)。
|
||||
- P1 `toolResultSummary` 补 delete/restore/purge case。
|
||||
- P1 `toolDisplayName` CRUD 类从 args 取 name/title 拼上。
|
||||
|
||||
---
|
||||
|
||||
## 三、clean(清空对话)与压缩对话
|
||||
|
||||
### clean — ❌ 具备但不可用
|
||||
|
||||
| 维度 | 状态 |
|
||||
|------|------|
|
||||
| 后端 `ai_chat_clear` | ✅ `commands.rs:215-220` |
|
||||
| 前端 `clearChat` | ✅ `useAiPanel.ts:89-96` |
|
||||
| **UI 入口** | ❌ 零组件调用(grep clearChat 仅命中 api/composable/store,AiChat.vue 无按钮) |
|
||||
| 语义 | ❌ 只清内存 session 不删 DB,刷新恢复 |
|
||||
|
||||
### 压缩对话 — ❌ 不具备
|
||||
|
||||
- 无显式压缩/总结功能(grep compress/compact/summarize 仅命中 context.rs 的"裁剪")。
|
||||
- 无 `/compact` 命令、无压缩技能、无对话总结。
|
||||
- 唯一相关:`ContextManager.build_for_request`(`context.rs:215-264`)预算感知裁剪——超 token 预算(默认 128k,0.85 安全 → budget ≈102k)自动丢弃旧消息,保留工具三元组原子性 + 最近 6 条(保护区)。
|
||||
- 裁剪机制本身良好(三元组原子、视图不污染持久化、有测试),但**是滑动窗口丢弃非摘要压缩**,且 128k 窗口日常难触发。
|
||||
|
||||
---
|
||||
|
||||
## 四、create_project 双审双 API(用户实测痛点)— ⚠️ 半成品(2026-06-14 核对)
|
||||
|
||||
### 现状:已改一半
|
||||
- ✅ schema 已加 `path`/`stack`(`tool_registry.rs:148-151`),描述已改"可选传 path/stack 一步完成"(`:147`)
|
||||
- ❌ **handler 仍写死 `path: None, stack: None`(`:162`),未读 args** → schema 假支持
|
||||
|
||||
### 后果
|
||||
LLM 见 schema 有 path 会传,handler 忽略 → 建出空项目 → 仍需 `bind_directory` 二审。**双审未解,反变误导**(schema 承诺了 handler 不兑现)。比原始"schema 无 path"更糟。
|
||||
|
||||
### 待改(别再加 schema,已加完)
|
||||
handler 从 args 读 `path`/`stack`,复用 IPC `create_project`(`project.rs:43-83`)的校验+防重复+`scan::detect_stack` 探测逻辑。`bind_directory` 保留改绑用。
|
||||
|
||||
### 关联
|
||||
handler 接上后 `bind_directory` 使用频率大降(只剩改绑),第二章 bind_directory 信息缺口随之缓解;但 bind_directory 仍需补信息完整性。
|
||||
|
||||
---
|
||||
|
||||
## 五、数据变更联动刷新方案
|
||||
|
||||
> 需求:AI chat 工具执行产生数据变更 → 左侧已打开视图(Projects/Tasks/Ideas/Dashboard)自动刷新。
|
||||
|
||||
### 现状缺口
|
||||
- `useProjectStore` 单例持 projects/tasks/ideas,各 view onMounted 调 loadXxx(Ideas.vue:444 / ProjectDetail.vue:412 / Dashboard.vue:212)。
|
||||
- **无应用级事件总线**(grep mitt/EventBus 零匹配)。
|
||||
- AI 工具执行 emit `AiToolCallCompleted`,前端**只更新 ToolCard,不通知 project store** → 视图不刷新。
|
||||
|
||||
### 方案对比
|
||||
|
||||
| 方案 | 机制 | 优 | 缺 |
|
||||
|------|------|----|----|
|
||||
| **A 后端 emit 数据变更事件(推荐)** | 工具成功后 emit `df-data-changed {entity,action,id?}`,各 store 监听刷新 | 后端是真相源埋点准;store 自治解耦;可扩展到手动 CRUD | 需后端埋点 |
|
||||
| B 前端据 `AiToolCallCompleted.name` 推断 | handleEvent 映射 entity 调 loadXxx | 零后端改动 | ai composable 耦合 project store;ai_approve 路径不走 AiToolCallCompleted 会漏 |
|
||||
| C store watch AI 状态 | project store watch ai.lastToolCall | — | 跨 store 耦合最重 |
|
||||
|
||||
### 推荐方案 A 要点
|
||||
- **后端埋点**:`audit.rs:206-214`(Low 执行成功)+ `commands.rs:148-184`(ai_approve 成功),按 tool name 映射 entity,emit `df-data-changed`。失败不 emit;run_workflow 不改实体表不 emit。
|
||||
- **tool→entity 映射**:create/update/delete/restore/purge/bind_directory=project;create task=task;create/update idea=idea。
|
||||
- **前端监听**:`useProjectStore` 创建时 listen,debounce + rAF 合并(一轮多 tool 只刷一次),加 loaded 标志仅刷新已加载实体。
|
||||
- 分离窗口独立 realm 各自 listen 各自刷新(天然支持)。
|
||||
- **未拍板**:A vs B;是否扩展到手动 CRUD 全局实时同步。
|
||||
|
||||
---
|
||||
|
||||
## 六、「想法→灵感」中文文案迁移残留
|
||||
|
||||
> 产品决定"想法"改称"灵感",迁移半途。
|
||||
|
||||
### 用户可见(必改)
|
||||
- `src/i18n/zh-CN/ideas.ts:18/42/65/68/71/75` — 详情/操作/模态框 6 处(页头已改灵感,这些漏改)
|
||||
- `src/i18n/zh-CN/aiTool.ts:24` — `ideaCount: '{n} 条想法'`(AI 工具结果摘要)
|
||||
- `src/i18n/zh-CN/projectDetail.ts:9/24/25/26` — 阶段标签/来源想法
|
||||
- `src/stores/project.ts:150/160` — 错误 toast
|
||||
|
||||
### 后端用户可见
|
||||
- `src-tauri/src/commands/idea.rs:105/108/148/152/179` — 错误信息(toast)
|
||||
- `src-tauri/src/commands/ai/tool_registry.rs:112/230` — LLM 工具描述(AI 回复会用"想法")
|
||||
|
||||
### en 版
|
||||
用 Ideas/Idea(英文术语),若产品要求统一 Inspiration 也需改,待定。
|
||||
|
||||
### docs + crates 注释
|
||||
大量"想法"(低优先),含文件名 `docs/03-模块文档/想法探索-对抗式评估-2026-06-12.md`。
|
||||
|
||||
### 根因
|
||||
上次迁移只改 ideas.ts 页头区,详情/操作/模态框 + 其他 i18n + 后端错误 + LLM 工具描述未跟进。
|
||||
|
||||
---
|
||||
|
||||
## 七、设计亮点(明确无问题)
|
||||
|
||||
| 机制 | 评价 |
|
||||
|------|------|
|
||||
| 流式看门狗(`useAiStream.ts`) | 无数据超时兜底,130s > 后端 120s 留余量 |
|
||||
| generating 复位先于 emit(`agentic.rs:74/170/228`) | 保证前端收 AiCompleted 时后端已可接下条 |
|
||||
| 错误路径 AiError 覆盖全 | idle/流中断/chunk error/provider 失败,无静默失败 |
|
||||
| 工具卡片折叠自治 + auto-collapse | shouldKeepOpen 保留 running/pending/rejected/write_file |
|
||||
| 审批乐观更新 + IPC 失败不回滚 | `useAiSend.ts:80-98` 防按钮卡死 |
|
||||
| Markdown 懒加载 + 历史消息缓存 | 首屏不阻塞,已完成消息命中缓存 |
|
||||
| 回到底部智能判断 | isNearBottom 避免上滑被打断 |
|
||||
| ContextManager 裁剪 | 三元组原子、视图不污染持久化、测试覆盖 |
|
||||
|
||||
---
|
||||
|
||||
## 八、修复优先级
|
||||
|
||||
| 优先 | 问题 | 方向 |
|
||||
|------|------|------|
|
||||
| P0 | H1 流式 Markdown 重解析 ✅ **退役**(AR-1,2026-06-15)— 自研块级 memo 取代(splitBlocks O(末块)+rAF 节流),详见 [流式渲染调研 §5](./aichat流式Markdown渲染调研-2026-06-15.md) | 流式态纯文本/增量渲染,完成后再 markdown;rAF 合并 |
|
||||
| P0 | H2 审批态新建对话卡死 ✅ **已修**(AR-2,commit 057a212) | `ai_conversation_create` 加 generating 守卫 |
|
||||
| P0 | 第二章 审批卡片裸 id + reason 模板 ✅ **已修**(AR-3,commit 36d68dd)| 后端 reason 拼对象名;前端 id→name |
|
||||
| P0 | 第四章 create_project 双审 ✅ **已修**(AR-4,commit 057a212)— schema 加 path/stack + handler 合并绑定 | handler 读 args 的 path/stack,复用 IPC `project.rs:43-83` 探测逻辑 |
|
||||
| P1 | H3 审批态 stop 无兜底 ✅ **已修**(AR-5,commit 9e2aeff)— stopChat 本地先复位 streaming + clearStreamWatchdog | stopChat 本地先复位 streaming |
|
||||
| P1 | M3 Low 工具失败语义 ✅ **已修**(AR-6,commit f82dd8b)— Low 失败非 AiError,错误回填 tool_result 让 LLM 自处理 | 统一 AiError 后 loop 也退出,或不 emit AiError |
|
||||
| P1 | 第三章 clean 无入口 ✅ **已修**(AR-7,commit 9e2aeff)— clear_messages 真删 + 垃桶按钮二次确认 | AiChat 加清空按钮 + 后端真删当前对话消息 |
|
||||
| P2 | M1+M2 delta 节流 + 滚动 🔄 **重评降级**(AR-8,2026-06-15)— 前端 rAF 节流已被 ARC-08 覆盖;剩后端 50ms 合批 + 滚动跟随 | 后端 50ms 合批 / 前端 rAF |
|
||||
| P2 | M4 friendlyError i18n ✅ **已修**(AR-9,commit 9e2aeff)— 全走 i18n.global.t + zh/en 双语补 key | 抽 i18n key |
|
||||
| P2 | 第六章 灵感迁移残留 ✅ **已修**(AR-10,commit 65c475b)— 13 文件批量统一 | i18n + 后端错误 + LLM 描述统一改 |
|
||||
| P2 | 第五章 数据联动 ✅ **已修**(AR-11,commit dc27e79)— 方案 A 后端 emit `df-data-changed` + store listen 已 attach | 方案 A 后端 emit + store 监听 |
|
||||
|
||||
---
|
||||
|
||||
## 九、write_file 覆盖事故与可靠性风险(2026-06-14 实测)
|
||||
|
||||
### 事故经过
|
||||
|
||||
会话 `3473fcb7`(2026-06-14 22:16)AI 拟对 `PROGRESS.md` 做 3 处精准更新(头部当前阶段、全局问题 #9 状态、新增 #10),但**误用 `write_file`(全文覆盖语义)只传了头部 3 行 content**,把原 **762行/72KB** 覆盖成 **248字节**。AI 自查发现(msg[59-61])尝试凭记忆重建恢复(write_file 17956 字符),**但该恢复写入未生效**(会话中断),用户无感知「恢复失败」。
|
||||
|
||||
### 暴露的潜在问题
|
||||
|
||||
| # | 问题 | 性质 | 修法方向 |
|
||||
|---|------|------|----------|
|
||||
| FR-S7 | write_file 覆盖已有非空文件无确认/备份 | **根因** | 覆盖非空文件前自动备份 `.bak`;或检测目标存在强制走 edit_file |
|
||||
| 关联-1 | 写入后无「预期 vs 实际」校验 | 可靠性 | write_file 返回新旧大小,差异巨大(如原 72KB→新 248B)时 warn/阻断 |
|
||||
| 关联-2 | AI 自恢复失败无感知 | agent 可靠性 | 工具失败/中断需明确通知用户,不静默吞掉 |
|
||||
| 备份 | DB 50KB 截断致无法从 DB 完整恢复 | 备份策略 | 长文档丢失仅 git 可救;考虑关键文件写前 git 快照 |
|
||||
|
||||
### 恢复方式与教训
|
||||
|
||||
DB 中 PROGRESS.md 原文已被 `TRUNCATE_THRESHOLD=50KB`(`conversation.rs:55`)截断(头尾拼接、中段省略),AI 重建版仅 17.9KB 残缺。**最终靠 `git restore PROGRESS.md`(HEAD 版本 762行/72KB 完整)恢复**。教训:本地文档类资产的实际保护层是 **git** 而非 DB 会话历史——会话历史是「对话快照」非「文件备份」。
|
||||
|
||||
### 关联待办
|
||||
|
||||
- `todo.md` FR-S7(write_file 覆盖保护)— P0 安全
|
||||
|
||||
---
|
||||
|
||||
## 十、文件工具系统性走查(2026-06-14,3-agent review 之外的补充走查)
|
||||
|
||||
`tool_registry.rs` 实际注册 **3 个文件工具**:`read_file`(:394) / `list_directory`(:428) / `write_file`(:444)。其余 edit_file/delete_file/rename_file/move_file/search_content/append_file **均未实现**——功能缺口,迫使 LLM 滥用 write_file 全量覆写,**放大 FR-S7 危害**。
|
||||
|
||||
### P0 — 阻断
|
||||
|
||||
| # | 问题 | 位置 | 修法方向 |
|
||||
|---|------|------|----------|
|
||||
| **FR-S8** | **路径 sandbox 系统性逃逸**:①`validate_path` 子串 `..` 检测对**绝对路径无效**(`C:\Windows\...` 不含 `..` 绕过);②canonicalize 仅对**已存在路径**跑,write_file 新建文件 + symlink 父目录场景失效;③Windows `Path::starts_with` 大小写敏感而文件系统不敏感,可误判/漏判 | :19-21, :53-69 | 统一 canonicalize(不存在路径取最长存在前缀)+ 大小写不敏感 prefix 比较 + parent 也校验 |
|
||||
| FR-S7(放大) | write_file 定级 Medium 可自动批准 + 非原子覆写,覆写任意已存在非空文件即数据丢失(见 §9) | :446, :461 | 覆写非空文件升 High 审批 + `.bak` 备份 + 原子写(tmp→rename) |
|
||||
|
||||
### P1 — 重要
|
||||
|
||||
| # | 问题 | 位置 |
|
||||
|---|------|------|
|
||||
| P1-1 | write_file 非原子写:中途崩溃留半截文件丢原内容(叠加 FR-S7 数据彻底丢失) | :461 |
|
||||
| P1-2 | write_file `create_dir_all(parent)` 不校验 parent,workspace 内 symlink 父目录可写逃逸 | :457-460 |
|
||||
| P1-3 | read_file 1MB 按**字节** + `read_to_string` 对非 UTF-8/二进制直接失败无降级 | :409, :413 |
|
||||
| P1-4 | read_file offset 无上限校验(超范围静默返空),limit 无硬上限 | :415-419 |
|
||||
| P1-5 | list_directory 噪音目录仍作为 entry 返回(仅不深入),max_depth=2 写死无文档 | :437, :439, :500 |
|
||||
| P1-6 | list_directory `DirEntry::metadata()` **跟随 symlink**,symlink 目录被当普通目录递归(信息泄露 + 与 P1-2/FR-S8 形成逃逸组合拳) | :491-492 |
|
||||
| P1-7 | `validate_path` 黑名单**子串匹配**:易误伤(`appdata-collector` 项目)易绕过(漏 `.config`/`.kube`/Program Files),冗余弱层 | :22-29 |
|
||||
|
||||
### P2 — 次要
|
||||
|
||||
list_directory 子目录无权限读整层 bail(:484)/ read_file 错误回显完整绝对路径泄露(:406)/ write_file bytes_written 字节非字符易误导(:463)/ max_entries off-by-one(:486)/ to_str 非 UTF-8 路径笼统报错(:401)/ 未实现工具缺口(edit/delete/rename/move/search/append 迫使滥用 write_file)。
|
||||
|
||||
### 总结
|
||||
|
||||
框架方向正确(schema+risk+handler 同源、双层校验、FR-S2 TOCTOU+1MB 已修),但 **sandbox 实现层有系统性缺口**:子串黑名单(弱)+ 词法 starts_with(Windows 大小写坑)+ canonicalize 只覆盖存在路径(新建漏)。优先级:**FR-S8 统一 canonicalize > P1-6/P1-2 symlink 不跟随 > FR-S7 原子写+升审批**。
|
||||
|
||||
关联 todo:FR-S7(覆盖保护)、FR-S8(sandbox 逃逸)。
|
||||
|
||||
---
|
||||
|
||||
## 附:相关 memory(指针)
|
||||
- `devflow-aichat-review-pending.md`
|
||||
- `devflow-idea-inspiration-migration.md`
|
||||
- `devflow-data-change-sync.md`
|
||||
|
||||
三者在 memory 中仅留指针,详情以本报告为准。
|
||||
64
docs/02-架构设计/构想审查/aichat异步审批构想-2026-06-14.md
Normal file
64
docs/02-架构设计/构想审查/aichat异步审批构想-2026-06-14.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# 构想:对话 AI 异步审批 — 2026-06-14
|
||||
|
||||
> 性质:功能升级构想,未实现。记录用户提出的方向 + 可行性评估。
|
||||
|
||||
## 构想
|
||||
|
||||
对话 AI 的对话与审批改成**异步审批**:审批 pending 时不卡住整个对话,用户可继续聊别的,审批挂着随时处理。
|
||||
|
||||
## 痛点:当前同步审批卡住对话
|
||||
|
||||
当前审批是同步阻塞模型:
|
||||
|
||||
1. LLM 返回 Medium/High `tool_calls` → `process_tool_calls`(`audit.rs:170-191`)推 `pending_approvals` + 占位 `tool_result`("需要用户审批,等待确认")→ agentic loop `return`(`agentic.rs:184-192`),**`generating` 保持 true**。
|
||||
2. 等待期间:`session.generating = true` → 新 `ai_chat_send` 直接 `Err("AI 正在生成中")`(`commands.rs:45`)→ 前端 `sendMessage` 把新消息入队(`useAiSend.ts:36`),`streaming = true` 输入框变停止按钮。
|
||||
3. 用户必须先审批(或 stop)才能继续对话。**整个对话被审批阻塞。**
|
||||
|
||||
典型困扰:AI 提出待审批操作,用户想先问个别的(比如"等等,这个项目之前是不是建过?"),被阻塞,必须先处理审批。
|
||||
|
||||
## 难点分析
|
||||
|
||||
异步审批的真正难点不在 UI,而在 **agent loop 的语义**:
|
||||
|
||||
- 同步模型:LLM 发 tool_call → 占位 tool_result → loop 挂起 → 审批后 tool_result 替换为真实结果 → LLM 据真实结果生成下一步。上下文连贯。
|
||||
- 异步模型:若审批 pending 时对话继续,LLM 已基于"占位结果"生成后续 → 审批结果回流时上下文已前进 → 不一致。
|
||||
|
||||
核心瓶颈是 `AiSession` 单例 + `generating` 单标志互斥(防并发混乱)。异步审批 + 并发对话需要 AiSession 多实例化或 sub-session——正是 [[aichat-arch-extensibility]] 记录的"剩四空壳/AiSession 单例未动"部分,属 B 路线。
|
||||
|
||||
## 方案分两档
|
||||
|
||||
### 档位一:轻量 — 跨对话异步(推荐先做)
|
||||
|
||||
审批 pending 的对话挂起(释放 generating 锁),用户**切到别的对话**继续聊,审批在原对话挂着,通过后结果回流原对话。
|
||||
|
||||
- 触及:AiSession 从单例 → 多对话独立状态(每对话一个活跃 loop 槽)。
|
||||
- 不触及:同对话内 agent loop 语义不变(同对话内审批仍阻塞)。
|
||||
- 复杂度:中等,是 B 路线(AiSession 多实例化)的一部分。
|
||||
- 价值:解决"审批时想干别的"主诉求(切对话即可),不破坏 agent 语义。
|
||||
|
||||
### 档位二:完整 — 同对话异步
|
||||
|
||||
审批不阻塞同一对话,用户在同一对话里继续发消息,审批通过后工具结果作为新上下文回流。
|
||||
|
||||
- 触及:agent loop 语义重设计——LLM 上下文如何处理"待执行工具"(标记转审批?LLM 基于"已转人工"假设继续?)。
|
||||
- 可能形态:审批转独立审批队列/通知中心,对话流遇到待审批工具不阻塞,告知"有 N 个待审批"后继续;审批通过后台执行工具,结果追加为新消息。
|
||||
- 复杂度:高,接近重做 agent loop。
|
||||
- 风险:LLM 上下文一致性、工具结果时效性、多任务并发安全。
|
||||
|
||||
## 评估
|
||||
|
||||
| 维度 | 档位一(跨对话异步) | 档位二(同对话异步) |
|
||||
|------|---------------------|----------------------|
|
||||
| 解决主诉求 | ✅ 切对话即可继续 | ✅ 同对话继续 |
|
||||
| 架构改动 | AiSession 多实例化 | agent loop 语义重设计 |
|
||||
| 与 B 路线 | 一部分 | 接近独立重做 |
|
||||
| 风险 | 中(并发状态管理) | 高(上下文一致性) |
|
||||
| 建议 | 先做 | 评估后定 |
|
||||
|
||||
**建议**:作为 B 路线一部分,先做档位一(跨对话异步),需先完成 AiSession 多实例化。档位二待 agent 能力升级时再评估。
|
||||
|
||||
## 关联
|
||||
|
||||
- 触及 [[aichat-arch-extensibility]] 记录的 AiSession 单例瓶颈。
|
||||
- 与 [[aichat-roadmap-ab-split]] B 路线(补决策/并发能力)相关。
|
||||
- 当前同步审批的其他问题(审批态 stop 卡死、新建对话破坏 session)见 `aichat审查报告-2026-06-14.md` H2/H3,异步化时一并解决。
|
||||
284
docs/02-架构设计/构想审查/aichat授权体验改进方案-2026-06-14.md
Normal file
284
docs/02-架构设计/构想审查/aichat授权体验改进方案-2026-06-14.md
Normal file
@@ -0,0 +1,284 @@
|
||||
# AIChat 授权功能体验改进方案
|
||||
|
||||
> 创建: 2026-06-14 | 状态: 待讨论
|
||||
|
||||
## 一、当前授权机制概览
|
||||
|
||||
### 1.1 核心流程
|
||||
|
||||
```
|
||||
用户发送消息
|
||||
→ Agentic Loop (最多 10 轮)
|
||||
→ LLM 流式响应
|
||||
→ 解析 tool_calls
|
||||
→ 按风险等级分流:
|
||||
├─ Low Risk → 自动并行执行(join_all)
|
||||
├─ Medium → 暂停循环,等待人工审批
|
||||
└─ High → 暂停循环,等待人工审批
|
||||
→ 审批通过 → 执行工具 → try_continue_agent_loop 恢复循环
|
||||
→ 审批拒绝 → tool_result="用户拒绝了此操作" → 恢复循环让 LLM 自行决策
|
||||
```
|
||||
|
||||
### 1.2 工具风险分级矩阵
|
||||
|
||||
| 风险等级 | 工具 | 执行方式 |
|
||||
|---------|------|---------|
|
||||
| **Low** | `list_projects`, `list_tasks`, `list_ideas`, `list_trash`, `read_file`, `list_directory` | 自动执行,并行 `join_all` |
|
||||
| Medium | `create_project`, `create_task`, `create_idea`, `update_project`, `update_task`, `bind_directory`, `write_file` | 需人工审批 |
|
||||
| **High** | `delete_project`, `restore_project`, `purge_project`, `delete_task`, `run_workflow`, `run_command` | 需人工审批 |
|
||||
|
||||
### 1.3 已实现的亮点
|
||||
|
||||
- **审计留痕**:`ai_tool_executions` 表完整记录每次工具调用的状态、风险等级、决策者、请求时间和执行时间
|
||||
- **断点恢复**:应用重启后通过 `restore_pending_approvals()` 从数据库重建内存中的待审批状态
|
||||
- **审批卡片可读化**:`build_approval_reason()` 解析工具参数,拼接人类可读的审批理由
|
||||
- **generating 状态 RAII 守护**:`GeneratingGuard` 确保无论正常退出还是 panic,`generating` 标志都能复位
|
||||
- **数据变更联动刷新**:工具执行成功后自动 emit `df-data-changed` 事件,前端自动刷新列表
|
||||
- **安全防护**:API Key 存 OS keyring、文件路径双层校验、write_file 覆盖前自动 .bak 备份 + 原子写
|
||||
|
||||
### 1.4 关键代码位置
|
||||
|
||||
| 模块 | 文件 | 职责 |
|
||||
|------|------|------|
|
||||
| 工具注册表 | `src-tauri/src/commands/ai/tool_registry.rs` | 工具定义 + 风险等级 + handler 同源 |
|
||||
| 审批处理 | `src-tauri/src/commands/ai/audit.rs` | 工具调用审计 + pending 审批恢复 + 审批后状态回填 |
|
||||
| Agentic 循环 | `src-tauri/src/commands/ai/agentic.rs` | 流式接收 → 工具执行 → 结果回传 LLM → 循环 |
|
||||
| IPC 命令 | `src-tauri/src/commands/ai/commands.rs` | `ai_approve` / `ai_chat_send` / `ai_chat_stop` 等 |
|
||||
| 审批卡片 UI | `src/components/ToolCard.vue` | 卡片渲染 + 参数展示 + 批准/拒绝按钮 |
|
||||
| 卡片列表 | `src/components/ToolCardList.vue` | 多卡片折叠管理 |
|
||||
| 聊天面板 | `src/components/AiChat.vue` | 消息列表 + 审批转发 + 输入区 |
|
||||
| AI Store | `src/stores/ai.ts` | 模块级单例 state |
|
||||
| 发送/审批 | `src/composables/ai/useAiSend.ts` | `approveToolCall` 乐观更新 + IPC 调用 |
|
||||
|
||||
---
|
||||
|
||||
## 二、用户体验痛点分析
|
||||
|
||||
### 痛点 1:逐个审批,无法批量操作
|
||||
|
||||
**现象**:当 AI 一次返回多个 Medium/High 工具调用时(比如同时创建 3 个任务 + 写 2 个文件),用户需要逐个点批准/拒绝。
|
||||
|
||||
**根因**:`process_tool_calls`(audit.rs)把每个待审批工具都推入 `pending_approvals` HashMap,前端为每个 pending 渲染独立的 ToolCard,每个卡片只有自己的"批准/拒绝"按钮。`ToolCardList.vue` 没有批量操作入口。
|
||||
|
||||
**影响**:高频交互场景下审批变成体力活,用户体验疲劳。
|
||||
|
||||
### 痛点 2:审批阻塞整个对话,期间无法输入
|
||||
|
||||
**现象**:审批等待期间 `generating=true`,用户虽然能上滑看历史,但无法发送新消息(`sendMessage` 会入队),也无法预知还有多少审批在排队。
|
||||
|
||||
**根因**:`ai_chat_send`(commands.rs:46)检查 `session.generating` 为 true 时拒绝新消息。审批等待期间 `generating` 保持 true(`agentic.rs` 的 `guard.disarm()` 保持 true 以便 `try_continue` 续生成)。
|
||||
|
||||
**影响**:用户处于"被动等待"状态,无法并行做其他事。
|
||||
|
||||
### 痛点 3:Medium 和 High 体验无差异
|
||||
|
||||
**现象**:两者都弹同样的审批卡片、同样的按钮,交互流程完全一致。
|
||||
|
||||
**根因**:`process_tool_calls`(audit.rs:103-120)中 Medium 和 High 走同一个 `pending_approvals.insert` 分支,区别仅在 `build_approval_reason` 的文案后缀("请确认是否执行" vs "高风险,需人工批准")。
|
||||
|
||||
**影响**:High 操作(如 `purge_project` 不可恢复)缺乏足够的警示力度,容易误操作。
|
||||
|
||||
### 痛点 4:write_file 审批信息不够直观
|
||||
|
||||
**现象**:`write_file` 是 Medium 风险,审批卡片只展示 path 和 content 参数。content 可能是几百行代码,在审批卡片里以 `formatArgValue` 截断到 300 字符展示。
|
||||
|
||||
**根因**:`ToolCard.vue` 的 `toolArgsEntries` → `displayArgValue` → `formatArgValue` 对超长值统一截断到 300 字符。
|
||||
|
||||
**影响**:用户无法看清要写入的完整内容,只能盲目批准。尤其覆盖已有文件时,用户不知道会改什么。
|
||||
|
||||
### 痛点 5:审批后无进度反馈
|
||||
|
||||
**现象**:点击"批准"后,卡片乐观置 `running`,但用户不知道:
|
||||
- 工具正在执行还是已执行完等待 LLM 续生成
|
||||
- 还有多少待审批在排队
|
||||
- 整个 agentic 循环进行到第几轮
|
||||
|
||||
**根因**:前端没有全局的 agentic 循环进度指示器。`AiAgentRound` 事件虽然通知了轮次,但没有在 UI 上持久化展示。
|
||||
|
||||
**影响**:用户对系统状态缺乏掌控感,尤其在多轮工具调用时。
|
||||
|
||||
### 痛点 6:审批卡片可能被滚出视口
|
||||
|
||||
**现象**:当消息很多时,审批卡片可能被新消息推到上方滚出视口。
|
||||
|
||||
**根因**:`AiChat.vue` 的 `collapseInactive` 不会收起 `pending_approval` 卡片,但也不会自动滚动到 pending 卡片。没有全局徽标提醒。
|
||||
|
||||
**影响**:用户可能看不到待审批项,对话看起来"卡住了"但不知道在等什么。
|
||||
|
||||
---
|
||||
|
||||
## 三、改进方案
|
||||
|
||||
### P0 — 快速改善体感
|
||||
|
||||
#### 3.1 批量审批
|
||||
|
||||
**方案**:当同一轮有多个 pending 时,在 ToolCardList 顶部显示"全部批准(N) / 全部拒绝"按钮。
|
||||
|
||||
**改动范围**:
|
||||
- `ToolCardList.vue`:新增批量操作栏,监听 toolCalls 中 pending_approval 数量
|
||||
- `useAiSend.ts`:新增 `approveAll(rejectAll)` 方法,循环调用 `ai_approve`
|
||||
|
||||
**交互**:
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ ⏳ 3 项待审批 │
|
||||
│ [✓ 全部批准] [✕ 全部拒绝] │
|
||||
├─────────────────────────────────┤
|
||||
│ [工具卡片 1 - pending] │
|
||||
│ [工具卡片 2 - pending] │
|
||||
│ [工具卡片 3 - pending] │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 3.2 审批计数器 + 跳转
|
||||
|
||||
**方案**:在输入框上方或 header 显示 `⏳ 2 项待审批`,点击跳转到第一个 pending 卡片。
|
||||
|
||||
**改动范围**:
|
||||
- `AiChat.vue`:header 区域增加审批徽标
|
||||
- `ToolCardList.vue`:暴露 `scrollToFirstPending` 方法
|
||||
|
||||
**交互**:
|
||||
```
|
||||
┌──────────────────────────────────┐
|
||||
│ 🤖 助手 ⏳2 [+][×] │ ← 徽标在 header
|
||||
├──────────────────────────────────┤
|
||||
│ ...消息列表... │
|
||||
│ ┌─ 工具卡片 (pending) ──┐ │ ← 点击徽标滚动到此
|
||||
│ │ 创建任务:XXX │ │
|
||||
│ │ [批准] [拒绝] │ │
|
||||
│ └────────────────────────┘ │
|
||||
├──────────────────────────────────┤
|
||||
│ [输入框] │
|
||||
└──────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 3.3 write_file diff 预览
|
||||
|
||||
**方案**:write_file 审批时,如果文件已存在,展示前后对比 diff 而非裸 content。
|
||||
|
||||
**改动范围**:
|
||||
- 后端 `tool_registry.rs`:write_file handler 在执行前读取旧文件内容,返回 diff 信息(或前端请求 diff)
|
||||
- `ToolCard.vue`:pending_approval + name=write_file 时渲染 diff 视图
|
||||
|
||||
**交互**:
|
||||
```
|
||||
┌─ 写入文件 src/main.rs (待审批) ──────┐
|
||||
│ │
|
||||
│ - fn main() { │ ← 红色:删除行
|
||||
│ - println!("hello"); │
|
||||
│ + fn main() { │ ← 绿色:新增行
|
||||
│ + println!("hello, world"); │
|
||||
│ + setup_logging(); │
|
||||
│ │
|
||||
│ ⚠ 覆盖已有文件 (23→45 行) │
|
||||
│ [查看完整内容] [批准] [拒绝] │
|
||||
└───────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### P1 — 增强控制力
|
||||
|
||||
#### 3.4 会话级授权 Session Trust
|
||||
|
||||
**方案**:引入会话级信任机制,替代全局宽松模式。用户在当前对话中一次性授权某目录的写/执行权限,后续该对话内同类操作自动放行。切换对话或新建对话时信任清空。
|
||||
|
||||
**配置项**:
|
||||
```
|
||||
当前会话信任目录:
|
||||
✅ E:/wk-lab/devflow/src (Write + Execute)
|
||||
✅ E:/wk-lab/devflow/docs (Write)
|
||||
+ 添加目录...
|
||||
```
|
||||
|
||||
**改动范围**:
|
||||
- 前端:Settings 或对话 header 新增「信任管理」入口
|
||||
- 后端:`AiSession` 增加 `trusted_dirs: HashSet<(PathBuf, TrustLevel)>`
|
||||
- `audit.rs`:`process_tool_calls` 先查 session trust,命中则跳过 pending
|
||||
|
||||
**安全边界**:
|
||||
- 仅纯读取操作(list_*/read_*/list_directory)保持自动放行
|
||||
- 所有 create/update/bind/write/delete 操作默认需审批或 session-trust
|
||||
- bind_directory 归类为修改操作
|
||||
- 信任仅限当前会话内存,不持久化
|
||||
|
||||
#### 3.5 High 二次确认
|
||||
|
||||
**方案**:delete/purge/run_command 等高风险操作,批准后弹出二次确认。
|
||||
|
||||
**改动范围**:
|
||||
- `ToolCard.vue`:High 风险 + approved=true 时,先弹 inline 确认("确定要永久删除?此操作不可恢复")
|
||||
- 或用现有 `ConfirmDialog` 组件
|
||||
|
||||
**交互**:
|
||||
```
|
||||
第一次点击"批准":
|
||||
→ 卡片内弹出确认提示
|
||||
→ "确定要永久删除项目「XXX」?此操作不可恢复"
|
||||
→ [确认删除] [取消]
|
||||
|
||||
第二次点击"确认删除":
|
||||
→ 才真正执行 ai_approve
|
||||
```
|
||||
|
||||
#### 3.6 审批超时(前端定时器)
|
||||
|
||||
**方案**:前端侧 5 分钟超时自动拒绝,避免对话永久卡住。超时策略独立于 Webhook 等外部动作路径。
|
||||
|
||||
**改动范围**:
|
||||
- 前端:`useAiSend.ts` 在 pending 时启动 5min 定时器,超时自动调 `ai_approve(id, false)`
|
||||
- 不改后端 AiSession 结构(远期 Webhook 走独立路径)
|
||||
|
||||
---
|
||||
|
||||
### P2 — 信息透明度
|
||||
|
||||
#### 3.7 Agentic 进度条
|
||||
|
||||
**方案**:在消息区域底部显示循环进度。
|
||||
|
||||
**改动范围**:
|
||||
- `AiChat.vue`:底部增加进度指示条
|
||||
- `useAiEvents.ts`:处理 `AiAgentRound` 事件时更新进度
|
||||
|
||||
**交互**:
|
||||
```
|
||||
┌──────────────────────────────────┐
|
||||
│ ...消息列表... │
|
||||
│ │
|
||||
│ 🔄 循环 3/10 · ⏳2待审批 · ✅5完成 │ ← 底部进度条
|
||||
├──────────────────────────────────┤
|
||||
│ [输入框] │
|
||||
└──────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 3.8 审计历史面板
|
||||
|
||||
**方案**:独立页面展示 `ai_tool_executions` 表的审计记录。
|
||||
|
||||
**改动范围**:
|
||||
- 后端:新增 `list_tool_executions` IPC 命令(查询审计表)
|
||||
- 前端:新增 `AuditLog.vue` 视图,表格展示历史记录
|
||||
|
||||
**展示字段**:
|
||||
| 时间 | 工具 | 风险 | 状态 | 决策者 | 参数摘要 | 结果摘要 |
|
||||
|------|------|------|------|--------|---------|----------|
|
||||
|
||||
---
|
||||
|
||||
## 四、实施优先级建议
|
||||
|
||||
| 优先级 | 改进项 | 预估工作量 | 用户价值 |
|
||||
|--------|--------|-----------|---------|
|
||||
| **P0** | 3.1 批量审批 | 0.5 天 | 🔥🔥🔥 |
|
||||
| **P0** | 3.2 审批计数器 + 跳转 | 0.5 天 | 🔥🔥🔥 |
|
||||
| **P0** | 3.3 write_file diff 预览 | 1 天 | 🔥🔥 |
|
||||
| **P1** | 3.4 会话级授权 Session Trust | 1.5 天 | 🔥🔥🔥 |
|
||||
| **P1** | 3.5 High 二次确认 | 0.5 天 | 🔥 |
|
||||
| **P1** | 3.6 审批超时(前端5min) | 0.5 天 | 🔥 |
|
||||
| **P2** | 3.7 Agentic 进度条 | 0.5 天 | 🔥🔥 |
|
||||
| **P2** | 3.8 审计历史面板 | 1 天 | 🔥 |
|
||||
|
||||
**建议第一批落地**:P0 三项(批量审批 + 计数器 + diff 预览),总计约 2 天工作量,覆盖最高频的体验痛点。
|
||||
146
docs/02-架构设计/构想审查/aichat流式Markdown渲染调研-2026-06-15.md
Normal file
146
docs/02-架构设计/构想审查/aichat流式Markdown渲染调研-2026-06-15.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# AI Chat 流式 Markdown 渲染调研(2026-06-15)
|
||||
|
||||
> 范围:`AiChat.vue` 流式渲染优化。当前 AR-1 修复(commit f58743e)用「流式纯文本短路」防掉帧,副作用是流式过程无格式。本调研找不掉帧且有格式的更好方案。
|
||||
> 方法:3 路并行调研(机制方案 / 现成库 / Vue3 落地)+ 主代理整合。
|
||||
> 性质:调研 + 方案,**未实施**。
|
||||
> 关联:[aichat审查报告-2026-06-14.md](aichat审查报告-2026-06-14.md) AR-1;[近期改动代码审查-2026-06-15.md](../05-代码审查/近期改动代码审查-2026-06-15.md) §亮点「renderMd 流式纯文本短路」。
|
||||
|
||||
---
|
||||
|
||||
## §1 问题根因
|
||||
|
||||
现状(`src/components/AiChat.vue:200,347`):
|
||||
|
||||
```vue
|
||||
<div v-html="renderMd(text, isLastAi(msg) && store.state.streaming)"></div>
|
||||
```
|
||||
```js
|
||||
function renderMd(text, isStreaming=false){
|
||||
if (isStreaming || !mdReady) return escapeHtml(text) // 流式纯文本短路
|
||||
return _purify.sanitize(_marked.parse(text))
|
||||
}
|
||||
```
|
||||
|
||||
掉帧两因素叠加:
|
||||
- **(A) 解析成本**:每个 delta 全量 `marked.parse()` O(N),N 随回复增长,后期单帧解析几十 ms。
|
||||
- **(B) 重渲染成本**:`v-html` 整段替换触发子树重布局。
|
||||
|
||||
当前方案牺牲「流式格式」躲掉 (A)(B),但 delta 20-80ms 一个,流式时用户看到裸 markdown 源码(`#`、`-`、```` ``` ```` 符号),结束才出格式。
|
||||
|
||||
---
|
||||
|
||||
## §2 五大机制对比
|
||||
|
||||
| 机制 | 消除瓶颈 | 流式有格式 | 成本 | 适用 | 独立够吗 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1. rAF 批量节流 | 中(砍频率) | 是 | 低 | 全部 | 否(长文本单次仍重) |
|
||||
| 2. 块级 diff + memo | **高**(砍到 O(末块)) | 是 | 低-中 | 全部 | **基本够(主流首选)** |
|
||||
| 3. Web Worker 解析 | 高(主线程归零) | 是 | 中 | 超长文档/重 sanitize | 通常与 2 叠加 |
|
||||
| 4a. 代码块延迟高亮 | 高(代码块零成本) | 代码块流式无色 | 低 | 有代码块 | 仅代码块,需叠加 |
|
||||
| 4b. shiki-stream 增量高亮 | 高 | 代码块流式有色 | 中 | 有代码块 | 仅代码块 |
|
||||
| 5. 虚拟滚动 | 中(砍 DOM 不砍 parse) | 是 | 中 | 长会话消息列表 | 否 |
|
||||
|
||||
**机制 2(块级 diff + memo)是业界主流首选**——Vercel AI SDK 官方 cookbook 做法。原理:`marked.lexer()` 按双换行/代码围栏切块,每块独立 memoize,只有「正在生长的末块」重 parse,已完成块缓存跳过。解析成本从 O(全文) 降到 O(末块)。
|
||||
|
||||
**大厂可见行为**:ChatGPT / Claude / Gemini 流式时均有格式,代码块流式时等宽 + 基本着色。Chrome 官方文档明确反对「整篇重 parse + innerHTML 替换」(正是当前实现),推荐 streaming-markdown 增量 append。
|
||||
|
||||
**rAF 实测数据**(Sitepoint,React 18.3 生产构建 M2):朴素逐 token setState 平均 commit 18ms(80 token/s 达 52ms 可见卡顿),rAF 批量后 3-5ms。
|
||||
|
||||
---
|
||||
|
||||
## §3 现成库评估
|
||||
|
||||
| 库 | Vue3 兼容 | 流式 | 安全 | 维护 | 结论 |
|
||||
|---|---|---|---|---|---|
|
||||
| **markstream-vue** | ✅ 原生组件 | ✅ 双模式(虚拟窗口 + 增量批处理) | ✅ 内置 safe HTML | ✅ 2.2k star / open issue 2 / 近乎日更 / 尤雨溪背书 / 1.0 稳定 | **首选** |
|
||||
| streamdown (Vercel) | ❌ React 绑定 + 强绑 Tailwind/shadcn | ✅ | ✅ rehype-harden | ✅ | 仅参考(issue #19 求 Vue 版未解决) |
|
||||
| streaming-markdown | ⚠️ callback 驱动需自己接线 | ✅ token 级 | ❌ 需自配 | 功能不全 | 参考 |
|
||||
| marked(当前用) | ✅ | ❌ 无官方流式 API | ❌ 需自配 DOMPurify | ✅ 36.9k star | 不直用做流式层 |
|
||||
| markdown-it | ✅ | ❌ 无原生流式 | - | ✅ | 同上 |
|
||||
| antfu/shiki-stream | ✅ 组件 | ✅ 增量高亮 | - | ✅ 511 star | 代码块高亮专库 |
|
||||
|
||||
**核心结论**:有 Vue3 原生可直接用的流式 markdown 库 **markstream-vue**(尤雨溪推荐),命中全部诉求——流式有格式、不掉帧、TS-first、内置 sanitize、`final` prop 解未闭合 token 卡死。内部已含 marked + Shiki + sanitize 组合,等于替你造好轮子。
|
||||
|
||||
**降级路径**:若样式侵入太重,只用其解析内核 `stream-markdown-parser`(框架无关纯函数)+ 现有 DOMPurify 自控渲染。
|
||||
|
||||
---
|
||||
|
||||
## §4 落地方案(递进)
|
||||
|
||||
### 方案 A:rAF 节流渲染(最小改动)
|
||||
流式时 `requestAnimationFrame` 每帧最多 parse 一次(封顶 60fps),`v-html` 绑响应式 `streamingHtml`。流式结束取消 rAF + 强制最终渲染落 mdCache。
|
||||
|
||||
- 性能:频率从「每 delta」降到「每帧」,主线程有空隙让浏览器 paint。
|
||||
- 观感:流式全程有格式;**瑕疵**:未闭合代码块(末尾 ```)会闪烁。
|
||||
- 成本:低(~60 行)。
|
||||
- 风险:超长回答(>20k 字)每帧 parse 全文仍偏重。
|
||||
|
||||
```js
|
||||
const streamingHtml = ref('')
|
||||
let rafId = null, lastStreamText = ''
|
||||
function scheduleStreamParse(text){
|
||||
if (rafId !== null) return
|
||||
rafId = requestAnimationFrame(()=>{
|
||||
rafId = null
|
||||
if (text === lastStreamText) return
|
||||
lastStreamText = text
|
||||
streamingHtml.value = _purify.sanitize(_marked.parse(text))
|
||||
})
|
||||
}
|
||||
watch(()=>store.state.streaming,(s,old)=>{
|
||||
if(old && !s){ if(rafId) cancelAnimationFrame(rafId); rafId=null; lastStreamText=''; streamingHtml.value='' }
|
||||
})
|
||||
onBeforeUnmount(()=>{ if(rafId) cancelAnimationFrame(rafId) })
|
||||
```
|
||||
|
||||
### 方案 B:方案 A + 代码块流式降级(体验最佳,推荐起步)
|
||||
在 A 基础上,流式期把 fenced code 块正则抠出降级为纯文本(`<pre class="md-code-streaming">`),其余正常 marked。流式结束一次完整 marked 替换。
|
||||
|
||||
- 消掉方案 A 的「未闭合代码块闪烁」瑕疵——AI 回答大量含代码块,高频可见。
|
||||
- 成本:中(~100 行 + CSS)。
|
||||
- **推荐起步方案**(A→B 平滑叠加,B 只替换 `doStreamParse` 一个函数,不返工)。
|
||||
|
||||
### 方案 C:Web Worker(彻底解耦)
|
||||
marked+sanitize 移 Worker,主线程零 parse。Worker 内 DOMPurify 需 jsdom shim(或换 `sanitize-html` 免 DOM)。
|
||||
|
||||
- 成本:高(~150 行 + worker 文件 + jsdom)。
|
||||
- 适用:极端长回答/多会话。方案 B 不够再上。
|
||||
|
||||
### 方案 D(换库):直上 markstream-vue
|
||||
用 `<MarkdownRender :content :final />` 替换整个 renderMd 手写层。
|
||||
|
||||
- 成本:中(库接入 + 样式对接)。
|
||||
- 收益:省自造轮子,拿到虚拟窗口 + 增量高亮 + 未闭合处理全套。
|
||||
- 风险:样式侵入、新依赖、迁移工作量需评估。
|
||||
|
||||
---
|
||||
|
||||
## §5 推荐结论
|
||||
|
||||
**两条路,按风险偏好二选一**:
|
||||
|
||||
| 路线 | 方案 | 收益 | 风险 | 工作量 |
|
||||
|---|---|---|---|---|
|
||||
| **保守(自研改造)** | 方案 B(rAF 节流 + 代码块降级) | 流式全程有格式、不掉帧、消代码块闪烁、无新依赖 | 超长回答边界需观察 | 中(~100 行 + CSS) |
|
||||
| **激进(换库)** | 方案 D(markstream-vue) | 同上 + 虚拟窗口 + 增量高亮 + 长期省维护 | 新依赖、样式侵入、迁移成本 | 中-高 |
|
||||
|
||||
**渐进建议**:先上方案 B 跑通(验证 rAF 节流 + 代码块降级在当前 delta 频率下不掉帧)→ 观察长回答边界 → 若需更强能力(虚拟窗口/增量高亮)再评估换 markstream-vue。
|
||||
|
||||
**当前 AR-1 临时方案(流式纯文本短路)由方案 D 替换后退役**——纯增量收益,流式全程有格式。
|
||||
|
||||
> **决策(2026-06-15):选方案 D**(换 markstream-vue)。理由:自研块级 memo 与 D 复杂度接近,D 白送 shiki 代码高亮 + 虚拟窗口 + 未闭合 token 修复器,自研只在「坚决不引新依赖」时才划算。落地 todo:ARC-260615-08。
|
||||
>
|
||||
> **决策转向(2026-06-15,同日复盘):方案 D 试装后弃用,改自研块级 memo(方案 B 增强版)**。复盘:markstream-vue@1.0.1 接入 + vue-tsc 通过无技术障碍,但「样式 100% 还原现有 .ai-md」成本高且脆——markstream DOM 异构于 marked 输出(代码块 `.code-block-container` chrome 结构 / 暗色 `--ms-*` 变量体系依赖 `.dark` class 而 DevFlow 用 `[data-theme]` / prose 作用域 `.markstream-vue`),4 处对接且随 markstream 升级易漂移。用户优先级是「保留原样式」>「虚拟窗口/shiki 高级能力」,转自研块级 memo:marked 输出标准 HTML → .ai-md 样式零对接,借鉴 §2 机制 2(块级 memo,业界主流)实现 splitBlocks(代码围栏整体一块/非代码双换行切)+ 前块缓存命中 O(末块) + 末块不缓存处理未闭合 token + rAF 节流。结论:**自研块级 memo = 方案 B 增强(rAF + 真块级 memo,非仅代码块降级),零新依赖、零样式对接、D 级流式性能**。§5 原决策表「自研只在坚决不引新依赖时才划算」判断在「不要高级能力、要原样式」前提下反转——此时自研反而最优。落地:ARC-260615-08 自研版已实施,vue-tsc exit 0,待 dev 运行时验证。
|
||||
|
||||
---
|
||||
|
||||
## 来源
|
||||
|
||||
- [Best practices to render streamed LLM responses — Chrome for Developers](https://developer.chrome.com/docs/ai/render-llm-responses)(streaming-markdown 增量 append、Paint flashing 验证)
|
||||
- [Markdown Chatbot with Memoization — Vercel AI SDK Cookbook](https://ai-sdk.dev/cookbook/next/markdown-chatbot-with-memoization)(块级 diff + memo 官方实现)
|
||||
- [Streaming Backends & React: Controlling the Re-render Chaos — Sitepoint](https://www.sitepoint.com/streaming-backends-react-controlling-re-render-chaos/)(rAF 实测数据)
|
||||
- [antfu/shiki-stream — GitHub](https://github.com/antfu/shiki-stream)
|
||||
- [markstream-vue — GitHub](https://github.com/Simon-He95/markstream-vue)
|
||||
- [vercel/streamdown — GitHub](https://github.com/vercel/streamdown)
|
||||
- [HuggingFace chat-ui: webworker for markdown parsing #1733](https://huggingface.co/spaces/jdelavande/chat-ui-energy/commit/7d6fc19984864d960f2875391858ea067b030dc6)
|
||||
- [shikijs/shiki Discussion #891](https://github.com/shikijs/shiki/discussions/891)(GrammarState 流式高亮底层)
|
||||
145
docs/02-架构设计/构想审查/产品定位调整-2026-06-12.md
Normal file
145
docs/02-架构设计/构想审查/产品定位调整-2026-06-12.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# 产品定位调整报告
|
||||
|
||||
> 从"想法到代码"到"想法到创作"的升级转型
|
||||
|
||||
## 📊 背景分析
|
||||
|
||||
### 原定位的问题
|
||||
- 过于狭窄:只面向开发者
|
||||
- 竞争激烈:代码工具市场已饱和
|
||||
- 限制场景:无法满足多元化的创作需求
|
||||
|
||||
### 新定位的优势
|
||||
- **普适性强**:覆盖所有创作者
|
||||
- **场景多样**:技术、商业、教育、创意
|
||||
- **价值更大**:从单一工具到创作平台
|
||||
|
||||
## 🎯 新产品定位
|
||||
|
||||
### 核心价值主张
|
||||
**"从想法到创作成果的全流程管理平台"**
|
||||
|
||||
### 目标用户画像
|
||||
| 用户类型 | 创作内容 | 使用场景 |
|
||||
|---------|---------|---------|
|
||||
| **开发者** | 代码、技术文档 | 项目开发、技术分享 |
|
||||
| **产品经理** | 需求文档、原型方案 | 产品规划、项目提案 |
|
||||
| **设计师** | 设计方案、创意文档 | 设计展示、概念提案 |
|
||||
| **研究者** | 学术论文、分析报告 | 研究、报告撰写 |
|
||||
| **内容创作者** | 博客、课程、培训 | 知识分享、教育 |
|
||||
|
||||
### 核心功能矩阵
|
||||
|
||||
| 功能模块 | 代码创作 | 文档创作 | 演示创作 | 内容创作 |
|
||||
|---------|---------|---------|---------|---------|
|
||||
| **想法池** | ✓ | ✓ | ✓ | ✓ |
|
||||
| **对抗评估** | ✓ | ✓ | ✓ | ✓ |
|
||||
| **任务管理** | ✓ | ✓ | ✓ | ✓ |
|
||||
| **工作流引擎** | ✓ | ✓ | ✓ | ✓ |
|
||||
| **模板系统** | ✓ | ✓ | ✓ | ✓ |
|
||||
| **协作功能** | ✓ | ✓ | ✓ | ✓ |
|
||||
|
||||
## 🔄 功能升级规划
|
||||
|
||||
### Phase 1: 基础创作支持
|
||||
- [x] 代码创作(现有)
|
||||
- [ ] Markdown 文档编辑器
|
||||
- [ ] PPT 演示文稿生成器
|
||||
- [ ] 文档模板库
|
||||
|
||||
### Phase 2: 智能创作辅助
|
||||
- [ ] AI 内容生成
|
||||
- [ ] 自动格式化
|
||||
- [ ] 多格式导出
|
||||
- [ ] 版本管理
|
||||
|
||||
### Phase 3: 创作生态
|
||||
- [ ] 创作市场
|
||||
- [ ] 团队协作
|
||||
- [ ] 知识库集成
|
||||
- [ ] 发布平台
|
||||
|
||||
## 📈 产品差异化
|
||||
|
||||
### 竞争优势
|
||||
1. **全流程覆盖**:从想法到发布
|
||||
2. **对抗式评估**:独特的质量控制机制
|
||||
3. **本地优先**:数据安全、隐私保护
|
||||
4. **跨平台支持**:桌面端 + Web 端
|
||||
|
||||
### 差异化场景
|
||||
- **学术研究**:论文写作 + 代码实现
|
||||
- **产品设计**:需求文档 + 原型设计
|
||||
- **技术培训**:课程内容 + 示例代码
|
||||
- **创意策划**:概念方案 + 可视化展示
|
||||
|
||||
## 🎨 视觉识别调整
|
||||
|
||||
### 品牌口号
|
||||
- **原**:"本地优先的开发流程工具"
|
||||
- **新**:"创意工作流的私人助手"
|
||||
|
||||
### 颜色系统
|
||||
保持现有的紫色系作为主色,增加:
|
||||
- 橙色:创意和活力
|
||||
- 绿色:成长和产出
|
||||
- 蓝色:专业和可靠
|
||||
|
||||
### 图标体系
|
||||
- 🧠 思维导图
|
||||
- ✍️ 创作工具
|
||||
- 📊 产出展示
|
||||
- 🚀 发布分享
|
||||
|
||||
## 📋 实施计划
|
||||
|
||||
### 短期(1个月)
|
||||
- 更新文档和营销材料
|
||||
- 完成文档创作基础功能
|
||||
- 发布 V2.0 版本
|
||||
|
||||
### 中期(3个月)
|
||||
- 完成演示文稿生成器
|
||||
- 实现模板系统
|
||||
- 上线创作市场 Beta
|
||||
|
||||
### 长期(6个月)
|
||||
- 建立创作者生态
|
||||
- 集成协作功能
|
||||
- 考虑 SaaS 服务
|
||||
|
||||
## 🎯 成功指标
|
||||
|
||||
### 用户增长
|
||||
- 月活跃用户:1000+
|
||||
- 创作者留存率:>60%
|
||||
- 日均创作次数:>3/用户
|
||||
|
||||
### 内容质量
|
||||
- 作品发布率:>40%
|
||||
- 用户满意度:>4.5/5
|
||||
- 重复使用率:>50%
|
||||
|
||||
### 业务指标
|
||||
- 付费转化率:>5%
|
||||
- 平均客单价:$50
|
||||
- 年营收目标:$100K
|
||||
|
||||
## 🔮 未来展望
|
||||
|
||||
### 5年愿景
|
||||
成为**创作者的首选工作平台**,连接想法与世界的桥梁。
|
||||
|
||||
### 技术演进
|
||||
- AI 驱动的智能创作
|
||||
- 虚拟现实创作空间
|
||||
- 区块链确权和版权保护
|
||||
|
||||
### 社会价值
|
||||
- 降低创作门槛
|
||||
- 促进知识分享
|
||||
- 支持创意经济
|
||||
|
||||
---
|
||||
|
||||
**总结**:从"想法到代码"到"想法到创作"不是功能减少,而是价值升级。我们不再局限于技术工具,而是成为所有创作者的伙伴。
|
||||
344
docs/02-架构设计/构想审查/任务推进构想-2026-06-14.md
Normal file
344
docs/02-架构设计/构想审查/任务推进构想-2026-06-14.md
Normal file
@@ -0,0 +1,344 @@
|
||||
# 构想: 任务推进全局设计(AI-First 推进链) — 2026-06-14
|
||||
|
||||
> 性质: 架构设计 / 实现方案
|
||||
> 关联: df-workflow · AiNode/HumanNode · knowledge 状态机范式 · devflow AI-First 定位(kms/devflow_ai_first_model.html)
|
||||
> 修订:
|
||||
> - 多角度对抗论证收敛(kind/状态机不抽层/范围精简)
|
||||
> - 对抗性验证升级(5 维度:收口/并发/崩溃/一致性/前端)
|
||||
> - **AI-First 定位确认**:任务由 AI 执行→AI 自审→人工最终核对(人从操作者转为审批者)
|
||||
|
||||
---
|
||||
|
||||
## 定位:AI-First 推进链(核心转向)
|
||||
|
||||
devflow 是 AI-First 工具。任务推进**不是人点按钮的操作流,是 AI 的执行流**:
|
||||
|
||||
```
|
||||
todo ──AI执行──▶ in_progress ──AI自审──▶ review_ready ──人工核对──▶ done
|
||||
AiNode AiNode HumanNode
|
||||
AI 干活 AI 审 AI 的活 人最终把关 AI 产出
|
||||
```
|
||||
|
||||
- **AI 执行**:任务内容由 AI 干(写代码、改文件、跑测试)。干完自动推进,人不必手动点「开始」。
|
||||
- **AI 自审**:AI 审 AI 自己的产出(code review,结构化结论)。审过推进,审出问题退回重做。
|
||||
- **人工最终核对**:人在 merge 关卡最终把关 AI 产出。**这是 AI-First 的核心契约——人监督 AI**,不是人确认自己的活。
|
||||
|
||||
**advance_task 的默认触发者从「人」变成「AI」**(执行/自审完成事件触发),人可介入/覆盖/微调。人从「操作者」转为「审批者」。
|
||||
|
||||
### 这修复了对抗验证的 merge 零因果批评
|
||||
|
||||
对抗验证 Agent 4 批评「单人场景 merge 审批零因果——自审自批≈手切」。**AI 执行 + 人工核对**正好修复:merge 不再是人确认自己的活,而是**人监督 AI 的活**——从形式主义升级为实质关卡。
|
||||
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
项目管理任务维护目前**只能创建,不能推进**——前端状态标签纯展示无入口。根因缺「推进编排层」:状态字段、工作流引擎、分支表、状态机范式各干各的,且**完全缺 AI 执行层**。
|
||||
|
||||
## 痛点
|
||||
|
||||
| 已有能力 | 位置 | 现状 |
|
||||
|---|---|---|
|
||||
| 任务状态字段(裸 String,无值域校验) | `models.rs:52` | 无状态机、无联动、前端不暴露 |
|
||||
| 工作流引擎(ScriptNode/HumanNode/**AiNode**) | `df-workflow/*` + `df-nodes/*` | 三种节点现成,AiNode 注释明示设计意图「AI 分析→人工审批」,但推进链没用上 |
|
||||
| 分支表状态 | `models.rs:69` | 语义同构,未联动 |
|
||||
| 状态机范式 | `knowledge.rs:53` | 只在 knowledge 用 |
|
||||
| **AI 执行能力** | `df-ai` provider + `ai_node.rs` | AiNode 通用 LLM 调用现成;agent 级「写代码改文件」能力渐进 |
|
||||
|
||||
---
|
||||
|
||||
## 核心模型:AI-First 推进链 + 状态机
|
||||
|
||||
### 状态机(AI 推进 + 退回 + 旁路)
|
||||
|
||||
```
|
||||
AI执行闸门 AI自审闸门 人工核对闸门
|
||||
todo ───────────▶ in_progress ──────────▶ review_ready ──────────▶ done
|
||||
▲ │ │
|
||||
└── AI自审block/人工拒绝 ┘ │ (AI 重做)
|
||||
▼
|
||||
abandoned (任意态可放弃,终态不可逆)
|
||||
```
|
||||
|
||||
**退回边** `review_ready → in_progress`:AI 自审 block 或人工拒绝 → 退回让 AI 重做。AI 推进下退回比人推进更频繁(AI 反复审自己),故 loop 管理必要。
|
||||
|
||||
### 闸门策略(三闸门各司其职,都必需)
|
||||
|
||||
| 边 | 闸门 | 节点 | 阶段一 | 阶段二 |
|
||||
|---|---|---|---|---|
|
||||
| `start` | **AI 执行** | AiNode/agent | ✅ 必需(最小形态) | + git worktree(code kind) |
|
||||
| `ready` | **AI 自审** | AiNode | ✅ 必需 | + lint/test 真校验 |
|
||||
| `merge` | **人工核对** | HumanNode | ✅ 必需(人监督 AI) | + git merge 副作用 |
|
||||
| `abandon` | 无 | — | 直接转 | 直接转 |
|
||||
|
||||
三闸门都必需(不再是「merge 强制 + start/ready 关闭」)——AI 推进链上每环都有节点把关。
|
||||
|
||||
### ⚠️ 失败路径定义(含 AI 执行/自审失败)
|
||||
|
||||
| 失败场景 | 工作流结果 | 任务状态 | 反馈 |
|
||||
|---|---|---|---|
|
||||
| **AI 执行失败**(agent 报错/超时) | failed | 保持 todo | 「AI 执行失败:<错误>」,人可重试或介入手干 |
|
||||
| **AI 自审 block**(审出严重问题) | failed | **退回 in_progress**(AI 重做) | 「AI 自审未通过:<问题清单>」 |
|
||||
| **AI 自审 warn**(轻微问题) | completed(带警告) | 推进到 review_ready | 警告附在任务上,人核对时可见 |
|
||||
| **人工拒绝** | failed | **退回 in_progress**(AI 重做) | 「人工核对未通过:<意见>」 |
|
||||
| **闸门脚本失败**(阶段二 lint/test) | failed | 保持推进前 | 「闸门失败」 |
|
||||
| **审批超时/取消** | failed/Err | 保持推进前 | 「超时/已取消」 |
|
||||
| **应用崩溃** | running 孤儿 | 保持推进前,可重新推进 | 启动提示「检测到中断的推进」 |
|
||||
|
||||
**关键**:AI 自审/人工核对的「拒绝/block」→ 退回 in_progress 让 AI 重做(不是退回给人干——AI-First 下人是审批者不是执行者)。
|
||||
|
||||
### AI 自审结果处理(建议性 vs 强制)
|
||||
|
||||
AiNode 输出纯文本,要判通过与否得约定结构化输出 + 解析:
|
||||
|
||||
```json
|
||||
{ "verdict": "pass" | "warn" | "block", "issues": [...], "summary": "..." }
|
||||
```
|
||||
|
||||
- `pass`:推进;`warn`:推进但带警告;`block`:退回 in_progress
|
||||
- 默认 AI 自审走 verdict 判定(非纯建议),否则 AI 推进链断在人审前
|
||||
- 人审(merge)仍是最终关卡,可覆盖 AI 自审结论
|
||||
|
||||
---
|
||||
|
||||
## AI 执行层(新增,核心缺口)
|
||||
|
||||
任务内容由谁干——这是原方案的最大盲区。AI-First 下由 AI 执行。
|
||||
|
||||
### 实现形态
|
||||
|
||||
- **AiNode/agent 执行**:start 闸门触发 AiNode(或更复杂的 agent 编排)干活——读任务描述 + 项目上下文 → 写代码/改文件/跑测试 → 产出 diff
|
||||
- **执行能力渐进**:阶段一最小形态(AiNode 跑执行 prompt / 接现有 AI 工具链),阶段二+ 逐步增强(agent 多步、文件操作、git worktree 内执行)
|
||||
- **执行产出**:代码 diff / 文件变更 / 测试结果,供下游 AI 自审节点消费
|
||||
|
||||
### advance_task 触发者变更
|
||||
|
||||
- **默认**:AI 执行完成事件 → 自动触发 advance_task(start→推进)
|
||||
- AI 自审完成 → 触发 advance_task(ready→推进或退回)
|
||||
- 人工核对完成 → 触发 advance_task(merge→done)
|
||||
- **人可介入**:任何节点人能手动推进/覆盖/接手(人转手干)
|
||||
|
||||
---
|
||||
|
||||
## 【P0】状态机收口(对抗验证最高优先级)
|
||||
|
||||
### 致命漏洞:update_task 是公开旁路
|
||||
|
||||
`task.rs:74` update_task 白名单含 `"status"`(`crud.rs:291`),任意调用方一行绕过所有闸门和状态机。且 `crud tests:249` 单测固化旁路。AI 推进下更危险——AI agent 若能调 update_task 改 status,整个 AI 执行/自审/核对链形同虚设。
|
||||
|
||||
### 收口措施
|
||||
|
||||
1. 从 tasks 白名单**移除 `"status"`**
|
||||
2. **advance_task 成为 status 唯一写入路径**(AI 触发也走它)
|
||||
3. 删除/改写 `update_field_allows_tasks_status` 单测
|
||||
4. advance_task 内联 `validate_task_status` 值域校验
|
||||
|
||||
---
|
||||
|
||||
## 状态集清理(非「定稿」)
|
||||
|
||||
对抗验证纠误:前端早已 5 态,后端 enum 多 3 个僵尸死状态(InReview/Testing/Blocked 零使用)。是「清理僵尸」非「7→5 定稿」。
|
||||
|
||||
措施:删后端 enum 死状态 + `merged→done` 改名 + 迁移前抽样 + status 值域校验。
|
||||
|
||||
```sql
|
||||
-- 迁移(幂等,conn.transaction() 包裹)
|
||||
UPDATE tasks SET status='done' WHERE status='merged';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务类型:阶段一不加 kind
|
||||
|
||||
对抗验证:阶段一 code/generic 行为零差异,违反 YAGNI。阶段二 git 联动需要区分时再加 kind(ALTER + 回填 generic)。`tags` 保留承担语义标注(doc/design)。
|
||||
|
||||
**AI 推进下的 kind 意义**:阶段二+ AI 执行内容按 kind 分化(code 任务 AI 写代码、doc 任务 AI 写文档、design 任务 AI 出图)。阶段一 AI 执行最小形态不区分,随能力增强再分。
|
||||
|
||||
---
|
||||
|
||||
## 状态机实现:不抽层 + 下沉 SQL
|
||||
|
||||
enum 补 `can_transition_to`(不新建 state_machine.rs,knowledge validate_transition 源码验证是空壳):
|
||||
|
||||
```rust
|
||||
impl TaskStatus {
|
||||
pub fn can_transition_to(&self, to: &TaskStatus) -> bool {
|
||||
match (self, to) {
|
||||
(Todo, InProgress | Abandoned) => true,
|
||||
(InProgress, ReviewReady | Abandoned) => true,
|
||||
(ReviewReady, Done | Abandoned | InProgress) => true, // 可退回(AI 重做)
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**状态机下沉 SQL**(TOCTOU 根治):advance_task 的校验+写入合并为带前置条件的 UPDATE:
|
||||
|
||||
```sql
|
||||
UPDATE tasks SET status=:new, updated_at=:now
|
||||
WHERE id=:id AND status=:expected -- affected_rows==0 即状态已变,拒绝
|
||||
```
|
||||
|
||||
终态保护:`AND status NOT IN ('done','abandoned')`。
|
||||
|
||||
---
|
||||
|
||||
## loop 管理(AI 推进下必需)
|
||||
|
||||
AI 自审/人工核对退回 → AI 重做 → 再审 → 可能反复。加 `review_rounds: i32` 计数,退回时 +1:
|
||||
|
||||
- 任务卡显示「第 N 轮 review」(迭代可见性)
|
||||
- 可选:轮数过高提示「是否卡住」(不强制终止——单人/AI 决定何时 done)
|
||||
- 强制终止/阈值不做(over-engineering)
|
||||
|
||||
---
|
||||
|
||||
## 并发与一致性护栏(对抗验证新增)
|
||||
|
||||
AI 推进下并发更常见(多个任务并行 AI 执行)。护栏不变:
|
||||
|
||||
1. **per-task 互斥锁**:`task_locks: Arc<Mutex<HashMap<String, Arc<Mutex<()>>>>>`
|
||||
2. **闸门工作流去重**:起 run_workflow 前查 running/interrupted 工作流
|
||||
3. **WorkflowEvent 加 execution_id** + 转发过滤(防多任务事件串台)
|
||||
4. **审批请求带 task_id**(task_id + execution_id + node_id 三元组)
|
||||
|
||||
---
|
||||
|
||||
## 数据一致性:跨表事务
|
||||
|
||||
`crud.rs` 无跨表事务,advance_task 多表写(task.status + workflow.status + 阶段二 branches/projects)半成品无法回滚。promote_idea 补偿范式不适用更新型。
|
||||
|
||||
措施:**补 `Database.transaction()`**(OwnedTransaction),advance_task 事务内提交。迁移幂等(column_exists + WHERE + conn.transaction 包裹)。tags 写入校验。
|
||||
|
||||
---
|
||||
|
||||
## 崩溃恢复(对抗验证新增,AI 推进下更关键)
|
||||
|
||||
AI 执行/自审是长时异步过程,崩溃恢复更关键:
|
||||
|
||||
1. **启动孤儿清理**:`UPDATE workflow_executions SET status='interrupted' WHERE status='running'`
|
||||
2. **审批请求持久化**:HumanNode 阻塞前落库(node_executions status='pending'),启动恢复
|
||||
3. **AI 执行状态持久化**:AI 执行(长时)需 checkpoint,崩溃后能恢复或安全重做(阶段二+)
|
||||
4. **审批拒绝语义化**:HumanNode/AiNode 区分同意/拒绝/block,拒绝走失败路径不当 Ok
|
||||
5. **重复触发守卫**:advance_task 入口检查 running/interrupted 工作流
|
||||
|
||||
---
|
||||
|
||||
## 前端改造(对抗验证新增 + AI 推进适配)
|
||||
|
||||
1. **pendingApprovals 数组化**(按 execution_id 索引)
|
||||
2. **liveEvents 按 task 路由**:event payload 加 task_id,store 改 liveEventsByTask
|
||||
3. **任务卡 AI 推进可视化**:显示当前在哪个环节(AI 执行中/AI 自审中/待人工核对/第 N 轮)
|
||||
4. **按钮防重入**:advancingTaskIds: Set
|
||||
5. **确认式更新**:等 IPC/workflow 事件再刷 task,非乐观更新
|
||||
6. **AI 产出展示**:AI 执行的 diff、AI 自审的意见清单,供人核对时查看
|
||||
7. **统一错误桥接**:全局 watch state.error → Message.error
|
||||
8. **回调判定**:run_workflow 完成回调 advance_task 条件 `task_id.is_some()`
|
||||
|
||||
---
|
||||
|
||||
## 两阶段落地
|
||||
|
||||
### 阶段一:AI-First 推进链 + 工程护栏
|
||||
|
||||
**推进链**:
|
||||
- 状态集清理(删僵尸 + merged→done)+ enum 补 can_transition_to
|
||||
- **状态机收口**(移除 status 白名单 + advance_task 唯一入口 + 值域校验)← P0
|
||||
- advance_task + 状态机下沉 SQL + on_task_advanced 空钩子
|
||||
- **AI 执行闸门**(AiNode 最小形态)+ **AI 自审闸门**(AiNode 结构化 verdict)+ **人工核对闸门**(HumanNode)
|
||||
- **失败路径定义**(AI 执行失败/AI 自审 block/人工拒绝→退回重做)
|
||||
- **loop 管理**(review_rounds 计数)
|
||||
- per-task 锁 + 闸门去重、跨表事务、WorkflowEvent 加 execution_id、启动孤儿清理 + 审批持久化
|
||||
- WorkflowRecord 填值 + event payload 加 task_id
|
||||
- 前端:pendingApprovals/liveEventsByTask/advancingTaskIds/确认式更新/AI 推进可视化
|
||||
|
||||
**触发者**:advance_task 支持 AI 事件触发 + 人手动介入双通道。
|
||||
|
||||
### 阶段二:Git + 联动 + AI 执行增强
|
||||
|
||||
- 加 kind 字段;code kind 闸门脚本换 git 命令串;start/ready 接真 git/lint/test
|
||||
- AI 执行增强(agent 多步、worktree 内执行、文件操作)
|
||||
- 填 on_task_advanced:分支联动 + 项目 completed(含边界守卫)
|
||||
- BranchRecord 加 worktree_path
|
||||
|
||||
### Git 集成:直接外部命令
|
||||
|
||||
git 是 ScriptNode/AiNode 一串命令,不特殊化。不建 worktree.rs/df-git crate;不做 git 检测框架。硬依赖 git ≥2.20。非 code 任务不依赖 git。
|
||||
|
||||
### 联动策略
|
||||
|
||||
阶段一剥离分支联动和项目 completed(~90 行 + 边界漏洞),阶段二填钩子返工 <30 行。
|
||||
|
||||
---
|
||||
|
||||
## 落地改动点(阶段一,按优先级)
|
||||
|
||||
| 级 | # | 文件 | 改动 |
|
||||
|---|---|---|---|
|
||||
| **P0** | 1 | `crud.rs`+`task.rs` | 移除 status 白名单 + advance_task 唯一入口 + 值域校验 + 改单测 |
|
||||
| **P0** | 2 | `task.rs` | advance_task + 状态机下沉 SQL + on_task_advanced 空钩子 + **支持 AI 事件触发** |
|
||||
| **P0** | 3 | 闸门 DAG 模板 | **AI 执行(AiNode)+ AI 自审(AiNode verdict)+ 人工核对(HumanNode)三闸门** |
|
||||
| **P0** | 4 | `human_node.rs`+`ai_node.rs`+`executor.rs` | **审批/自审拒绝语义化**(block/拒绝走失败路径不当 Ok) |
|
||||
| **P1** | 5 | `task.rs`/`models.rs` | **review_rounds 计数**(退回 +1) |
|
||||
| **P1** | 6 | `state.rs` | per-task 锁 + 闸门去重 |
|
||||
| **P1** | 7 | `db.rs`/`crud.rs` | 补 Database.transaction() + 事务包裹 |
|
||||
| **P1** | 8 | `events.rs`+`workflow.rs` | WorkflowEvent 加 execution_id + 转发过滤 |
|
||||
| **P1** | 9 | `state.rs` init | 启动孤儿清理 + 审批持久化恢复 |
|
||||
| **P1** | 10 | `types.rs` | 删 enum 僵尸 + 补 can_transition_to |
|
||||
| **P1** | 11 | 迁移 | merged→done(幂等 + 事务)|
|
||||
| **P1** | 12 | `workflow.rs` | run_workflow 加 task_id/project_id + event payload 加 task_id + 完成回调 |
|
||||
| **P1** | 13 | `models.rs` | TaskRecord 加 tags(kind 推阶段二)+ review_rounds + 白名单 |
|
||||
| **P1** | 14 | 前端 `project.ts`/vue | pendingApprovals 数组 + liveEventsByTask + advancingTaskIds + 确认式更新 + **AI 推进环节可视化** + **AI 产出/diff 展示** |
|
||||
| **P2** | 15 | `constants`+i18n | merged→done 键名 + tags + review_rounds 文案 + AI 环节文案 |
|
||||
| **P2** | 16 | `project.ts` | 全局 error 桥接 |
|
||||
|
||||
---
|
||||
|
||||
## 决策护栏(触发反转条件)
|
||||
|
||||
| 决策 | 反转条件 |
|
||||
|---|---|
|
||||
| AI-First 推进(AI 执行→自审→人核对) | AI 执行能力长期不足/不可靠 → 退回人执行 + AI 辅助审 |
|
||||
| 阶段一不加 kind | 阶段二 doc/design 真要 AI 执行不同内容;或按 kind 统计 |
|
||||
| 状态机不抽层 | 第三处状态机需统一审计 |
|
||||
| 阶段一剥离联动 | 用户验收反馈「想看到项目自动完成」 |
|
||||
| 不提前集成 git | worktree 异常恢复需 Rust 逻辑 |
|
||||
| 状态机收口 | 出现「需批量脚本直接改 status」运维场景 → 另开受控入口 |
|
||||
| AI 自审走 verdict 判定(非纯建议) | AI 自审误判率高 → 降级为建议性,人审全权 |
|
||||
|
||||
---
|
||||
|
||||
## 决策清单(人定取舍 · why)
|
||||
|
||||
| # | 决策 | 否决备选 | why |
|
||||
|---|---|---|---|
|
||||
| 1 | **AI-First 推进链**(AI 执行→AI 自审→人工核对) | 人点按钮推进 | devflow 是 AI-First 工具,任务是 AI 的执行流非人的操作流 |
|
||||
| 2 | **advance_task 默认 AI 触发**,人可介入 | 仅人触发 | AI 执行/自审完成自动推进;人转审批者 |
|
||||
| 3 | **AI 自审走 verdict 判定**(pass/warn/block) | 纯建议 | AI 推进链需 AI 自审能阻断,否则断在人审前 |
|
||||
| 4 | **人工核对 = 人监督 AI**(非自审自批) | 人确认自己的活 | 修复 merge 零因果;AI-First 核心契约 |
|
||||
| 5 | **拒绝/block → 退回 AI 重做**(非退回人干) | 退回人执行 | AI-First 下人是审批者不是执行者 |
|
||||
| 6 | **loop 管理 review_rounds**(AI 推进必需) | 无计数 | AI 反复审自己,循环比人推进频繁 |
|
||||
| 7 | 状态机收口(移除 update_task status) | 保留旁路 | 对抗验证:旁路让状态机形同虚设,AI 推进下更危险 |
|
||||
| 8 | 阶段一不加 kind,阶段二再加 | 阶段一二分 | 对抗验证:阶段一零行为差异 |
|
||||
| 9 | 状态机不抽层,enum 补方法 | 抽通用层 | 源码验证空壳 |
|
||||
| 10 | 状态机下沉 SQL(WHERE 前置) | 纯内存校验 | 对抗验证:根治 TOCTOU |
|
||||
| 11 | 失败路径全覆盖(含 AI 执行/自审失败) | 只描述快乐路径 | 对抗验证:拒绝被当成功是语义反转 |
|
||||
| 12 | 补跨表事务 | 无事务多写 | 对抗验证:半成品无法回滚 |
|
||||
| 13 | 崩溃恢复(孤儿清理+审批持久化+AI 执行 checkpoint) | 纯内存 | AI 执行长时异步,崩溃恢复更关键 |
|
||||
| 14 | WorkflowEvent 加 execution_id | 全局单通道 | 对抗验证:多任务事件串台 |
|
||||
| 15 | 状态集清理后端僵尸(非 7→5 定稿) | 当作待决策 | 对抗验证:前端早已 5 态 |
|
||||
| 16 | 闸门三必需(AI执行/AI自审/人工核对) | merge 强制+其余关 | AI 推进链每环都有节点把关 |
|
||||
| 17 | 阶段一剥离联动 | 顺带联动 | ~90 行+边界漏洞 |
|
||||
| 18 | 预留 on_task_advanced 钩子 | 不预留 | 阶段二补是挂插件 |
|
||||
| 19 | git=闸门脚本调外部命令 | worktree.rs/df-git crate | YAGNI |
|
||||
| 20 | merged→done(迁移) | 文案分流 | 命名中性化 |
|
||||
| 21 | 前端 pendingApprovals 数组 + 确认式更新 + AI 环节可视化 | 单值/乐观 | 对抗验证:多任务并发;AI 推进需环节可见 |
|
||||
|
||||
---
|
||||
|
||||
## 演进记录
|
||||
|
||||
1. **多角度论证收敛**:kind 二分、状态机不抽层、阶段一范围精简、闸门策略
|
||||
2. **对抗性验证升级(5 维度)**:状态机收口/并发/崩溃恢复/一致性/前端——挖出 P0 致命项(旁路、审批拒绝=成功、TOCTOU、纯内存)
|
||||
3. **AI-First 定位确认**:任务由 AI 执行→AI 自审→人工最终核对。补执行层(原方案最大盲区),advance_task 触发者改 AI,AI 审/loop 升必需,merge 升级为「人监督 AI」实质关卡
|
||||
110
docs/02-架构设计/构想审查/前后端类型对齐-2026-06-12.md
Normal file
110
docs/02-架构设计/构想审查/前后端类型对齐-2026-06-12.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# 前后端类型对齐
|
||||
|
||||
> 创建: 2026-06-10 | 状态: 初稿
|
||||
|
||||
---
|
||||
|
||||
> ## 实施状态(2026-06-18 核对)
|
||||
>
|
||||
> **本设计文档已大面积过时,正文枚举表不再反映真实代码。** 以下为实际落地形态(以 `crates/df-types/src/types.rs` 为准):
|
||||
>
|
||||
> **类型契约机制 — 未采用 ts-rs 代码生成,仍手写 types.ts**:
|
||||
> - ts-rs 依赖:`Cargo.lock` 0 处、`crates/df-types/Cargo.toml` 无 ts-rs 依赖、全 crate 无 `build.rs`、无 `#[ts_rs]`/`#[derive(TS)]` 标注。memory「未做/手写 types.ts」属实。
|
||||
> - 前端类型手维护:`src/api/types.ts:1` 注释「TypeScript 类型定义 — 与 Rust Record 结构体严格对齐」。
|
||||
> - 「ts-rs 代码生成」仍列在 todo:`docs/todo.md:122`(ARC-260615-07 架构清理项之一)。
|
||||
>
|
||||
> **Crate 重命名 — df-core 改名 df-types 已完成**:
|
||||
> - workspace 下无 `crates/df-core` 目录(`ls` 核验 "df-core NOT FOUND");类型定义现居 `crates/df-types/src/{types.rs,events.rs,error.rs,lib.rs}`。
|
||||
> - 正文出现的 `df-core/src/types.rs` 路径全部应读作 `crates/df-types/src/types.rs`。
|
||||
>
|
||||
> **枚举对齐 — 正文 PascalCase 表全部过时,实际为 snake_case 序列化 + 枚举值数已变**:
|
||||
> - 正文写 `#[serde] PascalCase "Created"` 字符串值;实际 `crates/df-types/src/types.rs:51/89/130/195/233` 全部 `#[serde(rename_all = "snake_case")]`,前端/DB 存小写 snake_case。
|
||||
> - **TaskStatus**:正文 6 值(Created/BranchCreated/InProgress/ReviewReady/Merged/Abandoned) → 实际 **7 值**(`types.rs:131-146`):`todo / in_progress / in_review / testing / done / blocked / cancelled`。正文 6 个枚举名已无一存在。前端 7 态对齐见 `src/constants/project.ts:55`(D-260616-01)。
|
||||
> - **IdeaStatus**:正文 8 值(Draft/Evaluating/Scored/Hot/Promoted/Parked/Merged/Discarded) → 实际 **6 值**(`types.rs:52-65`):`draft / pending_review / approved / rejected / promoted / archived`。正文 8 个枚举名已无一存在。
|
||||
> - **ProjectStatus**:正文 4 值(Active/Paused/Completed/Archived) → 实际 **7 值**(`types.rs:90-105`):`planning / in_progress / testing / releasing / completed / paused / cancelled`。
|
||||
> - **WorkflowStatus**(正文误标 "WorkflowRunStatus"):正文 6 值(Pending/Running/Paused/Completed/Failed/Cancelled) → 实际 **6 值**(`types.rs:195-208`):`pending / running / paused / completed / failed / cancelled`(枚举名同正文,序列化改 snake_case,枚举名 WorkflowStatus 非 WorkflowRunStatus)。
|
||||
> - **NodeStatus / BranchStatus / Priority** 正文未列,实际见 `types.rs:233-248 / 272-281 / 301-312`。
|
||||
> - **ID 类型**:正文「所有 ID = UUID v4」与实际 `types.rs:10-28` `pub type XId = String` + `new_id()` 一致(未漂移)。
|
||||
>
|
||||
> **校验能力追加**:`TaskStatus::is_valid` / `valid_values`(`types.rs:165-183`)用于落库前拦截拼写错误(R-P1-5 修复),正文未涉及。
|
||||
>
|
||||
> 原文以下设计正文保持不变,作为历史设计记录;当前真实枚举/类型契约形态以上方"实施状态"为准,查阅请直接读 `crates/df-types/src/types.rs`。
|
||||
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
DevFlow 前端 (TypeScript) 和后端 (Rust) 通过 Tauri IPC 和 JSON 序列化通信。两侧的类型定义必须保持一致。
|
||||
|
||||
## 类型映射
|
||||
|
||||
### 基础类型
|
||||
|
||||
| Rust | TypeScript | 说明 |
|
||||
|------|-----------|------|
|
||||
| `String` | `string` | 文本字段 |
|
||||
| `i64` | `number` | 时间戳 (Unix timestamp) |
|
||||
| `Option<String>` | `string \| null` | 可空字段 |
|
||||
| `Vec<String>` | `string[]` | 数组 (JSON 序列化) |
|
||||
| `bool` | `boolean` | 布尔值 |
|
||||
|
||||
### ID 类型
|
||||
|
||||
| 实体 | Rust | TypeScript | 格式 |
|
||||
|------|------|-----------|------|
|
||||
| 所有 ID | `String` | `string` | UUID v4 |
|
||||
|
||||
所有 ID 统一使用 UUID v4 字符串,便于前后端传递。
|
||||
|
||||
### 枚举对齐
|
||||
|
||||
#### IdeaStatus (8 值)
|
||||
|
||||
| Rust | TypeScript |
|
||||
|------|-----------|
|
||||
| `Draft` | `"Draft"` |
|
||||
| `Evaluating` | `"Evaluating"` |
|
||||
| `Scored` | `"Scored"` |
|
||||
| `Hot` | `"Hot"` |
|
||||
| `Promoted` | `"Promoted"` |
|
||||
| `Parked` | `"Parked"` |
|
||||
| `Merged` | `"Merged"` |
|
||||
| `Discarded` | `"Discarded"` |
|
||||
|
||||
#### TaskStatus (6 值)
|
||||
|
||||
| Rust | TypeScript |
|
||||
|------|-----------|
|
||||
| `Created` | `"Created"` |
|
||||
| `BranchCreated` | `"BranchCreated"` |
|
||||
| `InProgress` | `"InProgress"` |
|
||||
| `ReviewReady` | `"ReviewReady"` |
|
||||
| `Merged` | `"Merged"` |
|
||||
| `Abandoned` | `"Abandoned"` |
|
||||
|
||||
#### WorkflowRunStatus (6 值)
|
||||
|
||||
| Rust | TypeScript |
|
||||
|------|-----------|
|
||||
| `Pending` | `"Pending"` |
|
||||
| `Running` | `"Running"` |
|
||||
| `Paused` | `"Paused"` |
|
||||
| `Completed` | `"Completed"` |
|
||||
| `Failed` | `"Failed"` |
|
||||
| `Cancelled` | `"Cancelled"` |
|
||||
|
||||
#### ProjectStatus (4 值)
|
||||
|
||||
| Rust | TypeScript |
|
||||
|------|-----------|
|
||||
| `Active` | `"Active"` |
|
||||
| `Paused` | `"Paused"` |
|
||||
| `Completed` | `"Completed"` |
|
||||
| `Archived` | `"Archived"` |
|
||||
|
||||
## 约定
|
||||
|
||||
1. 枚举值使用 PascalCase 字符串,前后端保持一致
|
||||
2. JSON 字段(如 `scores`、`tags`)在 Rust 侧用 `TEXT` 存储 JSON 字符串,前端解析为对象/数组
|
||||
3. 时间字段统一用 `i64` (Unix timestamp),前端用 `new Date(ts * 1000)` 转换
|
||||
4. 新增枚举值时,Rust 和 TypeScript 两侧必须同步更新
|
||||
148
docs/02-架构设计/构想审查/多主题上下文管理愿景-2026-06-19.md
Normal file
148
docs/02-架构设计/构想审查/多主题上下文管理愿景-2026-06-19.md
Normal file
@@ -0,0 +1,148 @@
|
||||
# 多主题上下文管理愿景
|
||||
|
||||
> 来源:用户架构愿景(2026-06-19)。未来方向,非近期实施。
|
||||
> 关联:[意图识别层论证](./意图识别层论证-2026-06-19.md)(主题检测前置) / F-15 上下文管理(基础已落地)
|
||||
|
||||
## 愿景
|
||||
|
||||
**无感多主题对话(交织并行)**:同一对话中多主题**交织并行**(A-B-A-B,非线性前 A 后 B 分段),系统自动识别主题归属 + 多主题上下文并存 + 交织路由,实现:
|
||||
- ✅ **省 token**:每主题独立摘要,非全历史(交织场景 A-B 混杂,主题隔离收益更大)
|
||||
- ✅ **提速**:短上下文(当前主题摘要),LLM 处理快
|
||||
- ✅ **提精准**:主题聚焦(B 噪声不干扰 A 处理),LLM 注意力集中,回复更准
|
||||
|
||||
### 场景(交织并行,用户深化)
|
||||
|
||||
```
|
||||
消息1 → 主题 A(新,如"处理 bug X")
|
||||
消息2 → 主题 B(新,A 仍活跃,如"加 feature Y")
|
||||
消息3 → 主题 A(补充,A-B 交织)
|
||||
消息4 → 主题 B(补充,A-B 并行)
|
||||
```
|
||||
|
||||
**关键**:多主题**同时活跃 + 交织**(非"前 A 段|后 B 段"线性,非"一主题完成才切")。主题数不定(2+)。
|
||||
|
||||
### 意图识别 = 核心前置(用户深化)
|
||||
|
||||
**多主题并存 → 每消息必须识别"归属哪个主题"**(否则无法路由:消息3 是 A 补充还是新主题 C?)。
|
||||
|
||||
- **意图识别**(输入意图/会话意图)= 多主题并存的**前置依赖**(每消息主题归属)
|
||||
- 多主题并存是意图识别的**核心应用场景**
|
||||
- 两者**绑定**:做多主题并存,必须先做意图识别
|
||||
- **触发条件调整**:多主题并存需求 = 意图识别的强触发(非仅图片/文档输入 或 工具>40)
|
||||
|
||||
## 与 F-09 多会话的关系(架构复用)
|
||||
|
||||
- **F-09 多会话**(已落地 d899c58)= **会话级隔离**(conv_id,`HashMap<conv_id, PerConvState>`)
|
||||
- **多主题并行** = **会话内主题级隔离**(topic = 轻量会话)
|
||||
- **架构复用**:F-09 per_conv 模式 → 会话内 topic 层级
|
||||
|
||||
```
|
||||
conv_id(会话)
|
||||
└─ topics: HashMap<topic_id, {messages, summary, last_active}>
|
||||
├─ topic A(消息1,3...)
|
||||
├─ topic B(消息2,4...)
|
||||
└─ ...
|
||||
```
|
||||
|
||||
**多主题 = F-09 多会话的"会话内"深化**(topic 级 per-conv)。PerConvState/ContextManager 隔离模式复用到 topic 层。
|
||||
|
||||
## 与现有架构关系
|
||||
|
||||
| 现有 | 现状 | 愿景进化 |
|
||||
|---|---|---|
|
||||
| **F-15 上下文管理**(分段 archived_segment / 压缩 compressed) | ✅ 已落地(commit 4194842 等),按 **token 阈值**(budget*0.6)触发压缩 | **主题感知**:按主题边界分段,非 token 阈值 |
|
||||
| **ContextManager**(context.rs) | 单摘要/单分段 | **多摘要并存**(每主题一份) |
|
||||
| **意图识别**(预留 coordinator/intent.rs) | 空白(近期不做) | **主题检测前置**(主题=意图维度;图片/文档输入时启动) |
|
||||
| **router**(模型路由) | 静态 weight | 主题/意图→模型(远期) |
|
||||
|
||||
## 多主题识别与摘要
|
||||
|
||||
### 主题切换检测
|
||||
- **embedding 相似度**:当前消息 vs 历史主题向量,相似度低于阈值 = 新主题
|
||||
- **LLM 分类**:fast model 判主题归属(准但延迟)
|
||||
- **关键词/规则**:主题关键词变化(快但弱)
|
||||
- **渐进**:规则→embedding→LLM(随规模升级)
|
||||
|
||||
### 每主题独立摘要
|
||||
- 主题段(主题边界内消息)→ LLM 摘要 → **多摘要并存**(ContextManager 扩展:HashMap<topic_id, summary>)
|
||||
- 复用 F-15 `compress_prompt` 四段式(意图/决策/文件/约束),按主题
|
||||
- 摘要触发:主题切换时(非 token 阈值)
|
||||
|
||||
### 上下文按主题分段
|
||||
- 当前:`build_eviction_units` 三元组(保护区 + 可压缩)
|
||||
- 愿景:主题边界分段(每主题一段,切换时归档前主题 + 摘要)
|
||||
|
||||
## 智能摘要切换
|
||||
|
||||
### 当前主题识别
|
||||
- 用户消息 → 归属主题(检测:延续当前主题 / 切换新主题 / 回到旧主题)
|
||||
|
||||
### 上下文路由(主题→摘要)
|
||||
- 当前主题摘要 + 关键历史(其他主题摘要压缩/可选展开)
|
||||
- 无感切换(用户不手动切,系统自动选摘要)
|
||||
|
||||
### 场景
|
||||
- 用户聊主题 A(代码)→ 切主题 B(闲聊)→ 回主题 A:系统保留 A 摘要,B 切换时归档,回 A 时恢复 A 摘要(非全历史 reload)
|
||||
|
||||
## 收益量化(预估)
|
||||
|
||||
- **省 token**:多主题对话,每主题摘要 ~500-1000 token,vs 全历史 ~5-10K token(累积),**降幅 80%+**(长对话多主题)
|
||||
- **提速**:短上下文(当前主题),LLM 首 token 快 + 处理快
|
||||
- **提精准**:主题聚焦,LLM 不被跨主题噪声干扰
|
||||
|
||||
## 可行性
|
||||
|
||||
| 组件 | 实现 | 基础 |
|
||||
|---|---|---|
|
||||
| 主题检测 | embedding/LLM/关键词 | 新增(intent.rs 扩展) |
|
||||
| 多主题摘要 | ContextManager 扩展(HashMap<topic, summary>) | F-15 压缩基础 |
|
||||
| 智能切换 | 上下文路由(topic→summary) | 新增 |
|
||||
| 持久化 | 每主题摘要落 DB | conversation 扩展 |
|
||||
|
||||
## 实现路径(远期,分阶段)
|
||||
|
||||
1. **主题检测**(规则/embedding):消息→主题标签
|
||||
2. **主题分段**:ContextManager 按主题边界分段(替代 token 阈值)
|
||||
3. **多主题摘要**:每主题 LLM 摘要 + HashMap 存
|
||||
4. **智能切换**:当前主题识别 + 摘要路由
|
||||
5. **持久化**:主题摘要落 DB(跨会话恢复)
|
||||
|
||||
## 风险评估(用户深化·误判代价不对称)
|
||||
|
||||
### 误判代价不对称(核心风险)
|
||||
- **不做多主题**(全历史 A-B 混杂):LLM 信息在,可能跑题但**用户可纠正**(信息未丢)
|
||||
- **多主题误判**(消息3[A 补充]误判为 B):路由 B 上下文 → LLM 用 B 回 A → **完全错位**(比全历史更糟,信息丢失)
|
||||
|
||||
**误判 > 不隔离代价**。意图识别准确性是**硬约束**(必须高准确,否则不如不做)。
|
||||
|
||||
### fallback 策略(前提,降误判代价)
|
||||
- **低置信度→全历史**:意图识别不确定时**不隔离**(安全降级,避免走偏)
|
||||
- **摘要并存**:即使误判 A/B 摘要都在,信息不丢(LLM 可选/用户纠正)
|
||||
- **用户显式纠正**:"这是 A 主题"→ 重新路由(手动 override)
|
||||
|
||||
### 复杂度 vs 收益 vs 准确性
|
||||
- **复杂度**(高):主题识别(意图瓶颈)+ 多主题上下文管理(HashMap/交织路由/摘要)+ 持久化
|
||||
- **收益**(中,长对话交织):省 token + 提精准
|
||||
- **准确性风险**(高):embedding/LLM 分类中文意图+交织主题挑战大,准确率不够→误判走偏→比不做更糟
|
||||
|
||||
## 结论(近期不值得,远期可行)
|
||||
|
||||
- **近期不值得**:复杂度高 + 意图准确性瓶颈 + 误判代价不对称 → ROI 低。F-15(token 阈值)+ F-09(多会话手动切)够用
|
||||
- **远期可行**:意图识别准确率有保障(技术成熟/数据积累)+ 长对话交织场景多时,**fallback 是前提**(低置信度降级全历史)
|
||||
|
||||
## 触发条件(何时做)
|
||||
|
||||
- 当前 F-15(token 阈值压缩)够用,多主题是**长对话多主题场景**优化
|
||||
- 触发:用户反馈长对话跨主题时上下文混乱 / token 成本高 / 回复跑题
|
||||
- 依赖:意图识别(主题检测)**准确率有保障 + fallback 健壮**(非仅预留就绪)
|
||||
|
||||
## 与意图识别关系
|
||||
|
||||
- **主题识别 = 意图识别的一种**(主题是意图维度:代码/闲聊/搜索/项目/...)
|
||||
- 意图识别预留(图片/文档输入时启动),主题摘要可**先于完整意图识别**(主题检测独立于模型路由)
|
||||
- 两者共享前置层(coordinator/intent.rs 落地)
|
||||
|
||||
## 备注
|
||||
|
||||
- 用户原话:「多主题识别与摘要 + 智能摘要切换 → 无感多主题对话 + 上下文压缩(省 token)+ 提速 + 提精准」
|
||||
- 这是**远期愿景**,近期 F-15(token 阈值)够用。触发条件达成时启动。
|
||||
60
docs/02-架构设计/构想审查/多主题并存补充论证-多轮模式-2026-06-19.md
Normal file
60
docs/02-架构设计/构想审查/多主题并存补充论证-多轮模式-2026-06-19.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# 多主题并存补充论证:多轮模式(agentic 意图识别)
|
||||
|
||||
> 来源:multitopic-analysis 子代理补充(IRCoT/ReAct/Reflexion/FLARE/AwN/ECLAIR/Copilot/Cursor 硬数据)+ 用户深化(多轮请求上下文 + 实体 NER + 异步预热 + 边界场景)。
|
||||
> 对原报告(多主题并存论证-2026-06-19.md)维度 2/3/4/6/8 的修正。纯论证,不改代码。
|
||||
|
||||
## 核心修正
|
||||
|
||||
**原报告**:准确率天花板是硬约束(SOTA 55.8/73%,不可绕过)。
|
||||
**修正**:agentic 多轮模式**确实能突破天花板**(硬数据支撑),准确率从被动分类 55.8/73% → 可能 85%+。
|
||||
|
||||
## 突破证据(SOTA 硬数据)
|
||||
|
||||
| 模式 | 增益 | 来源 |
|
||||
|---|---|---|
|
||||
| IRCoT(检索+CoT 交替) | QA F1 **+7~15** | ACL 2023 |
|
||||
| ReAct(推理+行动) | 准确率 **+30%** | NeurIPS 2022 |
|
||||
| Reflexion(反思修正) | pass@1 **91% vs 80%**(+11%) | NeurIPS 2023 |
|
||||
| Agentic RAG(多跳) | 34% → 89%(+55pp) | Medium |
|
||||
|
||||
## 但仍有约束(修正不改变近期结论)
|
||||
|
||||
1. **>90% 仍是硬线**:devflow 有副作用工具(销账/状态机/文件写),Reflexion 91% 是上限非保证,**须沙箱实测**(不能假设 devflow 场景达标)
|
||||
2. **增益对场景敏感**:FLARE 大场景仅 56.5%;简单请求多轮无收益反增延迟
|
||||
3. **边界场景 30-50% fallback 不变**:多轮不消除边界(模糊/跨主题/新主题),ROI 仍稀释
|
||||
4. **三重栈复杂度**:多轮编排 + 实体 NER + 异步预热 ~1300-1700 行 + 意图层先决(远期重投入)
|
||||
5. **异步预热解"慢"**(关键技术):Copilot(sub-200ms 日 4 亿次)/ Cursor(生产落地)证明可行,但实现复杂度最高(草稿预分析 + 就绪判断 + 取消/重试 + 状态隔离)
|
||||
6. **主动澄清 vs 无感张力**:业界范式(AwN/ECLAIR)倾向"低置信→主动问用户",违反"无感"愿景
|
||||
|
||||
## 修正后分阶段路径
|
||||
|
||||
```
|
||||
近期(0-3月):不做(原结论不变)
|
||||
- 多轮是有前景的远期方向,但当前技术栈不具备(意图层未落/异步预热未建/多轮未验证)
|
||||
|
||||
中期(3-12月,低风险试点,按 ROI 排序):
|
||||
1. 用户显式标主题(零误判)
|
||||
2. 意图识别层 intent.rs 工具级落地(独立ROI + 多主题先决)
|
||||
3. 半自动高门槛(embedding>95%才隔离,多轮暂不上)
|
||||
|
||||
远期(12+月,完整 agentic 多主题):
|
||||
技术栈:意图层(稳定) + 异步预热(解延迟) + 多轮编排(IRCoT/Reflexion) + 实体NER
|
||||
触发(全部满足):准确率实测>90% + 异步预热就绪 + 意图层稳定 + 真实痛点
|
||||
顺序锁定:意图层 → 异步预热 → 多轮+NER(不可颠倒)
|
||||
```
|
||||
|
||||
## 关键风险
|
||||
|
||||
- **不能假设 devflow 场景多轮一定达>90%**:Reflexion 91% 是受控 benchmark,devflow 交织主题 + 副作用工具更难,**必须沙箱实测**
|
||||
- **"继续"/"1"短指代消息**:全历史 LLM 天然消解(零逻辑,可靠);多主题下需路由(继承上一条主题),若上一条误判则错误传播
|
||||
|
||||
## Sources
|
||||
|
||||
- [IRCoT (ACL 2023)](https://aclanthology.org/2023.acl-long.557/)
|
||||
- [ReAct (NeurIPS 2022)](https://arxiv.org/abs/2210.03629)
|
||||
- [Reflexion (NeurIPS 2023)](https://arxiv.org/abs/2303.11366)
|
||||
- [FLARE 复测 56.5%](https://beancount.io/bean-labs/research-logs/2026/05/18/flare-active-retrieval-augmented-generation)
|
||||
- [AwN Learning to Ask](https://arxiv.org/html/2409.00557v3)
|
||||
- [ECLAIR (AAAI)](https://ojs.aaai.org/index.php/aaai/article/view/35152/37307)
|
||||
- [GitHub Copilot 工程](https://github.blog/ai-and-ml/github-copilot/the-road-to-better-completions-building-a-faster-smarter-github-copilot-with-a-new-custom-model/)
|
||||
- [Cursor + Fireworks](https://fireworks.ai/blog/cursor)
|
||||
72
docs/02-架构设计/构想审查/多主题并存论证-2026-06-19.md
Normal file
72
docs/02-架构设计/构想审查/多主题并存论证-2026-06-19.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# 多主题并存(交织并行)多角度论证
|
||||
|
||||
> 来源:multitopic-analysis 子代理 8 维度论证 + WebSearch SOTA 硬数据 + 业界产品派/学术派佐证。
|
||||
> 纯架构论证,不改代码。供架构决策。
|
||||
|
||||
## TL;DR
|
||||
|
||||
**近期不做自动多主题路由**。SOTA 准确率天花板(55.8/73%)远低>90% 硬阈值 + devflow 有副作用工具(误判不可逆) + 边界场景 30-50% 降级稀释 ROI + 业界零参照(头部产品全用物理隔离)。
|
||||
|
||||
## 核心结论(数据驱动)
|
||||
|
||||
### 1. 准确率天花板是硬约束(不可绕过)
|
||||
- **TopiOCQA F1 = 55.8**(最贴近 A-B-A-B 交织 SOTA,TACL 2022)→ 误判率 25-45%
|
||||
- **MultiWOZ DST JGA ≈ 73.6%**(受控,开放域更差)
|
||||
- devflow 硬阈值(有副作用工具):**需 >90-95%** 才值得做
|
||||
- **当前 SOTA 远低于阈值** → 自动路由不具备落地条件
|
||||
|
||||
### 2. 误判代价不对称(因 devflow 有副作用工具)
|
||||
- 不做多主题(全历史):信息冗余但**都在**,可逆
|
||||
- 多主题误判(消息3[A]误判 B):信息**错误路由**,LLM 用 B 回 A → **完全错位**
|
||||
- devflow 工具(销账/状态机/文件写)**不可逆** → 误判触发不可逆副作用,**比全历史更糟**
|
||||
|
||||
### 3. 业界零参照(头部产品全用物理隔离)
|
||||
- ChatGPT:Projects(用户手动分会话)
|
||||
- Claude/Claude Code:memory 按 Project 隔离
|
||||
- Cursor 2.0:子代理 + git worktree 物理隔离
|
||||
- Devin 2.0:拆任务到隔离 VM
|
||||
- Cline:Tasks 独立会话,跨 session 不传上下文
|
||||
- **无一做单会话内自动主题路由** → devflow 若做是先行者(高风险)
|
||||
|
||||
### 4. 边界场景频率致命稀释 ROI
|
||||
- 新主题/通用寒暄(15-25%)+ 模糊不能明确 A/B(10-15%)+ 跨主题对比(5-10%)= **30-50% 消息降级全历史**
|
||||
- 代价 100% 承担(复杂度+误判风险),收益只作用于 50-70% 消息 → **ROI 为负**
|
||||
|
||||
### 5. 长上下文不救场
|
||||
- **lost-in-the-middle**(Liu et al. TACL 2023,被引 4690+):长上下文 U 型退化
|
||||
- A-B-A-B 切回旧主题 A 时,A 历史信息可能落在"中间段"被遗忘 → 即使全历史也在,关键信息仍可能丢
|
||||
|
||||
## 分阶段路径
|
||||
|
||||
| 阶段 | 触发条件 | 动作 |
|
||||
|---|---|---|
|
||||
| **近期**(0-3月) | 现状(29工具,单provider,中短对话) | **不做**,F-09+F-15 够用,储备设计 |
|
||||
| **中期**(3-12月) | 用户主动反馈痛点 | 试点**显式标主题**(用户手动标,零误判)或**半自动 fallback**(高门槛>95%才隔离) |
|
||||
| **远期**(12+月) | 准确率>90% + 意图层稳定 + 真实痛点(三者齐备) | 完整自动多主题 + 强 fallback |
|
||||
|
||||
**中期试点原则**:**绝不直接上全自动路由**。优先"用户显式标主题"(零误判)或"半自动高门槛"(embedding>95% 才隔离,其余全历史)。
|
||||
|
||||
## fallback 是硬要求(任何阶段)
|
||||
|
||||
- **置信度必须**(低→全历史不隔离)
|
||||
- **业界范式**:Rasa/工业对话系统用"阈值+双层 fallback(OOS/低置信澄清)",非"自动全历史兜底"
|
||||
- "低置信→全历史"看似安全,实则(a)token 高 (b)放大 lost-in-the-middle (c)边界 30-50% 触发 → **多主题愿景在边界退化为不做多主题**
|
||||
|
||||
## 与 F-09 关系(架构可行但非瓶颈)
|
||||
|
||||
- F-09 多会话(已落地 d899c58)铺路 85%:per_conv/ContextManager/压缩/持久化可复用到 topic 层
|
||||
- 多主题 = F-09 的"会话内"深化(topic 级 per-conv),架构改动 ~650-800 行
|
||||
- **架构就绪 ≠ 值得做**:真正瓶颈是准确率天花板 + 误判代价,非架构
|
||||
|
||||
## Sources
|
||||
|
||||
- [TopiOCQA F1=55.8](https://direct.mit.edu/tacl/article/doi/10.1162/tacl_a_00471/110550/)
|
||||
- [MultiWOZ 2.4 JGA≈73.6%](https://github.com/smartyfh/multiwoz2.4)
|
||||
- [Lost in the Middle](https://arxiv.org/abs/2307.03172)
|
||||
- [RAG 错误不可逆](https://aclanthology.org/2026.eacl-long.147.pdf)
|
||||
- [Pinecone Less is More](https://www.pinecone.io/blog/why-use-retrieval-instead-of-larger-context/)
|
||||
- [Rasa Failing Gracefully](https://medium.com/rasa-blog/failing-gracefully-with-rasa-8ead6b43f2f4)
|
||||
- [Claude memory per-project](https://simonwillison.net/2025/Sep/12/claude-memory/)
|
||||
- [Cursor 2.0 parallel agents](https://medium.com/towards-data-engineering/parallel-ai-agents-in-cursor-2-0-a-practical-guide-e808f89cffb9)
|
||||
- [Devin Manage Devins](https://cognition.ai/blog/devin-can-now-manage-devins)
|
||||
- [Cline Tasks](https://docs.cline.bot/core-workflows/task-management)
|
||||
143
docs/02-架构设计/构想审查/对抗论证裁决报告-2026-06-12.md
Normal file
143
docs/02-架构设计/构想审查/对抗论证裁决报告-2026-06-12.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# DevFlow 对抗论证裁决报告
|
||||
|
||||
> 创建: 2026-06-11 | 方法: 三路对抗论证(市场/技术/需求) | 结论: 方向有价值,scope 必须砍
|
||||
|
||||
---
|
||||
|
||||
## 一、论证方法
|
||||
|
||||
用"魔法打败魔法":三个独立 AI 代理分别从不同立场攻击这个项目,互不可见,最后综合裁决。
|
||||
|
||||
| 代理 | 立场 | 综合评分 |
|
||||
|------|------|---------|
|
||||
| 市场分析师 | 竞品全景 + 市场数据(带外部信源) | **4/10 — 不建议以当前形态推进** |
|
||||
| 技术架构师 | 13 crate(2026-06-12 评审时数;2026-06-14 删 5 僵尸 crate,现 8)/ Tauri / 引擎 / AI 可行性 | **2.7/5 — 可行但必须砍 scope** |
|
||||
| 恶魔代言人 | 逐功能质疑需求真实性 | **核心成立,60% 功能该砍** |
|
||||
|
||||
---
|
||||
|
||||
## 二、三方共识(站不住脚的地方)
|
||||
|
||||
### 共识 1:🔴 Scope 失控是最大风险
|
||||
|
||||
- 8 个核心功能横跨 4-5 个产品类别(PM + 工作流 + AI 编排 + 代码分析 + 知识库)
|
||||
- 22,745 字架构文档、16 张表、13 crate(评审时点数;2026-06-14 裁定为 8 crate)—— **这是操作系统的野心,不是 MVP 的规划**
|
||||
- 现实工时:v1.0 全功能需全职 8-12 个月 / 业余 1.5-2 年
|
||||
- 历史教训:Firebase/Heroku/全生命周期 API 平台都被"组件化组合"打败
|
||||
|
||||
### 共识 2:🔴 身份危机 — 无法一句话说清
|
||||
|
||||
- Cursor = "AI 编辑器",Linear = "快的 issue 追踪器",DevFlow = ?
|
||||
- "全流程"不是定位,是定位的缺失
|
||||
|
||||
### 共识 3:🔴 部分功能是伪需求(对个人开发者)
|
||||
|
||||
| 功能 | 需求方评分 | 市场方评分 | 裁决 |
|
||||
|------|-----------|-----------|------|
|
||||
| 插件系统 (WASM) | 1/5 | — | **砍掉**(为 0 个用户设计生态) |
|
||||
| 经验进化(自动沉淀) | 1/5 | 3/10 | **砍掉**(技术上无法落地,连骨架都是空的) |
|
||||
| 需求-测试追溯 | 1/5 | — | **砍掉**(企业需求硬塞给个人) |
|
||||
| 多模型路由 + Agent 协作 | — | 4/10 | **砍掉**(OpenClaw/大厂赛道,无法竞争) |
|
||||
| 想法池(完整版) | 2/5 | 2/10 | **降级**(简化为列表+对抗式评估) |
|
||||
| 决策留痕(独立子系统) | 2/5 | 4/10 | **降级**(字段级方案,不建独立体系) |
|
||||
|
||||
### 共识 4:🟡 AI 信任危机的时代背景
|
||||
|
||||
- Stack Overflow 2025:开发者对 AI 信任度从 40% 跌至 29%
|
||||
- 66% 开发者花更多时间修复 AI 的"差不多对"代码
|
||||
- **定位必须从"AI 帮你做事"转向"AI 帮你控制流程"**——AI 是副驾驶,不是自动驾驶
|
||||
|
||||
---
|
||||
|
||||
## 三、三方冲突点的调和
|
||||
|
||||
### 冲突 1:DAG 工作流引擎
|
||||
|
||||
- 需求方:**5/5 必须有**(产品的灵魂,本地工作流有空白)
|
||||
- 市场方:**2/10 伪需求**(GitHub Actions 已免费解决)
|
||||
|
||||
**裁决**:两者都对,但说的是不同的东西。
|
||||
- GitHub Actions 解决的是 **仓库内 CI/CD**(push 触发、云端跑)
|
||||
- DevFlow 的空隙是 **本地的、跨项目的、AI 参与的交互式流程**(不依赖 push、可以有人工审批节点、能调用本地资源)
|
||||
- **保留 DAG 引擎,但作为内部基础设施,不作为对外卖点**。用户看到的是"一键执行编码→审查→测试流程",而不是"DAG 编辑器"
|
||||
|
||||
### 冲突 2:标注系统
|
||||
|
||||
- 需求方:**1/5 砍掉**(IDE 已解决)
|
||||
- 市场方:**6.5/10 全场最高差异化机会**("扫描代码库 FIXME/TODO → AI 批量处理 → 关联任务"是真空地带)
|
||||
|
||||
**裁决**:需求方批的是"在文档/测试报告上加标注"的重模式(确实没人用);市场方挺的是"代码库 TODO 扫描器 + AI 处理"的轻模式。
|
||||
- **采用轻模式**:扫描代码 TODO/FIXME → 汇总 → AI 生成处理建议 → 一键转任务
|
||||
- 砍掉"任意实体标注"的重设计
|
||||
|
||||
---
|
||||
|
||||
## 四、站得住脚的部分
|
||||
|
||||
1. **本地优先** — Obsidian 证明了本地优先工具有大市场,订阅疲劳(52% 用户因此退订)反推一次性付费
|
||||
2. **Tauri 技术栈** — 比 Electron 小 96%,选型正确(4/5)
|
||||
3. **引擎代码质量** — 拓扑排序算法正确、trait 设计合理、依赖树无环
|
||||
4. **任务绑 Git 分支** — 6/10,最有价值的业务功能,做深"任务→分支→提交→合并→关单"全链路有空间
|
||||
5. **对抗式想法评估** — 这是本次论证方法本身的产品化,市场上没有工具这么做
|
||||
|
||||
---
|
||||
|
||||
## 五、调整方案
|
||||
|
||||
### 5.1 产品定位调整
|
||||
|
||||
**旧**:AI 原生的产研操作系统,从想法到上线的全流程编排(❌ 无法一句话说清)
|
||||
|
||||
**新**:**本地优先的个人开发流程驾驶舱 — 把想法、任务、分支和 AI 流程放进一个不联网也能跑的桌面应用**
|
||||
|
||||
一句话版本:「你的项目流程,本地跑,AI 辅助,数据不出门」
|
||||
|
||||
### 5.2 功能调整清单
|
||||
|
||||
| 功能 | 原计划 | 调整后 |
|
||||
|------|--------|--------|
|
||||
| DAG 工作流引擎 | 对外核心卖点 | ✅ 保留为内部引擎,UI 上呈现为"流程模板一键执行" |
|
||||
| 任务+分支 | 一般功能 | ✅ **升级为核心**:任务→分支→工作流→合并全链路 |
|
||||
| 想法池 | 完整漏斗系统 | ⬇️ 简化:列表 + **对抗式评估**(正方/反方/分析师三路论证,差异化卖点) |
|
||||
| 标注系统 | 任意实体标注 | ⬇️ 简化:代码库 TODO/FIXME 扫描器 + AI 批处理 |
|
||||
| 决策留痕 | 独立子系统 | ⬇️ 降级:关键操作自动写决策字段,无独立 UI |
|
||||
| AI 编排 | 多模型路由+四 Agent | ⬇️ 砍:单 Provider (Claude) + AI 节点,无 Agent 协作 |
|
||||
| 阶段插件 | 5 阶段 | ⬇️ 3 个内置流程模板(编码/测试/发布) |
|
||||
| 8 种节点 | 全部实现 | ⬇️ Phase 1 只做 Shell/AI/Subflow,Git 用 Shell 调 CLI |
|
||||
| 需求-测试追溯 | 完整体系 | ❌ 砍掉(v2.0 团队版再说) |
|
||||
| 经验进化 | 自动沉淀引擎 | ❌ 砍掉(降为手动 Snippet 收藏,Phase 5 再议) |
|
||||
| 插件系统 | WASM/动态加载 | ❌ 砍掉(v2.0 再说) |
|
||||
|
||||
**砍掉比例:约 60%,与三方建议一致。**
|
||||
|
||||
### 5.3 架构调整
|
||||
|
||||
- **13 crate 保留目录结构**(评审时点;2026-06-14 裁定删除 5 个僵尸 crate df-evolve/df-plugin/df-stages/df-task/df-traceability,现实际 8 crate),但 Phase 1 只激活 6 个:
|
||||
`df-core / df-workflow / df-storage / df-execute / df-nodes / src-tauri`
|
||||
- 其余 7 个 crate 标记为 `[预留]`,从 workspace 默认构建中保留但不再投入开发
|
||||
- Git 操作走 Shell CLI,不引入 libgit2(技术报告建议,省 1-2 周)
|
||||
|
||||
### 5.4 Phase 重排
|
||||
|
||||
| Phase | 旧目标 | 新目标 |
|
||||
|-------|--------|--------|
|
||||
| 1 | 引擎骨架(含一切基础) | **跑通一条 Shell→AI→Shell 工作流 + 任务/分支 CRUD + 前端真数据** |
|
||||
| 2 | AI 集成(多模型) | Claude 单 Provider + AI 节点 + 想法对抗式评估 |
|
||||
| 3 | 想法池+多项目 | TODO 扫描器 + 3 个流程模板 |
|
||||
| 4 | 节点丰富+阶段插件 | 任务→分支→合并全链路(Git 深度集成) |
|
||||
| 5 | 体验打磨 v1.0 | 打磨 + 自用验证 3 个月 → 决定是否对外 |
|
||||
|
||||
### 5.5 验证策略调整
|
||||
|
||||
市场报告的最重要建议:**先验证再深投**。
|
||||
- DevFlow 首先是**自用工具**(管理 wk-* 工作空间的真实项目)
|
||||
- 自用 3 个月,记录每天真实打开次数
|
||||
- 如果自己都不用,停止投入;如果离不开它,再考虑对外
|
||||
|
||||
---
|
||||
|
||||
## 六、裁决结论
|
||||
|
||||
> **方向有价值,形态要收敛。** "本地优先 + 任务分支驱动 + AI 辅助流程"是真空隙;"全流程操作系统"是幻觉。砍掉 60% 的功能不是失败,是论证的胜利——它们本来会消耗 6-9 个月却没人用。
|
||||
>
|
||||
> 同时,本次论证方法本身(三路对抗)被产品化为想法池的"对抗式评估"功能,详见 `docs/03-模块文档/想法探索-对抗式评估-2026-06-12.md`。这是 DevFlow 吃自己的狗粮的第一个案例。
|
||||
129
docs/02-架构设计/构想审查/工作流审批审查报告-2026-06-14.md
Normal file
129
docs/02-架构设计/构想审查/工作流审批审查报告-2026-06-14.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# 工作流审批子系统对抗审查报告
|
||||
|
||||
> 2026-06-14 · 多代理审查(31 agents / 5 维度 × 对抗验证) + 主代理独立复核 + 二轮对抗论证
|
||||
> 范围: df-workflow/{executor,state,eventbus}.rs · df-nodes/human_node.rs · df-core/events.rs · src-tauri/{commands/workflow,state}.rs · src/stores/project.ts · src/api/{types,workflow}.ts · src/views/ProjectDetail.vue
|
||||
> 方法: workflow fan-out 审查 → 每发现独立对抗验证(默认反驳) → 主代理读源码复核 criticals → 二轮对抗论证(存在性/可达性/危害三维)
|
||||
|
||||
## TL;DR
|
||||
|
||||
1. **头号 bug [P0 阻断]**: `human_node.rs:41` 发 `HumanApprovalRequest` 缺 `.await`。`EventBus::send` 是 async fn,`let _ = async_fn()` 丢弃 Future 未 poll → body 不执行 → **Request 从未进入 channel**。审批链最上游断裂。
|
||||
2. **①②(前端契约失配) 被头号遮蔽**: Request 没发 → 前端 `onEvent` 收不到 → type 匹配分支不可达。修 41 行后 ①② 才显形为 critical。
|
||||
3. **当前 UI 无 human 节点 DAG 入口**: `demoDag` 仅 script 节点;AI 工具 `run_workflow` 返回提示不执行。审批相关 9 项发现现实触发率=0,全部潜伏。
|
||||
4. **根因**: 审批功能前端从未端到端跑通(41 行 await 漏掉即铁证),单测绿但不覆盖 human→前端弹窗→审批→返回链路。
|
||||
|
||||
---
|
||||
|
||||
## 0. 头号发现 [P0]
|
||||
|
||||
### 0.1 缺陷定位
|
||||
|
||||
`crates/df-nodes/src/human_node.rs:41-47`
|
||||
```rust
|
||||
let _ = ctx.event_bus.send(WorkflowEvent::HumanApprovalRequest {
|
||||
execution_id: ctx.execution_id.clone(),
|
||||
node_id: ctx.node_id.clone(),
|
||||
title: title.to_string(),
|
||||
description: description.to_string(),
|
||||
options: options.clone(),
|
||||
}); // ← 无 .await
|
||||
```
|
||||
|
||||
### 0.2 机制
|
||||
|
||||
- `EventBus::send` 签名 (`eventbus.rs:33`): `pub async fn send(&self, event: WorkflowEvent)` — async fn。
|
||||
- `let _ = async_fn()` 求值得 Future,绑定 `_` 后语句结束立即 drop,**Future 零 poll**。
|
||||
- async fn body (`self.sender.send(event)`) 仅在 Future 被 poll 时执行 → 此处永不执行 → Request 未进 broadcast channel。
|
||||
|
||||
### 0.3 对抗自检(排除假阳)
|
||||
|
||||
| 质疑 | 核实 |
|
||||
|------|------|
|
||||
| 测试为何 pass? | `normal_approval_returns_decision` 的 helper `send_response` 用 `send(...).await`(`human_node.rs:172` 有 await) 发的是 **Response**;HumanNode 的 Request 那行没 await。测试只断言 Response 被 rx 收到并返回 decision,**不验证 Request 是否发出**。绿测不能证伪。 |
|
||||
| 编译器为何不报? | `let _ = expr` 合法通配符绑定;async fn 生成的 Future 默认无 `#[must_use]`,零 warning。 |
|
||||
| 是否误用同步 fn? | `eventbus.rs:44` `emit_human_approval_request` 是同步 fn(返 Result),但 HumanNode 未用它,用的是 async `send`。 |
|
||||
| 多代理为何漏? | 审查聚焦前端契约(①②)与串扰(③),未逐行核 HumanNode 内 send 调用点是否 await。主代理二轮读 human_node.rs 全文才发现。 |
|
||||
|
||||
### 0.4 触发路径
|
||||
|
||||
`human_node.rs:38 subscribe → :41 send(无await)` → Request 未发 → `workflow.rs` 转发任务 rx 收不到 → 前端 `onEvent` 不触发 `HumanApprovalRequest` 分支 → `pendingApproval` 恒 null → 弹窗不开 → HumanNode `select!` 阻塞至 `:86 sleep_until(deadline)` 默认 3600s 超时 → Err → 工作流 failed。
|
||||
|
||||
### 0.5 修复
|
||||
|
||||
```diff
|
||||
- let _ = ctx.event_bus.send(WorkflowEvent::HumanApprovalRequest { ... });
|
||||
+ ctx.event_bus.send(WorkflowEvent::HumanApprovalRequest { ... }).await;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. 反转结论
|
||||
|
||||
### 1.1 ①② 被头号遮蔽(降级: 当前不可达)
|
||||
|
||||
- ① `project.ts:214` `payload.event?.type === 'HumanApprovalRequest'`(大驼峰)vs 后端 `events.rs:18` `#[serde(tag="type", rename_all="snake_case")]` → 序列化值 `'human_approval_request'`,永不匹配。
|
||||
- ② `project.ts:215` `payload.event.data` —— event 是 `WorkflowEvent` 本体扁平结构(`{type, execution_id, node_id, title, description, options}`),无 `data` 包装层 → undefined。
|
||||
- 两者代码层面确凿,但 Request 未发(§0 遮蔽) → 前端收不到事件 → 分支不可达。**修 41 行后 ①② 立即变 critical**。
|
||||
|
||||
### 1.2 当前 UI 无 human 节点入口(多数发现现实触发率=0)
|
||||
|
||||
| 证据 | 位置 |
|
||||
|------|------|
|
||||
| 前端唯一 DAG = demoDag,仅 3 个 script 节点 | `ProjectDetail.vue:271-273` |
|
||||
| AI 工具 run_workflow 返回提示不执行 DAG | `tool_registry.rs:346-350` |
|
||||
| runDemoWorkflow 按钮 disabled=workflowRunning 防重入 | `ProjectDetail.vue:281-289` |
|
||||
|
||||
→ 审批相关发现(①②④⑤⑦⑧⑨⑩)全部潜伏在未接入路径。
|
||||
|
||||
---
|
||||
|
||||
## 2. 逐条对抗裁定
|
||||
|
||||
| # | 定位 | 存在性(代码层) | 现实可达性 | 危害校正 | 裁定 |
|
||||
|---|------|---------------|-----------|---------|------|
|
||||
| **0** | human_node.rs:41 | 确凿 缺await | human DAG 运行即必现,UI 无入口 | Request 不发,链最上游断 | **真·潜伏头号 P0** |
|
||||
| ① | project.ts:214 | 确凿 snake_case | 被0遮蔽+无human入口 | 潜伏,修0后才显形 | 降级: 当前不可达 |
|
||||
| ② | project.ts:215 | 确凿 flat无data | 同① 双重遮蔽 | 潜伏 | 降级: 同① |
|
||||
| ③ | workflow.rs:67-97 | 确凿 全局bus+Node*无exec_id+matches!只看变体 | 需并发工作流,UI防重入+AI不执行 | 审批路由不坏(Request自带exec_id),仅日志串扰+提前break | 真实架构缺陷,现实触发0;危害被夸大 |
|
||||
| ④ | project.ts:15-21 | 确凿 单槽 | 三重遮蔽(0+无入口+单流) | 潜伏 | 真实,潜伏 |
|
||||
| ⑤ | project.ts:208-261 | 确凿 无终态监听 | 同④;"稍后"按钮可视觉关 | UX退化非卡死 | 真实,危害偏低 |
|
||||
| ⑥ | state.rs:106 | 确凿 直接insert | 需⑦竞态命中 | snapshot()零调用方(死代码),DB不受影响 | **真实但无害** |
|
||||
| ⑦ | project.ts:228 | 确凿 无互斥 | 需0+①②+入口全通+双击+500ms窗口 | 窄窗口 | 真实,潜伏 |
|
||||
| ⑧ | workflow.rs:171 | 确凿 无校验(对比cancel有registry守卫) | 需human+超时窗口 | 诊断损失非功能损坏 | 真实,潜伏 |
|
||||
| ⑨ | human_node.rs:73-81 | 确凿 warn+continue | 需256积压;当前无节点发NodeProgress,每节点≤2事件,需128+并发节点 | 概率近0 | 真实,当前不可达 |
|
||||
| ⑩ | workflow.rs:91-97 | 确凿 Lagged+Closed死代码(bus持于AppState全程) | 同⑨ 需256积压 | DB终态仍正确,仅task泄漏 | 真实,当前不可达 |
|
||||
| ⑪ | workflow.rs:140 | 确凿 String::new() | demoDag失败即触发 | 低危: error字段含first_err.context"节点X失败",failed_node冗余空 | **真实且当前可达,危害低** |
|
||||
|
||||
---
|
||||
|
||||
## 3. 根因
|
||||
|
||||
审批功能前端从未端到端验证。证据链:
|
||||
|
||||
1. `B-260614-03a` 重写 HumanNode `execute`(subscribe→send→select!) 时引入 `:41` await 缺失,7 单测全绿未抓(单测不覆盖 Request 发出)。
|
||||
2. 前端无 human 节点 DAG 入口,无任何集成测试覆盖 human→弹窗→审批→返回链路。
|
||||
3. ①② 是前后端契约层断裂,`types.ts:127` `event.type: string` 弱类型无编译期拦截。
|
||||
|
||||
→ 单测绿 + 无端到端测试 = 这批潜伏 bug 的存活土壤。
|
||||
|
||||
---
|
||||
|
||||
## 4. 修复优先级
|
||||
|
||||
| 序 | 动作 | 优先级 | 依赖 | 会暴露 |
|
||||
|---|------|--------|------|--------|
|
||||
| 1 | 补 human 节点端到端集成测试(含human的DAG→运行→断言前端收到Request+弹窗开) | P0 | 无 | 0+①+② |
|
||||
| 2 | human_node.rs:41 加 .await | P0 | 测试暴露后修 | — |
|
||||
| 3 | project.ts:214 type→snake_case; :215 取 event 本体字段; types.ts event.type 收窄字面量联合 | P0(修2后) | 2 | — |
|
||||
| 4 | ③ Node*事件补 execution_id + 转发过滤 | P2 | 并发工作流时 | — |
|
||||
| 5 | ④⑤ pendingApproval 改 Map + 终态清空 | P2 | 2③后 | — |
|
||||
| 6 | ⑥ set_cancelled 查终态 no-op | P3 | 无(无消费者零危害) | — |
|
||||
| 7 | ⑦⑧⑨⑩⑪ | P2-P3 | 见§2 | — |
|
||||
|
||||
---
|
||||
|
||||
## 附: 多代理 workflow 元数据
|
||||
|
||||
- 31 agents / 5 维度(concurrency / state-machine / error-handling / lifecycle / frontend-contract) × 对抗验证
|
||||
- 26 原始发现 → 12 确认 / 11 反驳 / 3 验证代理因 API 限流未跑(主代理手动补判)
|
||||
- 验证阶段正确识别 `executor.rs:124` 三条为 not-a-bug(B-03b-R1 已修,`:127` 有 is_cancelled guard + test_cancelled_node_skips_set_failed)
|
||||
- 漏抓头号(§0): 因未核 send await,主代理二轮复核补
|
||||
106
docs/02-架构设计/构想审查/意图识别层论证-2026-06-19.md
Normal file
106
docs/02-架构设计/构想审查/意图识别层论证-2026-06-19.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# 意图识别层(通用前置)多角度论证
|
||||
|
||||
> 来源:intent-analysis 子代理 8 维度论证 + WebSearch 10 业界佐证 + devflow 源码核验。
|
||||
> 纯架构论证,不改代码。供架构决策。
|
||||
|
||||
## 核心结论
|
||||
|
||||
1. **方向正确**:意图识别作为通用前置层(每消息),服务四下游(工具预选/模型路由/上下文策略/审批预估)——业界共识(TianPan/NVIDIA/LangChain 佐证),用户洞察准确。
|
||||
2. **当前不急**:devflow 29 工具处于业界"产品派不做意图层"临界点(Claude Code <20 工具不分类 / OpenAI 原生 tool_choice 非前置),痛点不致命(未到 417 工具崩 20% 线)。
|
||||
3. **近期建议**:精简工具描述降 token(零架构改动,立即可做)。
|
||||
4. **中期触发**(工具>40 或多模型用户):上**方式 A 规则**(零延迟零成本纯赚),落 `intent.rs` + tool domain 标签。
|
||||
5. **远期升级**(工具>80 或 MCP):**方式 D 两阶段**(规则兜底 + Flash 分类),警惕 Tool RAG 生产退化(《340 Tools》反例)。
|
||||
6. **落地约束**:意图层只在 `agentic/mod.rs` loop 入口生效一次,不进 loop 体;输出"子集扩充+模型建议"非"硬性裁剪";None fallback 全量零回归。
|
||||
7. **架构兼容**:与双轨/审计/provider 工厂三高杠杆零冲突;`coordinator.rs` 空壳保留 B 路线多 Agent,意图层独立落 `intent.rs`。
|
||||
|
||||
## 痛点量化(现状)
|
||||
|
||||
- **工具全量下发**:`agentic/mod.rs:423 tool_definitions()` 全 29 工具 schema 每消息塞 request,~6000-8000 token/消息(中位估算)。
|
||||
- **模型路由静态化**:`router.rs:56-63` TaskRequirements 硬编码 needs_tool_use=true/modalities=[Text],闲聊和写代码走同模型。
|
||||
- **coordinator.rs 空壳**:B 路线占位(L5-30),意图识别无落脚点。
|
||||
- **上下文策略纯阈值**:`agentic/mod.rs:513-641` 自动压缩按 token>budget*0.6,不按意图。
|
||||
|
||||
## 实现方式对比
|
||||
|
||||
| 方式 | 延迟 | token | 准确 | 推荐 |
|
||||
|---|---|---|---|---|
|
||||
| A.规则/关键词 | <1ms | 0 | 中(中文意图,覆盖70%+) | ⭐ 近期 |
|
||||
| B.embedding | 10-50ms | 0+1次embedding | 中 | ✗ ROI低(单用户桌面) |
|
||||
| C.fast model | 300-800ms | ~200-500 | 高 | 中期补(盈亏工具>40+多模型) |
|
||||
| D.两阶段(A+C) | 混合 | 混合 | 高 | ⭐ 远期 |
|
||||
|
||||
## 收益量化(方式 A 规则,中期)
|
||||
|
||||
- 工具子集降 token:29→8-12 子集,**省 4000-5000 token/消息,降幅 60%**。
|
||||
- 模型路由省成本:60% 闲聊→Flash(¥0.0014/M)/ 40% 工具→Plus(¥5/M),**混合均价降 60%**(多模型用户)。
|
||||
- 决策准确:工具数 <10 时 LLM 选错概率显著降(反推 417→20% 数据)。
|
||||
- 审批预估前置:前端预判 High 风险,提前提示。
|
||||
|
||||
## 盈亏平衡(方式 C fast model)
|
||||
|
||||
| 维度 | 阈值 | devflow 现状 | 值得上 C? |
|
||||
|---|---|---|---|
|
||||
| 工具数 | >40 | 29 | 临界,即将 |
|
||||
| 多模型 | 用户配 Flash+Plus | 多数单 provider | 多数无收益 |
|
||||
| 延迟容忍 | 接受 +500ms 首字 | 流式敏感 | 负面 |
|
||||
|
||||
**结论**:方式 A 规则零成本纯赚(近期可上);方式 C 盈亏在"工具>40 且多模型"之后。
|
||||
|
||||
## 风险 + fallback
|
||||
|
||||
| 风险 | 缓解 |
|
||||
|---|---|
|
||||
| 意图误判(漏工具) | **子集扩充非裁剪**(project+file 兜底,18 工具仍<29) |
|
||||
| 单点故障 | None fallback 全量工具(零回归) |
|
||||
| 延迟敏感 | 方式 A 无延迟;C 需并行/异步预热 |
|
||||
| Flash 超时/非法 | fallback 全量/规则结果 |
|
||||
|
||||
**关键设计原则**:意图层是"加权推荐"非"硬性裁剪";None 时全量(现状)零回归。
|
||||
|
||||
## 业界佐证(WebSearch 10 来源)
|
||||
|
||||
**学术/框架派**(主张前置意图层):
|
||||
- TianPan《Intent Classification Layer》(417 工具崩 20%,论证需专用前置层)
|
||||
- NVIDIA AIQ《Intent Classifier》(单次 LLM 多输出:意图+元响应+判定)
|
||||
- Medium《Intent-to-Action Layer》(prompt→intent→structure→policy→route→tools→execution)
|
||||
- LangChain《Context Engineering》(RAG 工具描述,只发相关工具)
|
||||
- Red Hat《Tool RAG》(企业级工具扩展解法)
|
||||
|
||||
**产品派**(工具可控时不做前置):
|
||||
- OpenAI function calling(tool_choice 是"约束"非"前置分类",意图责任留开发者)
|
||||
- Claude Code 子代理(任务级路由,非消息级;<20 核心工具不做意图层)
|
||||
|
||||
**反例(警惕)**:《OpenAI 340 Tools 生产案例》——语义工具选择初期有效但准确率随时间退化,需持续监控。
|
||||
|
||||
**定价**:智谱 GLM Plus ¥5/M vs Flash ¥0.0014/M(500倍差,意图路由省钱空间)。
|
||||
|
||||
## devflow 整合(改动面)
|
||||
|
||||
| 模块 | 现状 | 接入点 | 改动 |
|
||||
|---|---|---|---|
|
||||
| coordinator.rs | B 路线空壳 | 保留(多Agent) | 不动 |
|
||||
| **intent.rs**(新增) | — | 意图识别落点 | ~200 行(规则引擎+Intent 枚举) |
|
||||
| tool_registry.rs | tool_definitions() 全量 | 加 tool_definitions_subset(intent) + 工具 domain 标签 | ~50 行 + 29 register 加 domain |
|
||||
| agentic/mod.rs | loop 外 tool_defs | loop 入口插意图识别 | ~30 行(入口加调用) |
|
||||
| router.rs | 静态 TaskRequirements | 意图→TaskRequirements 构造 | agentic 构造点改,router 不动 |
|
||||
|
||||
**总计 ~300-400 行,中等改动**。与双轨/审计/provider 工厂零冲突。
|
||||
|
||||
## 分阶段路径(触发条件)
|
||||
|
||||
```
|
||||
近期(29工具,单provider):精简工具描述(零架构),储备设计(本文档)
|
||||
中期(工具>40 或多模型):方式A规则(intent.rs + domain标签 + subset + 模型路由)
|
||||
远期(工具>80 或MCP):方式D两阶段(A规则兜底+C Flash分类),警惕Tool RAG退化
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
- [TianPan Intent Classification](https://tianpan.co/blog/2026-04-16-intent-classification-agent-routers)
|
||||
- [NVIDIA AIQ Intent Classifier](https://docs.nvidia.com/aiq-blueprint/2.0.0/architecture/agents/intent-classifier.html)
|
||||
- [LangChain Context Engineering](https://www.langchain.com/blog/context-engineering-for-agents)
|
||||
- [Red Hat Tool RAG](https://next.redhat.com/2025/11/26/tool-rag-the-next-breakthrough-in-scalable-ai-agents/)
|
||||
- [OpenAI 340 Tools 反例](https://pub.towardsai.net/openai-function-calling-works-great-until-you-have-340-tools-12-tenants-real-production-traffic-fe02da116e39)
|
||||
- [Claude Code Subagents](https://www.builder.io/blog/claude-code-subagents)
|
||||
- [OpenAI Function Calling](https://developers.openai.com/api/docs/guides/function-calling)
|
||||
- [智谱定价](https://open.bigmodel.cn/pricing)
|
||||
Reference in New Issue
Block a user