1. 为什么用AI重读《汉书》从史学体系到知识工程前阵子跟朋友聊起知识图谱他忽然说了一句让我愣住的话“你们天天研究数据切片、版本管理、领域限定班固在两千年前就已经把这套思路用得很熟练了。”回头想想真是这样。司马迁写《史记》通贯古今体例宏大但一个人、一支笔要面对几百年的史料注定没法保证每个时代的记录精度都一致。班固写《汉书》主动把范围切到西汉一朝以帝王纪年为时间轴把人物、事件、制度全部装进这个明确的窗口里去组织和取舍。用今天知识工程的话来说这是一次非常完整的“知识域限定”。我们正在做的一个系列项目“AI中国故事”目标是把历史人文内容转化为可交互的数字知识形态。本期这个子项目叫“对话班固”方向很直接用大语言模型、知识图谱和自然语言处理技术拆解《汉书》中体现的史学体系让“断代史法”“正统观念”“文化传承”这三个抽象概念变成可计算、可查询、可验证的知识结构并且让AI能够基于这套结构回答历史问题、可视化人物关系、输出带证据链的分析结果。做完整个项目我的核心感受是技术只是表面真正难的是概念转译。“断代史法”如何映射为人工智能里的时间边界“正统观念”如何不陷入主观评判而是化约为文本中可观测的叙事权重“文化传承”怎样成为一套可跨代复用的知识协议这三个问题想清楚之前任何模型、图谱和接口都是空谈。这篇文章就把我在这三条线上踩过的路、掉过的坑、形成的方案完整写出来给同样在做历史大模型应用和文化遗产数字化的朋友参考。项目里的代码和配置都以可复现的方式记录在文中你可以直接照着搭一版。1.1 断代史法的“数据切片”本质班固为什么放弃通史坚持做断代史史学界有各种各样的解释如果从数据建设的角度去看我认为最核心的原因是通史的时间范围太长信息来源太杂任何一个学者都不可能用同一种精度覆盖所有时代。断代史的本质是主动承认认知边界把研究范围压缩到一个人能驾驭的范围内用统一的选取标准和编写体例保证史实的连贯性。把这个逻辑映射到AI知识建构中就是非常典型的领域限定策略。项目初期我试图把先秦到东汉的所有史料都做成一个巨型知识图谱结果标注质量参差不齐关系抽取的准确率惨不忍睹。后来参考断代史的思路把范围收缩到《汉书》核心纪传配合《史记》中重合的部分做交叉验证效果立竿见影。这个经验值得记住做历史知识图谱第一步不是选模型而是选时间窗口。时间窗口的设定直接决定了三个重要参数实体规模、事件密度和关系可信度。如果把窗口切得太宽实体之间跨越数百年产生关系因果链就会变得极其薄弱切得太窄又会出现核心人物跨卷出现、上下文断裂的问题。班固用帝王纪年分割历史本质上就是一种以政治周期为边界的时间分区方案。我在项目里沿用了这个思路以皇帝在位区间作为一级时间桶以年份作为二级时间桶所有事件都挂到对应的时间桶里。实践证明这套方案极其好用后续做时间线查询、跨朝代对比、因果路径分析都非常顺手。时间层级划分依据对应AI数据模型一级时间桶帝王在位区间粗粒度事件分区二级时间桶具体年份细粒度事件锚点三级时间桶季节或月份高精度史实记录1.2 正统观念的“叙事权重”本质“正统”这个概念表面上看像是政治价值判断但在文本层面它有一套可以识别的表达模式。班固写《汉书》开头不是从汉高祖出生开始流水账式记录而是先给汉朝立了一个“承天命”的谱系又在“本纪”“列传”“表”“志”的编次上有意突出某些人物、淡化另一些人物。这种排列顺序和详略分配的背后都藏着叙事权重。在AI建模里这就启发我们用“事件权重”和“实体显著性”来描述正统观念。比如说同一件楚汉之争的史实在《史记》和《汉书》里的表述详略、措辞倾向都有差异这恰恰是建模“正统观念”的最佳素材。我们在实体识别的基础上增加了“叙事角色”标签和“详略系数”字段通过统计某个事件在文献中出现的篇幅、位置、修饰语数量量化文本对这件事的重视程度。具体实现时我给每一个事件计算四个维度篇幅权重、位置权重、称谓权重和情感倾向。篇幅权重看它在原文中的字数占比位置权重看它出现在本纪还是列传称谓权重看叙述主体使用的是尊称还是直称情感倾向则通过修饰语词典判断褒贬色彩。这四者加权合成后就形成一个可比较的“正统治叙事强度”指标。它不是判断历史事实的真假而是判断文本如何通过叙述策略传递立场这个定位非常重要。1.3 文化传承的“跨代协议”本质班固整理前代典籍、撰写当代历史的过程可以看作一次大规模的知识迁移。他不是简单复制《史记》的内容而是重新组织、注释、筛选后形成新的知识成果供后代使用。这个“整理—组织—筛选—传播”的循环与文化传承的实际机制高度吻合。从技术角度看文化传承就是构建一套跨代使用的知识协议。我们需要让今天产出的知识结构在未来不同的AI模型、不同的查询意图下仍然可用。为此在关系设计上我特别强调“证据链”每个三元组都附加出处、版本、置信度三个字段这样即使未来算法换了也能回溯知识来源不至于变成无根之水。后来测试时发现证据链不仅能增强可信度还能提升检索质量。用户问“汉初郡国并行制度是怎么来的”系统能沿着关系图谱找到“韩信建议—刘邦采纳—郡国并行”—这条链路上的每一条证据都指向原文对应卷次回答起来逻辑非常顺。这就是文化传承在数字层面的落点不是把古籍扫描成图片存起来而是让知识结构能够在不同时代、不同模型之间持续被引用、验证和再诠释。这三个概念的拆解最终统一到了一个方案里用图谱组织知识用时间窗口限定边界用权重表达立场用完整证据链保证传承可信。这就是整个项目最核心的设计思想后面所有实操都围绕它展开。2. 从史料到图谱整体方案与技术选型2.1 总体流程设计分为五个阶段整体流程没有用什么新奇的方法反而是刻意保持保守能规则解决的不上模型能人工校对的不全自动能分步走的不一步到位。整个项目分成五个阶段。第一阶段是语料分层。把《汉书》文本拆成原文层、注疏层和白话译文层避免模型混淆不同来源的信息。第二阶段是实体识别。建立领域词典训练命名实体识别模型抽取出人物、官职、地名、年号、典籍五类核心实体。第三阶段是事件抽取。以事件为粒度组织史实每个事件都按统一模板补全要素。第四阶段是图谱构建。搭建知识图谱为每个三元组挂上来源、版本和置信度。第五阶段是交互查询。提供自然语言问答和关系路径查询能力。这个流程的设计顺序是有讲究的。必须先做实体再做事件因为事件抽取依赖实体边界必须先做语料分层再做模型训练否则大模型会把注疏当原文。每一步的产出都是下一步的输入顺序不能乱。我见过不少项目跳过语料分层直接让模型抽关系结果后面调试成本比重新做一遍还高。2.2 技术栈选型与取舍技术栈的选择上我没有追求最新最热的大模型框架而是根据文本特性和团队维护成本做了保守选型。文本处理Python环境分词用pkuseg预标注用规则脚本。实体识别采用基础模型加领域词典的方式用HuggingFace加载一个开源中文BERT模型在标注语料上微调。知识图谱存储Neo4j社区版完全够用。可视化展示ECharts关系图配合一个简单的Flask后端提供查询接口。大语言模型接口仅在事件候选抽取和问答生成阶段接入不参与底层图谱构建。这个选型背后有几个考虑。单纯用通用大模型抽实体结果看起来专业实际上幻觉率很高尤其是古代官职名和年号这类低频词汇模型会一本正经地编出错误名称。先用规则和词典锁定高频实体再用模型处理开放性问题可以把错误率压到一个可控范围。知识图谱不用Neo4j而用其他内存型图数据库也可以但Neo4j的社区支持更成熟调试工具顺手团队上手成本低。需要提醒的是没有一种技术栈是万能的关键是匹配数据规模。项目初期语料只有几十篇用分布式框架纯属浪费。等量级做到几千篇再考虑弹性伸缩也不迟。做历史AI应用数据量往往不是最大的瓶颈数据质量才是。3. 一步一步落地语料处理、实体抽取与图谱构建3.1 语料分层不要把所有文本都丢给大模型很多人一开始会把《汉书》全文丢给大模型让它做抽取结果回答看起来专业实际上有很多幻觉。我自己就踩过这个坑模型把后世注疏里的内容误当成原文甚至把《汉书》中引用的前代文献片段归属到班固头上。正确的做法是先做语料分层。我把《汉书》文本分成三层原文层、注疏层、白话译文层。原文层以点校本整理出的电子文本为主体注疏层把古人的注释单独归类白话译文层只负责辅助理解不参与抽取。三者在知识图谱中有不同的来源标签防止被大模型混淆。在具体操作上我用一个简单的脚本做段落级对齐。以卷为单位拆分再用卷内序号对齐原文、注释和白话文。如果遇到多版本冲突的问题优先采用点校本作为基准其他版本仅用差异比对工具做记录。一开始不要追求把所有版本都合并进语料那样只会制造内部矛盾让模型无所适从。注意语料分层的粒度越细越好至少要做到“卷”这一级。如果只对全文打一个标签后续任何按出处检索的操作都会失效。3.2 领域词典与实体识别先把这个关卡打穿做历史文本的实体识别最大的难点不是技术实现而是领域词典。通用模型很难识别出人名、官职、年号、地名之间的复杂关系。比如同一个人在不同语境里可能以姓名、官职、封号、谥号四种形式出现还经常被省略成单字年号与地名共用同一个词形的情况也普遍存在。没有好的词典模型准确率很难超过七成。我的做法是先手工整理高置信度的核心实体词典覆盖《汉书》主要人物、中央官职、郡国县邑、年号等大概两千个条目然后基于这些基础数据做一次预标注再用预标注结果去微调命名实体识别模型。词典数量不用追求大而全关键是高频覆盖用80%的词典覆盖90%的实体出现频率就是合格。这里有一个容易被忽视的点实体类别不要设得太粗也不要太细。只设人名、地名两类很多关系无法区分设成二十几类标注样本量又撑不住。我最终保留了人物、官职、地名、年号、典籍五类刚好够用。官职单独成一类特别有价值因为历史事件里“某官职做了某事”是非常高频的关系模式官职实体可以作为关系抽取的中间节点。3.3 事件抽取把史实从“一段话”变成“一张卡”实体识别的上一层是事件抽取。历史文本里的事件不只有主语和谓语还包含时间、地点、动因、参与角色、结果等多重信息。我参照叙事学里的事件要素分类设计了统一的抽取模板主体、行为、对象、发生时间、发生地点、前置动因、直接后果、信息来源。实现上用了两步走。第一步先让大模型做候选事件提取给出开放性的事件段落第二步再用规则和词典对候选事件做结构化校验剔除不满足模板的事件。这一步很关键因为纯靠模型生成的事件经常要素不全或出现张冠李戴。比如某段文字讲的是臣子向皇帝上书劝谏模型可能把执行者标成皇帝导致整条关系反向。经验是宁可少一点不要错一点。我一开始抽出了上千个候选事件手工复核后只剩下大约三百个高频核心事件才进入图谱构建阶段。用三百个准确事件做出的图谱比用一千个含错事件的图谱有用得多。后续扩充事件库时也始终遵循先校验后入库的原则。事件要素示例用虚构代称表示校验规则主体某大臣必须是人物实体行为上疏必须匹配动词词典对象当朝皇帝可以是人物或机构发生时间某年必须在时间桶内前置动因边境冲突非必填但填写时需有原文依据直接后果朝廷出兵非必填需有原文依据信息来源卷七十必须指向原文卷次3.4 图谱构建三元组不是终点证据链才是很多知识图谱项目做完实体识别和事件抽取就急着导入图数据库结果做出来的图很漂亮却经不起几个“为什么”。问题在于三元组的质量没有校验机制一张关系图里混着高置信度和低置信度的关系查询时根本不知道哪些可以引用。我们在三元组上挂了三个附加属性来源卷次、版本说明、置信度分数。置信度由三个子分数组合而来实体识别可信度、关系抽取可信度、跨文献一致性。比如《汉书》本传里的记录与《史记》对照一致时一致性得分就高只有孤证时分数就低。在Neo4j里这三个属性作为关系属性存储查询时可以按阈值过滤。这样构建出的图谱虽然节点总数不算多但每个关系都有源有据。后续做历史问答时模型的回答能直接引用图谱中的证据链体验完全不同。用户问某个事件为什么发生系统给出的是“由哪个事件诱发、由谁主导、结果是什么”的完整链条而不是把检索到的一堆相关文本堆给用户去猜。提示置信度分数建议拆成子分存储不要只存一个总分。总分便于过滤子分便于排查问题。模型升级或者语料新增之后子分可以独立重算。3.5 可视化与查询让知识从前台走到后台图谱构建完成后我用ECharts做关系图展示用Flask做一个简单的后端接口再包装一层自然语言查询。用户输入一个历史问题系统先做实体识别匹配图谱节点然后返回相关子图。比较有用的一个功能是“人物关系路径”查询比如查某位功臣与皇室之间的间接关系会跑出好几条路径而每条路径上的事件都带着时间属性能看出关系的演变过程。交互设计上有一条建议不要把所有关系都画出来。超过两百个节点的图已经很难看懂要按事件类型、时间阶段做分层展示。我们最终默认只展示置信度高于0.75且时间在项目主时间段内的核心关系其他关系作为扩展选项保留。自然语言问答模块我采用的是检索增强配合图谱生成的方案。先用实体识别把用户问题映射到图谱节点拿到结构化证据再交由大模型组织成自然语言回答。这样回答的句式是模型生成的但事实内容是图谱给的。两相对比相比直接让模型生成幻觉明显减少。4. 实操中遇到的那些坑与排查方法4.1 异体字、错字与版本噪音古籍原文的电子化文本虽然经过点校但数字化过程中依然有扫描丢字、异体字不统一的问题不同来源的电子文本差异尤其明显。处理办法是建一个“异体字归一表”把常见异体字、古今字、繁简混淆字映射到统一编码在预处理阶段做全量替换。这个表需要人工维护模型无法完全替代因为存在上下文语义差异。排查时如果发现实体识别频频出错先别急着调模型参数检查预处理后的文本里有没有非标准字符。很多时候模型不是不认识这个实体而是被异常字符干扰了分词。我在debug时遇到过一次所有含地名的句子都抽不出实体最后发现是地名统一编码后少了一个映射关系。4.2 大模型幻觉与史实张冠李戴最头疼的问题是模型分不清原文、注疏和引文。例如查询“班固对某项制度的评价”时模型可能把《汉书》中引用的前人原话当成班固观点。这正是3.1节语料分层要解决的问题。解决方案是在抽取阶段强制给每个观点实体打上“说话者”标签同时要求回答环节必须引用具体卷次回答中不带卷次的论述默认不接受。后来我又加了一道人工抽检流程每周随机抽五十条关系做人工核对重点检查说话者归属和引文边界。抽检发现的错误会回填到标注集中持续优化模型。两轮迭代后张冠李戴率明显下降。对历史AI项目来说这种持续抽检机制比堆算力更有价值。4.3 正统观念的量化偏差最初我尝试让模型直接给事件打“正统支持度”分数结果非常不稳定同样的事件换一种问法分数就大幅波动。后来改成先抽取事件的情感倾向、篇幅权重、位置权重再用规则组合成间接指标。比如一个事件如果在“本纪”部分出现、篇幅超过四百字、且修饰语密度高它的叙事强度就会偏高。这样拆解后指标具备可解释性出现偏差也能定位问题。偏差还有一个来源表面措辞的褒贬并不等于史学立场的褒贬。历史文本往往用克制甚至冷静的笔法写重大事件单纯的褒贬情感分类会漏掉大量信息。后来增加了“详略对比”特征同样是叛乱事件在《汉书》某篇里的篇幅与对其他事件的篇幅差异才是更可靠的立场信号。4.4 数据稀疏导致的图谱孤岛早期图谱的关系密度很低很多孤立节点一查询就是空。有些小人物只出现过一两次没有任何关联关系直接删除又可惜。解决思路是引入“间接关系”通过共同出现的人物、相似的事件类型和相同地点为孤立节点建立弱连接。这些弱连接虽然置信度不算高但能提供候选线索也方便后续人工校核补全。做间接关系时要特别注意别把弱连接当成事实。我只是把它们作为“可能相关”的线索展示给用户置信度阈值也单独设置与事实关系分开。有一次测试时系统把两位年代相隔很远、只是因为同名官职被连在一起的人物关联了起来幸好置信度字段让问题快速暴露没有污染主图谱。5. 一些值得记住的经验与教训全程做下来最大的体会是历史知识建构的关键不在算法而在边界设计。你选择切哪一段历史、用什么样的来源、给每个概念定义什么样的边界这些决策最终决定了AI呈现出的历史叙事质量。模型可以迭代、图谱可以扩充但边界一旦定错方向就很难扳回来。还有三个细节值得单独说。第一术语表和词典的维护要放在建图谱之前做得越早后面返工越少。词典不是一次性的它要伴随项目生长每发现一个新词就补一条这种日常积累比反复训练模型划算得多。第二标注样本的规范文档比标注本身更重要哪怕只有五页纸也要写清楚“谁是说话者”“引号内内容归属谁”这样的硬规则。没有规范的标注集后期纠错成本会指数级上升。第三把置信度作为一等公民来对待不要在最后才补。一旦图谱里混入了大量低置信度关系再回头清洗会非常痛苦。这个项目后续还可以往两个方向扩展。一是跨朝代对比把断代史法扩展到多个断代文本对比不同朝代对同一类事件的历史书写差异二是面向大众的交互式历史叙事把图谱中的证据链包装成可浏览的“历史事件卡片”让普通用户也能沿着证据链理解历史书写者的选择与立场。班固在一千九百年前想清楚的道理今天的AI知识工程依然在用这大概就是文化传承在另一种形式上的体现。
阅读完成 · 觉得有帮助?