You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 17:44:57