PMFlow/mdproject/feishu-ai-steward-sync-fix-...

427 lines
14 KiB
Markdown
Raw Permalink 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 管家分层回复 + 历史需求不同步 — 修改计划
**目标问题**
- 飞书里把需求写成问句时,系统经常只回答,不同步到需求/信号链路。
- 飞书连续追问时,上一条需求和上下文不能稳定续上。
- 内置 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 触发** 五个点,否则“飞书里提需求慢 + 需求不同步 + 回答像汇报”会反复出现。