首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >把纸质文档一键变成知识库:WorkBuddy + 腾讯云 OCR Skill + TriviumDB 实战

把纸质文档一键变成知识库:WorkBuddy + 腾讯云 OCR Skill + TriviumDB 实战

原创
作者头像
晨星成焰
发布2026-08-16 23:26:17
发布2026-08-16 23:26:17
1870
举报
文章被收录于专栏:AI开发相关AI开发相关

把纸质文档一键变成知识库:WorkBuddy + 腾讯云 OCR Skill + TriviumDB 实战

前言 一个被 AI 公司"启发"出来的念头

前几天刷到条新闻,美国 AI 公司 Anthropic 为了给 Claude 凑训练数据,搞了个代号"巴拿马计划"的活儿:花几百万美元买下几百万本实体书,一刀切掉书脊,高速扫描仪扫完,原书直接销毁回收。两百万本书就这么没了,简直就是人间之屑 人类文明的破坏者,妄图将一切人类共享文明成果转为私有资产

顺便,扫描纸质书存进向量库这个点子其实不赖,我就想,这事儿能不能文明点复现?不切书脊、不烧书,书原样放回书架,内容却规规矩矩进了我自己的知识库,于是想着刚好做了一个RAG知识库的练手项目,顺手扩展一下相关能力。

于是有了这篇:用 WorkBuddy 装上腾讯云的 OCR Skill(通用文字识别高精度版),把一张纸质文档的照片识别成文字;文字切块、向量化;存进我自己一直在维护的嵌入式数据库 TriviumDB;最后用中文提问,直接命中英文论文里的原句。全程本地跑通,代码都贴在下面。

下面每个数字都是今天实机跑出来的,不是 PPT 配图。

1. 整条流水线长什么样

纸质文档到知识库的完整管线
纸质文档到知识库的完整管线

三个环节,各选了一个我认为最合适的组件:

  1. OCR 走腾讯云官方 Skill。让 WorkBuddy 装上 Skill 直接驱动,而不是自己在代码里拼 API。云能力封装成 Agent 能调用的原子能力,这才是 Skill 的用法。
  2. 向量库用 TriviumDB。Rust 写的嵌入式数据库,向量+图+文档三位一体,一个 .tdb 文件就是一个知识库,不用起服务。
  3. Embedding 用 multilingual-e5-small。384 维,关键点是中英跨语言:中文提问能命中英文文档。

2. 前置:装 Skill、配密钥、开服务

2.1 在 WorkBuddy 里装 OCR Skill

在workbuddy的技能市场搜 tencentcloud-ocr,一键安装(v1.0.4),或者你直接跟ai说一句让ai一键配好。

2.2 密钥与开通

先在腾讯云控制台开通通用文字识别服务,再去 CAM 访问管理创建 API 密钥。密钥走环境变量注入,不写进代码和文件:

代码语言:bash
复制
export TENCENTCLOUD_SECRET_ID="你的SecretId"
export TENCENTCLOUD_SECRET_KEY="你的SecretKey"

3. 素材:纸质文档照片怎么来

文章要真实,素材就得像回事,因为我实在懒得下楼去买纸笔手写模拟,干脆让ai给我模拟一个纸质环境文档。我手头正好有一篇从网上下载的 ANN 检索论文(QuIVer,讲二进制量化建图),把它做成两种形态:

  • 干净渲染(PNG,相当于扫描件)
  • 纸质照片模拟(JPG):灰度、轻微旋转、光照渐变、噪点、JPEG 压缩,模拟手机拍的打印纸
先从PDF转为png图片
先从PDF转为png图片
纸质照片模拟版(OCR 实际识别的输入)
纸质照片模拟版(OCR 实际识别的输入)

生成脚本(make_test_images.py,核心代码):

代码语言:python
复制
# 1) PyMuPDF 渲染页面 → 2) 灰度 → 3) 旋转 0.5° → 4) 光照蒙版 → 5) 噪点 → 6) JPEG
img = ImageOps.grayscale(img.rotate(angle, expand=True, fillcolor=235))
img = ImageChops.multiply(img, light_mask(img))       # 环境光不均匀
img = img.point(lambda i: clamp(i + randint(-6, 6)))  # 传感器噪点
img.save(out, "JPEG", quality=85)

这样生成的图既有真实文字,又带拍照常见的退化,OCR 识别出来才有说服力。两张图都是 2564×3310 像素。

4. 第一步:OCR 识别,看真实输出

用 WorkBuddy 调 Skill,对两张图分别识别,输出存成 JSON:

代码语言:bash
复制
python .../tencentcloud-ocr/scripts/main.py \
  --image-base64 "QuIVer_..._p1_paper.jpg"

返回的核心字段是 raw_text。第 1 页识别出 5502 字符,第 2 页 6292 字符。摘录第 1 页开头(双栏论文,识别顺序按栏流式输出):

代码语言:txt
复制
QuIVer: Rethinking ANN Graph Topology via Training-Free
Binary Quantization
Wenxuan Xiao  Peidong Zhu  Chengcheng Li
...
Approximate nearest neighbor (ANN) graph indices such as HNSW
Modern retrieval-augmented generation (RAG) pipelines [1], se-
and Vamana construct their edge topology in full-precision or high-
...

这里有个真实观察:双栏论文的 OCR 输出是按栏交错的。上面 HNSW 那句和 RAG 那句,原文里分属左右两栏,识别结果里却挨在一起。这个现象直接影响切块策略,下面会讲。

5. 第二步:切块 + Embedding

5.1 切块

OCR 结果是"行"的序列。我的切法:按行聚合到 ~400 字符/块,记录页码。2 页共切出 32 块

代码语言:js
复制
function chunkText(text, size = 400) {
  const lines = text.split("\n").map(s => s.trim()).filter(Boolean);
  const chunks = []; let cur = "";
  for (const line of lines) {
    if (cur && cur.length + line.length > size) { chunks.push(cur); cur = line; }
    else cur = cur ? `${cur} ${line}` : line;
  }
  if (cur) chunks.push(cur);
  return chunks;
}

5.2 Embedding

模型用 Xenova/multilingual-e5-small(384 维,q8 量化版,约 100MB,首次运行自动下载;国内访问慢的话设 HF_ENDPOINT=https://hf-mirror.com)。e5 系列官方推荐:文档侧加 passage: 前缀,查询侧加 query: 前缀。我照做了,但实测下来发现前缀的影响跟直觉不太一样,这点在第 7 节单独说。

6. 第三步:TriviumDB 入库 + 语义问答

6.1 为什么是 TriviumDB

我维护 TriviumDB 有一阵子了(开源,Rust 实现,Apache-2.0,向量+图+文档三位一体)。选它当向量库的理由:

  • 嵌入式:一个 .tdb 文件就是整个库,本地文件即知识库,不用起服务
  • napi 绑定:Node.js 直接 require,new TriviumDB(file, dim, "f32", "normal") 一行打开
  • 检索直接给余弦相似度search() 返回 01 的分数,语义越近分越高(本次演示命中 0.780.88),不用自己做距离换算
  • 自家人做的 得想办法给他宣传👿

入库代码(简化自我落地项目 RAG_librariestriviumdb-store.ts 的封装模式):

代码语言:js
复制
const { TriviumDB } = require("triviumdb");
const db = new TriviumDB("quiver_ocr_demo.tdb", 384, "f32", "normal");

// 32 个 chunk → 32 条向量记录,payload 里存原文
for (let i = 0; i < chunks.length; i++) {
  db.insert(vectors[i], { chunkId, page, text, source: "quiver-paper-ocr" });
}

6.2 语义问答,真实输出

三个问题,两个中文一个英文,全部命中英文论文原文:

Q: QuIVer 论文用二值量化做了什么创新?

代码语言:txt
复制
#1 [score=0.8383] (page 2) tests [13]) but violated by Euclidean-native features...
#2 [score=0.8336] (page 2) XOR and Popcount in O(D/64) word operations...
#3 [score=0.8330] (page 2) The parameter α ≥ 1 controls the trade-off between graph den-...

Q: Why does RAG need approximate nearest neighbor search?

代码语言:txt
复制
#1 [score=0.8831] (page 1) Modern retrieval-augmented generation (RAG) pipelines [1]...
#2 [score=0.8467] (page 2) The parameter α ≥ 1 controls the trade-off between graph den-...
#3 [score=0.8395] (page 2) u, v ∈ R^D with θ = arccos(⟨u, v⟩)...

Q: HNSW 和 Vamana 有什么不同?

代码语言:txt
复制
#1 [score=0.8096] (page 2) ogy. Evaluation on twelve million-scale datasets...  (Vamana 段落)
#2 [score=0.7968] (page 1) QuIVer: Rethinking ANN Graph Topology...  (标题块)
#3 [score=0.7823] (page 1) peting objectives: recall (search accuracy), throughput...

7. 个人见解:三个真实踩坑

① 双栏论文的切块边界是个真问题。 看 Q3 的命中:第二名是"标题块",而不是真正讲 HNSW/Vamana 对比的段落。原因很直接:标题块恰好同时含「QuIVer」「HNSW」「Vamana」这些词,向量相似度被拉高了。OCR 按栏流式输出让这个问题更明显(我另一版不带 query: 前缀的检索里,标题块直接排到了第一)。我的解法思路:识别结果来自双栏排版时,切块前先按栏重排(TextDetections 里有文字框坐标,可按 x 坐标分栏);或者检索时把阈值调高。这属于"把 OCR 结果当文档解析来做",我落地项目的下一步就是它。

② e5 的 query:/passage: 前缀,实测影响和直觉相反。 官方推荐这么写,我干脆做了个对照实验:同一批文档用 passage: 前缀入库,查询分别用 query: / passage: / 无前缀,各问 3 题。结果:

代码语言:txt
复制
Q1 二值量化创新   query: 0.8383   passage: 0.8293   无前缀 0.8338
Q2 RAG 与 ANN    query: 0.8831   passage: 0.8741   无前缀 0.8822
Q3 HNSW vs Vamana query: 0.8096  passage: 0.8211   无前缀 0.8220

三个发现:分数绝对值差异不到 1 个百分点,prefix 不是玄学但也没那么神;query: 前缀改变了排序,Q3 里它把真正讲 Vamana 的段落排到第一,无前缀时反而是标题块第一;但 Q3 的 query: 分数(0.8096)反而比无前缀(0.8220)低,因为它把高分但跑题的标题块压下去了。我的结论:前缀的价值在"排序质量"不在"分数",检索场景照官方推荐写,不能指望它能弥补切块或数据质量问题。

③ 维度一致是硬约束。 换 embedding 模型 = 维度变 = 已入库向量全部作废。TriviumDB 的维度在建库时固定,换了模型忘了清理 .tdb,检索结果就是垃圾。我在落地项目里把它写成了运行时校验:模型返回维度 ≠ 配置维度,直接报错。

8. 可复现清单

  1. 腾讯云开通通用文字识别,创建密钥,设 TENCENTCLOUD_SECRET_ID/KEY 环境变量
  2. WorkBuddy 技能市场安装 tencentcloud-ocr(v1.0.4)
  3. 准备图片:python make_test_images.py <your.pdf> ocr-demo 1(或直接用你的扫描件/照片)
  4. OCR:python .../main.py --image-base64 <img>
  5. 依赖:npm i triviumdb @huggingface/transformers(或复用 monorepo 的 node_modules)
  6. 跑管线:node pipeline-demo.mjs(首次会自动下载 e5-small 模型)

脚本和输出都已归档:make_test_images.py(图片生成)、ocr_output_p1/p2_paper.json(OCR 真实输出)、pipeline-demo.mjs(切块→向量→入库→问答)、test-prefix.mjs(前缀对照实验)、data/quiver_ocr_demo.tdb(库文件)。

9. 结尾

最实在的感受是:AI 太强了。越来越觉得人的价值在往“定方向、做判断、帮 QA 兜底背锅”上挪——甚至方向都能让 AI 先提一版。我全篇基本上就是在已有项目的基础上,让 AI 去推进实现的,程序员在AI时代最大的价值可能就是以前积累下来的判断力了。


文中所有输出均为 2026-08-16 本机实测;TriviumDB 0.7.4、tencentcloud-ocr v1.0.4、multilingual-e5-small (q8)。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 把纸质文档一键变成知识库:WorkBuddy + 腾讯云 OCR Skill + TriviumDB 实战
    • 前言 一个被 AI 公司"启发"出来的念头
    • 1. 整条流水线长什么样
    • 2. 前置:装 Skill、配密钥、开服务
      • 2.1 在 WorkBuddy 里装 OCR Skill
      • 2.2 密钥与开通
    • 3. 素材:纸质文档照片怎么来
    • 4. 第一步:OCR 识别,看真实输出
    • 5. 第二步:切块 + Embedding
      • 5.1 切块
      • 5.2 Embedding
    • 6. 第三步:TriviumDB 入库 + 语义问答
      • 6.1 为什么是 TriviumDB
      • 6.2 语义问答,真实输出
    • 7. 个人见解:三个真实踩坑
    • 8. 可复现清单
    • 9. 结尾
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档