内容参考于:图灵AI大模型全栈
Markdown元素处理器
元素处理器它把文档看做成元素的集合,会抽取表格、代码这种特殊内容,然后进行分割,也只把这种特殊内容进行索引生成
之前51节中也写了Markdown文档处理,它的处理是通过标题来进行分割,这次的元素分割器是按照特殊内容(表格、代码)来分割
也就是说这次的元素处理器,它是专门用来处理表格的,它会把表格专门抽取出来
如下效果图:
分割逻辑
它处理的逻辑是把表格取出来进行拆分,如下图红框 标题三 是一个标题才对,它直接分割到文本中了
如下图红框,表格的metadata信息,它还会给表格写总结
如下图红框,拆分后的文本,所以它并没有按照标题来分割,它是按照标签也就是表格分割,按照表格分割完,然后再使用之前的句子分割
它是先把表格独立出来然后再进行分割,如下图红框独立出来的表格是一个IndexNode(表格标签)
内容
json{ // 当前索引节点的唯一 ID(UUID) "id_": "c57188c9-2c3b-48c2-ae0e-890dd99af1ab", // 该节点的向量嵌入,null 表示尚未生成;后续可由嵌入模型填充 "embedding": null, // ========== metadata: 节点携带的元数据 ========== "metadata": { // 原始文件路径(Windows 风格) "file_path": "data_file\\test.md", // 文件名 "file_name": "test.md", // 文件 MIME 类型 "file_type": "text/markdown", // 文件大小(字节) "file_size": 5270, // 文件创建日期(可能来自系统) "creation_date": "2026-07-24", // 文件最后修改日期 "last_modified_date": "2026-07-10", // 列模式,这里为空字符串 "col_schema": "", // *** 以下两个字段是该节点特有的,来自表格解析结果 *** // table_df: 表格数据的 pandas DataFrame 的字典表示。 // 包含 ' 姓名 '、' 年龄 '、' 工作岗位 ' 三列,以及一列未命名的空列(Unnamed: 3,全为 NaN)。 // 注意:这里的姓名和年龄可能是虚构/示例数据(例如 888 岁)。 "table_df": "{' 姓名 ': {0: ' 张三 ', 1: ' 李四 ', 2: ' 王五 '}, ' 年龄 ': {0: 888, 1: 999, 2: 777}, ' 工作岗位 ': {0: ' 魔法开发 ', 1: ' 物理开发 ', 2: ' 科技开发 '}, 'Unnamed: 3': {0: nan, 1: nan, 2: nan}}", // table_summary: 对表格内容的自然语言摘要,也是这个索引节点的文本表示(text 字段也用到了它)。 // 结尾的 ",\nwith the following columns:\n" 看起来是拼接痕迹,实际摘要就是前面的句子。 "table_summary": "包含张三(888岁,魔法开发)、李四(999岁,物理开发)、王五(777岁,科技开发)的姓名、年龄与工作岗位信息。,\nwith the following columns:\n" }, // ========== 元数据过滤策略 ========== // 生成向量嵌入时,排除这些元数据键(不参与 embedding 计算) "excluded_embed_metadata_keys": [ "file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date" ], // 发送给 LLM 时,排除这些元数据键(避免无关信息干扰大模型) "excluded_llm_metadata_keys": [ "file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date" ], // ========== relationships: 与其他节点的关系图 ========== "relationships": { // 关系 1:指向源文档节点(node_type = 4,通常代表 DOCUMENT 类型) "1": { "node_id": "4f18172a-5760-47e9-8124-636ff1707dfa", // 源文档节点的 ID "node_type": "4", // 节点类型:4 一般对应 Document/根节点 "metadata": { /* 与上面相同的基础文件元数据 */ }, "hash": "29dc8e51...", // 该文档节点的内容哈希,用于去重/比较 "class_name": "RelatedNodeInfo" }, // 关系 2:指向同级或相关的另一个文本节点(node_type = 1,TEXT 类型) "2": { "node_id": "d5523ab1-af34-46aa-9344-5eedf34fcda7", "node_type": "1", "metadata": { /* 基础文件元数据 */ }, "hash": "544aed85...", "class_name": "RelatedNodeInfo" }, // 关系 3:指向该索引节点所对应的"详细内容文本节点"(也是 TEXT 类型)。 // 注意:这个文本节点包含了实际的表格数据(table_df)和摘要,而当前索引节点只保存摘要文本。 "3": { "node_id": "3174a7eb-f781-4682-a4a5-221a7d201695", // 与当前节点的 id_ 和 index_id 相同 "node_type": "1", // 文本节点 "metadata": { // 详细的表格 DataFrame 字符串 "table_df": "{' 姓名 ': {0: ' 张三 ', 1: ' 李四 ', 2: ' 王五 '}, ' 年龄 ': {0: 888, 1: 999, 2: 777}, ' 工作岗位 ': {0: ' 魔法开发 ', 1: ' 物理开发 ', 2: ' 科技开发 '}, 'Unnamed: 3': {0: nan, 1: nan, 2: nan}}", // 表格摘要 "table_summary": "包含张三(888岁,魔法开发)、李四(999岁,物理开发)、王五(777岁,科技开发)的姓名、年龄与工作岗位信息。,\nwith the following columns:\n", /* 基础文件元数据 */ }, "hash": "5a243c2b...", "class_name": "RelatedNodeInfo" } }, // 元数据模板:用于格式化元数据字符串,如 "{key}: {value}",换行分隔 "metadata_template": "{key}: {value}", "metadata_separator": "\n", // ========== 文本内容:该索引节点的核心文本,即表格摘要 ========== "text": "包含张三(888岁,魔法开发)、李四(999岁,物理开发)、王五(777岁,科技开发)的姓名、年龄与工作岗位信息。,\nwith the following columns:\n", // MIME 类型 "mimetype": "text/plain", // 该节点文本在原文档中的起始字符位置 "start_char_idx": 11, // 结束字符位置 "end_char_idx": 124, // 文本模板:用于将元数据与正文拼在一起的格式(如 "{metadata_str}\n\n{content}") "text_template": "{metadata_str}\n\n{content}", // 该索引节点所指向的详细内容节点的 ID,等同于关系 3 中的 node_id。 // 检索时通过这个 id 可以获取到包含表格真实数据的数据节点。 "index_id": "3174a7eb-f781-4682-a4a5-221a7d201695", // 预留的对象引用,当前为空 "obj": null, // 类名,表明这是一个 IndexNode "class_name": "IndexNode" }上方的json可以理解是针对表格做的一个简介,通过3找到的下一节点才是它真正的表格数据,如下真正的表格数据
python{ // 当前文本节点的唯一 ID。此 ID 被上游的 IndexNode.index_id 所引用。 "id_": "3174a7eb-f781-4682-a4a5-221a7d201695", // 向量嵌入,null 表示待生成。 "embedding": null, // ========== metadata: 节点携带的元数据 ========== "metadata": { // 原始文件路径 "file_path": "data_file\\test.md", // 文件名 "file_name": "test.md", // MIME 类型 "file_type": "text/markdown", // 文件大小(字节) "file_size": 5270, // 文件创建日期 "creation_date": "2026-07-24", // 最后修改日期 "last_modified_date": "2026-07-10", // *** 与 IndexNode 相比,这里没有 col_schema 字段,而是直接包含表格数据 *** // table_df: 表格数据的 pandas DataFrame 的字典表示。 // 包含 ' 姓名 '、' 年龄 '、' 工作岗位 ' 以及一个无用的 'Unnamed: 3' 列(全为 NaN)。 "table_df": "{' 姓名 ': {0: ' 张三 ', 1: ' 李四 ', 2: ' 王五 '}, ' 年龄 ': {0: 888, 1: 999, 2: 777}, ' 工作岗位 ': {0: ' 魔法开发 ', 1: ' 物理开发 ', 2: ' 科技开发 '}, 'Unnamed: 3': {0: nan, 1: nan, 2: nan}}", // table_summary: 表格内容的自然语言摘要,与 IndexNode 中的完全一致。 "table_summary": "包含张三(888岁,魔法开发)、李四(999岁,物理开发)、王五(777岁,科技开发)的姓名、年龄与工作岗位信息。,\nwith the following columns:\n" }, // ========== 元数据过滤策略 ========== // 生成向量嵌入时,排除以下元数据键(不参与 embedding 计算) "excluded_embed_metadata_keys": [ "file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date" ], // 发送给 LLM 时,排除以下元数据键 "excluded_llm_metadata_keys": [ "file_name", "file_type", "file_size", "creation_date", "last_modified_date", "last_accessed_date" ], // ========== relationships: 与其他节点的关系图 ========== "relationships": { // 关系 1:指向源文档节点(node_type = 4,DOCUMENT 类型) "1": { "node_id": "4f18172a-5760-47e9-8124-636ff1707dfa", // 根文档节点 ID "node_type": "4", // 文档节点 "metadata": { "file_path": "data_file\\test.md", "file_name": "test.md", "file_type": "text/markdown", "file_size": 5270, "creation_date": "2026-07-24", "last_modified_date": "2026-07-10" }, "hash": "29dc8e51bfabcb621c1c66cbd429e9d62d2419531d530428b0d10a8750e30488", "class_name": "RelatedNodeInfo" }, // 关系 2:指向配对的索引节点(node_type = 3,INDEX 类型) "2": { "node_id": "c57188c9-2c3b-48c2-ae0e-890dd99af1ab", // 这就是上一个 IndexNode 的 id "node_type": "3", // 索引节点 "metadata": { "file_path": "data_file\\test.md", "file_name": "test.md", "file_type": "text/markdown", "file_size": 5270, "creation_date": "2026-07-24", "last_modified_date": "2026-07-10", "col_schema": "" // 索引节点才有 col_schema }, "hash": "8be5eb07ec22a359bc244395b52b68e25645260b67468e4579f0c5e7d3002d2a", "class_name": "RelatedNodeInfo" }, // 关系 3:指向另一个索引节点(可能是同一表格的另一个处理版本,或另一表格) "3": { "node_id": "20996213-921e-4578-b778-8cfb269b9a92", "node_type": "3", "metadata": { "col_schema": "", "file_path": "data_file\\test.md", "file_name": "test.md", "file_type": "text/markdown", "file_size": 5270, "creation_date": "2026-07-24", "last_modified_date": "2026-07-10" }, "hash": "a9aa21cec2f10a73bf06d5b417f7fce283ab86a874ac5332c8b00872ad84b2f3", "class_name": "RelatedNodeInfo" } }, // 元数据展示模板,格式为 "key: value",换行分隔 "metadata_template": "{key}: {value}", "metadata_separator": "\n", // ========== 文本内容:表格的 Markdown 表示 + 摘要 ========== // 这里是实际提供给检索和 LLM 的完整文本,包含表格的 Markdown 源码。 "text": "包含张三(888岁,魔法开发)、李四(999岁,物理开发)、王五(777岁,科技开发)的姓名、年龄与工作岗位信息。,\nwith the following columns:\n\n| 姓名 | 年龄 | 工作岗位 |Unnamed: 3|\n|---|---|---|---|\n| 张三 |888| 魔法开发 |nan|\n| 李四 |999| 物理开发 |nan|\n| 王五 |777| 科技开发 |nan|\n", // MIME 类型 "mimetype": "text/plain", // 原文档中该表格的起始字符位置(与 IndexNode 一致) "start_char_idx": 11, // 结束字符位置 "end_char_idx": 124, // 文本模板:将元数据和正文拼接的格式 "text_template": "{metadata_str}\n\n{content}", // 注意:TextNode 没有 index_id 字段,因为它本身是"详细数据"的终点。 // 但 IndexNode 通过 index_id 指向了本节点的 id。 // 类名:标识这是一个 TextNode "class_name": "TextNode" }上方的表格信息的样子都是通过提示词来实现的,如下图红框,我们的提示词是让大模型把Markdown文档中的表格和内容做极简的摘要
使用LLamaIndex提供的Markdown元素分割器的缺点就是它丢失了标题,它只关注表格了,不关注标题,所以我们需要考虑如何处理这个标题,可以在进行元素分割之前,先使用标题分割一次,把标题的内容放到元数据中,下一节会处理这个问题






