把三万篇论文灌进知识库:一次 11 小时的流水线
2026 年 8 月。目标很朴素:让文献检索能带着出处。结果跑了 11.2 小时、处理 30,031 篇、成功率 99.96%。真正难的不是模型,而是让这条流水线在几万次重复里不出错。
先说结论
- 让长跑不失败的三件事:内容哈希幂等、任务表驱动续跑、失败按原因分类;
- 混合引擎(本机算力打底 + 云端补量)不是为了更快,而是为了不被单一资源卡死;
- 抽出来的内容不能直接当结论用,所以每条知识条目都挂了指向原文的证据链接。
一、跑了什么
| 指标 | 数值 |
|---|---|
| 论文总数 | 30,031 篇 |
| 完成数 | 30,018 篇(99.96%) |
| 总耗时 | 11.2 小时(平均约 2.5 秒/篇) |
| 知识条目 | 102 条正式条目 |
| 证据链接 | 18,125 条 |
| 待审草稿 | 177 条(人工复核后转正) |
| 中途故障 | 网络中断 1 次,自动续跑完成 |
二、流水线长什么样
PDF 目录
│
├─ ① 解析与分块 ──→ 本地缓存(记录内容哈希)
│
├─ ② 任务表 ────→ pending / running / done / failed(原因)
│ ↑ 唯一事实来源,进程重启后接着读
├─ ③ 推理调度 ──┬─ 本机 GPU(短文本、结构清晰的论文)
│ └─ 云端(长文与解析失败的补救批次)
│
└─ ④ 落库 ──────→ 知识条目 + 原文证据链接 + 待审队列四个环节里,只有 ③ 和"智能"有关,其余三个都是纯粹的工程问题。
三、三个关键设计
一、幂等靠内容哈希,不靠"断点续传"。 每个文件先算哈希,处理过就跳过:
h = content_hash(pdf_path)
if table.seen(h):
return # 重复执行天然安全
table.enqueue(h, pdf_path)这样重跑的代价接近零,也不需要维护"我处理到第几个了"这种脆弱状态。
二、任务表是唯一事实来源。 每篇的状态(待处理 / 处理中 / 完成 / 失败待重试)都在表里,进程被杀掉重启后直接接着读表。11 小时里遇到过一次网络中断,恢复后它自己继续跑完。
三、失败要分类。 "模型返回格式错误"重试有效,"文件本身损坏"重试一万次也没用。分开记录之后,最后剩下的 0.04% 每一篇都能一眼看出原因。
性价比最高的一步
把"失败原因"当成一等公民、从第一版就分类记录。这一步几乎不花时间,但它让最后 0.04% 的排查从"逐篇看"变成了"按类别处理"。
四、三个坑
一、先放并发,再谈质量。 我一开始就把并发拉满,结果模型服务被打爆、后面全在排队等超时。后来改成"先缓存结果,再让推理服务以稳定速率消费"——总耗时反而更短。
稍加注意
并发上限应该从服务端限额倒推,而不是从"我想多快"决定。这一点在云端 API 上尤其明显。
二、混合引擎要分工,不要"谁快用谁"。 本机显卡跑小模型吞吐有限,云端按篇计费但速度快。最后的做法是按论文特征分工(短文本走本地、长文走云端),而不是简单地看谁空闲。
三、条目质量要人兜底。 抽出来的内容不能直接当结论:一部分进了"待审草稿"队列,由人工复核后才转正。自动化可以提高吞吐,该人看的地方还是得人看。
五、如果再跑一次
- 从第一版就区分失败原因;
- 从第一版就用内容哈希做幂等;
- 先做通一篇的端到端质量检查,再放开并发——质量问题是批量的,发现得越晚越贵。