13 KiB
AI Chat 真实会话实测分析(上下文 / 工具 / Agent 行为)
日期:2026-06-22 | 方法:从生产 DB(
%APPDATA%/top.1216.devflow/devflow-dev.db)实测会话84dc36c8全量 86 条消息反推,Python 脚本统计(.temp/analyze_session.py) 基线:会话 prompt 1,320,713 / completion 7,578 tokens(completion/prompt 比 0.57%) 产物:3 P0 / 3 P1 / 2 P2 性质:实测数据反推(非静态代码审查)。finding 的源码根因为"假设",须独立 grep/read 核验后再定论 关联:devflow-compress-ui-no-fold devflow-generating-statemachine aichat-techdebt-audit-2026-06-21 code-review-anti-contamination devflow-aichat-streaming-md
会话概况
| 项 | 值 |
|---|---|
| conversation_id | 84dc36c8-b416-44bc-a7c6-c4e00de82b6f |
| 标题 | D:\Downloads\kms |
| 模型 | glm-5.2 |
| 跨度 | 2026-06-22 01:29 ~ 12:23(中间大间隔,有效工作段 ~11:57–12:23) |
| 消息数 | 86 |
| prompt / completion tokens | 1,320,713 / 7,578 |
| completion/prompt 比 | 0.57%(极端输入重) |
| 工具调用 | patch_file 16 / read_file 10 / list_directory 3 / grep 1 |
| tool 返回总量 | 194KB 跨 41 条 |
parts 字段 |
0/86(全 null) |
| 用户催促次数 | 7(继续×2 / 完成了吗×2 / 仔细检查 / 核对 收尾 / 核对 内容) |
| 任务 | 整理 D:\Downloads\kms 下 README/INDEX + 三知识库 HTML 头尾修复 |
P0(3 项)
[P0-1] 上下文管理实质失效:压缩标记 compressed 未降 prompt,token 累积至 1.32M
- 现象:seq 0–65
status=compressed(仅个别 active),但最终prompt_tokens=1,320,713。压缩"生效"了,prompt 却没降。 - db 证据:全量 86 条中 66 条
status='compressed';conv 元数据prompt_tokens=1320713 / completion_tokens=7578。 - 根因假设:
compressed仅压历史消息的展示态/落库态,未真正削减送入 LLM 的 prompt。与 devflow-compress-ui-no-fold(2026-06-18 决策"后端省 token 不前端藏")冲突——决策要求后端真省,实测后端没省。 - 影响:1.32M 接近模型上下文上限,长会话必爆;成本几乎全烧在重复搬运文件内容。
- 待核验源码点:compress 模块(
src-tauri/src/commands/ai/下 compress 相关)——压缩后重组 messages 时是否真替换为摘要,还是仅打标记原样回灌。 - 关联:印证 aichat-techdebt-audit-2026-06-21 3-compress 单元的 2 个 smell。
[P0-2] 工具返回值协议不一致:patch_file / read_file 部分路径裸吐文件全文
- 现象:同一工具返回结构两副面孔:
- seq 16 patch_file →
{"changed":true,"diff":...}✅ JSON 正常 - seq 37/40/42/46/49/51/53/60/63/65/75/76 patch_file →
raw 6204c❌ 裸文本(parse 失败) - seq 6/7 read_file →
{"content":...}✅ 正常 - seq 11/29/31/33 read_file →
raw 6204c❌ 裸文本
- seq 16 patch_file →
- db 证据:41 条 tool 返回总计 194KB;
6204字符数反复出现(≈被操作 HTML 文件大小)。 - 根因假设:
patch_file成功路径本应只回changed+diff,却把整个文件内容回灌;或某分支(超长 / 特定路径)跳过 JSON 包装直接返回文件串。6204c即文件实际长度被全文塞回 context。 - 影响:这是 prompt 1.32M 的直接元凶。每次 patch 一次 = 文件全文再进一遍 context。16 次 patch × ~6KB ≈ 100KB 仅 patch 回灌。
- 待核验源码点:
tool_registry.rspatch_file handler(~1247 区,devflow-patch-file-design 落地点)与 read_file handler(~892-976)的返回序列化分支——确认哪条路径丢 JSON 包装。 - 关联:与 aichat-techdebt-audit-2026-06-21 P1「expected_hash schema 契约破裂」同源(工具契约失配家族)。
[P0-3] 重复 tool 结果:同一结果多次持久化,去重缺失
- 现象:
- seq 11/12/13/14 → 连续 4 条
raw 6204c,同一 read 结果存 4 份 - seq 69/70/71 → 3×6204c;seq 83/84/85 → 3×6204c
- seq 75/76 → 2×6204c
- seq 11/12/13/14 → 连续 4 条
- db 证据:上述 seq 的 content 长度完全一致(6204),且时间戳相同(同一秒)。
- 根因假设:一次 assistant 回合并行触发多个 read(读 mysql+redis+linux 三文件),结果落库时按 tool_call 重复写,或同一
tool_call_id结果被多次持久化;前端流式接收去重逻辑缺失。 - 影响:context 进一步虚胖;且会污染后续压缩/摘要(同一内容被当作多条独立事实)。
- 待核验源码点:tool 结果落库路径(
ai_messages写入)——按tool_call_id是否做唯一约束/去重;流式 patch 合并逻辑。
P1(3 项)
总纲(用户归纳)——编排规划能力弱:P1-1(无自检)与 P1-3(无并行调度)同源。agent 无任务分解、无并行 fan-out、无宣称完成前的自检规划,单链 ReAct 逐工具串行推进,识别不出"N 个独立子任务可并行"。这是 agent 自主性/可靠性的核心缺口,印证 aichat-decision-capability 与 aichat-b-route-parallel-multiround。归 B 路线立项。
[P1-1] Agent 过早宣称完成,无 checklist 自检,用户被迫 7 次催促
-
现象:assistant 3 次宣称完成,3 次被用户推翻:
seq 时刻 宣称 推翻证据 #26 12:01 "整理完成" #27 用户"文档内容需要按要求整理" #66 12:10 "全部完成了!" #67"仔细检查" → #72 发现 theme.jsvsclaude-artifact-theme.js引用名错(漏改 2 个文件)#80 12:19 "全部核对完毕,7 个标记全部对齐无遗漏" #81"核对 内容"(用户不信,要求再核)→ 会话中断于此 -
db 证据:
theme.js引用名错误本可一次 grep 抓出,却要用户肉眼挑(实际 #78 才首次用 grep,且是用户第三次催后)。 -
根因假设:无宣称完成前的强制自检机制(如 grep 引用一致性 / 闭合标记核对)。Agent 倾向于 patch 完即宣布成功,不验证。
-
影响:用户对 agent 完成度零信任,交互成本极高;本质是 agent 自主性/可靠性的核心缺口。
-
待核验/落点:属 agent 行为策略层(prompt / loop 收尾钩子),非单点代码 bug。建议与 aichat-b-route-parallel-multiround B 路线(决策能力)合并立项。
-
关联:aichat-decision-capability(单链 ReAct,无规划式智能)的现实印证。
[P1-2] 末尾会话中断:tool 全部返回后无 assistant 回复(generating 状态机卡死)
- 现象:#82 assistant 触发读三文件 → #83/84/85 tool 全部正常返回(
status=active)→ 之后再无 assistant 消息,会话 12:23 停尸。 - db 证据:seq 85 是最后一条,role=tool;无 seq 86 的 assistant 总结回复。
active状态说明 tool 执行完成,但后续生成未发生。 - 根因假设:tool 执行完但
generating状态未复位,后续回复被吞。高度吻合 devflow-generating-statemachine 记录的"generating 复位散布 + 无 panic 兜底"卡死模式。 - 影响:用户看到"读完了"就没下文,必须手动重发;且该会话 token 已 1.32M,重发极可能直接触上限。
- 待核验源码点:agentic loop 的 tool-后-续生成衔接(
mod.rs收尾 /try_continue/ per-conv generating 复位)。
[P1-3] 三个独立文件整理任务严格串行,无并行 fan-out 调度
- 现象:
mysql_guide/redis_guide/linux_ubuntu_guide三个 HTML 整理是独立子任务(无依赖),本可并行。但 agent 严格串行:mysql(12:02–12:06)→ redis(12:07–12:08)→ linux(12:08–12:10),时段完全不重叠;每个文件内还 read→patch→read→patch 多轮。assistant 从未在一个 turn 内对三文件 fan-out 工具调用。 - db 证据:时间线三文件处理时段分明不重叠;seq 68"仔细检查"后只 read mysql 一个,未并行触发 redis/linux 的核对。
- 根因假设:单链 ReAct 无任务分解层。缺"识别 N 个独立子任务 → 同 turn 并行发起 N 路工具调用"的编排能力。
- 影响:耗时线性叠加;同一指令在 context 里反复加载三遍;用户等待感差。直接印证 aichat-b-route-parallel-multiround(用户 2026-06-20 已决策"单对话并行多轮必须做")。
- 归并:与 P1-1 同属"编排规划能力弱"(见 P1 区总纲),归 B 路线。
P2(2 项)
[P2-1] system 消息污染 + 时序错乱
- 现象:
- seq 0
role=system,content 却是 assistant 语义残留:"我需要查看 mysql_guide.html 的最后几行来确认尾部内容..." - seq 0 timestamp
12:08:02,seq 1 却是01:29:35——seq 0 比 seq 1 晚 10 小时。
- seq 0
- 根因假设:system/上下文注入消息的 role 标记错位;timestamp 用"插入时刻"而非"会话时刻"。
- 影响:排序、压缩、计费全受污染;system 消息混入 assistant 内容会误导模型。
- 待核验源码点:system prompt 注入路径(
ai_messages写入 system 行的位置)+ timestamp 赋值逻辑。
[P2-2] 同文件反复 read,无缓存 / 无 diff 感知
- 现象:
mysql_guide.htmlread 4×、linux_ubuntu_guide.htmlread 4×;patch_file 共 16× 改 3 个文件。read→patch→read→patch 循环。 - 根因假设:每次 patch 后又全文 read 确认(叠加 P0-2 全文回灌);无 session 级文件缓存或"patch 后不重读"约定。
- 影响:context 雪崩放大器;与 P0-2 叠加是 prompt 爆炸的复合原因。
- 待核验/落点:工具侧可加"会话内文件指纹缓存,LLM 重读同文件时返回缓存命中提示";或 prompt 侧约束 patch 后不重读。
附录:parts 字段全空(待观察项)
- 现象:
msgs_with_parts=0/86。devflow-aichat-streaming-md 记录块级 memo(memo=mapped.lexer+v-memo)已落地(ARC-260615-08)。 - 不定论:本会话可能早于改造,或
parts存于别处 / 未回填。需对照新产生的会话核验,不能据此断定流式渲染回退。
落点建议(未实施,遵守 session-role-diagnose-only)
| 项 | 落点 |
|---|---|
| P0-1 / P0-2 / P0-3 | 并入 aichat-techdebt-audit-2026-06-21 P1 主线,或单列"上下文/工具返回"专项 |
| P1-2 中断 | 印证 devflow-generating-statemachine 待落地链(已有详案) |
| P1-1 自检 + P1-3 并行调度 | 同属「编排规划能力弱」总纲,归 aichat-b-route-parallel-multiround B 路线(任务分解 + 并行 fan-out + 宣称前自检) |
| P2-1 / P2-2 | 低优登记 todo |
最高杠杆:P0-2(工具返回全文回灌)——改一处(工具序列化返回 diff/changed 而非全文),prompt 直接降一个量级。
复现方法
# 分析脚本(已留存)
python E:/wk-lab/devflow/.temp/analyze_session.py
# DB 只读连接
sqlite3 "file:%APPDATA%/top.1216.devflow/devflow-dev.db?mode=ro" -uri
# 表:ai_conversations / ai_messages / ai_tool_executions
数据快照:2026-06-22 12:36 抓取,会话可能仍在变化(WAL 活跃)。
2026-06-23 修正与落地(自主推进,290 src-tauri + 324 df-ai 测试全过)
核验推翻(实测 DB tool_call_id + timestamp 独立核验,code-review-anti-contamination):
- P0-3 撤销:两会话(4ae73423/84dc36c8)"重复 tool 结果"实测 tool_call_id 全不同 + timestamp 间隔数分钟/小时 → LLM 不同时刻重调,非落库去重 bug。原 P0-3 误判(06-22 报告 + 核验 agent 都错,实测数据证伪)。
- P0-2 性质修正:非"prompt 爆炸元凶"(prompt 用内存完整态,非落库截断版)。真因是
conversation.rs:72truncate_for_persist 对序列化 JSON 中间截断插裸\n\n[...省略 N 字符...]\n\n,破坏 JSON 致落库坏 JSON(reload/审计 parse FAIL,pos3072=TRUNCATE_HEAD)。 - 中断A 非bug:续轮机制完整(mod.rs:1362-1478),84dc36c8 seq85 后无回复疑达 max_iterations 或自然收敛。
- 中断B 真缺陷:4ae73423 末尾 advance_task 审批
__PENDING__卡死(mod.rs:1464 return 无超时),非 generating 卡死。
本次修复落地:
| 项 | 位置 | 修复 |
|---|---|---|
| intent 收敛误杀(4ae73423 主因) | intent.rs | L0 strip_mention_tags 剥离 mention 前缀 + L1 Project/Task/Idea 加 File domain |
| write_file parent 误拒(P0,授权内文件被拒) | tool_registry.rs:1114/1421/1559 | 改 allowed_dirs.is_authorized(脱 workspace_root) |
| read_file limit 忽略 | tool_registry.rs:1023 | 无 offset 尊重 LLM limit(原固定 500) |
| truncate 破坏 JSON(P0-2) | conversation.rs:175 | 跳 tool role 截断 |
| 压缩丢末条消息 | agentic/mod.rs:1225 | 全 provider 失败 return 前补 save_conversation |
| run_command && PS5 失败 | df-execute/shell.rs | pwsh(PS7)优先探测 + PS5 兜底(OnceLock 缓存) |
| remote_bridge args default | remote_bridge.rs:97 | custom default 返空 Object(#[serde(default)] 给 Null) |
| remote_bridge r1 双轨测试 | remote_bridge.rs:872 | 设态对齐双轨(conv_state=Generating) |
写 docs/待决策.md(非确定性,需决策):
- BUG-260623-03 审批 pending 无超时(中断B,推荐 b 前端倒计时)
- ARC-260623-01 workspace_root 写死残留(delete_file trash/resolve/run_command working_dir,分发适配)
生效:需重启 devflow app(cargo tauri dev / 重新 build),新会话才用新二进制。