离线索引做什么
离线索引把散落的文档批量加工成可检索的向量索引:解析出文本、清洗噪声、切成片段、批量向量化,再连同元数据写入向量库。它是批处理任务,通常在文档变更后或夜间窗口触发,可以排队重跑。检索质量的上限在这里就被定下来,后面的在线环节只能挑好的,不能凭空补出不存在的内容。
基本信息
| 常见叫法 | ingestion(入库流水线)、离线索引 |
|---|---|
| 输入 | 原始文档:PDF、Word、HTML、Markdown、扫描件 |
| 输出 | 向量 + 片段文本 + 元数据 |
| 触发方式 | 全量重建、增量更新、按文档变更事件 |
| 工程要求 | 幂等、可重跑、可抽样核对、可断点续跑 |
环节拆解
| 环节 | 做什么 | 常见工具与要点 |
|---|---|---|
| 解析 | 从 PDF/HTML/Word 提取文本 | PyMuPDF、pdfplumber、MinerU、Docling、Unstructured |
| 清洗 | 去页眉页脚、乱码、断行 | 自定义正则 + 人工抽检 |
| 切分 | 按长度、结构或语义分块 | RecursiveCharacterTextSplitter、SentenceSplitter 等 |
| 向量化 | 批量生成 embedding | BGE / E5 / OpenAI text-embedding-3 等 |
| 入库 | 写向量与元数据 | Milvus / Qdrant / pgvector 等 |
典型使用场景
- 首次上知识库:把历史文档一次性灌入,建立可检索的基线
- 文档更新:只对变更文件重算切分与向量,替换同 doc_id 的旧切片
- 更换 embedding 模型:全量重算向量,向量维度与语料的匹配度决定召回水平
- 解析工具升级:换解析器后必须重建索引,否则新旧切片混在同一库里无法比较
- 离线评测:为评测集准备与线上一致的切片,保证结论可迁移
批量索引伪代码
批量索引伪代码
for doc in iter_documents(source):
pages = parse(doc) # 解析
text = clean(pages) # 清洗
chunks = split(text) # 切分
vecs = embed_batch(chunks) # 向量化
store.upsert(chunks, vecs) # 入库(带 doc_id / 页码等元数据)常见失败与后果
| 失败点 | 表现 | 后果 |
|---|---|---|
| 解析丢版式 | 表格被拆成乱序文字 | 答案引用到错行数据 |
| 清洗不到位 | 页眉页脚混进切片 | 检索被导航文字占满 |
| 切分越界 | 一句话被切成两块 | 单块无法独立回答 |
| 重跑不幂等 | 同一文档出现多份切片 | 上下文重复、答案啰嗦 |
| 字段缺失 | 没有 doc_id 与版本 | 更新时删不掉旧切片 |
索引是批处理,解析与切分的错误会原样进入向量库,后续环节无法补救;入库前务必抽样人工核对,尤其抽查表格页与扫描页。
增量更新建议用 doc_id 加内容哈希判断:哈希未变就跳过重算向量,既能省掉 embedding 费用,也避免同一文档反复写入导致重复切片。