95 lines
5.7 KiB
JSON
95 lines
5.7 KiB
JSON
{
|
||||
|
|
"artifact": "t2l-h01-clarify-exit",
|
|||
|
|
"generated_at": "2026-09-19T01:58:51.965029+00:00",
|
|||
|
|
"date_local": "2026-09-19",
|
|||
|
|
"purpose": "执行批次 H 的 H-01「澄清出口 E1」(批次 H 的第一步;用户诉求:让客服「会问」而不是「一问就让转人工」)",
|
|||
|
|
"scope": [
|
|||
|
|
"app/service/agent/implementations/customer_service.py(业务层:E5a 判定)",
|
|||
|
|
"tests/unit/service/test_customer_service_agent.py(新增 12 条单测)"
|
|||
|
|
],
|
|||
|
|
"pre_existing_state": {
|
|||
|
|
"already_present": "E5a 的出口本体(`_exit_clarify` / `CLARIFY_TEMPLATE` / `MAX_CLARIFY_ROUNDS=2`)与 E5b/E5c 分级此前已在位",
|
|||
|
|
"real_gaps_found": [
|
|||
|
|
"`needs_clarification` 全仓无消费方(分类器算出来、契约里有字段、没人读)",
|
|||
|
|
"没有任何「族」判定 ⇒ 无法区分「同族并列」与「跨族并列」",
|
|||
|
|
"缺主语(指代/过短且上文接不上)没有任何触发路径",
|
|||
|
|
"澄清触发只看分数带 ⇒ 同族并列也会被问「你要哪个」(伪问题)"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"implementation": {
|
|||
|
|
"added_helpers": {
|
|||
|
|
"_intent_needs_clarification()": "消费意图分类的 `needs_clarification`(DoD ①)",
|
|||
|
|
"_family_of(hit)": "取 `family_id`(`D2.4` v1.4「同族 = 同一个父块」);取不到返回空串",
|
|||
|
|
"_missing_subject(request)": "判据与 `_search_query()` 同源(过短 or `_REFERRING_WORDS`),结论相反:上文接不上才为真",
|
|||
|
|
"_clarify_reason(request, hits, *, score, gap)": "返回四类理由码之一或 None(决策单点)"
|
|||
|
|
},
|
|||
|
|
"four_triggers": {
|
|||
|
|
"cross_family_tie": "候选跨族且 top1 与次优咬得紧(gap < MIN_GAP)",
|
|||
|
|
"weak_cross_family": "分数不足(< MID_SCORE)且跨族、gap 够大",
|
|||
|
|
"missing_subject": "过短/指代词,且上文取不出主语",
|
|||
|
|
"low_intent_confidence": "意图分类 `needs_clarification=True`"
|
|||
|
|
},
|
|||
|
|
"same_family_guard": "`family_id` 唯一且非空 + gap < MIN_GAP ⇒ 返回 None(DoD ⑥:同族并列该合并作答,不该问「你要哪个」)",
|
|||
|
|
"family_label_missing": "族标缺失**不当作同族**(按跨族处理)——宁可多问一句,也不把两个族的答案混着答",
|
|||
|
|
"wiring": "`_answer_from_knowledge` 的「不确定带」改为先问 `_clarify_reason`;理由码入 logger",
|
|||
|
|
"entry_guard": "澄清仅在**检索本身也不确定**时可达(分数够高或领先够多时直接作答)——不让「会问」把答得出的问题变成问一句"
|
|||
|
|
},
|
|||
|
|
"dod_mapping": {
|
|||
|
|
"① needs_clarification 被消费": "`_intent_needs_clarification()`;单测 `test_classifier_needs_clarification_is_consumed`",
|
|||
|
|
"② 四类触发条件": "`_clarify_reason` 四个理由码;四条单测各覆盖一个",
|
|||
|
|
"③ 一次只问一个问题、2—3 候选": "`CLARIFY_TEMPLATE` 单问句 + `CLARIFY_LIMIT=3`(口径此前已在位,本轮回归覆盖)",
|
|||
|
|
"④ 候选只来自当前可见档位": "候选即工具返回的 hits,已按 `visibility` 档位裁剪;澄清模板注释写明",
|
|||
|
|
"⑤ 同话题上限 2 轮,超限降 E5b": "`MAX_CLARIFY_ROUNDS=2` + 轮次取自 `request.metadata.clarification_round`;单测 `test_clarification_round_cap_falls_back_to_partial_not_transfer` 验证**不建单**",
|
|||
|
|
"⑥ 同族并列不澄清": "`known_single_family and gap < MIN_GAP ⇒ None`;单测 `test_same_family_tie_does_not_clarify` + 出口级 `test_knowledge_exit_does_not_clarify_on_same_family_tie`"
|
|||
|
|
},
|
|||
|
|
"tests_added": {
|
|||
|
|
"file": "tests/unit/service/test_customer_service_agent.py",
|
|||
|
|
"count": 12,
|
|||
|
|
"names": [
|
|||
|
|
"test_cross_family_tie_triggers_clarification",
|
|||
|
|
"test_same_family_tie_does_not_clarify",
|
|||
|
|
"test_weak_score_across_families_triggers_clarification",
|
|||
|
|
"test_missing_subject_triggers_clarification_when_history_cannot_resolve_it",
|
|||
|
|
"test_missing_subject_is_not_clarified_when_history_resolves_it",
|
|||
|
|
"test_classifier_needs_clarification_is_consumed",
|
|||
|
|
"test_no_candidate_above_the_clarify_floor_means_no_clarification",
|
|||
|
|
"test_missing_family_label_is_treated_as_cross_family",
|
|||
|
|
"test_knowledge_exit_clarifies_on_cross_family_tie",
|
|||
|
|
"test_knowledge_exit_does_not_clarify_on_same_family_tie",
|
|||
|
|
"test_knowledge_exit_clarifies_when_subject_is_missing",
|
|||
|
|
"test_clarification_round_cap_falls_back_to_partial_not_transfer"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"gates": {
|
|||
|
|
"targeted_pytest": {
|
|||
|
|
"file": "tests/unit/service/test_customer_service_agent.py",
|
|||
|
|
"passed": 32,
|
|||
|
|
"failed": 0
|
|||
|
|
},
|
|||
|
|
"full_pytest": {
|
|||
|
|
"result": "2 failed / 1591 passed / 2 skipped",
|
|||
|
|
"note": "2 failed = T0 基线同两项;passed 1579 → 1591(+12 = 本轮新单测)"
|
|||
|
|
},
|
|||
|
|
"ruff": {
|
|||
|
|
"scope": "app tests tools",
|
|||
|
|
"errors": 22,
|
|||
|
|
"note": "= 基线"
|
|||
|
|
},
|
|||
|
|
"mypy": {
|
|||
|
|
"scope": "app",
|
|||
|
|
"errors": 3,
|
|||
|
|
"note": "= 基线;中途曾因局部变量 `reason` 与「检索降级」分支同名报 str|None 赋值错误,已改名 `clarify_reason` 修掉"
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
"honest_notes": [
|
|||
|
|
"同族并列**本期走 E5b**(部分答/引导),不是合并作答——合并作答要等 H-03(E4 证据约束生成),DoD ⑥ 只要求「不澄清」",
|
|||
|
|
"跨族 + 缺主语会先命中 `cross_family_tie` / `weak_cross_family` 理由码(行为同样是澄清),理由码不同但**结果一致**",
|
|||
|
|
"`needs_clarification` 只在检索也不确定时生效;检索有把握时仍然直接作答——「会问」不得以牺牲「答得准」为代价"
|
|||
|
|
],
|
|||
|
|
"open_follow_ups": [
|
|||
|
|
"H-03(E4):同族并列的**合并作答**,把 E5b 替换成证据约束生成",
|
|||
|
|
"H-04(E5 + 白名单收口):转人工 4 类白名单与 E5c 上下文摘要",
|
|||
|
|
"H-06:46 条金标评测(`D3.7`)"
|
|||
|
|
]
|
|||
|
|
}
|