如何用LangChain在ChromaDB中增删分块文档且不重建向量库
LangChain + ChromaDB 文档分块后的增量增删方案
核心结论
- 必须为每个文档分块单独设置唯一ID,因为ChromaDB的最小管理单元是单个分块(向量条目)。
- 要实现原文档的批量增删,需要将分块与原文档关联起来(通过ID命名规则或metadata)。
分块与原文档的关联方式
有两种实用方案:
1. 分块ID包含原文档标识
给每个原始文档分配唯一ID,分块ID采用原文档ID_块索引的格式(比如doc_abc123_chunk_0),这样可以快速定位某篇原文档对应的所有分块。
2. 用Metadata记录原文档ID
在每个分块的metadata中添加source_doc_id字段,存储对应的原文档ID,后续可以通过Chroma的条件查询来批量操作。
修改后的代码实现
1. 增量加载Chroma库(避免每次重建)
去掉删除chroma_path的逻辑,改为加载现有库或创建新库,实现增量添加:
def process_documents(self, docs): print("Splitting and embedding documents...") # 给每个原始文档分配唯一ID,并生成带关联信息的分块 from uuid import uuid4 doc_ids = [str(uuid4()) for _ in docs] chunks = [] chunk_ids = [] chunk_metadata = [] for doc_id, doc in zip(doc_ids, docs): doc_chunks = self.text_splitter.split_documents([doc]) for idx, chunk in enumerate(doc_chunks): # 方案1:生成包含原文档ID的分块ID chunk_id = f"{doc_id}_chunk_{idx}" # 方案2:给分块添加原文档ID的metadata chunk.metadata["source_doc_id"] = doc_id chunks.append(chunk) chunk_ids.append(chunk_id) chunk_metadata.append(chunk.metadata) # 加载现有库或创建新库 if os.path.exists(self.chroma_path): example_db = Chroma( persist_directory=self.chroma_path, embedding_function=self.embeddings ) # 增量添加新分块 example_db.add_documents(chunks, ids=chunk_ids, metadatas=chunk_metadata) else: example_db = Chroma.from_documents( chunks, self.embeddings, persist_directory=self.chroma_path, ids=chunk_ids, metadatas=chunk_metadata ) # 持久化修改,否则重启后丢失 example_db.persist() print(f"成功添加 {len(chunks)} 个文档分块")
2. 批量删除原文档对应的分块
方案1:通过分块ID前缀删除
def delete_source_document(self, target_doc_id): all_chunk_ids = self.example_db._collection.get()["ids"] # 筛选目标原文档的所有分块ID target_chunk_ids = [cid for cid in all_chunk_ids if cid.startswith(f"{target_doc_id}_chunk_")] self.example_db._collection.delete(ids=target_chunk_ids) self.example_db.persist() print(f"成功删除 {len(target_chunk_ids)} 个分块")
方案2:通过Metadata条件删除
def delete_source_document(self, target_doc_id): # 利用Chroma的where条件直接过滤删除 self.example_db._collection.delete(where={"source_doc_id": target_doc_id}) self.example_db.persist() print(f"成功删除原文档 {target_doc_id} 的所有分块")
关键注意事项
- 不要每次删除
chroma_path重建,否则会丢失历史数据,无法实现增量操作。 - 每次增删后必须调用
persist()方法,确保修改被持久化到磁盘。 - 两种关联方案任选其一即可,用Metadata的方式更灵活,不需要严格遵守ID命名规则。
内容的提问来源于stack exchange,提问作者Cody Kletter
相关产品推荐
相关产品推荐

