From bbebd34d226880088f6c370545e920c2bdf88bf3 Mon Sep 17 00:00:00 2001 From: Jia Sui Date: Sat, 3 Oct 2026 22:41:44 +0800 Subject: [PATCH] =?UTF-8?q?docs(engine):=20=E8=A1=A5=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E6=96=87=E9=87=8D=E6=8E=92=E5=88=87=E5=88=86=E4=B8=8E=E7=94=A8?= =?UTF-8?q?=E4=BE=8B=E6=89=93=E5=88=86=E7=9A=84=E5=89=8D=E6=8F=90=E8=AF=B4?= =?UTF-8?q?=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit R2 的分层判据是 canonical_pinyin == winner_key。原注释只说明了「整句与词格行 同键」,没解释为什么整键档**必然**是 winner_key。而 query_single_cut_keyed 在精确 键查空时会退到前缀区间扫描,那类行的 canonical 是别的读音(gun'qi 捞出 gun'qiu), 放宽判据就会静默把同档整词沉到末尾——正是本任务在修的那类回归。补上这条不变量: decode_pool 由 query_exact_segmentations_keyed_flat 只收精确键构造,词库里没有整词的 切分进不了池,这条路在胜出切分上不可达。 测试侧补上「fixture 无 sc.lm ⇒ 启发式打分 ⇒ 用例确定」这个前提(同组 ranking fixture 已有,新用例依赖同一前提却没写)。 --- engine/quanpin/quanpin_dictionary.cpp | 6 ++++++ engine/tests/src/test_input_session.cpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/engine/quanpin/quanpin_dictionary.cpp b/engine/quanpin/quanpin_dictionary.cpp index ff2bfe77..23fc234b 100644 --- a/engine/quanpin/quanpin_dictionary.cpp +++ b/engine/quanpin/quanpin_dictionary.cpp @@ -518,6 +518,12 @@ std::vector QuanpinDictionary::query_exact(const std::string &raw_inpu // segmentation 填 canonical_pinyin,词格 select_distinct 用 path->key——所以 // 按 canonical_pinyin == winner_key 能干净地把前缀行摘出去。 // + // 这个判据依赖一个前置事实:整键档的 canonical 必然就是 winner_key 本身。 + // 胜出切分只能出自 decode_pool,那里用 query_exact_segmentations_keyed_flat + // 只收精确键,词库里没有整词的切分压根进不了池;于是整键档走的是 + // query_single_cut_keyed 的精确键分支,不会退到前缀区间扫描那层降级 + // (那种行的 key 是别的读音,会被这个判据误当成前缀行沉到末尾)。 + // // 不切开会破坏 merge_alternative_segmentations 的既有分层(merged_full 在前、 // 前缀作为 remaining 追加):query_series(ban'zheng) 先出 办证/辩证/整句,再出 // 班/办/半/般…,而班长、搬账这些同键位整词在 rest 里、排在单字之后,整组被挤 diff --git a/engine/tests/src/test_input_session.cpp b/engine/tests/src/test_input_session.cpp index ddb4366b..4641c885 100644 --- a/engine/tests/src/test_input_session.cpp +++ b/engine/tests/src/test_input_session.cpp @@ -416,6 +416,8 @@ void run_autocorrect_context_ranking_tests(const std::filesystem::path &data_dir // 办证/辩证/整句还带着首音节的单字;这些单字排在 rest(班长、搬账)之前,把同键位的 // 其他整词整组挤出首页。原 fixture 没有 tbl_1_b,前缀这条路根本没被走到。 // 这里补单字表,并直接断言「整键在前、前缀在后」这条分层不变量。 +// 同上一组 fixture:词库目录里没有 sc.lm,词格退回启发式打分,权重完全决定路径分, +// 因此 zheng 侧稳定胜出、重排稳定接管,用例不依赖任何模型文件。 void run_autocorrect_context_layering_tests(const std::filesystem::path &data_directory) { const std::filesystem::path directory = data_directory / "autocorrect-context-layering";