# 文档解析与向量检索说明 ## 相关文件 - `aliyun_doc_parser.py`:调用阿里云文档智能解析 PDF,生成原始 `layouts.json` - `layouts_to_vector_chunks.py`:把 `layouts.json` 转成适合向量数据库入库的三层结构 - `layouts.json`:阿里云返回的原始布局结果 - `vector_chunks.json`:转换后的结构化输出 ## 一、`layouts.json` 的结构 `layouts.json` 顶层是一个数组,每个元素代表一个布局块(layout)。常见字段如下: - `type`:主类型,例如 `title`、`text`、`table`、`figure` - `subType`:更细的语义类型,例如 `doc_title`、`para_title`、`para`、`picture`、`pic_title`、`pic_caption` - `text`:当前布局块的纯文本 - `markdownContent`:带 markdown 标记的文本 - `pageNum`:页码 - `index`:页内顺序 - `level`:标题层级 - `uniqueId`:布局块唯一标识 - `blocks`:更细粒度的文本与样式信息 - `cells`:表格单元格,仅 `table` 类型存在 这个结构不是简单 OCR 文本流,而是已经带有版面理解和语义分类的结构化数据。 ## 二、推荐的三层转换结构 ### 1. 结构层 `structure_nodes` 结构层用于恢复文档标题树,不直接作为最终向量检索单元。 示例: - `1 范围` - `2 规范性引用文件` - `3 术语和定义` - `3.1 儿童三轮车` - `3.2 轮距` 结构层主要用于给下游 chunk 绑定 `section_path`。 ### 2. 语义层 `semantic_blocks` 语义层是按文档意义聚合后的内容块,主要分为三类: - `section_text`:同一章节下连续正文聚合而成 - `table`:表格内容单独成块 - `figure`:图、图名、图注等单独成块 这一层比单 layout 更适合做语义理解,也适合后续做上下文扩展。 ### 3. 检索层 `vector_chunks` 检索层是最终写进向量数据库的 chunk。 处理方式: - 对 `semantic_blocks` 中较短的块直接入库 - 对较长的块按 `max_chars` 再切分 - 相邻切片保留 `overlap_chars` 重叠 - 每个 chunk 都带完整 metadata,便于后续过滤、重排和邻域扩展 ## 三、当前转换脚本做了什么 `layouts_to_vector_chunks.py` 当前已经实现: 1. 过滤目录页噪声(如 `目次`) 2. 根据标题层级维护章节路径 3. 将正文聚合成 `section_text` 4. 将表格单独转成 `table` 5. 将图相关内容单独转成 `figure` 6. 对长文本继续切分为最终 `vector_chunks` 7. 为每个检索 chunk 生成 `embedding_text` ## 四、为什么不要直接按 layout 入库 如果把 `layouts.json` 的每条 layout 直接做向量: - 颗粒度太碎 - 标题和正文容易分离 - 表格会丢失结构上下文 - 图示信息无法完整表达 - 检索命中结果噪声较大 对于标准文档,最合适的单位通常不是“句子”,而是“条款语义块”。 ## 五、建议的入库字段 建议向量数据库每条记录至少保存: - `embedding_text`:用于生成向量 - `text`:原始 chunk 文本 - `chunk_id` - `semantic_id` - `chunk_type`:`section_text` / `table` / `figure` - `section_path` - `section_title` - `section_level` - `page_start` - `page_end` - `doc_id` - `doc_title` - `source_ids` 其中: - 向量化字段:`embedding_text` - 展示字段:`text` - 检索增强字段:其余 metadata ## 六、推荐的检索方式 不要只做最简单的 top-k 向量搜索,建议采用: **向量召回 + metadata 重排 + 邻域扩展** ### 1. 向量召回 使用 `vector_chunks[*].embedding_text` 做 embedding,并在向量数据库中检索 top 10 ~ 15 条。 查询时可以对用户问题做轻微改写,例如: 原问题: `儿童三轮车的定义是什么?` 可改写为: `请检索 GB 14747—2006 儿童三轮车安全要求 中关于“儿童三轮车定义”的条款、术语、表格或图示说明。` 这样更适合标准文档检索。 ### 2. metadata 重排 向量召回后,根据 metadata 做轻量规则重排。 常见规则: - `chunk_type == section_text`:对定义类、要求类问题优先级更高 - `section_path` 命中查询关键词:例如查询“定义”时,`术语和定义` 章节优先 - `chunk_type == table`:对“尺寸 / 参数 / 数值 / 对照 / 要求”类问题加权 - `chunk_type == figure`:对“图 / 结构 / 状态 / 示意”类问题加权 ### 3. 邻域扩展 检索命中的是最终切片,但回答往往需要更完整上下文。 建议命中某个 `vector_chunk` 后: 1. 优先回捞同一个 `semantic_id` 下的所有 chunk 2. 如果还不够,再补充同 `section_path`、相邻页码或相邻 `chunk_index` 的内容 这样可以恢复完整条款,而不是只给模型一小段碎片。 ## 七、不同问题的检索重点 ### 1. 定义类问题 例如: - `儿童三轮车的定义是什么?` - `轮距是什么意思?` 优先检索: - `section_text` - `section_path` 中包含 `术语和定义` 的内容 ### 2. 要求类问题 例如: - `外露突出物有什么要求?` - `辅助推杆有哪些安全要求?` 优先检索: - `section_text` - `table` ### 3. 数值 / 尺寸 / 对照类问题 例如: - `鞍座到脚蹬距离要求是什么?` - `哪些项目需要满足规定尺寸?` 优先检索: - `table` - `section_text` ### 4. 图示说明类问题 例如: - `正常乘骑状态是什么意思?` - `图1表示什么?` 优先检索: - `figure` - 同章节相邻 `section_text` ## 八、推荐的最终检索流程 建议采用以下固定流程: 1. 用 `vector_chunks.embedding_text` 做 embedding 检索 2. 取 top 10 ~ 15 条候选 3. 按 `chunk_type + section_path` 做规则重排 4. 以 `semantic_id` 为中心回捞完整语义块 5. 选 3 ~ 5 组上下文提供给大模型回答 ## 九、给大模型的上下文组织方式 最终不要直接把原始 JSON 扔给模型,建议整理成如下格式: ```text [命中片段 1] 章节:3 术语和定义 > 3.1 儿童三轮车 页码:1-2 类型:section_text 内容: ...... [命中片段 2] 章节:4 要求 > 4.3 外露突出物 页码:5 类型:section_text 内容: ...... [命中片段 3] 章节:5 试验方法 页码:8 类型:table 内容: ...... ``` 这种格式更利于模型稳定回答并引用出处。 ## 十、转换命令 生成三层结构: ```bash python3 /home/huaci/dev/ai/SuperMew/tests/layouts_to_vector_chunks.py \ --layouts /home/huaci/dev/ai/SuperMew/tests/layouts.json \ --out /home/huaci/dev/ai/SuperMew/tests/vector_chunks.json ``` 自定义切片大小: ```bash python3 /home/huaci/dev/ai/SuperMew/tests/layouts_to_vector_chunks.py \ --layouts /home/huaci/dev/ai/SuperMew/tests/layouts.json \ --out /home/huaci/dev/ai/SuperMew/tests/vector_chunks.json \ --max-chars 500 \ --overlap-chars 80 ```