文言文NLP实战:甲言实现古汉语词库合成与断句标点恢复
简介Jiayan甲言是一套专注古代汉语处理的NLP工具包面向古汉语研究者、文史爱好者及NLP开发者用于解决文言文分词、词性标注、断句标点及文言词库自动合成等痛点。相较通用现代汉语NLP工具它针对古籍语料做了专门优化适合开展古籍数字化、文言文本挖掘与教学研究。资源压缩包共28个文件以20个Python源码文件为主体涵盖核心模块、分词器、词性标注器、断句器及示例脚本另含README、LICENSE、依赖清单等说明文档整体仅217KB轻量易部署、导入即可使用。目前已有3318人学习下载社区关注度较高。通过源码可深入理解基于无监督双向语言模型与最大概率路径的动态规划分词算法并借助lexicon目录快速构建自定义文言词典postagger与sentencizer模块分别提供词性标注和断句标点能力data目录内置基础语料配合examples.py可直接运行体验。整体代码注释规范、模块划分清晰便于二次开发与实验复现是一份兼具学习与实用价值的古汉语NLP参考资料。1. 甲言给文言文做 NLP先解决词库、分词、断句三件事做过古典中文 NLP 的人都有体会把白话文那一套分词器直接搬到文言文上结果基本是翻车现场。某高校古籍数字化小组处理一批明清日记时用通用工具跑“子曰学而时习之”输出变成“子/曰/学/而/时/习/之”七个字全切成了单字词更麻烦的是断句一整段没有句读的古文被切成二十多个碎片根本没法做后续标注。后来他们换了甲言Jiayan这套专注古代汉语的 Python 工具包才把词库合成、分词、词性标注、断句和标点整条流程跑通。它解决的正是通用 NLP 工具在古汉语语料上「词典不匹配、切分粒度乱、断句看心情」这三个核心痛点。这篇文章就从这三个能力展开讲清楚它怎么用、参数怎么调、坑在哪里适合正在做古籍语料清洗、文言信息抽取和句读恢复的从业者。2. 安装与文言词库合成把自定义词典变成可用语言模型2.1 安装与基础验证甲言是标准的 Python 包依赖 wheel 和 C 扩展编译环境。我一般建议直接创建独立虚拟环境后再装避免和已有的 NLP 项目出现依赖冲突。python -m venv venv_jiayan source venv_jiayan/bin/activate # Windows 下执行 venv_jiayan\Scripts\activate pip install jiayan安装完成后先做一个最小加载验证确认核心模块能被正常导入import jiayan print(jiayan.__version__)这段验证的目的不是看版本号而是确认 C 扩展编译成功。很多人在第二步就翻车import jiayan报 ImportError九成是编译器环境缺了 MSVC Build Tools 或 GCC。逻辑上你可以把甲言理解为两部分一层是 Python 调用接口另一层是底层用 C 实现的统计模型与解码器import失败通常意味着底层扩展没编译进当前环境。参数层面这里没有额外参数但如果安装时看到pyproject.toml相关报错优先升级pip和setuptools再重装。2.2 词库合成为什么甲言需要离线词典通用分词器的词典以现代汉语为主文言文里的实词、虚词、官职名、地名在词典里要么没有要么词频极低所以“学而时习之”会被拆成碎片。词库合成就是把你自己整理的领域词典合并进模型的词表中让分词、断句优先命中你提供的词条。我一般这样准备词典文件一行一个词词和词频用空格或 Tab 分隔。词频可以填统计次数也可以直接填所在语料的出现频率拿不准时统一填 1让模型靠上下文去决策。合成接口的思路是「原始词表 领域词典 → 新词表 → 新统计模型」三步import jiayan # 预加载的语言模型泛化能力强但领域词不足 base_model jiayan.create_language_model(base_model.klm) # 领域词典格式为“词 频次”每行一条 lexicon_path my_ancient_lexicon.txt # 执行词库合成返回新的模型实例 synthesized_model base_model.synthesize_lexicon(lexicon_path, output_pathmy_synth.klm) # 重新加载合成后的模型用于后续分词 lm jiayan.load_language_model(my_synth.klm)代码里的create_language_model负责把基础统计模型读进内存synthesize_lexicon是核心方法它对词典里的每个词做词频加权把新词插入模型词表的同时重新归一化概率分布load_language_model加载的是合成产物不是原模型。参数上要注意两点output_path一定要显式指定否则结果只存在内存里退出进程后合成就白做了词典编码必须是 UTF-8繁体或异体字保持和语料一致的写法否则合成后词条无法命中原文。2.3 参数与边界词频、词长与词典格式参数影响建议值词频决定词条在解码时的先验权重词频越高越容易被优先切出不确定时填 1避免过度干预词长影响切分粒度过长会把正常词组吞并以 26 字为主人名地名最多 8 字平滑控制未登录词的容忍度越高越容易切出词典外的组合保持默认除非发现分词过碎这里有一个边界很容易被忽略词库合成不是越多越好。某开发者一开始把整本辞书都塞进词典结果分词把所有二字常词都切成成语块反而拉低了准确率。词库合成解决的是「领域词缺失」不是「用词典替代统计模型」。合成后最好用一小段验证语料来回测分词校准词频权重而不是直接上全量数据。3. 分词与词性标注从原始文本到可读标注结果3.1 分词接口与基本用法分词是甲言最基础的功能加载合成后的语言模型直接对句子做切分from jiayan import load_language_model, get_segmenter lm load_language_model(my_synth.klm) segmenter get_segmenter(lm) text 子曰學而時習之不亦說乎 tokens segmenter.segment(text) print(tokens) # [子曰, 學而, 時習之, 不亦, 說乎]load_language_model返回的是解码器依赖的概率模型get_segmenter是外层封装的切分器它内部会做字符级图解码然后按最大联合概率搜索最优切分路径。参数上segment方法只接受字符串不接受列表文本里的换行符和空格会被当成切分边界处理所以如果你的语料带有行号先清洗干净再传入。分词的输出粒度由模型决定而不是由词典决定。这句话的意思是说词典只负责提供候选词到底切不切、切多长取决于整个句子的联合概率。从实操来看文言虚词如“之、乎、者、也”经常被单独切出这是正常的但如果把“天下”切成了“天/下”就要检查词典里有没有这两个字的合成词条以及词频是否太低。3.2 词性标注认识甲言的标签体系词性标注在分词结果上做二次分类。甲言对分词后的每个 token 输出一个标签标签体系接近北大词性标注集但针对文言文做了调整from jiayan import get_postagger tagger get_postagger(lm) tagged tagger.tag(tokens) print(tagged) # [(子曰, v), (學而, c), (時習之, v), (不亦, d), (說乎, v)]get_postagger返回一个标注器实例tag方法接收上文分词得到的词列表按顺序输出“(词, 词性)”元组。注意它不会自己再分词所以喂给它的列表必须是已经切好的如果你把原始句子直接传进去它会按单字逐字标注输出结果基本没法用。甲言的词性集合里v代表动词n名词c连词d副词p介词u助词。这套标签和白话文工具的主要差异在助词和语气词上文言文里大量出现的“也、矣、焉、哉”多数归入助词u或语气词y如果你看到的标注集定义有点不一样以你下载的源码包里的标签文档为准。标注速度在普通笔记本上大约每秒几百到一千词属于可接受范围。3.3 标注后处理把结果转成 JSON 或 DataFrame裸的分词和词性结果很难直接落地我一般会转成结构化的中间格式方便后续做统计、筛选或写回数据库。这里给一个通用的转换函数import pandas as pd def to_dataframe(tokens, tagged): rows [] for word, pos in tagged: rows.append({ token: word, pos: pos, length: len(word) }) return pd.DataFrame(rows) df to_dataframe(tokens, tagged) print(df)这个函数接收分词列表和标注列表逐条组装成字典再转 DataFrame。注意两个输入列表长度必须一致否则会造成行错位你可以把tag(tokens)的结果按词对齐检查一遍len(tokens) len(tagged)是硬性条件。length字段是我额外加的用于过滤超长未登录词如果发现某个 token 长度超过 10基本都是词库合成或分词阶段出了问题这种记录应该单独抽出来排查。4. 断句与标点文言文句读恢复的完整流程4.1 断句模块从连续文本到短句古文没有标点断句是最耗费人工的一步。甲言的断句模块本质上是一个序列标注模型判断每个字后面要不要切分。使用方式如下from jiayan import get_sentences_splitter splitter get_sentences_splitter(lm) raw 大學之道在明明德在親民在止於至善 sentences splitter.split_sentence(raw) print(sentences) # [大學之道在明明德, 在親民, 在止於至善]get_sentences_splitter返回断句器split_sentence按句读切分一整段文本。逻辑上它先对每个字位预测一个切分概率再用阈值选择最终断点较大的阈值会让断句更保守输出长句更多较小的阈值会切得更碎适合处理短句为主的语录体。这里有个经验值处理论说文时阈值调高处理语录、对话时阈值调低。文本长度方面split_sentence接收长段落没有问题但如果传入上千字的整篇文章建议先按段落拆开避免一次解码耗时过长。4.2 标点标注句读、逗号与语气词断句只解决“在哪里断”不解决“断完打什么标点”。甲言的标点功能进一步区分句号、逗号和问叹语气。我习惯的做法是先断句再对每个短句做内部停顿预测from jiayan import get_punct_tokenizer punct get_punct_tokenizer(lm) text_with_punct punct.punctuate(大學之道在明明德在親民在止於至善) print(text_with_punct) # 大學之道在明明德在親民在止於至善。get_punct_tokenizer对标点位置做分类输出带标点符号的完整文本。注意它的输入是原始连续文本不是分好词的列表因为标点和分词共用了内部的上下文特征。参数上标点模型对语气词比较敏感遇到“乎、哉、耶”倾向于输出问号遇到“矣、焉、也”倾向于输出句号如果你处理的文本是奏章或碑文这种语气判断不一定可靠最好在后处理里做规则修正。4.3 常见误用把白话文模型思路套到文言文最容易翻车的一点是有人把白话文 NER 或标点恢复模型的思路直接套过来拿甲言当黑匣子用。文言文的句读高度依赖句式结构和语气词分布用现代汉语标点模型硬跑结果通常是乱打逗号。另一个常见误用是混淆断句和分词断句器输出的每个子句仍然需要再走一遍分词和词性标注不能直接拿子句字符串去匹配关键词因为子句内部还可能存在未登录词。实操上我更推荐「断句 → 分词 → 词性标注」三步走每一步都保留原始位置信息最后再合并结果这样排查错误时能定位到具体环节。5. 避坑指南甲言使用中最容易翻车的五个问题5.1 现象一词典合成了但分词结果没变某个开发者按示例把词典合成后重新加载模型分词输出完全没变化他以为是合成接口失效。原因合成后的模型没有覆盖原模型路径。代码里合成是通过synthesize_lexicon生成新文件但如果后面load_language_model仍然指向基础模型路径等于没加载产物。解决每次加载后先打印模型路径确认落盘位置更稳妥的做法是直接比较base_model和synthesized_model的词表大小合成后词表一定比原来大。从那以后我每次做完词库合成都会先跑一行词表比对再进全量流程。5.2 现象二断句结果把并列句切碎了有一份地方志语料原文本是“山高水长林密路险”断句器输出变成“山高/水长/林密/路险”四个短句结构上确实切开了但人为破坏了并列关系。原因断句阈值设得太低模型在每一个对仗点都判了句读。解决调整断句阈值把每一次的切分概率打印出来结合语料判断最优值。处理对仗文本时我会在断句后加一条保护规则——如果切出的子句长度小于 4 字且前后子句结构相似就合并。这个规则看起来简单实际能救回一半以上被切碎的对仗句。5.3 现象三自定义词一直未被识别词库合成后词典里明明有“巡抚”和“布政使”分词结果还是“巡/抚”“布/政/使”。原因词典词频设置太低或词典文件里的词和语料写法不一致。比如语料用的是繁体“巡撫”词典里写了简体“巡抚”合成后词条永远匹配不上。解决写一个自动检查脚本把词典词逐一在验证语料里做字符串匹配统计命中率命中率低于 80% 就回查写法差异。另一个原因是词频把高频词频调到 50 以上让解码器优先选它。5.4 现象四安装时依赖版本冲突安装完甲言后同一个环境里别的新版工具报错反过来把甲言卸了又没法用。原因甲言的 C 扩展依赖特定版本的编译接口新编译器和旧包之间存在 ABI 不兼容。解决创建独立虚拟环境把安装命令和验证命令直接写进requirements.txt同时锁住 Python 版本建议使用 3.9 或 3.10等底层扩展更新后再尝试更高版本。这条经验是我踩过最久的坑后来所有古文项目组都强制统一环境版本。5.5 现象五处理长文本时速度骤降一段 2000 字的地方志跑了几分钟还没出结果最后内存直接拉满。原因断句和分词解码器的复杂度与输入长度呈非线性关系长文本一次解码的路径搜索空间巨大。解决用 200 字为窗口做切分窗口重叠 20 字先粗断再拼接。这个方法牺牲一点边界准确率但速度能提升几十倍。窗口边界处的切分结果我会单独抽出来人工核对尤其是涉及人名地名的位置。6. 进阶把甲言接进自己的语料处理管线当我需要批量处理一整批古籍时单条调用就不好使了。我通常会把甲言的四个核心能力封装成一个完整管线词库检查、断句、分词、词性标注统一输出结构化记录再配合正则在结果上做修正。def process_text(raw_text, lm, splitter, segmenter, tagger): lines [] for chunk in split_text(raw_text, size200, overlap20): sub_sents splitter.split_sentence(chunk) for sent in sub_sents: tokens segmenter.segment(sent) tagged tagger.tag(tokens) lines.extend(to_dataframe(tokens, tagged).to_dict(records)) return linessplit_text是我的窗口切分函数size200决定了每次送入解码器的文本长度overlap20保留边界上下文确保断句在窗口交界处不会断裂。to_dataframe复用上一章的转换逻辑把元组列表展开成结构化记录。封装完成后整批语料都以统一的 DataFrame 形式写回 CSV方便后续查重和人工校对。如果在管线里再叠加一个小技巧对分词结果里的专有名词单独维护一份规则表匹配到“左迁”“擢”“除”这类官职变动词时把相邻的人名一并抽出就能直接服务于官职任免类信息抽取。这类规则不依赖模型概率是纯字符串逻辑但恰好补上了通用统计模型在历史语境上的短板。从那以后我每次处理古籍语料都会强制走一遍先查词库命中率再调断句阈值最后人工抽查窗口边界。整套流程跑完分词的稳定性和断句的可用度都上了一个台阶。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Go 语言 JSON Schema 校验库 jsonschema/v6 完全指南:从库特性、Compiler API 到 jv 命令行工具

Go 语言 JSON Schema 校验库 jsonschema/v6 完全指南:从库特性、Compiler API 到 jv 命令行工具

CLI开发工具 【免费下载链接】cli The Docker CLI 项目地址: https://gitcode.com/gh_mirrors/cli5/cli 点击查看 免费下载 导读 本文围绕 Docker CLI 仓库中引入的第三方 Go 依赖 santhosh-tekuri/jsonschema v6 展开,这是一款以“先编译、后校验”为…

2026/10/12 4:11:30 阅读更多 →
python3 中的字符串(单引号、双引号、三引号)以及字符串与数字的运算

python3 中的字符串(单引号、双引号、三引号)以及字符串与数字的运算

前言 写 Python 3 的第一课往往是「字符串怎么表示」。单引号、双引号、三引号这三种写法都能创建字符串,但它们之间有没有区别、该用哪种,初学者常常是凭感觉选的。先说结论:在 Python 3 里,单引号和双引号创建的字符串没有任何语…

2026/10/12 4:11:30 阅读更多 →
别被“降AI率”带偏:让AI文本更有“人味”的5种方法

别被“降AI率”带偏:让AI文本更有“人味”的5种方法

先声明一句:这类“降AI率”的标题我刷到过很多次,自己也手痒实测过几轮。如果你是为了让AI写出来的东西更像“人话”,而不是为了在论文、作业、考核里耍小聪明,那这篇文章可以帮你省下大量瞎折腾的时间。我最后留下的是五个从根本…

2026/10/12 4:11:30 阅读更多 →

最新新闻

PostgreSQL性能压测实战:用TPC-H标准流程构建可复现基准测试环境

PostgreSQL性能压测实战:用TPC-H标准流程构建可复现基准测试环境

1. 项目概述:为什么TPC-H是检验PostgreSQL真实能力的“压力测试仪”你刚装好PostgreSQL,跑通了第一个CREATE TABLE,连上pgAdmin点了几次查询,心里有点小得意——数据库这玩意儿,好像也没那么难?别急&#x…

2026/10/12 5:09:00 阅读更多 →
基于Spring Boot的车牌识别停车场管理系统设计与实现

基于Spring Boot的车牌识别停车场管理系统设计与实现

1. 项目概述与选题价值1.1 这个系统到底解决什么问题我第一次看到这个题目的时候,第一反应是:这又是一个“典型的毕业设计式管理系统”?因为现在网上关于停车场、图书馆、宿舍管理这类CRUD项目太多了,很多同学开题时随手挑一个&am…

2026/10/12 5:09:00 阅读更多 →
Spring Boot农事管理系统毕业设计:从数据库建模到核心功能实现

Spring Boot农事管理系统毕业设计:从数据库建模到核心功能实现

写这个题目前,我先说句实在话:Spring Boot 农事管理系统,这个搭配在国内农业信息化方向的毕业设计里,已经算得上“经典款”了。经典意味着什么?意味着参考资料好找、技术路线成熟、踩坑记录也很多,不至于让…

2026/10/12 5:09:00 阅读更多 →
MATLAB快速谱相干:从一维时间序列到旋转机械多通道分析

MATLAB快速谱相干:从一维时间序列到旋转机械多通道分析

前几天我在一个设备诊断交流群里看到有人贴图:同一条轴上的两路振动信号,普通幅值谱看着都差不多,在某个轴承故障特征频率附近却同时出现了一处明显的相干峰。下面跟了几条回复,有人问“相干峰到底代表什么”,有人说“…

2026/10/12 5:09:00 阅读更多 →
SpringBoot+Vue+MySQL旅游网站毕设项目全解析:从数据库设计到部署答辩

SpringBoot+Vue+MySQL旅游网站毕设项目全解析:从数据库设计到部署答辩

每年毕业季我都会收到大量和“旅游网站”相关的咨询,这套 SpringBootVueMySQL 的某北方城市特色旅游网站平台,属于完成度很高的一类毕设项目。它带了完整数据库脚本、论文文档和部署说明,代码结构比多数网上流传的“半成品”要规矩得多。这篇…

2026/10/12 5:09:00 阅读更多 →
微客AI助手答疑:AI客服的会话记录存在哪?留存位置与合规要点

微客AI助手答疑:AI客服的会话记录存在哪?留存位置与合规要点

给商家配微客AI助手的时候,被问过的最认真的一组问题来自一位做母婴用品的店主。她问的不是价格也不是功能,而是:客户的聊天记录存在哪?谁能看到?会不会被拿去做别的?说实话,这三个问题比大多数…

2026/10/12 5:08:00 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →