Files
DevFlow/docs/02-架构设计/专项设计/AI对话目标丢失诊断-2026-06-26.md
绝尘 8ce18cb482 新增: AI 对话目标钉扎+探索熔断+话题标记降级
治 AI Chat 目标丢失/意图丢失(实测会话 480万token,目标消息被压缩出局,LLM 尾部盲搜死循环):
- G1 目标钉扎:首条 user 目标提取存 PerConvState.pinned_goal,run_agentic_loop 入口拼进
  system_prompt 尾部(loop 不变量,免疫 F-15 压缩/裁剪/sanitize,治目标物理出局)
- G2 探索熔断:连续 N 次空结果无进展 → 两段式警示 + AiHelpRequired 熔断(治游荡死循环)
- G4 话题标记降级:pinned_goal 存在时跳过 topic marker insert(治反向误导+双锚点稀释)
- G3 衔接:pinned_goal 内容态与 ConvState 生命周期态正交,不进 enum
各改进配开关 flag(GOAL_PIN_ENABLED/STALL_BREAKER_*/TOPIC_MARKER_GOAL_AWARE)可单点回退。
诊断报告见 docs/02-架构设计/专项设计/AI对话目标丢失诊断-2026-06-26.md。
2026-06-26 20:01:28 +08:00

107 lines
7.0 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.
# AI 对话「目标丢失 / 意图丢失」诊断报告
> 日期2026-06-26
> 触发AI Chat 使用中,用户发送 Bug / 分析需求目标后,分析过程中目标丢失,系统不知道做什么、完全跑偏。
> 方法:直读对话数据库(`AppData/Roaming/top.1216.devflow/devflow-dev.db`)实测会话 + 源码机制走查。
> 性质:基于代码 + 数据库实证的机制级诊断(非模型分析猜测)。
---
## 一、现场铁证(会话 `54c8b5bd`
| 指标 | 实测值 | 含义 |
|---|---|---|
| `prompt_tokens` | **4,809,714**(约 480 万) | 远超 GLM 1M 窗口,反复触发压缩 / 裁剪 |
| 消息数 | 308 条 | 长 ReAct 链,工具结果堆积 |
| 原始目标 `[seq5]` | `分析一下 灵感模块 存在的不足 [项目: DevFlow]``status=compressed` | **目标消息已被踢出 LLM 上下文**`sanitize_messages` step0 过滤 `is_active` |
| 话题标记 `[seq0]` | `task → project`active | 系统判定「当前 project 话题」,但真实目标是 idea 域(灵感模块) |
| 尾部 `[seq287307]` | 连续 10+ 次 `search_files`,关键词 `auto-execute-mode / auto_execute / 全部接管 / autoExecute / execute-mode / execute_mode / auto-exec / 接管 / df-ai-auto`**全部 `total:0` 空结果** | 失去目标后的游荡死循环 |
**结论**原始目标是「分析灵感模块存在的不足」LLM 最终在反复搜索「自动执行模式 / 全部接管」——与目标毫无关系。目标彻底丢失。
---
## 二、根因(机制级)
### 根因 1上下文爆炸 → 目标消息物理出局(核心)
- `df-ai/src/context.rs``sanitize_messages` step0 按 `is_active()` 过滤发送视图。目标 user 消息被 F-15 压缩标 `status=compressed` 后,**不再进入 LLM 上下文**。
- 目标仅靠**压缩摘要 system 消息**「续命」。`prompt.rs::compress_prompt` 四段式(意图 / 决策 / 文件 / 约束)+ 主题词锚点保留——但摘要是 **LLM 二次生成,信息降级严重**。「分析灵感模块不足」这类具体目标,在数次压缩后语义稀释到无法指导后续动作。
- 480 万 token 的会话,目标消息经历多轮压缩,保真度无法保证。
### 根因 2话题切换标记误判反向强化错误方向
- `agentic/mod.rs:735-772``pending_topic_marker` 基于末两条 user 消息的 `IntentRecognizer` 关键词推断(双高置信 ≥0.7 才标),`insert_at(0)` 软提示 system「请以新话题为准」。
- 失效点:
- 长链里 user 消息早被压缩出局topic 推断基于**已失真历史**。
- 本例最后 active 标记是 `task→project`,与真实目标(灵感模块 / idea 域)**背离**——软提示反而告诉 LLM「现在是 project 话题」,帮倒忙。
- marker 只在 push **user 消息**时检测,工具轮次间不参与。
### 根因 3单链 ReAct无目标重锚定架构本质
- `df-ai/src/coordinator.rs`**纯空壳 TODO**B 路线占位,`AgentCoordinator::run` 直接返 `"TODO: Agent 协作结果"`)。
- `df-ai/src/planner.rs`Plan DAG + Kahn 分层 + validate 齐全,但文件头明确「纯函数零 IO 零状态」「不接入 agentic loop待 Phase B+C」。`PLANNING_ENABLED=true` 只门控**工具排序**`filter_tool_defs_planned`**不做多步规划执行**。
- agentic loop 每轮只在 push 新 user 消息时检测话题切换,**工具轮次间不重申目标**。没有「当前目标 + 进度」结构化状态LLM 每轮自行决定下一步,长链必然游荡(`[seq287307]` 实证)。
### 根因 4无探索熔断
- `[seq287307]` 连续 10+ 次空结果不中断。系统不跟踪「已搜过什么 / 连续 N 次无进展」LLM 无限换关键词。
- 这是目标丢失的**放大器**:不知道目标 → 不知道该停 → 无限游荡token 失控480 万)。
### 根因 5system prompt「聚焦准则」是文字说教非机制
- `prompt.rs:104-108` 有「聚焦准则:始终围绕用户当前请求的核心目标」——纯 prompt 文字,靠 LLM 自觉。
- 目标一旦从上下文(消息流)消失,文字准则**无锚点可抓**。没有「每轮把目标钉在 system 顶部」的机制。
---
## 三、为什么现有设计压不住
| 现有机制 | 性质 | 为什么压不住 |
|---|---|---|
| 压缩摘要F-15 | **被动**信息降级 | 摘要保真靠 LLM多轮压缩后目标语义稀释 |
| 话题切换标记 | 软提示 + 关键词推断 | 基于失真历史,本例反向误导 |
| 聚焦准则 prompt | 文字说教 | 目标消息出局后无锚点 |
| `insert_at(0)` system 锚点 | 多个堆首位 | 话题标记 + 压缩摘要 + 关键词兜底三个锚点互相稀释 |
三个 `insert_at(0)`(话题标记 `agentic/mod.rs:762`、压缩摘要 `:918`、关键词兜底 `:969`)堆在首位,互相稀释,没有一个是「权威目标」。
---
## 四、关联现状
- 当前分支 `conv-state-convergence` + `agentic/conv_state.rs`452 行状态机)已在尝试收敛对话状态,**但目标作为一等状态尚未固化进状态机**——这是未完成的工作。
- memory `devflow-aichat-session-analysis-2026-06-22` 已标的「最高杠杆 P0-2 编排规划能力弱」即此问题的上层概括。本报告是其**数据库实证版**。
---
## 五、方向建议(仅诊断,未实施)
最高杠杆:**把「用户当前目标」从消息流提升为一等结构化状态**。
1. **目标钉扎**:首轮提取用户目标为结构化字段(不依赖压缩摘要),每轮 agentic loop 顶部重注入 system。目标消息压缩出局后结构化目标仍在。
2. **探索熔断**:跟踪连续无进展 / 空结果次数,超阈值强制「回顾目标」或停止,防游荡死循环 + token 失控。
3. **状态机收敛**:把目标 + 进度纳入 `conv_state.rs` 状态机(当前分支已在做),目标作为状态而非消息。
4. **弱化 / 修正话题标记**:话题标记基于失真历史且可能反向误导,宜降级或改为「目标漂移检测」而非 topic 关键词切换。
---
## 附:待查 Bug
- `[seq1]` 一条 LLM 内部独白("等等,`process_tool_calls` 是从 `super::audit` 导入的。让我检查一下…")被存为 `system` 消息(`status=active`)。疑似 reasoning / 思考内容泄漏进 system 消息(`stream_recv` 归位问题),进一步污染上下文。待独立排查。
---
## 证据定位(源码)
| 机制 | 位置 |
|---|---|
| 上下文压缩 / sanitize / topic 字段 | `crates/df-ai/src/context.rs` |
| 话题切换 marker 消费 | `src-tauri/src/commands/ai/agentic/mod.rs:735-772` |
| 压缩 insert_at 摘要 | `src-tauri/src/commands/ai/agentic/mod.rs:820, 918, 969` |
| 多 Agent 协调(空壳) | `crates/df-ai/src/coordinator.rs` |
| Plan 规划(未接入 loop | `crates/df-ai/src/planner.rs` |
| 意图识别(关键词) | `crates/df-ai/src/intent.rs` |
| system prompt 聚焦准则 / 压缩 prompt | `src-tauri/src/commands/ai/prompt.rs:104, 233` |
| 对话状态机(进行中) | `src-tauri/src/commands/ai/agentic/conv_state.rs` |