在dify中构建父子文档块关联的高级rag系统需显式建立层级关系:预处理文档为嵌套markdown并添加yaml front matter声明归属;配置markdown header splitter或自定义python分块脚本注入parent_id、parent_title、child_order元数据;启用metadata filtering与rerank策略,并在提示词中强制模型识别父子语义边界。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

在Dify中构建父子文档块关联的高级RAG系统,需绕过默认扁平化文本切分逻辑,显式建立文档层级关系,使子块能回溯父级元数据(如章节标题、作者、来源URL),避免上下文断裂或归属混淆。
准备带层级结构的原始文档
将原始PDF/Word文档按语义层级预处理为嵌套结构:一级为文档整体(Parent),二级为章节/小节(Child),三级为段落或列表项(Grandchild)。推荐用Markdown格式保存,用#、##、###标记层级,并在每个区块开头添加YAML Front Matter声明归属关系。
例如,在“## 3.2 数据预处理”章节开头插入:---
parent_id: doc_abc123
parent_title: "机器学习工程实践"
section_level: 2
---
这一步不可跳过。Dify默认切分器会忽略Front Matter,但后续自定义Loader可读取并注入metadata字段。若直接上传未标注的PDF,系统无法识别父子关系,所有chunk将丢失上下文锚点。
配置自定义文本分割器与元数据注入
进入Dify控制台 → 【知识库】→【新建知识库】→【高级设置】→【自定义分块规则】。
方法一:启用Markdown Header Splitter
选择Splitter类型为“Markdown Header”,设置Header级别匹配范围为“##”和“###”,勾选“Preserve parent headers as metadata”。系统会自动将##标题内容注入其下属所有###及段落chunk的metadata.parent_title字段。
方法二:编写Python分块脚本(适用于复杂结构)
在Dify私有部署环境中,修改knowledge/embedding/splitter.py,继承BaseTextSplitter类,重写split_text()方法:对每个chunk调用get_parent_metadata()函数,递归向上查找最近的#或##标题行,提取text并存入chunk.metadata['parent']。部署后重启embedding服务。
【必须重启Embedding服务】否则新分块逻辑不会生效,仍使用旧的RecursiveCharacterTextSplitter。
构建父子关系索引与检索增强
第一步:在知识库内启用“Metadata Filtering”开关。
第二步:为每个Child chunk手动或批量补全以下三个关键字段:
• parent_id(唯一字符串,如pdf_sha256前8位)
• parent_title(不超过64字符,用于展示)
• child_order(整数,表示该子块在父文档内的顺序)
第三步:在应用编排中,编辑RAG节点的检索参数:
→ 设置filter条件为{"parent_id": "{query.parent_id}"}(需前置从用户输入或上下文提取parent_id)
→ 启用rerank策略:按child_order升序重排结果,确保段落连贯性。
不填child_order会导致同一章节下的多个段落被随机排序,生成答案时出现逻辑断层。例如“先描述模型训练,再说明数据清洗”,顺序颠倒将引发事实错误。
在LLM提示词中激活父子上下文拼接
进入【应用编排】→【提示词工程】→ 编辑RAG后的LLM节点系统提示词,在“请基于以下信息回答”之后插入:
「参考内容来自文档《{metadata.parent_title}》第{metadata.section_number}节。当前段落是该节的第{metadata.child_order}部分,请结合上级标题理解语义边界。若引用内容涉及步骤或列表,请严格保持原有编号连续性。」
这句提示强制模型识别parent_title与child_order的耦合关系。测试时若删除“第{metadata.section_number}节”,模型可能将“步骤1”误判为独立操作而非某子流程中的环节。











