Skip to content

fix(knowledge): 复用未变化的文档重解析结果#1902

Open
DadaVinqi wants to merge 1 commit into
Tencent:mainfrom
DadaVinqi:feat/1679-incremental-chunk-reuse
Open

fix(knowledge): 复用未变化的文档重解析结果#1902
DadaVinqi wants to merge 1 commit into
Tencent:mainfrom
DadaVinqi:feat/1679-incremental-chunk-reuse

Conversation

@DadaVinqi

Copy link
Copy Markdown

摘要

Fixes #1679.

本 PR 修复知识文档重解析时,未变化内容仍会被重复处理的问题。

在现有实现中,文档 reparse 流程会先清理旧的 chunks / vectors,再基于新的解析结果重新生成全部下游数据。即使文档内容没有变化,或只有少量内容发生变化,系统也无法识别哪些 chunks 可以安全复用,因此会重复执行 chunk 构建、embedding、多模态图片 OCR/caption、Wiki map 阶段生成等成本较高的处理。

这会带来两个主要问题:

  1. 重复执行昂贵处理

    对未变化内容重新 embedding 或重新执行多模态 / Wiki 处理,会显著增加重解析耗时和模型调用成本。

  2. 过早删除旧数据

    旧 chunks / vectors 在新解析结果完成 diff 前就被清理,导致系统无法基于旧结果做增量判断,也增加了重解析过程中数据关系被破坏的风险。

根因分析

问题的根因是 reparse 流程缺少稳定的“可复用性判断”。

当前逻辑主要基于一次完整重建来处理文档:

  1. 文档触发重新解析。
  2. 系统清理旧 chunks 和相关 vectors。
  3. 基于新解析结果重新生成 chunks。
  4. 对所有 chunks 重新执行 embedding / OCR / caption / Wiki map 等后续处理。
  5. 重新写入新的 chunks 和向量索引。

这种流程没有保存并比较“内容 + 处理配置”的稳定标识,因此无法判断某个新 chunk 是否等价于旧 chunk。

仅比较文本内容本身也不够,因为 chunk 的最终处理结果还会受到上下文和配置影响,例如:

  • chunk 类型
  • chunking 配置
  • embedding 模型
  • 图片内容
  • VLM 模型
  • OCR / caption prompt
  • Wiki map 阶段的语言、模型和抽取粒度

如果这些输入没有变化,则对应的下游产物可以复用;如果其中任意关键输入变化,则必须重新处理。原实现缺少这样的 fingerprint 机制,因此只能选择全量重建。

此外,旧 chunks 在 diff 前被删除,也使得新旧结果之间无法建立可靠映射。这样不仅无法复用旧向量索引,也会导致 parent_idprev_idnext_id 等 chunk 关系只能重新生成,无法稳定继承未变化 chunks 的已有持久化结果。

解决方案

本 PR 将文档 reparse 从“先删除、再全量重建”调整为“先解析、再 diff、最后按需更新”的增量复用流程。

新的流程如下:

  1. 保留旧 chunks 和 vectors,不在 reparse 开始时提前删除。
  2. 完成新的文档解析结果生成。
  3. 为新旧 chunks 计算稳定的 cache fingerprint。
  4. 根据 fingerprint 判断哪些 chunks 可以复用。
  5. 对未变化 chunks 复用已有持久化结果和向量索引。
  6. 只对新增或变化 chunks 执行重新处理。
  7. 在新结果确定后删除 stale chunks / vectors。
  8. 最后刷新复用 chunks 的 parent_idprev_idnext_id 等关系指针。

主要变更

文本 chunk 增量复用

为文档 chunks 增加 cache fingerprint,用于判断 chunk 是否可以复用。

fingerprint 会纳入影响 embedding 结果的关键输入,包括:

  • chunk 内容
  • chunk 上下文
  • chunk 类型
  • embedding 模型
  • chunking 配置

当这些输入保持不变时,reparse 会复用旧 chunk 及其向量索引,避免重新 embedding。

多模态图片结果复用

图片类 chunks 的处理结果不仅取决于图片本身,也取决于多模态模型和 prompt 配置。

本 PR 为图片 OCR/caption chunks 增加 fingerprint,纳入:

  • 图片内容
  • VLM 模型
  • prompt
  • chunk 类型

当图片内容和处理配置没有变化时,reparse 会复用已有 OCR/caption 结果,避免重复调用多模态处理流程。

Wiki map 阶段结果复用

Wiki ingestion 的 map 阶段也可能产生重复计算。

本 PR 为 Wiki map 阶段生成结果增加 fingerprint,纳入:

  • 重建后的输入内容
  • 语言
  • 合成模型
  • 抽取粒度
  • chunk 类型

当这些输入未变化时,可以复用已有 map 阶段 chunks,减少重复生成成本。

延后删除 stale 数据

旧 chunks / vectors 不再在 reparse 开始时立即删除。

新的流程会先完成解析和 diff,确认哪些 chunks 已经过期后,再删除 stale chunks / vectors。这样可以确保:

  • 未变化 chunks 可以被正确匹配和复用
  • 旧向量索引不会被提前删除
  • reparse 过程中数据状态更安全
  • 删除操作只作用于确认为过期的数据

关系指针刷新

复用 chunks 后,旧 chunk ID 和新解析结构之间需要重新建立关系。

本 PR 在完成 ID 重映射后刷新:

  • parent_id
  • prev_id
  • next_id

这样可以避免复用旧 chunk 时保留过期关系指针,确保新的 chunk 结构仍然正确表达文档层级和顺序关系。

Repository 查询能力

新增按文档和 cache fingerprint 查询 chunks 的 repository 能力,使 service 层可以在 reparse diff 阶段查找可复用的旧 chunks。

测试

本 PR 补充了以下测试覆盖:

  • 文档 reparse 时复用未变化 chunks
  • cache fingerprint 在输入不变时保持稳定
  • cache fingerprint 在关键配置变化时正确失效
  • 多模态图片 cache fingerprint 行为
  • Wiki map 阶段 cache fingerprint 行为
  • repository 按文档和 fingerprint 查询 chunks
  • FAQ chunk 元数据行为

已执行:

  • go test ./internal/application/service/...
  • CGO_CFLAGS="-O2 -g -IE:\\hermes\\oss-contrib\\work\\tools\\sqlite-amalgamation" go test ./internal/application/repository/...
  • go test ./internal/types/...

避免知识重解析时重复执行昂贵的下游处理。

本次修改将文档 reparse 从“先清空、再全量重建”调整为增量复用模式:
对内容和处理配置未变化的结果复用已有持久化产物,只对新增、变更或过期内容重新处理。

主要变更:

- 重解析时保留已有文档 chunks,并基于内容哈希做增量 diff
- 复用未变化的文本 chunks 及其向量索引,避免全量删除和重新 embedding
- 文档 chunk cache key 纳入内容、上下文、chunk 类型、embedding 模型和 chunking 配置
- 基于图片内容、VLM 模型、prompt 和 chunk 类型缓存图片 OCR/caption chunks
- 基于重建内容、语言、合成模型和抽取粒度缓存 Wiki map 阶段结果
- 仅在新解析结果确定后删除 stale chunks / vectors
- 刷新复用 chunks 的 parent / prev / next 关系,避免重解析后关系指针过期
- 补充文档 chunk 复用、多模态 cache fingerprint、Wiki map cache fingerprint 和 repository 查询测试
- 添加 changelog,说明 reparse 性能改进
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: 重建/重解析知识时应复用 OCR、Embedding、Wiki Map 等缓存,避免全量重算

1 participant