427 lines
14 KiB
Markdown
427 lines
14 KiB
Markdown
# 飞书提问慢 + AI 管家分层回复 + 历史需求不同步 — 修改计划
|
||
|
||
**目标问题**
|
||
- 飞书里把需求写成问句时,系统经常只回答,不同步到需求/信号链路。
|
||
- 飞书连续追问时,上一条需求和上下文不能稳定续上。
|
||
- 内置 AI 管家回复偏“分层汇报/任务分派”,不够直接。
|
||
- 部分问题会被拉进深度推理链路,导致响应时间明显偏长。
|
||
|
||
**本计划目标**
|
||
- 问句式需求也能进入同步链路,不再被 `QA bypass` 吃掉。
|
||
- 飞书问答建立可持续的 chat/session 上下文,不再依赖 `asked_by`。
|
||
- 历史需求支持“即时可见 + 默认可召回”,不依赖“之前/上次/历史”关键词。
|
||
- AI 管家事实问答改成直接回答风格,执行回执和问答风格分离。
|
||
- 控制飞书直答长尾时延,避免无必要进入 deep reasoning。
|
||
|
||
**非目标**
|
||
- 本次不改飞书卡片 UI。
|
||
- 本次不做多渠道统一会话中心重构。
|
||
- 本次不改业务字段模型的大范围语义定义,只修正问答/同步链路。
|
||
|
||
## 实施状态(2026-03-06)
|
||
- [x] Phase 1 已启动:问句式需求从“只答不入队”改为“答复 + 继续同步”。
|
||
- [x] Phase 5 部分已启动:RAG 事实问答关闭默认角色 prompt 注入,减少模板化分层回答污染。
|
||
- [x] 已补首批轻量单测:问句需求识别与问句转陈述归一化。
|
||
- [x] Phase 2 部分已启动:飞书问答接入 `conversation_key`,`asked_by=None` 也可复用 Redis recent turns。
|
||
- [x] Phase 3 部分已启动:飞书 recent conversation 走同步缓存读取,不依赖向量入库完成。
|
||
- [x] Phase 4 部分已启动:飞书渠道默认补充 `feishu` 检索域(有 `source_chat_id` 时)。
|
||
- [x] Phase 6 部分已启动:飞书渠道 deep 触发改为“显式深查意图”白名单,默认不强制 deep。
|
||
- [x] Phase 6 部分已启动:飞书 deep 检索预算收紧(steps/top_k 下调),降低长尾时延风险。
|
||
- [x] Phase 3 部分补齐:`capture_from_feishu` 在非 RAG 分支同步写 recent cache(Redis),减少“刚发需求即追问”丢上下文。
|
||
- [x] 回归压测脚本补齐:`ai_steward_pressure_coach.py` 新增 `feishu_capture` 模式与 `question_requirement_hit_rate` 指标,`ai_steward_eval_compare.py` 可比较 pressure 报告。
|
||
- [x] 飞书分流稳定性补丁:`level/signal/project_prefill` 在 LLM 空返回或异常时走规则兜底,不再直接 `pipeline_failed`。
|
||
|
||
---
|
||
|
||
## 一、根因拆分
|
||
|
||
### 1. 问句式需求被直接路由为 QA
|
||
- 现状:`intent == "question"` 时直接走 `rag_service.answer_question(...)`,并跳过 `signal/project` 处理。
|
||
- 结果:用户把需求写成“这个要不要支持 X”“能不能加 Y”时,只得到回答,不会同步到需求链路。
|
||
|
||
### 2. 飞书侧没有会话态
|
||
- 现状:飞书问答传入 `asked_by=None`,RAG 层不创建 session,也不加载 recent conversation。
|
||
- 结果:后续追问缺少主语继承、纠错继承、最近 10 轮上下文。
|
||
|
||
### 3. 飞书历史是异步 eventual consistency
|
||
- 现状:飞书消息向量化使用 `asyncio.create_task(...)` 后台入库。
|
||
- 结果:用户刚发完需求马上追问时,上一条消息可能还没进入检索库。
|
||
|
||
### 4. 飞书历史不是默认检索域
|
||
- 现状:只有命中“之前/上次/历史”等关键词才显式加入 `feishu` 检索域。
|
||
- 结果:即使同群同线程,系统也不会默认回看最近飞书上下文。
|
||
|
||
### 5. 问答 prompt 与执行回执 prompt 混用
|
||
- 现状:RAG 问答默认套用“产品经理(任务分派)”角色 prompt;飞书回复层又要求“先确认,再给建议”。
|
||
- 结果:事实问答也会被答成分层汇报风格。
|
||
|
||
### 6. Deep reasoning 触发范围偏宽
|
||
- 现状:纠错类、引擎链类问题会被强制切到 deep;同时存在 mixed routing / escalation / 较长 timeout。
|
||
- 结果:飞书直答的长尾延迟被放大。
|
||
|
||
---
|
||
|
||
## 二、总体改造策略
|
||
|
||
本次按 4 条主线并行改:
|
||
|
||
1. **路由修正**
|
||
- 把“问句”和“需求”从互斥关系改成可并行判定。
|
||
- 新增 `question_requirement` 场景:既回答用户,也同步需求。
|
||
|
||
2. **会话补齐**
|
||
- 给飞书引入基于 `source_chat_id + sender_open_id` 的 conversation key。
|
||
- 让飞书侧也能复用 `session state / rewrite history / recent turns`。
|
||
|
||
3. **同步改强**
|
||
- 最近消息缓存同步写入 Redis。
|
||
- 向量化继续异步,但“最近上下文”不再依赖向量写库完成。
|
||
|
||
4. **回答链路瘦身**
|
||
- 事实问答关闭任务分派型 role prompt。
|
||
- 飞书执行回执与事实问答拆成两套 prompt。
|
||
- 缩小 deep 模式触发面,限制长尾。
|
||
|
||
---
|
||
|
||
## 三、详细改造项
|
||
|
||
## Phase 1 — 问句式需求不再丢同步
|
||
|
||
### 目标
|
||
- “这个需求要不要支持飞书同步?”
|
||
- “能不能给项目列表加筛选?”
|
||
- “这个是不是也要记录到需求池?”
|
||
|
||
以上消息不再只走 QA,而是进入“回答 + 需求同步”双通道。
|
||
|
||
### 修改点
|
||
- `backend/app/services/feishu_signal_pipeline.py`
|
||
- 把当前 `question / mixed / statement` 三段式改为:
|
||
- `pure_qa`
|
||
- `qa_with_requirement`
|
||
- `pure_requirement`
|
||
- 在 `intent == "question"` 后增加二次判定:
|
||
- 是否包含需求动作词
|
||
- 是否存在功能/模块/页面/流程对象
|
||
- 是否指向已有项目或潜在新需求
|
||
- 命中时:
|
||
- 保留 direct reply
|
||
- 同时继续执行 signal/project 分流
|
||
|
||
### 实现建议
|
||
- 新增 helper:
|
||
- `_is_requirement_like_question(message: str) -> bool`
|
||
- `_extract_question_requirement_statement(message: str) -> str`
|
||
- 对 `question_requirement`:
|
||
- `rag_question_part` 继续回答
|
||
- `message_for_sync` 进入 `_classify_level` / `_extract_signal` / `_project_prefill`
|
||
|
||
### 验收
|
||
- 问句式需求消息能生成 direct reply。
|
||
- 同一消息同时落需求队列或自动入 signal。
|
||
- `AIProcessingLog.routing_decision` 不再统一落到 `direct_qa`。
|
||
|
||
---
|
||
|
||
## Phase 2 — 为飞书补 session / state
|
||
|
||
### 目标
|
||
- 飞书连续两三句追问时,可以继承上一轮主语。
|
||
- “不是这个意思”“我说的是刚才那个需求”可以命中纠错链路。
|
||
|
||
### 修改点
|
||
- `backend/app/services/adaptive_rag_service.py`
|
||
- `backend/app/schemas/rag.py`
|
||
- `backend/app/api/rag.py`
|
||
- `backend/app/api/ai_steward.py`
|
||
- `backend/app/services/context_cache.py`
|
||
|
||
### 设计
|
||
- 新增统一字段:`conversation_key`
|
||
- Web: `user:{asked_by}:session:{session_id}`
|
||
- Feishu: `feishu:{source_chat_id}:{sender_open_id or sender_hash}`
|
||
- `answer_question(...)` 新增可选参数:
|
||
- `conversation_key`
|
||
- `external_actor_id`
|
||
- `channel_thread_id`
|
||
- `asked_by is None` 时:
|
||
- 不再直接返回空 session
|
||
- 改为基于 `conversation_key` 维护轻量会话态
|
||
|
||
### 数据方案
|
||
- 优先最小改造,不先扩 DB 表:
|
||
- `QASessionState` 继续存结构化 state
|
||
- Redis 里为飞书维护 recent turns
|
||
- 如现有表难以复用,再补一张轻量表:
|
||
- `external_qa_sessions`
|
||
- `id`
|
||
- `tenant_id`
|
||
- `channel`
|
||
- `conversation_key`
|
||
- `source_chat_id`
|
||
- `external_actor_id`
|
||
- `last_message_at`
|
||
- `message_count`
|
||
|
||
### 验收
|
||
- 飞书下第二句“分别是什么”“不是这个意思”可以继承上一轮主语。
|
||
- 不依赖 `asked_by` 也能拿到 recent conversation。
|
||
|
||
---
|
||
|
||
## Phase 3 — 最近消息同步写缓存,向量化继续异步
|
||
|
||
### 目标
|
||
- 解决“上一条需求刚发完,下一条就检索不到”的即时一致性问题。
|
||
|
||
### 修改点
|
||
- `backend/app/services/signal_capture.py`
|
||
- `backend/app/services/adaptive_rag_service.py`
|
||
- `backend/app/services/context_cache.py`
|
||
|
||
### 方案
|
||
- 飞书消息接收后,拆成两层写入:
|
||
- **同步写 Redis recent turns**
|
||
- key: `pmflow:feishu:recent:{tenant_id}:{conversation_key}`
|
||
- 保存最近 20 条消息
|
||
- **异步写向量库**
|
||
- 保留原 `ingest_feishu_message_async(...)`
|
||
- RAG 检索时增加优先级:
|
||
- 先读 recent turns cache
|
||
- 再查结构化 state
|
||
- 最后再查向量库历史
|
||
|
||
### 好处
|
||
- 不阻塞主链路。
|
||
- 用户下一句追问时,最近上下文立即可用。
|
||
- 避免把“即时续聊”完全压到 embedding/vector 检索上。
|
||
|
||
### 验收
|
||
- 连续两条飞书消息间隔 < 3 秒,第二条仍可读到第一条内容。
|
||
|
||
---
|
||
|
||
## Phase 4 — 飞书历史默认参与召回
|
||
|
||
### 目标
|
||
- 不再要求用户必须说“之前/上次/历史”才能召回飞书历史。
|
||
|
||
### 修改点
|
||
- `backend/app/services/adaptive_rag_service.py`
|
||
|
||
### 方案
|
||
- `_route_domains(question)` 增加 channel-aware 行为:
|
||
- 若 `asked_via == "feishu"` 且存在 `source_chat_id`
|
||
- 默认把 `feishu_recent` 加入检索域
|
||
- 区分两类历史:
|
||
- `feishu_recent`:同 chat 最近 N 轮,低成本、默认启用
|
||
- `feishu_vector`:更早历史,命中 history cues 或低证据时再启用
|
||
|
||
### 检索顺序
|
||
1. recent chat cache
|
||
2. session state
|
||
3. db / graph / pmflow
|
||
4. feishu vector history
|
||
|
||
### 验收
|
||
- 不带“之前/上次”关键词,仍可在同群连续追问中续上上下文。
|
||
|
||
---
|
||
|
||
## Phase 5 — 问答 prompt 与执行回执 prompt 解耦
|
||
|
||
### 目标
|
||
- AI 管家 factual QA 直接回答,不再默认“复述需求 + 下一步动作”。
|
||
- 飞书执行回执保留有人味,但不污染事实问答。
|
||
|
||
### 修改点
|
||
- `backend/app/services/llm.py`
|
||
- `backend/app/config/ai_prompts.py`
|
||
- `backend/app/services/feishu_integration.py`
|
||
- `backend/app/services/adaptive_rag_service.py`
|
||
|
||
### 方案
|
||
- 新增 2 类 prompt 配置:
|
||
- `rag_factual_qa`
|
||
- `feishu_execution_receipt`
|
||
- `AdaptiveRAGService._generate_answer(...)`
|
||
- 默认 `use_prompt_profile=False`
|
||
- 或只允许使用专门的 `rag_factual_qa` role
|
||
- `FeishuIntegrationService._reply_with_active_role_prompt(...)`
|
||
- 只用于执行回执、纠错说明、状态反馈
|
||
- 不再包裹 direct QA 的正文
|
||
|
||
### 回复规范
|
||
- factual QA:
|
||
- 先直接给答案
|
||
- 证据不足直接说“不确定/缺少字段”
|
||
- 不强制“下一步动作”
|
||
- execution receipt:
|
||
- 可保留确认式口吻
|
||
- 但限制为 1 句确认 + 1 句后续动作
|
||
|
||
### 验收
|
||
- “这个接口在哪?”这类问题不再答成任务分派。
|
||
- 飞书 direct QA 不再出现“先确认,再给 1-3 条建议”的固定模板。
|
||
|
||
---
|
||
|
||
## Phase 6 — 收紧 deep reasoning 触发条件
|
||
|
||
### 目标
|
||
- 降低飞书长尾时延。
|
||
|
||
### 修改点
|
||
- `backend/app/services/adaptive_rag_service.py`
|
||
- `backend/app/services/llm.py`
|
||
|
||
### 方案
|
||
- `_forced_deep_reason(...)` 收紧:
|
||
- 仅对显式引擎链/代码链/纠错且证据不足场景触发
|
||
- Feishu 普通产品问答默认不自动 deep
|
||
- `_should_auto_deep_retry(...)` 增加预算:
|
||
- Feishu 渠道最多一次 retry
|
||
- 若 recent chat 命中充分,禁止 deep retry
|
||
- 配置预算:
|
||
- Feishu direct QA 目标 `p95 < 3s`
|
||
- deep 模式 hard timeout 更短
|
||
|
||
### 验收
|
||
- 同类飞书问题不再轻易进入 deep。
|
||
- 平均耗时和 p95 明显下降。
|
||
|
||
---
|
||
|
||
## 四、接口/数据变更清单
|
||
|
||
### 1. RAG 请求入参
|
||
- 新增:
|
||
- `conversation_key?: str`
|
||
- `external_actor_id?: str`
|
||
- `channel_thread_id?: str`
|
||
|
||
### 2. Redis keys
|
||
- `pmflow:feishu:recent:{tenant_id}:{conversation_key}`
|
||
- `pmflow:feishu:state:{tenant_id}:{conversation_key}`
|
||
|
||
### 3. 日志字段
|
||
- `conversation_key`
|
||
- `sync_mode` = `sync_recent_cache` / `async_vector_only`
|
||
- `question_requirement` = `true/false`
|
||
- `reply_style` = `factual_qa` / `execution_receipt`
|
||
|
||
---
|
||
|
||
## 五、测试计划
|
||
|
||
## 1. 单元测试
|
||
- `tests/test_feishu_question_requirement_routing.py`
|
||
- 问句式需求不再 bypass
|
||
- `tests/test_feishu_conversation_state.py`
|
||
- `asked_by=None` 时仍可续接上下文
|
||
- `tests/test_feishu_recent_cache_sync.py`
|
||
- recent cache 同步可见
|
||
- `tests/test_rag_prompt_style_split.py`
|
||
- factual QA 不再输出任务分派模板
|
||
|
||
## 2. 集成测试
|
||
- 基于现有 `backend/evals/feishu_replay_eval.py`
|
||
- 新增 case:
|
||
- “这个功能是不是也要支持飞书同步?”
|
||
- “再加一个导出按钮”
|
||
- “分别是什么”
|
||
- “不是这个意思,我说的是刚才那个需求”
|
||
|
||
## 3. 回归压测
|
||
- 扩展现有压测脚本:
|
||
- `scripts/ai_steward_pressure_coach.py`
|
||
- `scripts/ai_steward_eval_compare.py`
|
||
- 重点指标:
|
||
- Feishu direct QA `p50`
|
||
- Feishu direct QA `p95`
|
||
- deep hit rate
|
||
- requirement sync hit rate
|
||
- recent-context recall hit rate
|
||
|
||
---
|
||
|
||
## 六、验收标准
|
||
|
||
### 功能验收
|
||
- 问句式需求能同时“回答 + 同步”。
|
||
- 飞书连续追问能继承上一轮上下文。
|
||
- 不带“之前/上次”关键词也能续上同 chat 最近上下文。
|
||
- direct QA 回复风格改为直接回答,不再模板化分层。
|
||
|
||
### 性能验收
|
||
- Feishu direct QA:
|
||
- `p50 < 1.5s`
|
||
- `p95 < 3s`
|
||
- 无明显 template leak
|
||
- 无大面积 deep auto-trigger
|
||
|
||
### 稳定性验收
|
||
- recent cache 写入失败不影响主流程
|
||
- async vector ingestion 失败不影响 direct reply
|
||
- queue / signal / project 逻辑不回归
|
||
|
||
---
|
||
|
||
## 七、实施顺序
|
||
|
||
### 第 1 天
|
||
- Phase 1 路由修正
|
||
- 补 `question_requirement` 测试
|
||
|
||
### 第 2 天
|
||
- Phase 2 会话补齐
|
||
- recent turns cache 接入
|
||
|
||
### 第 3 天
|
||
- Phase 3 即时同步
|
||
- Phase 4 默认召回 recent feishu history
|
||
|
||
### 第 4 天
|
||
- Phase 5 prompt 解耦
|
||
- 修 direct QA 风格
|
||
|
||
### 第 5 天
|
||
- Phase 6 deep 触发收紧
|
||
- 压测与 replay 回归
|
||
|
||
---
|
||
|
||
## 八、风险点
|
||
|
||
1. **问句式需求误判增加**
|
||
- 对策:增加白名单/黑名单词表 + replay eval。
|
||
|
||
2. **Feishu recent cache 引入脏上下文**
|
||
- 对策:只保留最近 20 条,同 chat + 同 actor 隔离。
|
||
|
||
3. **prompt 解耦导致执行回执变冷**
|
||
- 对策:仅 direct QA 关闭分派 prompt,执行回执不动。
|
||
|
||
4. **deep 收紧后准确率下降**
|
||
- 对策:保留显式 deep 开关和低证据兜底 retry。
|
||
|
||
---
|
||
|
||
## 九、建议的首批改动文件
|
||
|
||
- `backend/app/services/feishu_signal_pipeline.py`
|
||
- `backend/app/services/adaptive_rag_service.py`
|
||
- `backend/app/services/context_cache.py`
|
||
- `backend/app/services/feishu_integration.py`
|
||
- `backend/app/services/llm.py`
|
||
- `backend/app/config/ai_prompts.py`
|
||
- `tests/test_feishu_question_requirement_routing.py`
|
||
- `tests/test_feishu_conversation_state.py`
|
||
|
||
---
|
||
|
||
## 十、一句话决策
|
||
|
||
这次不要只调 prompt。要同时改 **路由、会话、即时同步、回复风格、deep 触发** 五个点,否则“飞书里提需求慢 + 需求不同步 + 回答像汇报”会反复出现。
|