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

如何在LangChain框架中结合Parent Document与Self Query检索器

结合Self Query与父文档检索的实现方案

核心思路:用Self Query Retriever精准检索400token小片段(保持小尺寸保证检索准确性),再通过小片段关联的父文档标识,提取对应的2000token大父片段,既保留Self Query的元数据检索能力,又能获取完整上下文。

步骤1:文档预处理——拆分父子片段并添加关联元数据

先将原始文档拆分为2000token的父片段,再把每个父片段拆分为400token的子片段,给每个子片段添加parent_id元数据,关联到所属父片段。

from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.docstore.document import Document

# 父片段拆分器(2000token,可根据需求调整重叠度)
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=2000, chunk_overlap=200)
# 子片段拆分器(400token)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=400, chunk_overlap=40)

# 示例原始文档列表
raw_docs = ["你的长文档内容1...", "你的长文档内容2..."]

# 拆分得到父片段列表
parent_chunks = parent_splitter.split_documents(raw_docs)

# 生成带parent_id的子片段
child_chunks_with_parent = []
for parent_idx, parent_chunk in enumerate(parent_chunks):
    # 将父片段拆分为子片段
    child_texts = child_splitter.split_text(parent_chunk.page_content)
    # 给每个子片段添加父ID元数据,同时继承父片段的业务元数据
    for child_text in child_texts:
        child_doc = Document(
            page_content=child_text,
            metadata={**parent_chunk.metadata, "parent_id": parent_idx}
        )
        child_chunks_with_parent.append(child_doc)

步骤2:构建含parent_id元数据的Self Query Retriever

确保Self Query的元数据字段包含parent_id,让检索结果能带回父片段的关联标识。

from langchain.chains.query_constructor.base import AttributeInfo
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings

# 定义元数据字段(包含业务元数据+parent_id)
metadata_field_info = [
    AttributeInfo(
        name="parent_id",
        description="父片段的唯一索引ID",
        type="integer"
    ),
    # 添加你的业务元数据,比如:
    # AttributeInfo(name="category", description="文档所属分类", type="string"),
    # AttributeInfo(name="publish_date", description="文档发布日期", type="string")
]

# 用子片段构建向量索引
vectorstore = Chroma.from_documents(
    documents=child_chunks_with_parent,
    embedding=OpenAIEmbeddings()
)

# 构建Self Query Retriever
self_query_retriever = SelfQueryRetriever.from_llm(
    llm=your_llm_instance,  # 替换为你的LLM实例(如GPT-3.5/4)
    vectorstore=vectorstore,
    document_contents="文档的小片段内容",
    metadata_field_info=metadata_field_info,
    verbose=True
)

步骤3:检索后替换为父片段

用Self Query拿到子片段后,提取唯一的parent_id,再从父片段列表中获取对应的大片段。

def retrieve_parent_docs(query):
    # 用Self Query检索子片段
    retrieved_child_docs = self_query_retriever.get_relevant_documents(query)
    
    # 提取不重复的parent_id,避免返回重复父片段
    unique_parent_ids = list({doc.metadata["parent_id"] for doc in retrieved_child_docs})
    
    # 根据父ID获取对应的大父片段
    retrieved_parent_docs = [parent_chunks[idx] for idx in unique_parent_ids]
    
    return retrieved_parent_docs

# 使用示例
query = "你的检索问题,比如:'2023年Q3的产品营收数据'"
result_parent_docs = retrieve_parent_docs(query)
# 输出父片段内容
for doc in result_parent_docs:
    print(f"父片段内容:\n{doc.page_content}\n---")

生产环境优化建议

  • 父片段存储:不要用内存存储父片段,可写入数据库或本地文件系统,用UUID替代索引作为parent_id,更稳定。
  • 元数据扩展:子片段继承父片段的所有业务元数据,确保Self Query可以基于分类、日期等字段精准过滤。
  • 去重逻辑:可根据父片段内容哈希去重,避免不同parent_id对应相同内容的情况。

内容的提问来源于stack exchange,提问作者Andrea Neri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 03:37:23