Files
DevFlow/docs/05-代码审查/aichat效率走查-2026-08-09.md
T

157 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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_breaker2 次持 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 次 INSERTjoin_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 AiCommandOutputrun_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 promptregenerate/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 仅 tiebreakChat 意图也应降档)
- **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-2cache_control + 稳定前缀)→ 命中率从 ~0% 提升到可复用
---
## 八、登记去向
- 本报告:`docs/05-代码审查/aichat效率走查-2026-08-09.md`
- 看板:`docs/todo.md` 增登记条目
- memory 指针:待补齐