<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[联想功能的两个小问题，就是用户词库是否参与联想，以及满码顶屏后的联想]]></title><description><![CDATA[<p dir="auto"><a href="/assets/uploads/files/1789879301724-%E7%BB%99%E4%BD%9C%E8%80%85%E7%9A%84%E6%8A%A5%E5%91%8A-%E8%AF%8D%E8%AF%AD%E8%81%94%E6%83%B3%E4%B8%A4%E4%B8%AA%E9%97%AE%E9%A2%98.txt">给作者的报告-词语联想两个问题.txt</a> ,md文件不支持，麻烦群主大人改一下后缀名。看一下，DSH分析的，参考啊。</p>
]]></description><link>https://forum.windinput.com/topic/185/联想功能的两个小问题-就是用户词库是否参与联想-以及满码顶屏后的联想</link><generator>RSS for Node</generator><lastBuildDate>Sat, 24 Oct 2026 23:42:40 GMT</lastBuildDate><atom:link href="https://forum.windinput.com/topic/185.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 20 Sep 2026 04:42:32 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to 联想功能的两个小问题，就是用户词库是否参与联想，以及满码顶屏后的联想 on Sun, 20 Sep 2026 08:22:27 GMT]]></title><description><![CDATA[<p dir="auto">词语联想的两个问题：用户词库不可见 + 满码自动上屏不触发联想</p>
<blockquote>
<p dir="auto">给 WindInput 作者的问题报告与改进建议（可直接作为 issue / discussion 正文提交）</p>
<ul>
<li><strong>环境</strong>：WindInput <strong>v0.122.0</strong>（<code>build 2026-09-20T01:31:34Z</code>，<code>git:a93e0de-dirty</code>，release），Windows 10 IoT 企业版 LTSC 10.0.19044</li>
<li><strong>方案</strong>：<code>wubi86</code>（五笔 86，最大码长 4），词库 = 极点主库 + extra + emoji + 行政区划（+ 用户自建的镜像库，见附录）</li>
<li><strong>相关配置</strong>：<code>[input.association] kind = "word"</code>、<code>mode = "continuous"</code>；<code>[schema.codetable] auto_commit_at_full</code> 在测试期间为 <strong><code>true</code></strong>（非出厂值，出厂 <code>false</code>）</li>
<li><strong>日志</strong>：<code>[debug] log_level = "debug"</code> 下的实录，正文引用均为原文</li>
</ul>
</blockquote>
<h2><a class="anchor-offset" name="摘要"></a>摘要</h2>
<p dir="auto">用户诉求只有一句：<strong>「词语联想也应该能联想我自己的词库」</strong>（原话参照：QQ 五笔可以）。实测下来是两条独立的问题叠加在一起：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>#</th>
<th>问题</th>
<th>影响</th>
<th>性质</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>A</strong></td>
<td>词语联想（以及其它消费反查索引的展示点）<strong>看不到用户词库与临时词</strong></td>
<td>联想里永远没有用户自己的词</td>
<td>数据源覆盖范围问题，是否支持请作者定夺</td>
</tr>
<tr>
<td><strong>B</strong></td>
<td><strong>满码唯一自动上屏（及同源的顶码上屏）不触发联想</strong></td>
<td>开了自动上屏的五笔用户，<strong>单字上屏后永远没有联想</strong></td>
<td>明确的接线缺口，建议修</td>
</tr>
</tbody>
</table>
<p dir="auto">两者叠加的用户可见现象就是「清风输入法的联想对我没用」。而 B 单独看更严重：五笔单字的全码绝大多数唯一 ⇒ 开自动上屏的用户，<strong>联想最主要的那个用法（打完一个字给以它开头的词）等于整个失效</strong>。</p>
<hr />
<h2><a class="anchor-offset" name="问题-b-先讲-因为它是-bug"></a>问题 B（先讲，因为它是 bug）</h2>
<h3><a class="anchor-offset" name="现象"></a>现象</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>操作</th>
<th>上屏路径</th>
<th>联想窗</th>
</tr>
</thead>
<tbody>
<tr>
<td>打<code>awsk</code>（「荷」，全码唯一，开了满码自动上屏）</td>
<td><strong>满码自动上屏</strong></td>
<td><img src="https://forum.windinput.com/assets/plugins/nodebb-plugin-emoji/emoji/android/274c.png?v=898858d396f" class="not-responsive emoji emoji-android emoji--x" style="height:1.4em;width:auto;vertical-align:middle" title="❌" alt="❌" /> 不出现</td>
</tr>
<tr>
<td>打<code>awfa</code> → 候选〔花卉 / 荷载〕→ 按空格选「荷载」</td>
<td>选词上屏</td>
<td><img src="https://forum.windinput.com/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=898858d396f" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:1.4em;width:auto;vertical-align:middle" title="✅" alt="✅" /> 正常（3 条，全部来自用户词库）</td>
</tr>
</tbody>
</table>
<h3><a class="anchor-offset" name="日志证据-同一份配置-同一次运行"></a>日志证据（同一份配置、同一次运行）</h3>
<p dir="auto"><strong>选词上屏 —— 正常：</strong></p>
<pre><code>2026-09-20 12:19:00.738 DEBUG wind_coordinator::coordinator::message_handler: key_event: code=0x20 mods=0x0000 chinese=true full=false caps=false prev_char=0x0000 buf='awfa'
2026-09-20 12:19:00.741 DEBUG wind_coordinator::handle_assoc: 进入联想态 n=3 kind=Word mode=Continuous
</code></pre>
<p dir="auto"><strong>自动上屏 —— 整段没有任何 <code>handle_assoc</code> 输出</strong>（<code>maybe_enter_assoc</code> 的三个静默 early-return 一个都没进）：</p>
<pre><code>（打 awsk 的整个时段只有 caret_update / 组合矩形 / 候选窗相关日志，无 handle_assoc 行）
</code></pre>
<p dir="auto"><strong>把 <code>auto_commit_at_full</code> 关掉之后，同一个键序立刻通了：</strong></p>
<pre><code>2026-09-20 12:24:41.550 DEBUG ... key_event: code=0x20 mods=0x0000 ... buf='awsk'      ← 第 4 键后按空格，不再自动上屏
2026-09-20 12:24:41.552 DEBUG wind_coordinator::handle_assoc: 进入联想态 n=9 kind=Word mode=Continuous
2026-09-20 12:24:42.579 DEBUG ... key_event: code=0x20 ... prev_char=0x8377 buf=''      ← 空格选中「荷载」
2026-09-20 12:24:42.579 DEBUG wind_coordinator::handle_assoc: 进入联想态 n=3 kind=Word mode=Continuous
</code></pre>
<p dir="auto">（<code>n=9</code> 那次的首条正是「荷载」，<code>n=3</code> 那次是「荷载取值 / 荷载效应 / 荷载组合」。）</p>
<h3><a class="anchor-offset" name="定位"></a>定位</h3>
<p dir="auto">联想的触发点被刻意放在 <code>commit_selected</code>，<code>docs/design/association.md</code> §3.1 原文：</p>
<blockquote>
<p dir="auto"><code>commit_selected</code> 的整串分支是<strong>六类选词触发的唯一汇合处</strong>（空格 / 数字键 / 次三选键 / 修饰键选词 / 鼠标点选 / 数字键越界 overflow）</p>
</blockquote>
<p dir="auto">而满码自动上屏（以及顶码上屏）走的是<strong>另一条路</strong>——<code>wind_input/crates/wind-coordinator/src/handle_candidate.rs</code> 里的 <code>InputOutcome::AutoCommit</code>：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>位置（v0.122.0）</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>L1068</td>
<td><code>let auto_commit = if result.should_commit &amp;&amp; !result.commit_text.is_empty() {</code></td>
</tr>
<tr>
<td>L1521–1523</td>
<td>`let auto_commit = auto_commit.or_else(                                         |</td>
</tr>
<tr>
<td>L1528</td>
<td><code>let outcome = match auto_commit {</code></td>
</tr>
<tr>
<td>L1563</td>
<td><code>InputOutcome::AutoCommit(c.text.clone())</code></td>
</tr>
<tr>
<td>L1648</td>
<td><code>Some(InputOutcome::AutoCommit(c.text.clone()))</code>（短语侧 <code>phrase_auto_commit</code>）</td>
</tr>
<tr>
<td>L1690（注释）</td>
<td>「顶码与全码自动上屏两条路径<strong>共用</strong>它——两者都是「引擎替用户做主上屏」」</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>旁证</strong>：整份 <code>handle_candidate.rs</code>（351 KB）里 <code>assoc</code> 出现 <strong>0 次</strong>——联想根本没有接在这条路上。</p>
<h3><a class="anchor-offset" name="影响面"></a>影响面</h3>
<ul>
<li>受影响人群 = <strong>所有开了 <code>schema.codetable.auto_commit_at_full</code> 的码表用户</strong>（本机就是；该值是用户配置里手动开的，出厂 <code>false</code>）。</li>
<li>五笔单字全码绝大多数唯一 ⇒ 单字几乎必然走自动上屏 ⇒ <strong>「打完『中』给『中国』」这个词语联想最核心的用法在他们那里完全不可用</strong>，而且<strong>完全静默</strong>：没有日志、没有提示，用户只会认为联想功能坏了。</li>
<li>顶码上屏（<code>top_code_commit</code>，<strong>出厂就是 <code>true</code></strong>）与自动上屏同源（见上表 L1690），推测同样不触发联想——这条没实测，请作者确认。</li>
</ul>
<h3><a class="anchor-offset" name="建议修法-供参考"></a>建议修法（供参考）</h3>
<ol>
<li><strong>最省事</strong>：让自动上屏复用 <code>commit_selected</code> 的整串分支，或在 <code>InputOutcome::AutoCommit</code> 真正提交文本的那一处，调用与 <code>commit_selected</code> 末尾同一段联想接线。
<ul>
<li><img src="https://forum.windinput.com/assets/plugins/nodebb-plugin-emoji/emoji/android/26a0.png?v=898858d396f" class="not-responsive emoji emoji-android emoji--warning" style="height:1.4em;width:auto;vertical-align:middle" title="⚠" alt="⚠" />️ 关键是<strong>状态形状</strong>：联想态要求「缓冲已清空 + <code>state.active = None</code> + 无已转换段」，而自动上屏发生在「缓冲非空 + 引擎仍 active」的时刻。<code>commit_selected</code> 的整串分支本来就把这三件事都做完了，所以走同一条收敛路径能省掉一整类边界。</li>
<li>联想取的「上文」应是<strong>实际提交给宿主的文本</strong>（含简繁转换、英文补空格之后）——与 <code>commit_selected</code> 取 <code>out</code> 而非 <code>final_simplified</code> 的理由一致。</li>
</ul>
</li>
<li><strong>兼容性</strong>：自动上屏用户多为盲打型五笔用户，突然每次上屏都弹联想、且联想态占用数字键与空格（<code>space_commits</code>），行为变化很突兀（这也是桌面默认关联想的原因）。建议至少给一个显式开关，例如 <code>[input.association] after_auto_commit = false</code>（默认关，不改变既有用户行为），而不是无条件接上。</li>
<li><strong>测试</strong>：<code>handle_assoc::wiring_tests</code> 里加一条「自动上屏后进联想态」的断言，从 <code>handle_key_event</code> 进（与既有接线测试同层）。注意 headless 下两处坑：不调 <code>prewarm_indexes()</code> 拿不到联想（索引没就绪就返回空）、不调 <code>debug_mark_coords_ready()</code> 拿不到 UI 通道。</li>
</ol>
<hr />
<h2><a class="anchor-offset" name="问题-a-反查索引不含用户词库与临时词"></a>问题 A：反查索引不含用户词库与临时词</h2>
<h3><a class="anchor-offset" name="现象"></a>现象</h3>
<p dir="auto">用户把自己常用的专业词（幕墙/荷载一类）上屏过很多次，<code>userdata.redb</code> 里也确实有（<code>dict export</code> 能导出），但<strong>联想里永远不出现这些词</strong>——无论上文是单字还是词。</p>
<h3><a class="anchor-offset" name="原因-据代码"></a>原因（据代码）</h3>
<ul>
<li>反查索引（<code>.wridx</code>）<strong>只由「启用的 <code>.dict.yaml</code> 词库」构建</strong>（<code>load_dicts_individually</code> 那条路），每个方案一份，键是「词 → 编码」。</li>
<li>用户词库与临时词存在 <code>userdata.redb</code> 里，是<strong>引擎的 store 层</strong>，不参与索引构建。</li>
<li>于是所有 <strong><code>reverse_index_if_ready</code> 的消费点</strong>都看不到它们：词语联想（<code>assoc_prefix_words</code>）、候选注释里的 <code>${code_all}</code>（联想态下 <code>code_hint</code> 为空，正好显示的是它）、悬停 <code>[编码]</code> 段。
<ul>
<li>顺带一问：<code>manager.rs::reverse_index_for</code> 的注释说加词去重校验也用它（「那里返回空表会导致<strong>重复加词</strong>，是正确性问题」）——那么<strong>用户词在这个校验里同样不可见</strong>，是否会造成用户词与用户词/词库词之间的去重漏判，请作者判断。</li>
</ul>
</li>
</ul>
<h3><a class="anchor-offset" name="我的验证方式"></a>我的验证方式</h3>
<p dir="auto">对 <code>%LOCALAPPDATA%\WindInput\cache\wubi86\wubi86.wridx</code> 做原始字节搜索：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>词</th>
<th>镜像进<code>.dict.yaml</code> 之前</th>
<th>之后</th>
</tr>
</thead>
<tbody>
<tr>
<td>基础验收 / 幕墙节能 / 工厂化加工 / 散索鞍</td>
<td><strong>搜不到</strong></td>
<td>搜得到</td>
</tr>
</tbody>
</table>
<p dir="auto">即：<strong>同一个词，只要不进 <code>.dict.yaml</code>，联想就取不到它。</strong></p>
<h3><a class="anchor-offset" name="建议-供作者取舍"></a>建议（供作者取舍）</h3>
<ul>
<li>联想取数时叠加引擎层的用户词（前缀查询 + 权重合成），或在索引构建时把 store 层用户词/临时词一并并入（后者对 <code>${code_all}</code>、悬停编码也一并生效，但索引需要随用户词变化增量更新，代价更大）。</li>
<li>若结论是「用户词不参与词语联想」是有意设计，也建议在文档里写明，免得用户像我这样绕一大圈。</li>
</ul>
<hr />
<h2><a class="anchor-offset" name="附录-本机的规避方案与实测数据-供作者参考-不需要上游采纳"></a>附录：本机的规避方案与实测数据（供作者参考，不需要上游采纳）</h2>
<p dir="auto"><strong>规避 A</strong>：把用户词库/临时词<strong>镜像成一本普通 <code>.dict.yaml</code></strong>（<code>dict export</code> → 生成码表 → 作为 extra 词库挂进方案），这样它们就进了反查索引。已装：2033 条 / 1993 键，索引规模 91126 词（5 本词库）。</p>
<p dir="auto"><strong>规避 B</strong>：镜像后有个副作用——新词的权重取的是<strong>码表文件权重</strong>，而系统词库的权重是真实词频（工 9999、工艺 1717…），用户词以权重 0 参与排序会被挤到第 88 位之后，等于看不见。实测把用户词权重统一抬到 <strong>1900</strong>：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>上文</th>
<th>修前</th>
<th>修后</th>
</tr>
</thead>
<tbody>
<tr>
<td>工</td>
<td>前 9 条全是系统词</td>
<td>工作 / 工具 / 工资 之后<strong>全是用户词</strong>（第 4 名起）</td>
</tr>
<tr>
<td>基</td>
<td>前 9 条全是系统词</td>
<td>基本 / 基础 / 基金 / 基于 之后全是用户词</td>
</tr>
<tr>
<td>荷载（2 字词）</td>
<td>竞争少，本来就能出</td>
<td>全部用户词</td>
</tr>
</tbody>
</table>
<p dir="auto">抬权重的代价也量化过（1993 个码位）：689 个用户码位与系统词重码、812 个系统词被挤到后面、650 个码位用户词成为首选；<strong>1304 个码位没有系统竞争对手，正常打字零影响</strong>。</p>
<p dir="auto"><strong>规避 C（问题 B）</strong>：把 <code>auto_commit_at_full</code> 关回出厂 <code>false</code>，换回联想——代价是满码后要多按一次空格。这只是规避：本该由输入法同时提供的两件事，被迫二选一。</p>
<hr />
<h2><a class="anchor-offset" name="复现清单-最小步骤"></a>复现清单（最小步骤）</h2>
<ol>
<li>方案 <code>wubi86</code>，配置 <code>[input.association] kind = "word"</code>，<code>[debug] log_level = "debug"</code>。</li>
<li><strong>问题 B</strong>：<code>[schema.codetable] auto_commit_at_full = true</code> → 打 <code>awsk</code>（荷，满码唯一）→ 上屏成功但日志无 <code>handle_assoc</code>；改成 <code>false</code> → 打 <code>awsk</code> + 空格 → 出现 <code>进入联想态 n=9</code>。</li>
<li><strong>问题 A</strong>：对任意曾经上屏过的用户词（例如两个字以上、系统词库里没有的），确认 <code>dict export</code> 里有它，再打它的首字上屏 → 联想的候选里不会有它；把它写进 <code>.dict.yaml</code> 后立刻出现。</li>
</ol>
]]></description><link>https://forum.windinput.com/post/756</link><guid isPermaLink="true">https://forum.windinput.com/post/756</guid><dc:creator><![CDATA[xzznf]]></dc:creator><pubDate>Sun, 20 Sep 2026 08:22:27 GMT</pubDate></item><item><title><![CDATA[Reply to 联想功能的两个小问题，就是用户词库是否参与联想，以及满码顶屏后的联想 on Sun, 20 Sep 2026 06:57:19 GMT]]></title><description><![CDATA[<p dir="auto">你应该把内容直接贴到帖子里，帖子支持 md 的</p>
]]></description><link>https://forum.windinput.com/post/740</link><guid isPermaLink="true">https://forum.windinput.com/post/740</guid><dc:creator><![CDATA[admin]]></dc:creator><pubDate>Sun, 20 Sep 2026 06:57:19 GMT</pubDate></item></channel></rss>