--- status: published published_as: 公众号文章/2026-03-08_给史记装上语法高亮.md platforms: [01fish] published_date: 2026-03-08 --- # 史记语法高亮的创造过程:人与AI协作的古籍数字化实验 > 记录2026年1月22日至2月10日,与Claude Code协作构建《史记》语法高亮系统的完整过程。 --- ## 目录 1. [缘起:一个大胆的想法](#1-缘起一个大胆的想法) 2. [第一天:从零到一的爆发(1月22日)](#2-第一天从零到一的爆发1月22日) 3. [第二天:精雕细琢(1月23日)](#3-第二天精雕细琢1月23日) 4. [规模化生产(2月6日-8日)](#4-规模化生产2月6日-8日) 5. [深度完善(2月9日-10日)](#5-深度完善2月9日-10日) 6. [设计哲学](#6-设计哲学) 7. [技术架构全貌](#7-技术架构全貌) 8. [反思与感悟](#8-反思与感悟) --- ## 1. 缘起:一个大胆的想法 这个项目的前身可以追溯到2025年2月。最初的尝试是手工编写RDF/TTL知识图谱——从高祖本纪的两个小节开始,手动创建本体定义文件`ontology.ttl`。这种纯手工方式虽然严谨,但进展极其缓慢:130篇、52万字的《史记》,靠人工标注恐怕要数年之功。 到了2026年1月,AI的能力已经发展到了一个关键拐点。Claude Code这样的AI编程助手不仅能理解古文语义,还能直接编写代码、操作文件系统。一个念头浮现出来: **能不能让AI像IDE给代码加语法高亮一样,给古文也加上"语法高亮"?** --- ## 2. 第一天:从零到一的爆发(1月22日) ### 2.1 第一个提示词(08:47) 2026年1月22日上午,第一条指令发出: > "请对人名、地名、书名、年号、纪年、官职这些命题实体识别出来,用下划线、黑体、颜色等视觉辅助方法辅助阅读,用markdown能够支持的视觉能力。如果markdown能接受的html扩展也可以用。先实验001章。之前的转化逻辑在史记Markdown转化逻辑.md" 这条指令包含了几个关键信息: - **目标**:命名实体识别(NER)+ 视觉辅助阅读 - **方法**:利用Markdown和HTML扩展 - **范围**:先从第一章《五帝本纪》开始实验 - **约束**:遵循已有的转化逻辑文档 Claude立刻开始工作,在《五帝本纪》的文本中识别出人名、地名、官职等实体,并尝试用HTML `` 标签配合内联样式进行标注。 ### 2.2 第一次颜色方案确定(09:07) 看到初步效果后,我对样式做了具体调整: > - 人名:brown + underline(去掉bold) > - 地名:deep yellow + underline > - 官职:deep red > - 时间:cyan > - 请找出其他实体类型 这次反馈确立了一个重要原则:**每种实体类型用不同的颜色和视觉样式区分**。Claude在此基础上扩展,最终形成了11类实体的完整分类体系。 ### 2.3 人工纠错的价值(09:14) > "岳" 在"岳曰"中是人名 这是一个典型的人工纠错案例。古文中"四岳"既可指官职(四方诸侯之长),也可指具体人物。AI识别出了这个词,但判断错了类型。这个纠正帮助Claude理解了古文中人名的复杂性——同一个字在不同上下文中可能有不同的语义角色。 ### 2.4 标记体系的设计革命(09:51) 处理到第二章时,我意识到一个根本问题: > "原始文件的语义结构变得难以阅读了。需要更可读的标记……文档应该保留最小的语义标签,样式/渲染应该由一个单独的渲染函数或CSS来完成。" 这条指令触发了一个关键的架构转型——从内联样式的HTML标注,转向**内容与样式分离**的设计: **之前**(内联HTML样式): ```html 黄帝 ``` **之后**(轻量Token标记): ```markdown @黄帝@居=轩辕之丘=,娶於&西陵&之女。 ``` 这个设计突破至关重要。Token标记系统的好处是: 1. **人类可读**:标记符号简短,不影响阅读原文 2. **机器可处理**:正则表达式即可完成Token到HTML的转换 3. **内容与样式分离**:样式由CSS统一控制,修改样式不需要修改内容 4. **最小侵入**:保留原文字符,标注只是"包裹" 这一天诞生了11种Token标记符号的完整映射表: | 标记符号 | 实体类型 | CSS类名 | 颜色 | |---------|---------|---------|------| | `@人名@` | 人名 | `.person` | #8B4513 棕色 | | `=地名=` | 地名 | `.place` | #B8860B 金黄 | | `$官职$` | 官职 | `.official` | #8B0000 深红 | | `%时间%` | 时间 | `.time` | #008B8B 青色 | | `&朝代&` | 朝代/氏族 | `.dynasty` | #9370DB 紫色 | | `^制度^` | 制度/典章 | `.institution` | #4682B4 钢蓝 | | `~族群~` | 族群/部落 | `.tribe` | #2F4F4F 深灰 | | `*器物*` | 器物/书名 | `.artifact` | #CD853F 秘鲁棕 | | `!天文!` | 天文/历法 | `.astronomy` | #483D8B 深蓝紫 | | `?神话?` | 神话/传说 | `.mythical` | #8B008B 深洋红 | | `〖+生物〗` | 生物 | `.biology` | #228B22 森林绿 | ### 2.5 并行处理多章节(16:05-19:42) 确立了标记体系后,工作转入实际标注: - **Session 636e2ea3**(16:05-18:00):为第002章《夏本纪》标注实体,同时开发`tag_002_entities.py`辅助脚本 - **Session d26fe3a7**(18:01-18:53):处理过程中遇到Git错误,同时搜索语法高亮、对话渲染、HTML渲染相关的文件,为系统化设计做准备 - **Session 345ccd58**(18:54-19:42):处理第004章《周本纪》。这里引入了**段落长度控制**的概念——检查超过150字符的叙事段落并进行拆分 **段落拆分请求的原文**: > "检查 chapter_md/001_五帝本纪.simple.md 文件,找出所有超过150字符的叙事段落(不包括NOTE块内的内容)。对于每个超长段落,报告:1. 段落编号 2. 字符数 3. 是否需要拆分" 这个请求被同时派发给三个章节(001、002、003),体现了**并行子任务分发**的工作模式。 ### 2.6 文档化标记逻辑(19:43-20:11) > [打开 doc/methodology/史记Markdown转化逻辑.md] 在这个session中,将前面摸索出的所有规则整理成了正式的技术文档——《史记Markdown转化逻辑.md》。这份文档后来成为整个项目的"宪法",包含: - 完整处理流程(4个步骤) - 层级结构规范 - 实体高亮与语义化标记的Token约定 - 对话引号的自动识别规则 - 段落长度控制原则 - 基于大模型的实体识别方法论 ### 2.7 格式转换工具(20:42-次日03:37) > [打开 tools/convert_spans_to_simple.py] 这个深夜session开发了`convert_spans_to_simple.py`——将之前已经用内联HTML样式标注的文件,批量转换为新的Token标记格式。这是一个承前启后的关键工具,确保早期工作成果不被浪费。 --- ## 3. 第二天:精雕细琢(1月23日) ### 3.1 凌晨的密集提交 1月23日凌晨,一连串的git commit记录了一系列快速迭代: | 时间 | Commit | 内容 | |------|--------|------| | 00:47 | `24277b5` | 修复NOTE和地名标记 | | 01:56 | `902d7cd` | 诗歌(赞)按行排版 | | 02:13 | `7f9f630` | **对话引号语法高亮:斜体+网纹阴影** | | 02:25 | `f90463a` | 对话拆分规则和辅助工具 | | 02:28 | `16504e7` | 修复:保留对话引号在HTML渲染中 | | 02:32 | `4f75414` | 重新渲染002和003章节 | | 03:27 | `35bd834` | 对话内容:淡底色+下划线 | | 04:08 | `39ca166` | 长段落划分逻辑和段落编号逻辑 | | 04:17 | `61da0e2` | 文件重命名:simple.md → tagged.md | 这些commit中,`7f9f630`(对话引号语法高亮)特别值得一提。古文中大量内容是对话,如"尧曰:'谁可顺此事?'"。为对话设计专门的视觉样式,是提升阅读体验的关键一步。 最终的对话样式设计体现了"克制优雅"的美学: ```css .quoted { font-style: italic; /* 斜体区分对话与叙述 */ background-color: rgba(139, 69, 19, 0.03); /* 极淡褐色底色 */ border-bottom: 1px dashed rgba(139, 69, 19, 0.3); /* 褐色虚线边界 */ padding: 0 2px; } ``` ### 3.2 段落编号系统:致敬Doug Engelbart(05:03-13:39) | 时间 | Commit | 内容 | |------|--------|------| | 05:03 | `245904c` | 段落序号渲染为小黄框,实体类型mouseover提示 | | 12:38 | `baa5a63` | 改善列表渲染 | | 12:52 | `6fdda1b` | **Purple Number致敬** | | 13:39 | `15b6870` | 段落号码可点击,hash URL可分享 | **Purple Numbers**(紫色编号)是对计算机先驱Doug Engelbart的致敬。Engelbart在1960年代提出了"增强人类智力"的愿景,其中包括给文档的每个段落分配永久、唯一的编号,使得精确引用和知识链接成为可能。 在本项目中,每个段落都有一个可点击的编号锚点: ```html 1 ``` 最初设计为紫色背景(致敬Purple Numbers),后改为淡米色小框,视觉更柔和: ```css .para-num { background-color: #FFF8E1; /* 淡米色 */ color: #6D4C41; /* 深棕色 */ font-size: 0.85em; border-radius: 3px; cursor: pointer; } ``` ### 3.3 增加生物实体和完整流程(14:09-17:52) | 时间 | Commit | 内容 | |------|--------|------| | 14:09 | `7085ff1` | 添加章节跳转链接和原文链接 | | 14:42 | `8455e42` | 修复发布页面的链接 | | 15:33 | `f94b395` | **增加生物实体(第11类)** | | 17:52 | `73c7aed` | 明确完整处理流程,处理005秦本纪 | 生物实体的加入让分类体系从10类扩展到11类。使用emoji `〖+〗` 作为标记符号,是因为ASCII特殊字符已经用完了——这也是一个有趣的工程决策。 标注规则也非常讲究: - 标记名词性的生物:`〖+柳〗`、`〖+马〗` - 不标记动词用法:`蚕食`中的"蚕"不标记 - 不标记比喻用法:`龙颜`不标记 - 神兽也标记:`〖+龙〗`、`〖+凤〗` 到1月23日结束时,`73c7aed`这个commit标志着**核心系统的建立**: - 11类实体标注规范 - Purple Numbers段落编号系统 - Markdown转HTML核心渲染器`render_shiji_html.py` - 完整的CSS样式体系 - 对话语法高亮 - 段落拆分和结构化逻辑 - 已完成52/130章的标注 **两天时间,从零开始,完成了一套完整的古籍语法高亮系统的核心架构。** --- ## 4. 规模化生产(2月6日-8日) ### 4.1 批量处理130章 经过约两周的间歇工作,2月6日开始了大规模生产。这是一个超长session(`3b0000db`),用户和AI之间进行了密集的协作。 关键指令序列: - "继续转化没有完成的章" → 批量下载和标注 - "继续处理010-100" → 大规模并行处理 - "检查后台运行情况" → 监控AI Agent的并行任务 - "你可以选几个你手工来做,给你的agent重新分配任务" → 人工调度AI子任务 2月8日凌晨,里程碑达成: ``` f379b11 02-08 03:04 第一次完整的build,生成了全部130章 adad334 02-08 04:07 fix:所有130章的index ``` **130篇、52万字的《史记》全部完成语法高亮标注和HTML渲染。** ### 4.2 小节划分的人工美学 130章生成后,用户发现需要更细的结构化: > "头12章都是分了小节的,请为后面的章也加小节划分" 但紧接着就提出了质量要求: > "小节划分要有意义,不能是'段落40'这样" 这个要求看似简单,实际上需要深入理解每章的内容。比如《项羽本纪》需要按"起义"、"巨鹿之战"、"鸿门宴"、"楚汉争霸"等历史事件来划分,而非机械地按段落数分块。 经过多轮迭代和检查: - "多少章的小节划分已经完成了" → 进度追踪 - "再检查有没有太长的小节,太长就继续拆分" → 质量保证 - "再检查一遍。如果都拆分好了,更新index" → 最终验收 最终在`98d97a3`(02-08 14:41)完成了全部130章的有意义小节划分。 ### 4.3 项目愿景的表达 在这个漫长的协作session中,用户表达了一些深刻的项目愿景: > "我的目标是让史记能活起来。另一个次要目的是用语法加亮的方法有一个特别适合阅读的版本。" > "语法加亮就是当代更强大的'标点符号'。" > "现在没有人再会读没有标点符号的文章,未来也不会有人愿意读没有语法加亮的文章。" > "我还打算大规模地处理所有的古籍……下一步先打算做26史和通鉴系列。" 这些话后来被写入了项目的README,成为项目愿景的核心表述。 ### 4.4 项目结构整理 同期还进行了大量的工程化整理工作: - 将工具脚本统一到`scripts/`目录 - 知识图谱相关代码统一`kg_`前缀 - 清理脚本中的个人隐私路径(`/home/baojie/work`) - 创建CHANGELOG.md,为每个里程碑添加commit链接 - HTML渲染修复:嵌套标注符号处理、韵文格式、对话缩进 --- ## 5. 深度完善(2月9日-10日) ### 5.1 十表的表格渲染(02-09) 史记中的"十表"(第013-022章)是年表形式的内容,传统阅读中极难使用。 Commit `b77c59f` 实现了完整的表格渲染管线: - 将HTML表格转换为Markdown并嵌入tagged.md - 支持全视口宽度突破(表格可以比正文更宽) - sticky表头(滚动时表头固定) - 交替行背景色 - 表格单元格内的实体标注高亮 - 016号秦楚之际月表的特殊结构拆分(31列→两个独立子表) ### 5.2 命名实体索引系统(02-09) Commit `f586a61` 建立了完整的实体索引系统: - `build_entity_index.py`:扫描130篇tagged.md,提取所有实体 - `entity_aliases.json`:586条人名别名规则(如"沛公"→"刘邦") - 12个HTML索引页面(11类实体+总览) - 拼音排序、字母导航栏、搜索过滤功能 - 正文中所有实体可点击跳转到索引条目 ### 5.3 语义消歧(02-10) Commit `2580cfc` 解决了一个棘手的古文NLP问题——同名消歧: - "武王"在不同章节可能指周武王、秦武王 - "昭王"可能指秦昭王、燕昭王、楚昭王 - "惠王"可能指秦惠王、魏惠王、燕惠王、周惠王 采用4层启发式策略:共现全名 > 附近国名(80字窗口)> 前置国名 > 章节主题国 结果:1,281处自动消歧 + 11处手工修正,覆盖率90%。 ### 5.4 时间线实体(02-10) Commits `60d6728`→`59c3814` 建立了年份映射系统: - 从历史年表中提取君主在位年份 - 构建叙事年份→公元年份映射(288种格式) - 生成可视化时间线页面 --- ## 6. 设计哲学 ### 6.1 "语法高亮是当代的标点符号" 这个类比是整个项目的灵魂。古代的原始文本是没有标点符号的,句读(断句)是读书人的基本功。现代标点符号的普及,让"人人可读"成为可能。 语法高亮做了同样的事——通过颜色和样式,让读者一眼就能区分人名、地名、官职、时间,大幅降低古文阅读的认知负担。 ### 6.2 克制优雅的视觉设计 CSS样式设计遵循"克制"原则: - 颜色不过于鲜艳,使用深沉的暗色系(棕、暗红、深蓝紫) - 背景色透明度极低(0.03),不干扰阅读 - 虚线边界而非实线,提供视觉提示但不喧宾夺主 - 字体使用"Noto Serif SC"(思源宋体),契合古籍的庄重感 - 行高设为2,给每行文字留出呼吸空间 ### 6.3 大模型NER优于关键词匹配 项目明确选择了用大模型进行实体识别,而非基于关键词列表的字符串匹配,原因是: - 古文多义词极多:"和"可以是人名、动词、形容词 - 复合实体需要语义理解:"夏后帝启"、"西伯昌" - 动词性用法不应标记:"蚕食"中的"蚕"、"龙颜"中的"龙" - 上下文决定语义角色:同一个"岳"字,可能是人名也可能是官职 ### 6.4 内容与样式分离 Token标记系统的设计,让`.tagged.md`文件同时服务于两个目的: 1. **人类阅读**:标记符号简短不干扰,可以直接用文本编辑器阅读 2. **机器渲染**:正则表达式一遍扫描即可转换为HTML 这种"双模"设计是实用主义工程哲学的体现。 --- ## 7. 技术架构全貌 ### 7.1 处理管道 ``` 原始文本(.txt) ↓ 大模型NER + 人工审核 标注文件(.tagged.md) ↓ render_shiji_html.py (正则替换Token→HTML span) HTML文件(.html) ↓ publish_to_docs.sh GitHub Pages 发布 ``` ### 7.2 核心文件 | 文件 | 功能 | |------|------| | `render_shiji_html.py` | Markdown→HTML核心渲染器 | | `generate_all_chapters.py` | 批量生成130章HTML+索引页 | | `docs/css/shiji-styles.css` | 11类实体样式+页面排版 | | `docs/js/purple-numbers.js` | 段落编号交互(点击复制链接) | | `build_entity_index.py` | 实体索引生成器 | | `entity_aliases.json` | 实体别名映射(586条) | | `disambiguation_map.json` | 语义消歧映射(644条) | ### 7.3 渲染器核心逻辑 `render_shiji_html.py`的核心是一组有序的正则替换规则(`ENTITY_PATTERNS`),处理顺序至关重要: 1. `**粗体**` 必须在 `*器物*` 之前处理(避免冲突) 2. 外层标记(`$官职$`)先于内层标记(`@人名@`)处理 3. `@人名@` 放在最后,因为人名最常作为内层标注(如`$@安国君@$`) 4. 所有正则排除 `<>` 和 `"` 字符,避免匹配已生成的HTML标签 ### 7.4 最终规模 | 指标 | 数值 | |------|------| | 标注章节 | 130/130 (100%) | | 实体词条 | 5,282个 | | 实体标注次数 | 24,249次 | | 实体类别 | 11类 | | 人名别名 | 586条 | | 语义消歧 | 1,281处 | | 索引页面 | 12个 | | 索引条目 | 11,000+ | --- ## 8. 反思与感悟 ### 8.1 人机协作的模式 回顾整个过程,人与AI的分工非常清晰: **人(决策者)的角色:** - 提出愿景和设计理念("语法高亮是当代的标点符号") - 做审美判断("去掉bold"、"克制优雅") - 纠正语义错误("岳是人名") - 把控质量标准("小节划分要有意义") - 调度并行任务("你选几个手工做,给agent重新分配") **AI(执行者)的角色:** - 大规模实体识别(130篇×52万字) - 代码开发(渲染器、索引生成器、工具脚本) - CSS样式实现 - 文档编写 - 批量文件操作 - 并行子任务执行 ### 8.2 关键转折点 整个过程中有几个关键转折点: 1. **从内联样式到Token标记**(1月22日09:51)——架构层面的顿悟,决定了整个系统的可扩展性 2. **对话语法高亮的引入**(1月23日02:13)——让语法高亮不只关注名词实体,还关注文本的叙事结构 3. **Purple Numbers的致敬**(1月23日12:52)——将计算机先驱的理念融入古籍数字化,形成了跨越时空的知识联结 4. **"语法高亮是标点符号"的顿悟**(2月7日21:57)——将技术实践升华为文化使命 ### 8.3 速度 整个核心系统在**两天**内从零搭建完成。从想法到130篇全部标注渲染完成,不到三周。在AI出现之前,类似的工作可能需要一个团队工作数年。 这不仅是效率的提升,更是一种新的研究范式:**人提供方向和判断,AI提供规模和速度**。 ### 8.4 未完成的愿景 在协作过程中,用户表达了更大的雄心: > "我还打算大规模地处理所有的古籍……下一步先打算做26史和通鉴系列。" 从史记的52万字,到二十四史的4,600万字,再到全部古籍的数亿字——语法高亮作为"当代标点符号"的愿景,还有漫长的路要走。但核心的技术架构和方法论,已经在这两天的密集协作中奠定了基础。 --- ## 附录:完整会话时间线 | 日期 | 时间 | Session | 消息数 | 主要内容 | |------|------|---------|--------|---------| | 01-22 | 08:47-11:47 | 9d1e6197 | 69 | 首次实体识别请求,Token标记体系设计 | | 01-22 | 11:47-13:15 | ae0ea332 | 50 | 002章夏本纪处理 | | 01-22 | 16:05-18:00 | 636e2ea3 | 76 | 002章实体标注脚本 | | 01-22 | 18:01-18:53 | d26fe3a7 | 122 | Git错误处理,系统化搜索 | | 01-22 | 18:54-19:42 | 345ccd58 | 52 | 004章周本纪,段落长度控制 | | 01-22 | 19:43-20:11 | 7dc217d2 | 49 | 文档化转化逻辑 | | 01-22 | 20:42-次日03:37 | 1bbc8810 | 46 | convert_spans_to_simple.py | | 01-23 | 03:38-05:08 | bd646885 | 108 | HTML渲染系统 | | 01-23 | 05:53-07:12 | 06abb051 | 110 | 段落编号系统 | | 01-23 | 07:14-07:42 | d80c88ae | 43 | render_shiji_html.py | | 01-23 | 09:47-10:14 | 489f986b | 12 | 005章秦本纪 | | 02-06~08 | 全天 | 3b0000db | 59+ | 大规模生产(130章标注+渲染+小节划分+项目整理) | | 02-08~09 | 全天 | c8299f0d | — | HTML修复、表格渲染 | | 02-09 | 全天 | 62de01b7 | — | 实体索引系统 | | 02-09~10 | 全天 | 66277a8c | — | 语义消歧、时间线 | **总计会话消息数**:约800+条人机交互 --- *本文档基于项目git历史、Claude Code会话日志、技术文档和源代码逆向重建。* *最后更新:2026-03-06*