Files
AIRegulation-DocAnalysis/aliyun_parser/嵌入和召回.md
wangwei dcda7e0423 @
chore: delete old layout/common/tabs components before redesign
@
2026-06-03 16:58:35 +08:00

6.7 KiB
Raw Blame History

文档解析与向量检索说明

相关文件

  • 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:主类型,例如 titletexttablefigure
  • subType:更细的语义类型,例如 doc_titlepara_titleparapicturepic_titlepic_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_typesection_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 扔给模型,建议整理成如下格式:

[命中片段 1]
章节3 术语和定义 > 3.1 儿童三轮车
页码1-2
类型section_text
内容:
......

[命中片段 2]
章节4 要求 > 4.3 外露突出物
页码5
类型section_text
内容:
......

[命中片段 3]
章节5 试验方法
页码8
类型table
内容:
......

这种格式更利于模型稳定回答并引用出处。

十、转换命令

生成三层结构:

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

自定义切片大小:

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