fix(knowledge): 复用未变化的文档重解析结果#1902
Open
DadaVinqi wants to merge 1 commit into
Open
Conversation
避免知识重解析时重复执行昂贵的下游处理。 本次修改将文档 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 性能改进
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
摘要
Fixes #1679.
本 PR 修复知识文档重解析时,未变化内容仍会被重复处理的问题。
在现有实现中,文档 reparse 流程会先清理旧的 chunks / vectors,再基于新的解析结果重新生成全部下游数据。即使文档内容没有变化,或只有少量内容发生变化,系统也无法识别哪些 chunks 可以安全复用,因此会重复执行 chunk 构建、embedding、多模态图片 OCR/caption、Wiki map 阶段生成等成本较高的处理。
这会带来两个主要问题:
重复执行昂贵处理
对未变化内容重新 embedding 或重新执行多模态 / Wiki 处理,会显著增加重解析耗时和模型调用成本。
过早删除旧数据
旧 chunks / vectors 在新解析结果完成 diff 前就被清理,导致系统无法基于旧结果做增量判断,也增加了重解析过程中数据关系被破坏的风险。
根因分析
问题的根因是 reparse 流程缺少稳定的“可复用性判断”。
当前逻辑主要基于一次完整重建来处理文档:
这种流程没有保存并比较“内容 + 处理配置”的稳定标识,因此无法判断某个新 chunk 是否等价于旧 chunk。
仅比较文本内容本身也不够,因为 chunk 的最终处理结果还会受到上下文和配置影响,例如:
如果这些输入没有变化,则对应的下游产物可以复用;如果其中任意关键输入变化,则必须重新处理。原实现缺少这样的 fingerprint 机制,因此只能选择全量重建。
此外,旧 chunks 在 diff 前被删除,也使得新旧结果之间无法建立可靠映射。这样不仅无法复用旧向量索引,也会导致
parent_id、prev_id、next_id等 chunk 关系只能重新生成,无法稳定继承未变化 chunks 的已有持久化结果。解决方案
本 PR 将文档 reparse 从“先删除、再全量重建”调整为“先解析、再 diff、最后按需更新”的增量复用流程。
新的流程如下:
parent_id、prev_id、next_id等关系指针。主要变更
文本 chunk 增量复用
为文档 chunks 增加 cache fingerprint,用于判断 chunk 是否可以复用。
fingerprint 会纳入影响 embedding 结果的关键输入,包括:
当这些输入保持不变时,reparse 会复用旧 chunk 及其向量索引,避免重新 embedding。
多模态图片结果复用
图片类 chunks 的处理结果不仅取决于图片本身,也取决于多模态模型和 prompt 配置。
本 PR 为图片 OCR/caption chunks 增加 fingerprint,纳入:
当图片内容和处理配置没有变化时,reparse 会复用已有 OCR/caption 结果,避免重复调用多模态处理流程。
Wiki map 阶段结果复用
Wiki ingestion 的 map 阶段也可能产生重复计算。
本 PR 为 Wiki map 阶段生成结果增加 fingerprint,纳入:
当这些输入未变化时,可以复用已有 map 阶段 chunks,减少重复生成成本。
延后删除 stale 数据
旧 chunks / vectors 不再在 reparse 开始时立即删除。
新的流程会先完成解析和 diff,确认哪些 chunks 已经过期后,再删除 stale chunks / vectors。这样可以确保:
关系指针刷新
复用 chunks 后,旧 chunk ID 和新解析结构之间需要重新建立关系。
本 PR 在完成 ID 重映射后刷新:
parent_idprev_idnext_id这样可以避免复用旧 chunk 时保留过期关系指针,确保新的 chunk 结构仍然正确表达文档层级和顺序关系。
Repository 查询能力
新增按文档和 cache fingerprint 查询 chunks 的 repository 能力,使 service 层可以在 reparse diff 阶段查找可复用的旧 chunks。
测试
本 PR 补充了以下测试覆盖:
已执行:
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/...