为什么给模型 Markdown 而不是 PDF
把 PDF 附到聊天里,应用会替你提取文字,但你看不到模型实际拿到了什么。先自己转换有三个好处:
- 看得到文字。 坏掉的表格、错乱的分栏、没有文字的页面,会在把模型搞糊涂之前就暴露出来。
- 结构保留下来。 标题、列表和表格保留为模型读得懂的 Markdown,而不是一串平铺的文字行。
- 更省 token。 页码、重复的页眉、行尾连字符和排版留白都会去掉,上下文窗口能更多地留给内容。
这个页面打开时已经按这个目的调好了设置:不保留图片,每页开头加一个 <!-- Page N --> 注释方便模型引用页码,并去掉图片行。
可信的 token 计数
Markdown 上方的数字,是你将要复制或下载的内容的准确 token 数,包括 front matter 和页码标记。计数使用 o200k_base,也就是 GPT-4o 及之后 OpenAI 模型的编码。Claude 等其他模型用各自的分词器,对它们来说这个数字是接近的估计值,不是精确值。
为大模型精简下的每个开关,在你打开之前就会显示它能为你的文件省多少 token:
| 开关 | 作用 |
|---|---|
| 去掉链接地址 | 保留链接文字,去掉 URL |
| 去掉粗体和斜体 | 去掉 ** 和 * 标记 |
| 去掉图片行 | 不留图片占位符,也不留图片链接 |
| HTML 标签转成纯文本 | <sup>、<sub> 和 <br> 变成纯文本 |
| 规范化字符 | fi 这类连字变成 fi,奇怪的空格变成普通空格 |
| 紧凑表格 | 去掉空列和单元格周围的空白 |
因为不用重新读取 PDF,开关切换只需几毫秒。
给 RAG 用的分块
检索需要把文档切成小到能做向量嵌入、又能独立读懂的片段。分块标签页会替你切分 Markdown:
- 先按标题切。 只要能避免,分块就不会从某一节的中间开始,所以每块只讲一个主题。
- 不超过你选的 token 上限,可选 256 到 8,192。比上限大的章节在句子之间切开,大表格在行之间切开,并重复表头行。
- 带着标题路径。 每个分块都知道自己上面的各级标题,比如
方法 › 数据收集,也可以用它们开头,这样检索到的分块依然说得清自己来自哪里。 - 带着页码,回答可以指回原文第 12 页。
下载 JSONL 得到的文件每行一个 JSON 对象:
{
"id": "report.pdf#3",
"source": "report.pdf",
"chunk": 3,
"headings": ["Methods", "Data collection"],
"page_start": 4,
"page_end": 5,
"tokens": 812,
"text": "..."
}
几行代码就能把它导入你用的向量库。
一个好用的流程
- 拖入 PDF,先看待检查页面。转得不对的页面,修正或用 OCR 重新识别。
- 打开那些省下的 token 值得的精简开关;想让模型引用来源,就保留链接。
- 用于聊天,就复制 Markdown 粘贴进去。用于流程,就拿 JSONL 分块。
一切都在你的浏览器里完成,这一点在这里很重要:人们喂给模型的文档,常常是内部报告、合同或研究资料,不该再上传到又一个服务。
常见问题
对大模型来说,Markdown 真的比纯文本好吗?
对有结构的文档,通常有帮助:标题告诉模型各节如何嵌套,表格让每个数字挨着它的标签。如果只是一页散文,差别不大。你可以用开关保留或去掉这些结构。
分块大小该设多少?
针对文档做问答,先从 512 或 1,024 token 开始。小分块和具体问题匹配得更准,大分块能把更多上下文放在一起。分块标签页下方的摘要会显示分块数量和最大的一块,效果一眼就能看到。
token 是在我的设备上数的吗?
是的。分词器和转换器的其他部分一样在标签页里运行,不会为了计数把任何东西发给 OpenAI 或别人。
能为数据集处理很多 PDF 吗?
一次最多可以拖入 20 个,并打包成一个 .zip 全部下载。几千个文件的话,脚本更合适,见 用 Python 把 PDF 转成 Markdown。