ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Langchain-Chatchat 知识库 Chunk Summary 服务(KBSummaryService)原理与实战指南

Langchain-Chatchat 知识库 Chunk Summary 服务(KBSummaryService)原理与实战指南 Langchain-Chatchat 知识库 Chunk Summary 服务KBSummaryService原理与实战指南【免费下载链接】Langchain-ChatchatLangchain-Chatchat原Langchain-ChatGLM基于 Langchain 与 ChatGLM, Qwen 与 Llama 等语言模型的 RAG 与 Agent 应用 | Langchain-Chatchat (formerly langchain-ChatGLM), local knowledge based LLM (like ChatGLM, Qwen and Llama) RAG and Agent app with langchain项目地址: https://gitcode.com/GitHub_Trending/la/Langchain-Chatchat本指南以 Langchain-Chatchat 的 KBSummaryService 类为线索系统讲解知识库文件级摘要chunk summary的底层设计摘要向量存储如何落盘、LLM 摘要如何入库、以及重建与删除摘要的完整数据生命周期。读完本文你将掌握KB_ROOT_PATH下的目录规划、summary_vector_store的读写机制、线程安全 FAISS 缓存池的使用方式并能够通过 HTTP 接口触发摘要的创建、增量更新与全量重建。一、Chunk Summary从文档切块检索到文件级语义摘要在常规 RAG 流程中一个 PDF 会被切分成大量 chunk 分别向量化。Langchain-Chatchat 在其上叠加了一层文件级摘要summary机制为每个知识库文件或按 doc_id 选取的若干文档调用 LLM 生成一段概括性总结文本将该总结文本与底层 doc_ids 绑定后一并写入独立的摘要向量库与数据库表。从源码注释看这套机制承担两类任务见 SummaryChunkModel 模型定义矢量库构建对summary_chunk表中的summary_context字段建立索引并构建向量库meta_data其中含doc_ids作为向量元数据语义关联通过用户输入的文件描述与自动切分生成的总结文本计算语义相似度把问题 → 文件级总结 → 具体 chunk串成两级检索。支撑这套能力的代码集中在两个类上KBSummaryService负责摘要向量库与数据库记录的增、删、查本文讲解的重点SummaryAdapter负责调用 LLM 生成摘要文本。补充阅读本文档的源码版解读可参考 kb_summary/base.py配套的摘要生成适配器见 summary_chunk.py 文档 与 kb_summary_api.md。二、KBSummaryService摘要服务的抽象基类设计KBSummaryService是定义在chatchat.server.knowledge_base.kb_summary.base中的一个抽象基类ABC用于统一创建摘要、添加摘要、删除摘要三件事的标准流程。它本身不绑定具体向量数据库而是通过统一的 FAISS 池与数据库仓储完成操作。2.1 类属性与职责属性类型含义kb_namestr知识库名称embed_modelstr用于摘要向量化的嵌入模型名称vs_pathstr摘要向量存储的完整路径kb_pathstr知识库所在目录的完整路径方法职责get_vs_path()返回摘要向量存储完整路径get_kb_path()返回知识库目录完整路径load_vector_store()加载或按需创建线程安全的 FAISS 向量库add_kb_summary(summary_combine_docs)将文档摘要写入向量库并同步到数据库create_kb_summary()确保摘要存储路径存在不存在则创建drop_kb_summary()删除摘要向量存储与对应的数据库记录在 kb_summary_api.py 中recreate_summary_vector_store与summary_file_to_vector_store均通过KBSummaryService(knowledge_base_name, embed_model)实例来重建或更新知识库摘要这正是摘要服务的典型使用场景。2.2 构造方法__init__目录即约定构造函数的签名如下实际实现见 base.py 第 26-36 行def __init__( self, knowledge_base_name: str, embed_model: str get_default_embedding() ): self.kb_name knowledge_base_name self.embed_model embed_model self.kb_path self.get_kb_path() self.vs_path self.get_vs_path() if not os.path.exists(self.vs_path): os.makedirs(self.vs_path)初始化共四步保存知识库名与嵌入模型名调用get_kb_path()计算知识库目录调用get_vs_path()计算摘要向量目录若向量目录不存在则用os.makedirs创建保证后续写入安全。注意embed_model的默认值来自get_default_embedding()即全局配置中默认嵌入模型的动态解析结果调用方可通过显式传参覆盖例如为不同摘要任务使用不同的 embedding。三、路径设计一条路径如何串联知识库、向量库与数据库KBSummaryService的目录约定集中在两个方法中。3.1get_kb_path()知识库根目录 库名def get_kb_path(self): return os.path.join(Settings.basic_settings.KB_ROOT_PATH, self.kb_name)它把全局知识库根目录常量KB_ROOT_PATH来自Settings.basic_settings与库名拼接。例如当KB_ROOT_PATH为/data/knowledge_bases、kb_name为tech_docs时返回/data/knowledge_bases/tech_docs。因为使用了os.path.join在 Windows 与类 Unix 系统下均能正确处理路径分隔符。3.2get_vs_path()知识库目录 固定子目录summary_vector_storedef get_vs_path(self): return os.path.join(self.get_kb_path(), summary_vector_store)get_vs_path内部复用get_kb_path()再拼接固定子目录名summary_vector_store因此摘要向量库与普通文档向量库后者位于vector_store/子目录见 faiss_cache.py天然隔离/data/knowledge_bases/ └── tech_docs/ ← get_kb_path() ├── summary_vector_store/ ← get_vs_path()存该库全部文件摘要的向量 └── vector_store/ ← 普通 chunk 向量库可以推断这种每个知识库一个摘要子目录的设计使得drop_kb_summary可以仅凭一条路径完成物理清理也便于不同知识库拥有各自独立的摘要索引空间。四、向量存储加载线程安全 FAISS 缓存池load_vector_storeload_vector_store不直接 new 一个 FAISS而是走全局缓存池def load_vector_store(self) - ThreadSafeFaiss: return kb_faiss_pool.load_vector_store( kb_nameself.kb_name, vector_namesummary_vector_store, embed_modelself.embed_model, createTrue, )关键点有三vector_name固定为summary_vector_store与vs_path目录名保持一致保证磁盘路径 ↔ 缓存键一一对应createTrue向量库不存在时自动创建空库而非报错返回的ThreadSafeFaiss是线程安全封装见 faiss_cache.py 第 27-51 行__repr__形如ThreadSafeFaiss: key: ..., obj: FAISS ..., docs_count: 100其中的docs_count()直接统计底层docstore._dict中的文档数。kb_faiss_pool是模块级单例KBFaissPool(cache_numSettings.kb_settings.CACHED_VS_NUM)见 faiss_cache.py 第 172 行缓存键使用(kb_name, vector_name)元组。加载时若磁盘上已存在index.faiss则load_local读回否则走new_vector_store——先from_documents造一个空库再删除 init 文档实现干净的空向量库见 faiss_cache.py 第 55-66 行。五、添加摘要向量库与数据库的双写一致性add_kb_summaryadd_kb_summary(summary_combine_docs: List[Document])是摘要落地的核心入口接收一个文件对应的单条合并摘要List[Document]中通常只有一项由SummaryAdapter.asummarize产出。完整实现见 base.py 第 52-67 行。5.1 第一步向量入库并本地保存with self.load_vector_store().acquire() as vs: ids vs.add_documents(documentssummary_combine_docs) vs.save_local(self.vs_path)acquire()为读写加锁确保多线程并发场景下向量库操作安全add_documents把摘要文档向量化并写入索引返回每个文档对应的向量 idsave_local(self.vs_path)立即把内存索引持久化到磁盘避免进程退出丢失。5.2 第二步构造记录并写库summary_infos [ { summary_context: doc.page_content, summary_id: id, doc_ids: doc.metadata.get(doc_ids), metadata: doc.metadata, } for id, doc in zip(ids, summary_combine_docs) ] status add_summary_to_db(kb_nameself.kb_name, summary_infossummary_infos) return status每一条入库记录的字段与summary_chunk表严格对应见 knowledge_metadata_model.py字段来源说明kb_name实例属性知识库名summary_contextdoc.page_contentLLM 生成的总结文本summary_idadd_documents返回 id摘要向量在 FAISS 中的 id实现向量 ↔ 记录关联doc_idsdoc.metadata[doc_ids]该摘要覆盖的底层 chunk 向量 id 列表逗号分隔meta_datadoc.metadata冗余存储的完整元数据数据库写入由仓储层add_summary_to_db完成见 knowledge_metadata_repository.py 第 51-68 行逐条session.add后统一session.commit()成功返回True。因此调用方拿到的返回值是一个布尔值而非摘要本身。5.3 文档对象从哪来SummaryAdapter 简述summary_combine_docs由 SummaryAdapter.summarize 生成。其asummarize通过 MapReduce 完成两步self.chain.combine_docs(docsdocs, task_briefing描述不同方法之间的接近度和相似性...)—— 对每个 chunk 各自生成子摘要Map再合并成最终总结Reduce将doc_idsdocs中所有 chunk 的 id 用逗号连接、file_description、summary_intermediate_steps组装为metadata最终返回一个DocumentDocument(page_contentsummary_combine, metadata{ file_description: file_description, summary_intermediate_steps: summary_intermediate_steps, doc_ids: doc_ids, })这正是add_kb_summary读取metadata.get(doc_ids)的数据来源。form_summary工厂方法见 summary_chunk.py 第 36-94 行负责用llm/reduce_llm均通过get_ChatOpenAI(..., local_wrapTrue)创建装配完整的MapReduceDocumentsChain其中token_max默认 1300用于限制 reduce 阶段合并的 chunk 数上限。六、创建与删除摘要空间的完整生命周期6.1create_kb_summary()幂等的目录准备def create_kb_summary(self): if not os.path.exists(self.vs_path): os.makedirs(self.vs_path)该方法只负责路径就绪不返回任何值。因为构造方法__init__已做过同样的目录创建这里更多是语义化 防御性的显式步骤保证在整库重建或单文件更新前存储目录必然存在。实际调用点为kb_summary_api.py中的recreate_summary_vector_store与summary_file_to_vector_store分别见 kb_summary_api.py 第 60 行 与 第 154 行。6.2drop_kb_summary()三管齐下的彻底清理def drop_kb_summary(self): with kb_faiss_pool.atomic: kb_faiss_pool.pop(self.kb_name) shutil.rmtree(self.vs_path) delete_summary_from_db(kb_nameself.kb_name)删除按内存缓存 → 磁盘 → 数据库三层递进缓存层kb_faiss_pool.pop(self.kb_name)从 FAISS 缓存池移除该库条目整个删除被包在kb_faiss_pool.atomic中避免并发读写交错文件层shutil.rmtree(self.vs_path)物理删除summary_vector_store目录数据库层delete_summary_from_db(kb_nameself.kb_name)见 knowledge_metadata_repository.py 第 36-48 行先查出待删记录再批量query.delete(synchronize_sessionFalse)。注意该操作不可逆会同时清空缓存、文件系统与数据库三处数据。在recreate_summary_vector_store中它是先删后建流程的前半段drop_kb_summary()→create_kb_summary()确保整库重建时不会残留旧摘要。七、服务接线从 Python 类到 HTTP APIKBSummaryService的三个使用入口被注册在kb_summary_api.py再由路由层挂载见 kb_routes.py 第 126-137 行接口路由触发动作summary_file_to_vector_storePOST /kb_summary_api/summary_file_to_vector_store对知识库内单个文件生成摘要并入库增量更新summary_doc_ids_to_vector_storePOST /kb_summary_api/summary_doc_ids_to_vector_store对指定 doc_ids生成摘要返回但不落库recreate_summary_vector_storePOST /kb_summary_api/recreate_summary_vector_store删除全库旧摘要后逐文件重建SSE 流式汇报进度其中两个落库接口共享的参数与默认值如下FastAPIBody声明见 kb_summary_api.py 第 20-31 行knowledge_base_name必填示例samplesallow_empty_kb默认True为False且库不存在时返回{code: 404}vs_type默认Settings.kb_settings.DEFAULT_VS_TYPEembed_model默认get_default_embedding()file_description默认空串会被写入摘要metadata用于描述该文件的业务语义参与后续语义关联model_name默认None落到Settings.model_settings.MAX_TOKENS语义指定用于摘要生成的 LLMtemperature默认0.01ge0.0, le1.0max_tokens默认None模型最大值None/0时回退为Settings.model_settings.MAX_TOKENS。关键调用链以重建整库为例recreate_summary_vector_storeSSE 生成器 ├─ KBServiceFactory.get_service(kb_name, vs_type, embed_model) # 拿到文档向量库服务 ├─ KBSummaryService(kb_name, embed_model) │ ├─ drop_kb_summary() # 清缓存 删目录 删表 │ └─ create_kb_summary() # 重建目录 ├─ get_ChatOpenAI(...) × 2 # llm 与 reduce_llm ├─ SummaryAdapter.form_summary(...) # 装配 MapReduce 摘要链 ├─ for file in list_files_from_folder(kb_name): │ ├─ kb.list_docs(file_name) # 取该文件全部 chunkDocumentWithVSId │ ├─ summary.summarize(...) # LLM 生成文件级摘要 Document │ └─ kb_summary.add_kb_summary(...) # 双写向量库与 summary_chunk 表 └─ yield {code:200, msg:(i/n): file, total, finished, doc} # SSE 进度recreate_summary_vector_store以EventSourceResponse返回生成器客户端可实时收到每个文件(i 1) / total的处理进度单个文件失败仅记日志并跳过code:500不会中断整库流程。单文件版本summary_file_to_vector_store的响应则形如{code:200, msg:test.pdf 总结完成, doc:test.pdf}。八、最佳实践与注意事项先确认路径体系使用前确保Settings.basic_settings.KB_ROOT_PATH指向存在且有写权限的根目录否则构造函数os.makedirs会抛权限异常摘要质量与性能权衡temperature0.01接近确定性输出适合摘要这类追求稳定的事实抽取场景token_max1300控制 reduce 合并时的文本量超长文件会产生更多中间步骤可用summary_intermediate_steps元数据追溯model_name选择摘要任务对 LLM 上下文长度要求较高应选择能覆盖单文件全部 chunk 总和的模型max_tokens限制单次生成长度过长摘要会因截断而质量下降form_summary注释明确提示第一次生成摘要时大于 token_max 长度的摘要会报错并发安全add_kb_summary内部已通过acquire()与kb_faiss_pool.atomic完成线程安全控制业务层不要重复加锁删除前务必确认drop_kb_summary三处数据一并删除且无回收机制误操作只能通过重新recreate_summary_vector_store恢复增量更新优于全量重建仅变更了知识库内个别文件时优先用summary_file_to_vector_store按文件名增量摘要避免recreate_summary_vector_store对全库逐文件调用 LLM 带来的时间与成本开销两级检索配合使用摘要向量库存的是文件级语义普通vector_store存的是chunk 级语义。构建或删除摘要后若下游检索依赖两级联查问题 → 摘要定位文件 → doc_ids 定位 chunk应保持两者同步更新避免summary_chunk.doc_ids指向已被重建的失效 chunk id。九、总结KBSummaryService用最精简的抽象把摘要变成了与文档向量库并列的一等公民get_kb_path/get_vs_path定义目录约定load_vector_store接入线程安全 FAISS 池add_kb_summary完成向量库 summary_chunk表双写drop_kb_summary按缓存、文件、数据库三层彻底清理。配合 SummaryAdapter 的 MapReduce 总结与 kb_summary_api.py 的三个 HTTP 接口开发者即可在 Langchain-Chatchat 上构建先文件级摘要定位、再 chunk 级精确检索的两级知识库问答管线。【免费下载链接】Langchain-ChatchatLangchain-Chatchat原Langchain-ChatGLM基于 Langchain 与 ChatGLM, Qwen 与 Llama 等语言模型的 RAG 与 Agent 应用 | Langchain-Chatchat (formerly langchain-ChatGLM), local knowledge based LLM (like ChatGLM, Qwen and Llama) RAG and Agent app with langchain项目地址: https://gitcode.com/GitHub_Trending/la/Langchain-Chatchat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表