WeKnora 繁体转简体字典数据(textconv)详解:OpenCC 词库的移植、实现与 FAQ 归一化应用
2026/9/13 4:17:01 网站建设 项目流程

WeKnora 繁体转简体字典数据(textconv)详解:OpenCC 词库的移植、实现与 FAQ 归一化应用

【免费下载链接】WeKnoraOpen-source LLM knowledge platform: turn raw documents into a queryable RAG, an autonomous reasoning agent, and a self-maintaining Wiki.项目地址: https://gitcode.com/GitHub_Trending/we/WeKnora

导读:本文围绕 WeKnora 仓库中internal/textconv/data/README.md所描述的「繁体转简体字典数据」展开,深入讲解TSPhrases.txtTSCharacters.txt两份 OpenCC 词库的来源与许可证约束、字典文件格式与 SHA-256 校验、纯 Go 标准库查表转换器的实现原理,以及该能力在 FAQ 问题归一化(NormalizeQuestion)中的实际调用链。读完本文,你将掌握 WeKnora 如何在去除 GPL 依赖的前提下保留历史繁体转简体转换行为,以及如何安全地审查字典更新对持久化内容哈希的影响。

一、背景:为什么 WeKnora 需要一份「纯净」的繁转简字典

WeKnora 是一个开源 LLM 知识平台,其 FAQ 命中能力依赖对用户提问与知识库问题的文本归一化:繁体中文问题需要先转换为简体,才能与语料库中的简体问题做一致性匹配(相关调用见 internal/types/faq.go 中的NormalizeQuestion,其中第 4 步即toSimplifiedtextconv.ToSimplified)。

历史上,这份能力来自第三方 Go 库longbridgeapp/opencc(OpenCC 的 Go 移植),但该库的底层依赖cedar-go采用GPL 许可证,对以 Apache-2.0 分发的 WeKnora 构成许可兼容性风险。因此仓库将字典数据转换实现解耦:

  • 仅保留 OpenCC 的两份纯数据文件(Apache-2.0);
  • 用 Go 标准库map重写了查表转换器(见 internal/textconv/simplified.go);
  • 不再 vendor 或 importliuzl/da与 GPL 的cedar-go

如 data/README.md 所声明:TSPhrases.txtTSCharacters.txtlongbridgeapp/opencc v0.3.13词典的未修改原样拷贝,许可证归属 OpenCC 及 longbridge/opencc 贡献者,完整许可证保留在 licenses/OpenCC-Apache-2.0.txt。

二、字典文件:格式、规模与内容示例

2.1 文件格式

两份文件均为 UTF-8 纯文本,每行一条映射,采用TAB 分隔

繁体词/字 \t 首选简体转换 [备选1 备选2 ...]

以 internal/textconv/data/TSPhrases.txt 为例:

一目瞭然 一目了然 不瞭解 不了解 乾乾淨淨 干干净净 乾坤 乾坤 乾隆 乾隆

注意短语词典中「乾元」「乾卦」「乾坤」等保留了「乾」原形,因为它们在简体语境中不应统一变为「干」——这正是 OpenCC 词典将短语优先于单字设计的原因。

2.2 文件规模

文件词条规模(实际行数)内容
TSCharacters.txt4113 行单字级映射,如㑮 𫝈
TSPhrases.txt277 行多字短语级映射,处理一字多义场景

单字词典覆盖了从常用字到生僻扩展区(含𫝈𪠟等 CJK 扩展区字符)的大量映射,保证了转换的覆盖面。

三、许可证与来源合规

数据文件本身是 OpenCC 词典的未修改拷贝,因此必须保持 Apache-2.0 的许可证声明与归属。仓库通过两层机制落实:

  1. 许可证文件落盘:完整保留 Apache License 2.0 原文于 licenses/OpenCC-Apache-2.0.txt,并在 data/README.md 中显式注明出处longbridgeapp/opencc v0.3.13与贡献者归属;
  2. 不引入 GPL 代码:README 明确「liuzl/da与 GPL 许可证的cedar-go实现未被 vendor 或 import」,转换实现完全基于 Go 标准库。

四、转换实现原理:Go 标准库 map + 最长匹配

4.1 嵌入与初始化

internal/textconv/simplified.go 使用go:embed将两份字典在编译期嵌入二进制:

//go:embed data/TSPhrases.txt var phrasesText string //go:embed data/TSCharacters.txt var charactersText string var traditionalToSimplified = newConverter(phrasesText, charactersText)

newConverter(第 28-44 行)按行解析:用strings.Cut切出 TAB 前的 key 与之后的备选串,strings.Fields拆出多个候选值,只取第一个作为首选转换,并记录每个字典的最大 rune 长度用于最长匹配上限。两份字典按「短语在前、单字在后」的顺序构建。

4.2 转换算法

convert(第 53-80 行)采用「短语优先、逐字典最长匹配、首选项、逐 rune 推进」的策略:

for pos := 0; pos < len(runes); { matched := false for _, d := range c { // 历史上限:单次最多匹配 10 个输入 rune limit := min(10, d.maxRunes, len(runes)-pos) for size := limit; size > 0; size-- { if replacement, ok := d.values[string(runes[pos:pos+size])]; ok { result.WriteString(replacement) pos += size matched = true break } } if matched { break } } if !matched { result.WriteRune(runes[pos]); pos++ } }

关键设计点:

  • 按 UTF-8 正确处理多字节:先转[]rune,按 rune 滑动窗口,天然支持中文与 emoji、扩展区字符混合的输入;
  • 兼容历史行为:注释明确「The previous converter searched at most ten input runes」,即限制单次窗口不超过 10 个 rune,与旧longbridgeapp/opencc转换器的行为保持一致;
  • 并发安全:字典在初始化后只读,转换函数可安全并发调用;
  • 性能保障result.Grow(len(text))预分配缓冲区,避免多次扩容。

4.3 行为优先级测试佐证

internal/textconv/simplified_test.go 的TestDictionaryPrecedenceAndAlternatives用一个微型字典精确验证了三项语义:

c := newConverter("甲乙\t首選 次選\n甲乙丙\t最長\n", "甲乙丙丁\t不應優先\n丁\t尾\n") // convert("甲乙丙丁甲乙") == "最長尾首選"

期望结果最長尾首選同时印证:短语字典优先于单字字典(甲乙丙命中而非甲乙+)、同窗口内最长匹配优先(甲乙丙优于甲乙)、同词条取第一个备选(首選而非次選)。

五、FAQ 归一化中的实际调用链

繁转简能力在 FAQ 检索链路中的入口是NormalizeQuestion(internal/types/faq.go),其处理流水线为:

  1. 去首尾空白 → 2. 移除 URL → 3. 转小写 → 4. 去除首尾标点 →5. 繁体转简体(toSimplifiedtextconv.ToSimplified→ 6. 全角转半角 → 7. 智能空格处理。

其中第 5 步toSimplified(internal/types/faq.go)直接委托给textconv.ToSimplified。同文件的NormalizeQueryText(第 768-769 行)复用同一逻辑,确保搜索查询文本入库问题走完全一致的归一化路径,从而保证「繁體提问」能命中「简体知识库问题」。

此外toHalfWidth(第 744-764 行)处理全角空格(\u3000)与全角 ASCII(0xFF01–0xFF5E0x21–0x5E),与繁转简一起构成了 FAQ 匹配前的完整中文文本规整链。

六、变更安全红线:哈希固定与历史语料回归

README 提出了两条重要的工程约束:

  1. 字典更新会影响 FAQ 归一化结果与持久化内容哈希:词典变更会改变ToSimplified的输出,进而改变基于归一化文本计算的 FAQ 哈希;因此字典更新必须独立于转换器代码变更单独审查
  2. 历史语料测试固定行为TestHistoricalConversionCorpus(internal/textconv/simplified_test.go)将旧longbridgeapp/opencc v0.3.13转换器在13,177 个输入上的转换结果计算 SHA-256 摘要并固定:
  • 每个字典 key 分别以「单独出现」「+key+上下文出现」「key 连续重复两次」三种形态测试;
  • 另附加若干混合样例(含乾隆年間乾乾淨淨的頭髮😀臺灣ABC𠮷\x00後等多字节与空字符边界输入);
  • 期望摘要f3afa240…bfbcc0与输入计数13177任一不符即测试失败。

这意味着任何对字典或转换逻辑的修改,都会被该测试拦截,除非有意识地评估 FAQ 哈希兼容性。替换或升级字典时,必须先运行该回归测试,确认对已持久化 FAQ 的影响范围。

七、如何验证与使用

在仓库根目录运行转换器测试即可验证字典与实现的完整性:

go test ./internal/textconv/ -v

该命令会依次执行基础转换用例(如請聯繫客服,開發環境请联系客服,开发环境一目瞭然,不瞭解?一目了然,不了解?)、历史语料摘要校验与优先级语义测试。若输出包含ok internal/textconv且无 digest 失败,则说明字典数据与旧版转换行为完全一致。

字典数据本身可人工检查,例如确认单字文件首行为㑮 𫝈、短语文件首行为一目瞭然 一目了然,并可用sha256sum对照 data/README.md 中的两张摘要表(TSCharacters.txt6b5a0a79…9ecf09aTSPhrases.txtb2ef895d…fa6324f)校验文件未被改动。

八、总结

WeKnora 的繁转简字典数据模块是「数据合规 + 行为固化 + 轻量实现」三者的平衡样例:

  • 数据层面:仅保留 Apache-2.0 的 OpenCC v0.3.13 原始词典,明确归属与许可证;
  • 实现层面:以 Go 标准库 map 重建「短语优先、最长匹配、首选替代」的转换器,去掉 GPL 依赖;
  • 工程层面:通过 13,177 输入的语料测试将旧转换行为固定为不可变基线,确保 FAQ 归一化与持久化哈希的长期稳定。

对任何需要简体中文文本归一化能力的开发者而言,这套「保留数据、重写实现、回归固话」的迁移思路本身,就是一份可直接借鉴的工程范本。

【免费下载链接】WeKnoraOpen-source LLM knowledge platform: turn raw documents into a queryable RAG, an autonomous reasoning agent, and a self-maintaining Wiki.项目地址: https://gitcode.com/GitHub_Trending/we/WeKnora

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询