18 KiB
18 KiB
Unified Project AI Handoff 成功案例验收包
目的
这份文档把 统一 Project Operating Context + 三路 handoff 的 12 条黄金场景收成可直接过目的“成功案例包”。
本文聚焦三件事:
- 每条 case 的最小输入
- 从哪里入站、经过哪些主链、按什么步骤验
- 成功时应该看到的结构化输出与最终用户可见输出
使用边界
- 本文是“成功目标样例 + 验收步骤”文档,不等于 12 条都已经做完人工业务走读。
- 文中的结构化输出与最终输出,表示该 case 验收成功时应看到的目标结果。
- 自动化证据以 2026-04-17-feishu-problem-inventory.md 为真源。
- 飞书前台验收默认先看“后端最终出站”:
- 非交互 QA 看
qa_direct文本 - 强交互 requirement / draft 看 action card payload
- 非交互 QA 看
- 所有 Feishu 场景都必须经过
feishu_reply_outbox;如果没有看到 outbox,就不能算飞书链路验收成功。
通用验收步骤
每条 case 都按同一顺序验:
- 准备前置上下文
- 用真实入站面发送最小输入
- 先看结构化输出是否命中预期主链
- 再看最终用户可见输出是否符合合同
- 记录 pass / fail 与证据
每条 case 至少记录这 6 项:
- 输入
- 入站面
- 主链
- 结构化输出
- 最终输出
- 结果判定
Feishu 场景统一 Transport 合同
凡是本文中真实入站面包含 Feishu 的 case,除了看业务主链,还必须额外确认 transport 层。
非交互 QA 文本
必经链路:
message.receive_v1
-> handle_message_event()
-> _handle_message_receive()
-> capture_from_feishu()
-> _route_scene_reply()
-> _build_feishu_qa_direct_reply_text()
-> _safe_reply_text()
-> FeishuReplyOutboxMixin._enqueue_reply_outbox()
-> feishu_reply_outbox
必验点:
reply_route=qa_directfeishu_reply_outbox.message_text是纯文本- 文本里包含成功案例要求的正文 / 当前项目 / 外部判断 / 下一步
交互卡片
必经链路:
message.receive_v1 或 card.action.trigger
-> handle_message_event()
-> _handle_message_receive() / _handle_card_action_trigger()
-> _route_scene_reply()
-> _build_action_card_from_capture_result()
-> _safe_reply_card()
-> FeishuReplyOutboxMixin._enqueue_reply_outbox()
-> feishu_reply_outbox
必验点:
reply_route=qa_action_card或对应 card action 路由feishu_reply_outbox.message_text以__pmflow_feishu_card__:开头- 解码后的 card payload 保留正确
action和work_item_id
Case 01
场景
纯内部系统问题
前置条件
- 当前在项目页或带
project_id=17的 Web 问答入口 - 无 active requirement-plan / draft confirm 干扰
输入
- 用户原话:
当前 PMFlow 里 MCP 模板有几个? - 真实入站面:Web
POST /rag/ask
示例请求:
{
"question": "当前 PMFlow 里 MCP 模板有几个?",
"asked_via": "pmflow_manual",
"project_id": 17,
"action_mode": "read"
}
详细步骤
- 从项目页问答入口发起问题。
- 查看
/rag/ask返回 payload 中的route_decision。 - 确认
route_mode=internal,且没有被转成 external。 - 查看最终
answer是否以内部知识库查询:开头。
成功结构化输出
{
"route_decision": {
"route_mode": "internal",
"effective_source_policy": "internal"
}
}
成功最终输出
内部知识库查询:当前 PMFlow 里共有 2 个 MCP 模板。
成功判定
- 命中 internal 主链
- 不混入外部来源摘要
- 不是泛化聊天式说明
Case 02
场景
纯外部事实问题
前置条件
- 普通 QA 线程
- 无 active requirement-plan
输入
- 用户原话:
OpenAI Docs 最近有没有新的 Responses API 最佳实践? - 真实入站面:Web
POST /rag/ask
示例请求:
{
"question": "OpenAI Docs 最近有没有新的 Responses API 最佳实践?",
"asked_via": "pmflow_manual",
"action_mode": "read"
}
详细步骤
- 从 Web QA 入口提交问题。
- 检查
route_decision.route_mode是否为external。 - 检查 external 证据是否经过 fail-closed 过滤。
- 查看最终回答是否保持
外部实时查询:合同。
成功结构化输出
{
"route_decision": {
"route_mode": "external",
"effective_source_policy": "external"
}
}
成功最终输出
外部实时查询:OpenAI Docs 最近补充了新的 Responses API 最佳实践说明。
成功判定
- 只能走 external 主链
- internal 来源不得混进 external 正文
Case 03
场景
先判断,再给 plan 入口
前置条件
- 当前项目明确
- repo 摘要可用
- 允许 external lane 构建
fit_brief
输入
- 用户原话:
OpenAI Docs 这种能力适不适合我们当前项目? - 真实入站面:
- Web
POST /rag/ask - Feishu
message.receive_v1
- Web
Web 示例请求:
{
"question": "OpenAI Docs 这种能力适不适合我们当前项目?",
"asked_via": "pmflow_manual",
"project_id": 12,
"source_chat_id": "chat-12",
"action_mode": "read"
}
Feishu 最小入站:
{
"message_type": "text",
"chat_id": "chat-12",
"sender_open_id": "ou-alpha",
"message_id": "om-case-03",
"content": "OpenAI Docs 这种能力适不适合我们当前项目?"
}
详细步骤
- 从 Web 或 Feishu 发问题。
- 检查
project_operating_context是否带上当前项目。 - 检查
execution_recipe.plan_handoff_mode是否为offer_after_answer。 - 检查
handoff_mode / can_enter_plan / recommended_next_step。 - Feishu 侧检查
_route_scene_reply()是否走到qa_direct。 - Feishu 侧检查
feishu_reply_outbox.message_text是否为最终出站文本。 - Feishu 侧再看最终
qa_direct文本是否已经变成围绕当前项目实体的自然分析回复,而不是标签摘要。
成功结构化输出
{
"project_operating_context": {
"current_project_id": 12,
"fit_scope": "current_project_and_repo",
"decision_strategy": "answer_then_offer_plan"
},
"execution_recipe": {
"primary_lane": "external",
"fit_brief_required": true,
"external_evidence_required": true,
"plan_handoff_mode": "offer_after_answer"
},
"handoff_mode": "offer_after_answer",
"can_enter_plan": true,
"recommended_next_step": "如果你要,我可以基于当前结论进入 plan,继续把需求范围和下一步收清楚。"
}
成功最终输出
Web:
外部实时查询:目前更像背景相关,建议先验证它是否能映射到当前项目正式对象。
Feishu:
外部实时查询:目前更像背景相关,建议先验证它是否能映射到当前项目正式对象。
结合当前项目看,Alpha 是一个 AI 项目管理工作台,当前仓库负责统一项目上下文与 AI handoff。就这次判断来说,这条外部信息目前更像背景相关,还不能直接映射到当前正式对象,所以现在更适合作为参考,而不是直接当成已经命中当前项目的正式变化。
如果你要,我可以基于当前结论进入 plan,继续把需求范围和下一步收清楚。
成功判定
- 先给判断
- 再给 plan 入口
- 不得首轮直接切到 plan 主链
Case 04
场景
显式强锚点直接进 plan
前置条件
- 上一轮已经给出结论
- 当前消息显式 reply 到上一轮结论
输入
- 用户原话:
那按这个推进 - 真实入站面:Feishu
message.receive_v1reply/thread
示例入站:
{
"message_id": "om-case-04",
"reply_to_message_id": "om-case-03-bot",
"chat_id": "chat-12",
"content": "那按这个推进"
}
详细步骤
- 用 reply/thread 回复上一条结论消息。
- 检查 canonical thread context 是否恢复成功。
- 检查
execution_recipe.plan_handoff_mode是否命中explicit_plan_now,或直接回到 active requirement context。 - 检查
_route_scene_reply()后是否进入 card 或 follow-up 对应出站路径。 - 检查最终 Feishu 回包是否通过
feishu_reply_outbox出站。 - 检查输出是否继续 requirement-plan,而不是普通 QA。
成功结构化输出
{
"execution_recipe": {
"plan_handoff_mode": "explicit_plan_now"
}
}
成功最终输出
AI PMO 需求收敛:我先按这条结论继续收敛需求范围。
成功判定
- 直接 handoff 到 plan
- 不是重新解释 internal / external 模式
Case 05
场景
reply/thread 明确续问
前置条件
- 机器人上一条已给出解释性回复
- 当前消息显式 reply 到该条回复
输入
- 用户原话:
你刚才这条说的“模型路由”具体指哪层? - 真实入站面:Feishu reply/thread 或 QA session follow-up
详细步骤
- 对上一条机器人解释消息做显式回复。
- 检查 follow-up anchor 是否优先命中 reply anchor。
- 检查问题是否被重写到上一条回复对象。
- 确认没有被旧
last_subject抢走。
成功结构化输出
{
"anchor_mode": "reply_anchor",
"resolved_anchor": {
"source_message_id": "om-prev-answer"
}
}
成功最终输出
内部知识库查询:这里说的“模型路由”指的是 PMFlow 本地路由层里的 tier / provider / response contract 决策层。
成功判定
- 续问对象来自 reply anchor
- 不是把它当新问题重开
Case 06
场景
同群同人但切新话题
前置条件
- 同一群聊、同一用户
- 上一轮刚结束 requirement-plan
输入
- 用户原话:
另外,现在 PMFlow 里 signal source onboarding 做到哪了? - 真实入站面:Feishu
message.receive_v1
详细步骤
- 在同一群里直接发一条新的事实问题。
- 检查 session inheritance guard 是否拦住旧 requirement-plan 续写。
- 检查显式 signal-source 请求是否避开 draft/plan 劫持。
- 检查最终回答是否回到 internal query。
成功结构化输出
{
"route_decision": {
"route_mode": "internal"
}
}
成功最终输出
内部知识库查询:当前 PMFlow 的 signal source onboarding 已支持受控接入与运行时探测。
成功判定
- 不得继续沿 requirement-plan 解释
- 必须识别为新的 internal query
Case 07
场景
旧 active context 劫持新问题
前置条件
- 上一轮挂着
pending_clarification(kind=query_route_selection) - 当前用户显式改题
输入
- 用户原话:
不是说那个,我现在问 external gateway。 - 真实入站面:Feishu
message.receive_v1或 Web QA session
详细步骤
- 先制造一个 query-route 澄清状态。
- 再发送这条显式改题消息。
- 检查 ingress 是否调用
WorkflowSemanticPlanner看topic_switch=new。 - 检查旧
pending_clarification是否被立即清空。 - 确认没有继续调用旧 session 的澄清协议消费链。
成功结构化输出
{
"pending_clarification": null,
"next_route": "query.answer"
}
成功最终输出
外部实时查询:external gateway 当前负责统一外部查询计划、provider 分发和结果校验。
成功判定
- 旧
pending_clarification必须失效 - 当前消息必须作为新 query 进入主链
Case 08
场景
明明该继续 plan,却掉回 query.answer
前置条件
- active requirement-plan 正在进行
- 上一轮刚发 A/B/C 选项
输入
- 用户原话:
我选 C - 真实入站面:Feishu
message.receive_v1
详细步骤
- 先进入 requirement-plan 并发出 A/B/C。
- 再发送
我选 C。 - 检查 active requirement context 是否命中当前 option map。
- 确认协议解析直接 bypass 普通 QA semantic gate。
- 查看最终输出是否继续 requirement-plan follow-up。
成功结构化输出
{
"reply_template_key": "requirement_plan_followup",
"parsed_choice": "C"
}
成功最终输出
C. 混合增强路径
⭐ 当前我更推荐:C
成功判定
- 不得掉回普通 QA
- 必须继续当前 requirement-plan 主链
Case 09
场景
明明只是问结论,却被直接拉进 plan
前置条件
- 无 active plan
- 无显式 reply/thread 强锚点
输入
- 用户原话:
这个方案适不适合我们现在这套 PMFlow? - 真实入站面:Web
POST /rag/ask或 Feishumessage.receive_v1
详细步骤
- 直接发一条适配性判断问题。
- 检查
execution_recipe.plan_handoff_mode。 - 确认首轮还是
offer_after_answer,不是explicit_plan_now。 - 确认最终输出先给结论,再给下一步。
成功结构化输出
{
"execution_recipe": {
"plan_handoff_mode": "offer_after_answer"
},
"recommended_next_step": "如果你要,我可以基于当前结论进入 plan。"
}
成功最终输出
外部实时查询:目前适合作为背景参考,但还需要验证它与当前 PMFlow 正式对象的映射关系。
成功判定
- 首轮不能直接进入 plan
- 必须保留“先答结论,再给下一步”
Case 10
场景
卡片动作和纯文本回复不一致
前置条件
- 同一 requirement thread 同时支持按钮和文本协议
- 当前 active
work_item_id已存在
输入
- 文本输入:
选 B - 卡片输入:点击
B按钮 - 真实入站面:
- 文本:Feishu
message.receive_v1 - 卡片:Feishu
card.action.trigger
- 文本:Feishu
详细步骤
- 在同一 requirement 轮次里保留当前 action card。
- 用文本发
选 B。 - 再用卡片点击
B。 - 检查两条路径是否都命中同一
work_item_id和 canonical thread context。 - 检查文本和卡片两条路径都写入
feishu_reply_outbox。 - 检查最终都继续 requirement-plan。
成功结构化输出
{
"work_item_id": 88,
"action": "plan_choice",
"choice": "B"
}
成功最终输出
{
"header": {
"title": {
"content": "AI PMO 需求收敛"
}
},
"elements": [
{
"tag": "action",
"actions": [
{
"value": {
"action": "plan_choice",
"choice": "B",
"work_item_id": 88
}
}
]
}
]
}
成功判定
- 文本和按钮都命中同一 requirement thread
- 不能出现“一条续上、一条掉链”
Case 11
场景
Web 与 Feishu 对同一句话不同链路
前置条件
- 当前项目一致
- Web 与 Feishu 都从同一项目语境发问
输入
- 用户原话:
这个适合吗 - 真实入站面:
- Web
POST /rag/ask - Feishu
message.receive_v1
- Web
详细步骤
- 用同一句话分别从 Web 和 Feishu 发起问题。
- 对比两边的
project_operating_context。 - 对比两边的
execution_recipe和handoff_mode。 - Web 看结构化 meta。
- Feishu 检查
_route_scene_reply()是否进入qa_direct,并写入feishu_reply_outbox。 - Feishu 再看最终
qa_direct文本。
成功结构化输出
{
"execution_recipe": {
"plan_handoff_mode": "offer_after_answer"
},
"handoff_mode": "offer_after_answer",
"can_enter_plan": true
}
成功最终输出
Web:
外部实时查询:目前更像背景相关,还不能直接映射到当前正式对象。
Feishu:
外部实时查询:目前更像背景相关,还不能直接映射到当前正式对象。
结合当前项目看,Alpha 是一个 AI 项目管理工作台,当前仓库负责统一项目上下文与 AI handoff。就这次判断来说,这条外部信息目前更像背景相关,还不能直接映射到当前正式对象,所以现在更适合作为参考,而不是直接当成已经命中当前项目的正式变化。
如果你要,我可以基于当前结论进入 plan,继续把需求范围和下一步收清楚。
成功判定
- 两边都必须是
offer_after_answer - 不能一边进 plan、一边留在普通 QA
Case 12
场景
多候选 meta follow-up 需要澄清
前置条件
- 最近 5 分钟内有 2 条候选回复
- 当前问题无法唯一锚定某一条
输入
- 第一轮:
那你刚才那条是哪个模型回复的? - 第二轮:
第二条 - 真实入站面:Feishu / QA session follow-up
详细步骤
- 先制造两个最近候选回复。
- 发送第一轮 meta follow-up。
- 检查是否返回
ambiguous_recent_reply和编号候选。 - 再发送
第二条。 - 检查是否恢复
original_question并绑定正确selected_qa_id。
成功结构化输出
第一轮:
{
"clarification_code": "ambiguous_recent_reply",
"clarification_candidates": [
{"index": 1},
{"index": 2}
]
}
第二轮:
{
"selected_qa_id": 102,
"effective_question": "我问你这个是哪个模型执行回复的?"
}
成功最终输出
第一轮:
我找到两条可能对应的回复:
1. ...
2. ...
请告诉我是第几条。
第二轮:
内部知识库查询:你选的是第二条,那条回复由当前 query.answer 主链执行。
成功判定
- 第一轮必须先澄清
- 第二轮必须支持中文编号恢复原问题
建议过目顺序
如果你是要先审文档,再决定人工走读顺序,建议按这 4 条先看:
- Case 03:先判断,再给 plan 入口
- Case 07:旧澄清失效
- Case 08:A/B/C 继续 requirement-plan
- Case 11:Web / Feishu 同句一致
这 4 条最能看出 unified handoff 现在是不是真的站住了。