文档: 项目详情页走查(60项) + aichat效率走查(74项,含LLM缓存命中率核心发现)登记
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
# aichat 运行效率走查报告(多角度)
|
||||
|
||||
> 走查日期:2026-08-09
|
||||
> 范围:aichat 前后端全链路(后端 agentic 2910 行 + audit + tools + 流式;前端 composables/ai + MessageList/ChatInput/TopBar)
|
||||
> 方法:6 路并行 Explore agent(单轮成本/工具执行/流式渲染/前端交互/会话生命周期/LLM成本)
|
||||
> 性质:**只走查登记,不实施代码**
|
||||
> 触发:用户反馈「aichat 运行的效率很低」+「成本走查,比如有的 LLM 要求的缓存命中率规则」
|
||||
|
||||
---
|
||||
|
||||
## 一、单轮执行成本(13 项)
|
||||
|
||||
### P1
|
||||
- **R1-1 每轮全量历史重放,无增量**(context/mod.rs:184-253 + agentic:1492-1527)——第 k 轮 prompt≈Σ历史,R 轮总 input≈O(R²);追加尾部的每轮新 tool_result 是必然 cache miss
|
||||
- **R1-2 上一轮已见工具结果本轮仍全量重放**(summarize_tool_results view-only,:1540-1551)——grep/search 的 `matches:[]` 每轮重复
|
||||
- **R1-3 自动压缩阈值过惰性**(context_lifecycle.rs:88-95,>61K token 才触发)——普通会话永不压缩,全量重放无兜底
|
||||
|
||||
### P2
|
||||
- **R2-1 每轮 ≥4 次全历史深克隆**(build_for_request + save + count_recent_failures + check_stall_breaker,2 次持 session 锁)
|
||||
- **R2-2 每轮必 save_conversation**(全量 clone + truncate_for_persist + 序列化 + DB 元数据重写)
|
||||
- **R2-3 estimated_prompt 每轮全量重估 token**(与 history_tokens 增量维护重复)
|
||||
|
||||
### P3
|
||||
R3-1 重试/候选切换全量 to_vec clone · R3-2 summarize 对未变化历史每轮重算 · R3-3 system_prompt 每轮整体克隆(未打 cache_control 断点)· R3-4 build_system_prompt 每次 loop/resume 查库(list_active×2)· R3-5 每轮重建 provider + keyring 解析 · R3-6 process_tool_calls 每工具全量扫历史 · R3-7 无 token 预算型终止(空转到 10 轮)
|
||||
|
||||
---
|
||||
|
||||
## 二、工具执行开销(9 项)
|
||||
|
||||
### P1
|
||||
- **T1-1 审计每工具 ≥1 次串行 INSERT**(audit/mod.rs:684-721,全经单全局 DB 锁,无批量)——单轮 N 工具 = N 次 INSERT,join_all 后的串行尾巴
|
||||
- **T1-2 只读缓存是"假缓存"**(cache.rs:251-330)——每工具全量扫历史 + 1 次 DB SELECT,非 O(1) 索引;miss 代价>收益
|
||||
- **T1-3 git 工具不进只读缓存**(git.rs:99-133,每轮跑子进程;module.rs 5s git 缓存不共享)——LLM 失忆重调 git 完全没被治
|
||||
- **T1-4 每轮对完整历史重处理**(build_for_request + summarize + estimated_prompt + 2 次全量 clone)
|
||||
|
||||
### P2
|
||||
- **T2-1 审批/授权每 Med/High 工具最多 3 次 DB 往返 + 全量历史扫**(auto_exec_mode 等低频配置每轮查库)
|
||||
- **T2-2 read_file/read_symbol 每次全量读文件(≤1MB)**(分段读也全读,offset 不同缓存 miss)
|
||||
- **T2-3 缓存命中把全量内容直接 push messages(不 namespace)+ 审计落全量** → 缓存反放大历史
|
||||
- **T2-4 entity_resolve 每工具 clone args + 每工具一次 list_active 全表查询**
|
||||
|
||||
### P3
|
||||
T3-1 工具事件双写 + 每工具一个心跳 task
|
||||
|
||||
---
|
||||
|
||||
## 三、流式渲染效率(12 项)
|
||||
|
||||
### P1
|
||||
- **S1-1 每帧全量 lexer + 单块回复整段重 parse,块级 memo 退化**(useStreamRenderer.ts:77-97/130-154)——无 `\n\n` 的长文回复每帧全文 lexer+parse+sanitize,整轮 O(n²),长文卡顿主因
|
||||
- **S1-2 长尾代码块/末块每帧重跑 hljs 高亮**(:146-149 + useMarkdown:87-111)
|
||||
|
||||
### P2
|
||||
- **S2-1 每次 flush 两次整组件重渲染**(currentText 触发 + streamingBlocks rAF 触发,:219-236)~40 次/s 整树求值
|
||||
- **S2-2 renderMd 缓存命中前先跑 wrapNakedDiff 全文扫描**(useMarkdown.ts:191-197)
|
||||
- **S2-3 isToolResultJson 对每条 JSON 形消息每帧 JSON.parse**(MessageList:698-708)
|
||||
- **S2-4 handleEvent 每活跃事件重复 setConvState('generating')**(useAiEvents.ts:122-124,同值无短路)
|
||||
- **S2-5 AiCommandOutput(run_command 逐行)未合批,事件风暴**(command_stream.rs:39-48,几百上千行命令→每秒上百 IPC)
|
||||
- **S2-6 已完成块每帧重算 simpleHash + 新子串做 Map key 哈希**
|
||||
|
||||
### P3
|
||||
S3-1 每 delta 文本空闲计时器/看门狗重建 · S3-2 切会话缓冲双清 no-op · S3-3 tail-${tailSeq} 恒等于 tail-1(注释误导)· S3-4 messages deep watch 每工具翻转 JSON.stringify 全量
|
||||
|
||||
### 已核查无问题(Info)
|
||||
后端 50ms 合批真生效(stream_recv.rs:346-352)· rAF 节流真生效 · 消息侧无 O(n²)(isLastAi O(1))· 内存缓存界内(_blockCache≤300/_mdCache≤200/currentText 完成即清)
|
||||
|
||||
---
|
||||
|
||||
## 四、前端交互效率(12 项)
|
||||
|
||||
### P1
|
||||
- **F1-1 回合收尾双拉会话列表**(useAiLifecycleEvents.ts:119 + notify→listener 再拉,每回合 2 次全量 list IPC)
|
||||
- **F1-2 notifyConversationChanged 同窗口自触发冗余重拉**(aiShared.ts:21 emit 回传同窗口 listener;删除活跃会话可达 5 IPC)
|
||||
- **F1-3 loadConversations 无防抖**(8+ 处调用,整体替换数组→侧栏全量重渲染)
|
||||
|
||||
### P2
|
||||
- **F2-1 switch 无条件多 1 次 pendingToolCalls IPC**(纯文本会话也白拉)
|
||||
- **F2-2 switch 主线程同步全量 parse**(JSON.parse + parseConvMessages 每条 toolCall 再 parse)
|
||||
- **F2-3 MessageList deep watch 每次 messages 变更全量 JSON.stringify 快照**
|
||||
- **F2-4 输入联想每键全量过滤 + 首次 @ 全量拉 tasks**
|
||||
- **F2-5 TopBar 多个 computed 每次 messages 变更全量扫描**(historyMsgs/summaryMsgs/contextInfo)
|
||||
|
||||
### P3
|
||||
F3-1 滚动边沿 buildActiveToolIds 全量遍历 · F3-2 每 delta 定时器重建(看门狗+文本空闲)· F3-3 AiChat 启动串行 IPC 链(约 5 次)· F3-4 persistUiState 每次写整包 df-ai-ui
|
||||
|
||||
---
|
||||
|
||||
## 五、会话生命周期(16 项)
|
||||
|
||||
### P0
|
||||
- **L0-1 save_conversation 每轮 O(N) 全量克隆+截断+记录构建,CPU 在主线程**(conversation.rs:254-343,单线程 runtime)——"无变化捷径"在 records 构建后才判定,每轮白付全部 CPU;N 轮工具对话 ≈N+1~N+2 次 save
|
||||
- **L0-2 system prompt 每次用户操作全量重建 + 串行 6-8 次 DB 查询**(chat.rs:527-651 + prompt.rs:280-343)——全部落在「点击→首 token」关键路径,project/task 清单可缓存
|
||||
- **L0-3 自动压缩在 loop 内同步阻塞整轮**(context_lifecycle.rs:159-167,非流式 LLM 最长 60s)+ 压缩后必全量 DELETE+INSERT 重写
|
||||
|
||||
### P1
|
||||
- **L1-1 最终轮重复 save**(agentic:1918 + :2111 收敛时再 spawn)
|
||||
- **L1-2 每轮 build_for_request + sanitize + pairing + estimated_prompt 共 5-6 次全量遍历**
|
||||
- **L1-3 会话切换全量读库 + 全量重估 token + 全量重跑意图识别**(restore 时对每条 re-estimate + re-recognize)
|
||||
- **L1-4 每次生成结束在所有窗口触发会话列表全量刷新 + 事件双写**(55 处 emit + publish_event 双写)
|
||||
- **L1-5 知识注入每次发送全量克隆消息 + 两次 DB 检索**(keyword + vector,关键路径)
|
||||
|
||||
### P2
|
||||
L2-1 Checkpoint 每 20 条消息全量序列化 · L2-2 单次 save 对 session 锁加锁 3 次 · L2-3 active provider 在 send→loop 各查一次库 · L2-4 estimated_prompt 每轮全量重算 · L2-5 空标题会话切换触发额外 LLM 标题生成 · L2-6 心跳每 20s 无条件广播
|
||||
|
||||
### P3
|
||||
L3-1 所有重生成路径同样重建 system prompt(regenerate/edit/force_send)· L3-2 事件总线双写在热点仍存在(app.emit 全窗口广播)
|
||||
|
||||
### 关键前提
|
||||
Tauri Windows 单线程 tokio runtime——所有 CPU 密集操作主线程串行,任一长任务阻塞全部 IPC。最高优先级:L0-1 save 提前判定 + L0-2 缓存 + L0-3 压缩后台化。
|
||||
|
||||
---
|
||||
|
||||
## 六、LLM 成本 / 缓存命中率(12 项)
|
||||
|
||||
> **核心结论**:DevFlow **从未向任何 provider 发送 `cache_control`/`cache_breakpoint`**,且 system prompt 每轮用实时 DB 数据重建 → 前缀缓存既没开、前缀也不稳定,**多轮对话几乎 100% 缓存不命中,每轮全价支付全量历史 + 全量 system**。代码只做了「读回 cache_read/cache_creation 计费展示」,从未「请求缓存」。
|
||||
|
||||
### P0
|
||||
- **C0-1 全链路无 cache_control 注解,Anthropic 提示缓存根本没启用**(anthropic_helpers.rs:22-36 无字段;system 是纯 String 无法表达 breakpoint,需改 text-block 数组)
|
||||
- **C0-2 system prompt 每轮用实时 DB 数据重建,前缀字节不稳定 → 跨轮缓存全废**(prompt.rs:295/315 list_active 20+20 注入,agent 改数据即变;建议挪到消息流只留静态指令)
|
||||
|
||||
### P1
|
||||
- **C1-1 日期在 system prompt 位置 0,跨天失效整条前缀**(prompt.rs:45 当前日期)
|
||||
- **C1-2 每轮全量重发全部历史,成本 O(n²),无缓存兜底**(10 轮实测单次请求可达 ~12 万 token 全价)
|
||||
- **C1-3 augmentation/知识注入拼进 system,随轮变化再添失效源**(chat.rs:639-652)
|
||||
|
||||
### P2
|
||||
- **C2-1 模型路由从不因简单意图降档,贵模型低用**(router.rs weight 主键,tier 仅 tiebreak;Chat 意图也应降档)
|
||||
- **C2-2 重试发送字节完全相同请求,无缓存 → 每次重试重复全价**
|
||||
- **C2-3 system prompt 本身膨胀(文档探索段 140-180 行常驻)+ 重复注入技能/工作流/目标**
|
||||
- **C2-4 标题生成/规划/压缩是独立 LLM 调用,不共享前缀缓存**
|
||||
|
||||
### P3
|
||||
C3-1 tools 每轮全量序列化无 cache_control 与 system 一起缓存 · C3-2 AnthropicRequest.system 纯 String 需结构改造 · C3-3 采样参数合理(确认项)
|
||||
|
||||
### 修复优先级(成本 agent 建议)
|
||||
1. **C0-1 + C0-2 一起修**(加 cache_control + 稳定 system 前缀)才能产生真实命中率
|
||||
2. C1-1/C1-2/C1-3(日期与易变段挪出稳定前缀、augmentation 改注入消息流)→ 多轮 loop 输入成本砍 ~1/5~1/10
|
||||
3. C2-1 模型降档(收益独立于缓存,可并行)
|
||||
|
||||
---
|
||||
|
||||
## 七、优先级建议(合并 6 路)
|
||||
|
||||
**成本大头(后端)**:R1-1 全量历史重放 + R2-1 每轮 4 次深克隆 → 增量/窗口化
|
||||
**卡顿主因(渲染)**:S1-1 单块回复每帧全量渲染 → 增量 lex/parse
|
||||
**无谓开销(前端)**:F1-1/2/3 列表刷新收敛(合并一个 debounced scheduleConversationsRefresh)
|
||||
**DB 瓶颈**:T1-1 审计批量事务 + T1-2 只读缓存 O(1) 索引
|
||||
**成本(LLM 缓存)**:C0-1 + C0-2(cache_control + 稳定前缀)→ 命中率从 ~0% 提升到可复用
|
||||
|
||||
---
|
||||
|
||||
## 八、登记去向
|
||||
|
||||
- 本报告:`docs/05-代码审查/aichat效率走查-2026-08-09.md`
|
||||
- 看板:`docs/todo.md` 增登记条目
|
||||
- memory 指针:待补齐
|
||||
@@ -0,0 +1,91 @@
|
||||
# 项目详情页走查报告(概览/文件/依赖图)
|
||||
|
||||
> 走查日期:2026-08-09
|
||||
> 范围:`src/views/ProjectDetail.vue`(1346 行)+ `src/components/project/`(FileExplorer 837 / FileTree 405 / DependencyGraph 490 / FilePreview / GitChanges / ModuleNode)+ 后端 `src-tauri/src/commands/module.rs`
|
||||
> 方法:3 路并行 Explore agent(概览/文件/依赖图)+ 主代理独立核查 ProjectDetail.vue 本体
|
||||
> 性质:**只走查登记,不实施代码**(守 session-role-diagnose-only)
|
||||
> 关联:UIUX 扩展审查(2026-08-02)、TaskDetail 走查(2026-08-09,同批父子任务详情页)
|
||||
|
||||
---
|
||||
|
||||
## 一、概览 tab(ProjectDetail.vue)— 18 项
|
||||
|
||||
### P1(3 项)
|
||||
|
||||
| # | 问题 | 位置 |
|
||||
|---|---|---|
|
||||
| O1 | **projectTasks 无 df-data-changed 本地监听** → AI/其它视图改任务后概览任务列表陈旧(TaskDetail 已做 B-260616-18,此处漏做) | :534-542, :849-863 |
|
||||
| O2 | **工作流日志/DAG/进度读全局 liveEvents,无项目隔离** → 跨项目数据错配(正在看项目 A 显示 B 的工作流) | :676-689, :696-709 |
|
||||
| O3 | **概览工程列表与 FileExplorer 双向不同步** → 文件 tab 增删改工程后切回概览 modules 陈旧 | :548-555 |
|
||||
|
||||
### P2(5 项)
|
||||
|
||||
| # | 问题 | 位置 |
|
||||
|---|---|---|
|
||||
| O4 | 快速切项目 loadProjectTasks/loadModules 竞态(无 seq 守卫) | :866-871 |
|
||||
| O5 | WorkflowDagDisplay 边条件编辑 emit update:dagJson 父级未监听 → 编辑静默失效回退 | :326 |
|
||||
| O6 | onUnmounted stopEventListener 停全局 workflow 监听,可能波及其他视图(共享单例) | :876-880 |
|
||||
| O7 | 折叠态 descExpanded/workflowLogCollapsed 跨项目残留 | :457-462 |
|
||||
| O8 | 概览任务列表无 loading 态、无 limit 分页(超上限静默截断) | :537, :292-309 |
|
||||
| O9 | 项目状态映射不完整:in_progress/testing 等无 i18n 文案 | constants/project.ts:11-15 |
|
||||
|
||||
### P3(10 项)
|
||||
O10 checkPath 重复触发(watch+显式双发)· O11 loading 态误判(store.error 非空显示"不存在")· O12 任务卡片只读不可点击跳详情 · O13 模板多次 parseStack 重复 JSON.parse · O14 sourceScores 宽度未 clamp · O15 日志自动滚动打断上翻 · O16 descCollapsible 字符数近似 vs TaskDetail DOM 测量不一致 · O17 onMounted 链式 await startEventListener 抛错跳过 checkPath · O18 handleSync 未刷模块/灵感
|
||||
|
||||
---
|
||||
|
||||
## 二、文件 tab(FileExplorer/FileTree/FilePreview/GitChanges)— 24 项
|
||||
|
||||
### P1(3 项)
|
||||
|
||||
| # | 问题 | 位置 |
|
||||
|---|---|---|
|
||||
| F1 | **AI 写文件后自动切变更视图不刷新 GitChanges 列表 + 徽标计数被清零**(v-show 不重挂载,GitChanges 唯一重拉是 watch moduleId) | FileExplorer:399-411, :368 |
|
||||
| F2 | **子目录展开失败把父级整棵树替换为错误态且无法自愈**(error 置父实例,优先于列表渲染) | FileTree:157-181, :14 |
|
||||
| F3 | **中文文件名 git status 八进制转义未还原** → 变更视图乱码/打不开/树无徽标(core.quotepath 默认) | module.rs:1081-1091, GitChanges:66-73 |
|
||||
|
||||
### P2(9 项)
|
||||
F4 git diff 仅 unstaged(staged/untracked 空 diff)· F5 切工程后 gitStatusData 不清 → 徽标张冠李戴 · F6 GitChanges 切工程遗留提交详情/选中态 · F7 文件树切工程双重请求+短暂显示旧文件 · F8 零工程文件 tab 永久转圈无空态 · F9 打开文件 tab 即全量 git status+log 扫描(纯浏览也扫)· F10 变更视图点文件默认看原文非 diff · F11 切 tab v-if 反复销毁重建 FileExplorer(状态全丢+重复扫描)· F12 FilePreview 大文件同步高亮阻塞 UI
|
||||
|
||||
### P3(12 项)
|
||||
F13 GitChanges.selectFile 拉 diff 从不渲染 · F14 refresh 用固定 50ms 睡 · F15 展开目录无加载反馈 · F16 findEntryGitStatus 全缓存线性扫描 · F17 双击目录无 in-flight 去重 · F18 FilePreview 切文件头部 size 残留 · F19 R 状态样式不一致 · F20 提交搜索只过滤已加载 50 条 · F21 提交 diff 含空格路径解析失败 · F22 目录不存在误显"非 Git 仓库" · F23 面包屑点击不展开目标目录 · F24 文件树 git 徽标模块路径≠仓库根失效
|
||||
|
||||
---
|
||||
|
||||
## 三、依赖图 tab(DependencyGraph)— 18 项
|
||||
|
||||
### P0(1 项)
|
||||
|
||||
| # | 问题 | 位置 |
|
||||
|---|---|---|
|
||||
| G1 | **节点 Vue 组件从未注册到 x6-vue-shape → 节点根本不渲染**(`register({shape,component})` 未调用,`component` 字段库内不读;ModuleNode 读 props.data 但 vue-shape 传 {node,graph}) | :82, :174-185, ModuleNode:18-26 |
|
||||
|
||||
### P1(3 项)
|
||||
|
||||
| # | 问题 | 位置 |
|
||||
|---|---|---|
|
||||
| G2 | UX-P0-4 环高亮仍是空操作(attrs.body 选择器在 vue-shape 无 body 元素) | :186-190 |
|
||||
| G3 | **删除参与依赖的工程必失败**(FK 约束无级联清理)→ remove_project_module 报错+前端误导 | module.rs:249-260 |
|
||||
| G4 | 点击节点无任何效果(emit 无人监听 + router.push 重复导航空操作) | :230-233 |
|
||||
|
||||
### P2(9 项)
|
||||
G5 cycleNodes 跨数据变更/跨项目不重置 · G6 重复依赖可重复添加(前后端无去重)· G7 添加依赖不防环 · G8 边删除按钮定位偏移(未计工具栏高度)· G9 依赖加载失败静默吞掉→误导性空态 · G10 添加依赖失败无反馈 · G11 边 hover 监听重复累积(off 删不掉旧 handler)· G12 每次 renderGraph 重置视野 + 拖拽位置被 dagre 覆盖 · G13 无加载态
|
||||
|
||||
### P3(5 项)
|
||||
G14 后端 add_module_dependency 不校验 from==to 与模块归属 · G15 exportPNG 回调错误无法 catch · G16 ModuleNode 路径截断省略号混用+兜底丢根锚点 · G17 死配置/未过滤项(History/Snapline 无 UI、archived 进图、dep_type 回落)· G18 detect_module_cycles 只标节点不标边(需确认是否逐环展示)
|
||||
|
||||
---
|
||||
|
||||
## 四、优先级建议
|
||||
|
||||
**P0(崩页/核心不可用)**:G1 依赖图节点不渲染
|
||||
**P1(数据正确性/一致性)**:F3 中文 git 乱码 · G3 删依赖工程必失败 · O2 工作流跨项目串数据 · O1 任务列表陈旧 · F1 变更视图不刷新
|
||||
**P2(体验/打磨)**:O3 模块双向同步 · F8 零工程空态 · F9 全量 git 扫描 · F11 切 tab 状态丢失 · G2 环高亮 · G4 节点点击死代码
|
||||
|
||||
---
|
||||
|
||||
## 五、登记去向
|
||||
|
||||
- 本报告:`docs/05-代码审查/项目详情页走查-2026-08-09.md`
|
||||
- 看板:`docs/todo.md` 增登记条目(P0/P1 优先,P2/P3 分批)
|
||||
- 不实施:本次仅走查登记(用户明确要求先检查做记录)
|
||||
Reference in New Issue
Block a user