本文档完整记录了通过与 AI 对话进行 Agentic Coding 开发 EpubToSplitTxt 项目的全过程,展示了人机协作编程的真实体验。
初始需求: 将网络小说《蛊真人》的 Epub 电子书转换为按章节切分的纯文本文件,为后续 TTS(文本转语音)处理做准备。
核心挑战:
- Epub 内部是 HTML 格式,需要清洗
- 《蛊真人》结构特殊:按"卷-节"组织,每卷从"第一节"开始
- 需要保持正确的阅读顺序
- 文件命名要兼顾语义和排序
背景: 在开始对话之前,我先定义了一份项目规则文件 epub_processing.md,作为 AI 的开发指南。
Rules 核心内容:
## Codebase
- 语言: C# (.NET 10 Preview)
- 职责边界:
- EpubConverter: 负责解析 .epub 文件结构并提取纯文本
- TextSplitter: 负责基于正则规则扫描文本,并按章节物理切割文件
- 文件命名规范: 切分后的文件名必须包含序列号以保持阅读顺序
## Dependencies
- VersOne.Epub:3.2.1 - Epub 解析库
- HtmlAgilityPack:1.11.59 - HTML 标签清洗
## Config
- Splitter:ChapterRegex - 章节匹配正则
- Splitter:MinChapterLength - 最小章节长度
- Paths:RawEpubFolder / SplitOutputFolder - 路径配置
## AI Coding Rules
- 正则必须使用 RegexOptions.Compiled
- 禁止一次性 File.ReadAllText,必须流式处理
- 输出必须使用 UTF-8 (without BOM) 编码
- 文件名必须清洗非法字符AI 基于 Rules 生成了:
EpubToSplitTxt.csproj- 项目配置,引入指定依赖Program.cs- 主程序入口EpubConverter.cs- Epub 解析模块TextSplitter.cs- 章节切分模块AppSettings.cs- 配置管理appsettings.json- 配置文件
学到的:通过预定义 Rules,AI 能一次性生成符合规范的完整项目骨架,而不是从零开始摸索。
我说:
用 global using,然后把 bin 和 obj 文件全部忽略,还有就是为什么没有解决方案文件
AI 做了什么:
- 创建
GlobalUsings.cs,集中管理常用命名空间 - 创建
.gitignore,忽略 bin/obj 等编译产物 - 生成
EpubToSplitTxt.sln解决方案文件
学到的:AI 能快速理解 .NET 项目的最佳实践,一次性完成多个配置任务。
我说:
@appsettings.json 这个好像不生效
问题根源: Directory.GetCurrentDirectory() 返回的是 Shell 当前目录,而不是程序所在目录。
AI 的修复:
// 修复前:使用当前工作目录
SetBasePath(Directory.GetCurrentDirectory())
// 修复后:使用程序所在目录
SetBasePath(AppContext.BaseDirectory)学到的:描述问题现象,AI 能准确定位 .NET 配置加载的常见陷阱。
我说:
不用编译 [WARN] 在 bin\Debug\net9.0\RawEpub 中未找到任何 .epub 文件 我不要用编译文件的那个文件夹,我这里不是有一个文件夹吗
AI 理解了: 我想用项目根目录下的 RawEpub 文件夹,而不是 bin 目录。
解决方案: 配置文件中使用相对路径 ../../../RawEpub,并在代码中正确解析。
我展示了书中内容:
类似这种章节: 序:不是走向成功,就是走向毁灭 第一节:纵身亡魔心仍不悔
AI 更新了正则配置:
{
"ChapterRegex": "(^第[0-9一二三四五六七八九十百千]+章.*)|(^序[::].*)|(^序章.*)|(^楔子.*)",
"SectionRegex": "(^第[0-9一二三四五六七八九十百千]+节.*)|(^内容简介.*)"
}同时实现了:如果内容为空则不生成 txt 文件。
我说:
其实根本不完整 这个文件是完整的,下面是最后一小节:第三百六十八节:方源、巨阳战星宿
问题诊断: 源文件有 2335 节,但只生成了 2158 个文件,缺失 177 节!
AI 的排查过程:
- 添加调试计数器统计识别的节数
- 对比发现确实少了很多节
- 检查正则表达式...
根本原因: 正则 [0-9一二三四五六七八九十百千] 缺少 "零" 和 "两" 字符!
像 "第一百零一节"、"第两百节" 这样的标题无法匹配。
修复:
- [0-9一二三四五六七八九十百千]+节
+ [0-9一二三四五六七八九十百千零两]+节学到的:中文数字的完整字符集容易遗漏,AI 能通过数据对比快速定位问题。
我说:
不对,还有内容没有分割处理,它是分章然后再分小节的,你可以把每章放到一个文件夹中,里面是那些小节
AI 重构了 TextSplitter:
- 章 → 文件夹
- 节 → 文件夹内的独立文件
输出结构:
SplitOutput/蛊真人/
├── 01.第一章:前言/
│ ├── 001.前言.txt
│ └── 002.内容简介.txt
├── 02.第二章:纵身亡魔心仍不悔/
│ ├── 003.第一节:纵身亡魔心仍不悔.txt
│ ├── 004.第二节:逆光阴五百年觉悟.txt
│ └── ...
我说:
你能根据每个第一节帮我分割吗,然后根据上下文以及语义取标题
AI 分析了源文本: 发现有 6 个 "第一节",意味着全书分 6 卷。
新策略:
- 遇到 "第一节" 开始新章
- 用第一节标题冒号后的内容作为章名
第一节:纵身亡魔心仍不悔→ 章名纵身亡魔心仍不悔
我说:
每一节前面还是要这样命名:第一百三十节:"父子"相见 然后每一章按照顺序排序:第一章:前言
AI 理解了双重需求:
- 节文件保留完整标题格式
- 章文件夹用 "第X章:" 前缀
但遇到排序问题: 中文数字在文件系统中按字符排序(第一、第七、第三...)
我说:
可以试试,你给我看看改动
最终方案: 阿拉伯数字前缀 + 中文标题
01.第一章:前言
02.第二章:纵身亡魔心仍不悔
...
003.第一节:纵身亡魔心仍不悔.txt
004.第二节:逆光阴五百年觉悟.txt
兼顾了 正确排序 和 语义可读性。
Program.cs (主程序入口)
│
├── EpubConverter (Epub 解析模块)
│ ├── VersOne.Epub 3.3.0 - 读取 Epub 结构
│ └── HtmlAgilityPack 1.11.59 - 清洗 HTML 标签
│
├── TextSplitter (章节切分模块)
│ ├── 按"第一节"识别新章
│ ├── 正则匹配节标题
│ └── 中文数字转换
│
└── AppSettings (配置管理)
└── appsettings.json
┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐
│ Epub 文件 │ → │ EpubConverter │ → │ 全本 TXT │ → │ TextSplitter │
└─────────────┘ └──────────────┘ └─────────────┘ └──────────────┘
│ │
解析 HTML 结构 按"第一节"分章
清洗标签/实体 正则匹配节标题
合并为纯文本 序号+语义命名
↓
┌──────────────────┐
│ 章节文件夹集合 │
└──────────────────┘
// 第一节作为新章的开始标志
_firstSectionRegex = new Regex(@"^第一节[::]", RegexOptions.Compiled);
if (isFirstSection)
{
// 保存当前章
SaveCurrentChapter();
// 用第一节标题的冒号后内容作为章名
currentChapterTitle = ExtractChapterTitle(trimmedLine);
// "第一节:纵身亡魔心仍不悔" → "纵身亡魔心仍不悔"
}private string ConvertToChineseNumber(int number)
{
string[] digits = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" };
if (number < 10) return digits[number];
if (number < 20) return "十" + (number % 10 > 0 ? digits[number % 10] : "");
// ... 百、千的处理
}private string SanitizeFileName(string fileName)
{
// 移除文件系统非法字符: \ / : * ? " < > |
char[] invalidChars = Path.GetInvalidFileNameChars();
foreach (char c in invalidChars)
{
fileName = fileName.Replace(c, '_');
}
return fileName;
}| 指标 | 数值 |
|---|---|
| 识别章数 | 7 章 |
| 识别节数 | 2336 节 |
| 平均每节字数 | 3168 字 |
| 处理耗时 | ~5 秒 |
输出目录结构:
SplitOutput/蛊真人/
├── 01.第一章:前言/
│ ├── 001.前言.txt
│ └── 002.内容简介....txt
├── 02.第二章:纵身亡魔心仍不悔/
│ ├── 003.第一节:纵身亡魔心仍不悔.txt
│ ├── 004.第二节:逆光阴五百年觉悟.txt
│ └── ... (共 199 节)
├── 03.第三章:黄龙江上竹筏倾/
├── 04.第四章:凤九歌/
├── 05.第五章:回归狐仙福地/
├── 06.第六章:一切都是天意/
└── 07.第七章:新天外之魔/
└── 2336.第三百六十八节:方源、巨阳战星宿.txt
-
快速迭代: 描述需求 → AI 实现 → 运行验证 → 发现问题 → 继续对话,循环只需几分钟
-
问题诊断: 当我说"不完整",AI 能添加调试代码、对比数据、定位到正则缺少"零两"字符
-
渐进式完善: 从基础功能开始,通过持续对话逐步添加:
- 配置化 → 两级目录 → 第一节分章 → 命名格式优化
-
知识补充: AI 自动处理了我没想到的细节:
- UTF-8 无 BOM 编码
- 正则超时保护
- 流式读取大文件
- 明确表达期望: "我要这样..." 而不是模糊描述
- 提供具体示例: 展示书中实际内容,比抽象描述更有效
- 及时验证反馈: 运行后告诉 AI 结果对不对
| 项目 | 说明 |
|---|---|
| 开发时间 | 2025-12-13 ~ 2025-12-14 |
| 开发方式 | Agentic Coding |
| 对话轮次 | ~15 轮核心交互 |
| 技术栈 | .NET 9.0 / C# |
| 核心依赖 | VersOne.Epub, HtmlAgilityPack |
本文档由人类与 AI 协作编写,记录真实的对话开发过程。