know-engine

文档如何做多版本管理?

know engine 的文档管理系统实现了一套完整的多版本管理方案,核心目标是:在不停机的前提下,支持知识文档的版本迭代、历史追溯与任意版本切换,同时保证 RAG 检索的向量数据与文档内容始终保持版本一致性。 PS:本章功能演示用…

TL;DR

know engine 的文档管理系统实现了一套完整的多版本管理方案,核心目标是:在不停机的前提下,支持知识文档的版本迭代、历史追溯与任意版本切换,同时保证 RAG 检索的向量数据与文档内容始终保持版本一致性。 PS:本章功能演示用…

know-engine 的文档管理系统实现了一套完整的多版本管理方案,核心目标是:在不停机的前提下,支持知识文档的版本迭代、历史追溯与任意版本切换,同时保证 RAG 检索的向量数据与文档内容始终保持版本一致性。 PS:本章功能演示用到的测试数据: https://nfturbo-file.oss-cn-hangzhou.aliyuncs.com/llm/%E6%B5%8B%E8%AF%95%E7%94%A8%E6%95%B0%E6%8D%AE.zip

多版本支持的数据模型设计

设计思路:逻辑文档与物理版本分离

之前我们设计的只有knowledge_document的单表方案在面对版本管理时会遇到诸多问题:每次更新都会覆盖原始数据,无法回溯;切换版本需要删除再重建,存在服务中断窗口。 于是我们改成采用 「逻辑文档 + 物理版本快照」 分离模型,将文档的"身份信息"与"内容版本"拆分存储:

knowledge_document(逻辑文档)
    │  doc_id         文档唯一身份
    │  doc_title      标题(跨版本不变)
    │  knowledge_base_type  知识库类型(跨版本不变)
    │  accessible_by  权限(跨版本不变)
    └─ current_version_id ──────────────────────┐
                                                ▼
knowledge_document_version(版本快照)          当前激活版本
    │  version_id     版本唯一ID
    │  doc_id         关联逻辑文档
    │  version        语义化版本号(1.0.0)
    │  doc_url        MinIO 原始文件地址
    │  converted_doc_url  转换后文件地址
    │  content_hash   SHA-256 内容哈希
    └─ status         版本处理状态

knowledge_segment(知识分段)
    │  document_id    关联逻辑文档 ID
    └─ document_version  关联版本 ID(version_id)

核心表结构

knowledge_document(逻辑文档表)该表只存储文档的不变属性,新增 current_version_id 作为指向当前激活版本的"激活指针"。通过更换这个指针即可完成版本切换,代价极低且原子。

create


)

knowledge_document_version(版本快照表)每行存储一个版本的完整快照,通过 UNIQUE KEY uk_doc_version(doc_id, version) 约束保证同一文档的版本号不重复。

create


)

knowledge_segment(知识分段表)分段通过 document_version 字段绑定到具体版本 ID,使得不同版本的分段数据可以并存于同一张表中,互不干扰。

CREATE


)

上传新版本

同一份文档,如果有新的版本,可以通过上传新版本的方式更新文档内容。流程如下: 上传后数据变化如下:1.0.0 -> 2.0.0 | 数据表 | 数据变化 | | --- | --- | | knowledge_documen | current_version_id 更新为新版本的 version_id(2.0.0); | | knowledge_document_version | 新增 1 条新版本记录(2.0.0);status 从 UPLOADED 演进至 VECTOR_STORED; | | knowledge_segment | 新增新版本(2.0.0)对应的 N 条片段;新版本片段 status 从 STORED → VECTOR_STORED 并回填 embedding_id; | | Elasticsearch 向量库 | 写入新版本向量;(2.0.0) |

上传后重新选择新的分段方式后,就可以把新文档的内容存储到向量数据库中。这个过程为了不影响用户体验,实现了一个不停机更新:

✅文档如何实现不停机更新

RAG系统中,文档的更新也是个比较常见的操作。我们也支持文档的更新,支持以下这三种操作: 1、文档的基本信息更新,如名称、描述等。 2、指定分段的内容更新。 3、整个文档的更新 文档基本信息更新 更新范围限制 文档基本信息更新(PUT /a LLMentor

版本切换

版本切换(switchVersion)的语义是:将指定的历史版本重新激活为当前版本,使其分段重新进入向量库,接管 RAG 检索流量。 主要流程如下: 版本切换后数据状态如下:2.0.0 -> 1.0.0 | 数据表 | 数据变化 | | --- | --- | | knowledge_documen | current_version_id 更新为目标版本的 version_id(1.0.0); | | knowledge_document_version | 目标版本(1.0.0) status 由 CHUNKED 升为 VECTOR_STORED; | | knowledge_segment | 目标版本(1.0.0)片段 status 从 STORED → VECTOR_STORED 并回填 embedding_id; | | Elasticsearch 向量库 | 写入目标版本(1.0.0)向量;删除原当前版本(2.0.0)的向量 |

版本启停能力(deactivate / activate)

版本切换的底层由两个对称操作支撑: 版本失效(deactivateVersion) 将一个 VECTOR_STORED 版本下线:

① 校验版本状态为 VECTOR_STORED
② 调用 cleanupOldVersionData:按 docId + versionId 清理旧版本的 ES 向量
③ 将该版本所有分段状态 VECTOR_STORED → STORED,清空 embeddingId
④ 版本状态 VECTOR_STORED → CHUNKED

关键代码(KnowledgeDocumentServiceImpl.deactivateVersion):

// 清理 ES 向量
documentCleanupService

// 分段状态降级,清空 embeddingId
LambdaUpdateWrapper


knowledgeSegmentMapper

// 版本状态降级
version
knowledgeDocumentVersionService

版本生效(activateVersion) 将一个已切片但未向量化的版本(CHUNKED)重新向量化上线:

① 校验版本状态为 CHUNKED
② 分页扫描该版本下所有 status=STORED 且 skip_embedding=0 的分段
③ 批量 embed 写入 ES → 记录 embeddingId
④ 分段状态 STORED → VECTOR_STORED
⑤ 版本状态 CHUNKED → VECTOR_STORED

关键代码(KnowledgeDocumentServiceImpl.activateVersion):

// 分页向量化,避免单批数据量过大
Page
while


        seg
        seg
        knowledgeSegmentService

    page
}

version
knowledgeDocumentVersionService

switchVersion 完整流程

switchVersion 将上述两个操作串联,实现版本的原子切换:

// DocumentProcessServiceImpl.switchVersion
// ① 旧版本所有分段状态降为 STORED(退出向量检索)
LambdaUpdateWrapper


knowledgeSegmentMapper

// ② 目标版本重新向量化(activateVersion 内部已处理完整激活流程)
boolean

// ③ 更新激活指针
document
knowledgeDocumentService

整个切换的过程中,向量数据的处理我们是通过embedAndStore方法实现的,这里面其实

版本提示

模型、框架与接口会持续变化。涉及版本号、参数与生产配置时,请在实践前对照对应官方文档。

LLMentor系统化学习大模型应用工程

内容来自个人课程知识库备份,并经过结构化整理。技术版本持续演进,生产使用前请结合官方文档验证。