跳转至

生产级 RAG 处理流程与异常补偿清单

本文档描述标书知识库从文件解析、正文与 Chunk 落库、Embedding、向量索引,到最终检索和上下文返回的生产级处理流程。

租户、用户权限、知识库与标书的业务关系由 tender-service 负责;本文只描述 rag-service 内部的 RAG 能力。

整体 RAG 处理链路如下:

flowchart TD
    A["tender-service 提交标书文件与业务范围"] --> B["文件接收与异步处理任务"]
    B --> C["文档解析与标准化"]
    C --> D["Markdown + Document Blocks + 表格/图片资产"]
    D --> E["通用切片,生成基础 Chunk"]
    E --> F["标书业务识别与内容关联"]

    F --> G["有检索价值的基础 Chunk"]
    F --> H["完整业务基础 Chunk 增加业务标签"]
    F --> I["分散业务内容生成业务派生 Chunk"]

    G --> J["Embedding 向量化"]
    H --> J
    I --> J

    J --> K["写入候选向量索引"]
    K --> L["索引完整性检查"]
    L --> M{"候选索引是否完整"}
    M -->|"否"| N["候选版本失败,保留当前活动版本"]
    M -->|"是"| O["切换活动索引并清理旧版本"]

    P["AI 助手问题 + tender-service 检索范围"] --> Q["问题理解、查询改写与检索路由"]
    O --> R["活动向量索引"]
    Q --> S["通用 / 业务 / 关键词混合召回"]
    R --> S
    S --> T["范围与阈值过滤、去重"]
    T --> U["Rerank 与相邻内容补充"]
    U --> V["按 Token 预算组装上下文"]
    V --> W["返回 Chunk 正文、分数和引用信息"]
    W --> X["tender-service / AI 助手用于问答或正文生成"]

一、核心功能

核心功能 基本说明
1. 文档解析与标准化 将 PDF、Word、Excel 等文件转换为结构化 Markdown,识别正文、标题、表格和图片,并保留页码等来源信息
2. 文档切块 按标题、段落和语义边界生成可检索 Chunk;表格保留表头与数据关系,图片通过 OCR 或内容描述转成可检索信息
3. Embedding 与向量索引 批量生成 Chunk 向量并写入向量数据库(当前为 Qdrant),支持模型和索引版本管理
4. 索引版本管理 使用候选版本构建新索引,完成后切换活动版本,并清理旧版本
5. 向量检索 根据用户问题召回相关 Chunk,支持知识库、文件和 metadata 范围过滤
6. 检索结果处理 对候选结果进行阈值过滤、去重、相邻 Chunk 合并和来源多样性控制
7. Rerank 与混合检索 使用 Rerank 提升语义相关度,并通过关键词或稀疏检索补充编号、参数和条款原文召回
8. 上下文与引用输出 按 Token 预算组装 AI 上下文,返回 Chunk 正文、文件、标题路径、页码和引用信息

文档解析与标准化重点问题

一份标书在解析阶段主要经过格式识别、格式解析、内容分类和标准化输出,处理正文、表格、图片、原文位置、质量信息五类内容:

flowchart TD
    A["标书文件"] --> B["文件校验与真实格式识别"]
    B --> C{"格式解析适配器"}

    C -->|"PDF"| P["文本提取 / 版面分析 / 扫描页 OCR"]
    C -->|"DOCX / DOC"| W["DOC 转换 / 段落、列表、表格、图片解析"]
    C -->|"XLSX / XLS"| X["XLS 转换 / Sheet、单元格、公式、图片解析"]

    P --> N["统一 Document Block 标准化"]
    W --> N
    X --> N

    N --> T["正文、标题与列表"]
    N --> TB["表格 TableBlock"]
    N --> I["图片 ImageBlock"]
    N --> L["原文位置记录"]
    N --> Q["解析质量与警告"]

    T --> O["标准化输出"]
    TB --> O
    I --> O
    L --> O
    Q --> O

    O --> M["Markdown + Document Blocks + 图片资产 + 解析元数据"]
  1. 文件解析与标准结构

  2. 统一格式识别

    • 不能只根据文件扩展名选择解析器,需要同时校验扩展名、MIME、文件头和 OOXML 包内容。
    • 通过 OLE 魔数识别旧版 .doc.xls,通过 Zip 文件头和 [Content_Types].xml 区分 .docx.xlsx,解决扩展名与真实格式不一致的问题。
  3. PDF

    • 文本型 PDF:建议使用 PyMuPDF 按页提取文本 Block、坐标和阅读顺序;现有 pypdf 可以保留为基础或降级解析器。
    • 扫描型 PDF:根据页面文本量判断是否需要 OCR,将页面渲染为图片后调用 OCR Provider,再合并回对应页的标准结构。
    • 图文混合 PDF:保留原生文本,同时对无文本区域或关键图片单独执行 OCR/视觉分析,避免整页重复识别。
    • 针对问题:多栏排版可能导致阅读顺序错乱;页眉页脚和水印可能重复;加密、损坏或字体编码异常的 PDF 需要返回明确解析错误或降级处理。
  4. Word

    • 新格式 .docx:使用 python-docx 解析 OOXML,按文档真实顺序遍历段落、列表、表格和图片关系;结合样式名称、编号和文本特征识别标题层级。
    • 旧格式 .doc:先通过 OLE 魔数确认真实格式,再使用 LibreOffice/soffice headless 转换为 .docx,转换成功后复用同一 DOCX 解析器。
    • 扩展名错误:文件名为 .docx 但内容是 OLE 时仍走旧格式转换;文件名为 .doc 但内容实际是 OOXML 时直接按 DOCX 解析。
    • 针对问题:LibreOffice 可能未安装、转换超时或转换后排版发生变化;Word 没有稳定的物理页码,默认使用段落和 Block 位置定位,需要精确页码时可额外渲染为 PDF。
  5. Excel

    • 新格式 .xlsx:使用 openpyxl 解析工作表、单元格、合并区域、公式、显示值和隐藏状态,并记录 Sheet 名和单元格范围。
    • 旧格式 .xls:先通过 OLE 魔数确认格式,再使用 LibreOffice/soffice 转换为 .xlsx,后续统一交给 XLSX 解析器。
    • 公式处理:同时保留公式文本和可获得的缓存计算值,避免只保存公式或只保存结果导致信息缺失。
    • 针对问题:多级表头、合并单元格、隐藏行列、跨 Sheet 引用和复杂公式可能无法完整还原;Excel 没有自然页码,来源定位应使用 sheet_name + cell_range
  6. 统一标准结构

    • 使用 Pydantic 或 dataclass 定义 Document Block,统一表示 headingparagraphlisttableimage 等类型。
    • 每个 Block 保存正文、层级、页码或 Sheet、原文位置、坐标、资源引用和解析警告,Markdown 只是标准输出之一,结构化 Block 作为后续处理的事实数据。
  7. 正文、标题与列表

  8. 技术方案:按原文顺序提取正文、标题、段落和列表,保留原始编号与样式信息,并统一转换为 Markdown 和 Document Block;解析阶段不判断内容是否属于业务条款。

  9. 可能问题:非标准标题、多栏排版、自动编号和自定义样式可能导致正文顺序、标题层级或列表编号还原错误。

  10. 原文位置记录(辅助能力)

  11. 基本作用:给解析后的段落、表格和图片记录其在原文件中的大致位置,方便后续展示引用和排查解析问题;它不是核心解析结果。

  12. 实现方式:PDF 记录页码和内容顺序,Word 记录段落或表格顺序,Excel 记录 Sheet 和单元格范围。第一版保存这些基础信息即可,不要求精确坐标还原。
  13. 可能问题:Word、Excel 没有稳定的物理页码,文件重新排版后位置也可能变化;精确定位能力可以后续按实际引用需求增强。

表格与图片解析方案

  1. 表格

  2. 应用方案

    • 解析器发现表格时,将其作为独立 TableBlock 保留在文档原始顺序中,不与前后正文直接拼成普通文本。
    • 优先使用文档原生结构提取行列;原生结构不可用时再使用版面分析或 OCR 表格识别。
    • 同时保存 Markdown 表示、结构化行列数据和原文位置,供统一展示、精确还原和后续处理使用。
  3. Word 表格

    • 使用 python-docx 按文档顺序读取表格,保留表格与前后正文的相对位置。
    • 提取行列、单元格文本、合并关系和附近标题,将表格转换为 Markdown,同时保留结构化行列数据。
  4. Excel 表格

    • 使用 openpyxl 读取 Sheet、单元格、合并区域、隐藏行列、公式和缓存值。
    • 使用 sheet_name + cell_range 记录来源位置;多个独立数据区域应分别保存,避免把整个 Sheet 误认为一个表格。
  5. 文本型 PDF 表格

    • 优先根据文字 Block、坐标和线条信息恢复表格区域、行列和阅读顺序。
    • 无边框表格需要结合文字对齐和间距推断,不应只依赖表格边框。
  6. 扫描型 PDF 表格

    • 将表格所在页面或区域渲染为图片,通过 OCR 表格识别提取单元格和文字。
    • OCR 结果需要保留置信度;低置信度表格应记录解析警告,避免被当成可靠原文。
  7. 标准输出

    • 输出 TableBlock,保存表名、Markdown、表头、行列数据、合并单元格、页码或 Sheet、原文位置和解析警告。
    • Markdown 用于统一展示,结构化行列数据用于后续精确还原和处理,两者不能互相替代。
  8. 可能问题

    • 多级表头、合并单元格、跨页表格、嵌套表格和无边框表格可能还原不准确。
    • PDF 表格可能出现错列、漏行和阅读顺序错误;Excel 公式可能缺少缓存结果;Word 表格可能包含图片或嵌套表格。
  9. 图片

  10. 应用方案

    • 解析器先提取原图并创建独立 ImageBlock,保存图片与标题、正文、页面或 Sheet 的位置关系。
    • 有明显文字的图片优先执行 OCR;流程图、架构图和示意图再调用视觉模型补充内容描述。
    • 原图、OCR 原文和视觉描述分别保存,任何派生结果都不能覆盖或替代原始图片。
  11. 图片提取

    • 从 PDF、Word 中提取原始图片或页面区域,保存文件格式、尺寸、所在页、文档顺序和附近标题、图题、正文。
    • Excel 中的浮动图片需要保存所属 Sheet、锚定单元格和附近数据区域。
  12. 图片分类与过滤

    • 根据尺寸、重复次数、位置和内容特征区分业务图片、扫描页、Logo、水印、页眉图标和装饰图片。
    • 装饰图片不进入后续内容处理,但仍可保留基础审计信息,避免误删后无法追溯。
  13. OCR 解析

    • 对文字截图、扫描页、证书、参数图等调用 OCR Provider,保存原始识别文本、文本区域和置信度。
    • OCR 前可进行旋转矫正、裁边、降噪和清晰度增强,提高中文、数字和表格文字识别率。
  14. 视觉内容解析

    • 对流程图、架构图、示意图和无法仅靠 OCR 理解的图片调用视觉模型 Provider。
    • 视觉模型输出内容描述、关键实体和结构关系;模型描述属于派生信息,不能替代 OCR 原文和原图。
  15. 标准输出

    • 输出 ImageBlock,保存原图引用、图题、OCR 文本、视觉描述、页码或 Sheet、原文位置、置信度和解析警告。
    • 原图、OCR 结果和视觉描述分别保存,便于后续校验、重新分析和引用展示。
  16. 可能问题

    • OCR 可能误识别数字、单位和中文字符;视觉模型可能遗漏细节或产生不可靠描述。
    • 图片与附近正文的关联可能错误;过滤规则也可能误删较小但有业务价值的印章、证书或参数图片。

通用 Chunk 与业务 Chunk 的关系

通用 Chunk 是忠实保留原始文档结构的基础数据;业务 Chunk 是基于一个或多个通用 Chunk 识别、关联后生成的业务派生数据。

flowchart TD
    A["Document Blocks"] --> B["通用 Chunk"]

    B --> C["基础文档检索"]
    B --> D["标书业务识别与内容关联"]
    D --> E["业务 Chunk"]
    E --> F["资格、评分、参数、废标等业务检索"]

    E -. "通过 source_chunk_ids 关联" .-> B
    C --> G["统一候选结果"]
    F --> G
    G --> H["去重、Rerank 与上下文组装"]
    H --> I["返回通用 Chunk、原文位置和引用信息"]
  • 一个业务 Chunk 可以组合多个通用 Chunk;一个通用 Chunk 也可能参与多个业务 Chunk。
  • 业务 Chunk 可以随业务规则重新生成,通用 Chunk 和原文引用关系保持不变。
  • 两类 Chunk 可以分别召回,最终统一去重和排序;引用仍回到通用 Chunk 及原始文件。

通用文档切片(Chunk)方案

文档切片只处理解析和标准化后的 Document Block,不再直接读取 PDF、Word 或 Excel 原文件。

flowchart TD
    A["Markdown + Document Blocks + 图片资产 + 解析元数据"] --> B["恢复文档顺序与标题层级"]
    B --> C["识别标题、段落、列表、表格和图片边界"]
    C --> D{"按 Block 内容类型处理"}

    D -->|"正文 / 列表"| T["按结构组合相邻内容"]
    D -->|"表格"| TB["小表整体保留 / 大表按行组拆分"]
    D -->|"图片"| I["组合图题、OCR 文本和视觉描述"]

    T --> L["Token 长度检查"]
    TB --> L
    I --> L

    L -->|"超长"| S["按段落、句子或表格行二次拆分"]
    L -->|"长度合适"| M["生成候选 Chunk"]
    S --> M

    M --> H["继承标题上下文"]
    H --> O["补充必要的相邻内容重叠"]
    O --> R["关联来源 Block、页码、Sheet、表格和图片"]
    R --> Q["空内容、重复、超长和来源完整性检查"]
    Q --> Z["通用 Chunk 输出"]

    Z --> E["进入 Embedding 或标书业务切片"]
  1. 结构边界优先

  2. 优先按照标题、段落、列表、表格和图片等 Block 边界切片,不从一个完整 Block 的中间截断。

  3. 一个 Chunk 不跨文件;默认也不跨一级章节,避免不同主题内容混在一起。

  4. 长度控制

  5. 使用 Token 数控制 Chunk 长度,不使用固定字符数作为唯一标准。

  6. 初始可采用目标 500~800 Tokens、最大 1000~1200 Tokens,后续根据 Embedding 模型和检索效果调整。
  7. 单个 Block 超过最大长度时,再按段落、句子或行进行二次拆分。

  8. 标题上下文继承

  9. 每个 Chunk 保存完整 heading_path,正文中可附带必要的上级标题,使片段脱离原文后仍能表达所属章节。

  10. 标题只作为上下文补充,不应在每个 Chunk 中重复过多无关目录内容。

  11. 相邻内容重叠

  12. 连续正文 Chunk 保留少量 overlap,避免定义、条件或句子在边界处断开。

  13. 初始 overlap 可设置为 80~150 Tokens;标题变化、表格和图片边界不采用简单文本重叠。

  14. 正文与列表规则

  15. 相邻短段落可以合并,但不跨越明显标题边界。

  16. 列表标题与列表项尽量保存在同一 Chunk;超长列表拆分时,每个 Chunk 保留列表标题和必要上下文。
  17. 条款语义识别属于切片或内容增强阶段,可根据编号模式辅助确定边界,但不能修改原文内容。

  18. 表格规则

  19. 小型表格作为一个独立 table Chunk,保留表名、表头和完整数据。

  20. 大型表格按行组拆分,每个 Chunk 重复必要表头,并保存同一个 table_id 和行范围。
  21. 表格默认不与大段正文合并;可以附带附近标题和简短说明作为检索上下文。

  22. 图片规则

  23. 有效图片使用 OCR 文本、视觉描述和图题形成独立 image Chunk,并保留原图引用。

  24. 图片附近的标题和说明文字可以作为上下文,但不能用模型描述覆盖 OCR 原文。
  25. 无有效文字或描述的装饰图片不生成可检索 Chunk。

  26. Chunk 类型与元数据

  27. Chunk 类型至少区分 textlisttableimagemixed

  28. 每个 Chunk 保存 chunk_indexcontent_hashtoken_countheading_path、来源 Block、页码或 Sheet、表格或图片引用和处理版本。

  29. 质量检查

  30. 过滤空 Chunk、纯标题 Chunk、明显重复 Chunk 和无业务内容的 Chunk。

  31. 检查 Chunk 是否超长、是否缺少来源信息、表格是否缺少表头、图片是否缺少可检索内容。
  32. 切片结果通过检查后再进入 Embedding,避免无效内容污染向量索引。

标书业务切片(待确认)

标书业务切片建立在 Document Block 和通用 Chunk 之上,不替代通用切片。它的作用是将分散在标题、正文、列表和表格中的内容重新关联为可独立检索、可直接回答问题的完整业务单元。

flowchart TD
    A["Document Blocks + 通用 Chunk"] --> B["识别章节、关键词、编号和表头"]
    B --> C{"判断标书业务类型"}

    C --> Q["资格要求 / 实质性要求 / 废标条件"]
    C --> S["评分标准 / 分值 / 证明材料"]
    C --> T["技术参数 / 功能要求 / 偏离要求"]
    C --> P["报价 / 付款 / 合同商务条款"]
    C --> D["工期 / 交付 / 验收 / 售后服务"]
    C --> F["投标文件编制 / 递交 / 开标要求"]

    Q --> U["关联相邻正文、列表项和表格行"]
    S --> U
    T --> U
    P --> U
    D --> U
    F --> U

    U --> V["组合为一个完整业务单元"]
    V --> W["检查条件、数值、对象和结果是否完整"]
    W --> X["生成业务类型和业务标签"]
    X --> Y["生成业务派生 Chunk"]
    Y --> R["关联通用 Chunk、原文位置和引用信息"]
    R --> O["输出通用 Chunk + 业务派生 Chunk"]
  1. 业务模块识别

  2. 根据章节标题、条款编号、关键词和表头,初步识别资格审查、评分办法、技术要求、商务要求、合同条款、投标文件编制等模块。

  3. 业务模块识别发生在通用切片之后,不在文档解析阶段判断业务含义。

  4. 资格要求与废标条件

  5. 将资格条件、适用对象、证书或证明材料、有效期要求组合为一项完整资格要求。

  6. 将触发条件、否决或废标结果以及例外说明保存在同一个业务单元中,避免只检索到“不得”“无效”等孤立文字。

  7. 评分标准

  8. 将评分项、分值、评分档次、判断条件和证明材料组合为一条完整评分标准。

  9. 对表格形式的评分办法,按评分项或评分档次处理,保留上级评分分类和表头,不能只保存单独的分值。

  10. 技术参数与功能要求

  11. 将参数名称、要求值、单位、范围、是否必须满足、证明方式和偏离规则组合为完整技术要求。

  12. 技术参数表可以按单行或相关行组形成业务单元;同一设备、部件或功能组的关联参数不应被完全拆散。

  13. 报价与商务合同条款

  14. 报价清单按项目、产品或费用组保留名称、数量、单位、限价、税费和报价说明。

  15. 付款条款按付款节点保留触发条件、付款比例、时间和所需材料;合同条款保留权利义务、违约条件和处理结果。

  16. 工期、交付、验收与售后

  17. 将交付对象、地点、期限、实施条件和交付成果组合为完整交付要求。

  18. 将验收标准、验收方式、参与方和不通过后的处理方式组合为完整验收要求。
  19. 将质保期限、服务范围、响应时间、到场时间和维护要求组合为完整售后服务要求。

  20. 投标文件编制与递交要求

  21. 将文件组成、签章、装订、份数、格式和密封要求按事项形成业务单元。

  22. 将递交截止时间、地点、方式、开标时间和注意事项保留为可单独检索的要求,避免关键时间与适用事项分离。

  23. 业务切片基本原则

  24. 一个业务 Chunk 应能独立回答一个具体问题,至少保留“要求对象、条件或数值、要求内容、结果或证明材料”等必要信息。

  25. 业务切片只组合和标注原文,不修改原文事实;模型生成的分类或摘要只能作为辅助字段。
  26. 同一内容在不同文件或章节中出现时,分别保留原文来源,不直接合并成无法追溯的新结论。
  27. 每个业务派生 Chunk 关联原始 source_block_idssource_chunk_ids 和原文位置,保证引用能够返回基础内容。

初步建议同时保留两类结果:

  • 通用 Chunk:忠实保留文档原始结构,保证基础召回完整性。
  • 业务派生 Chunk:面向标书问答,增强对资格、评分、参数和合同条款等内容的检索能力。

以上业务类型和边界是初始方案,仍需使用实际招标文件、投标文件和评分办法验证后确认首期范围。

Embedding 与向量索引方案

Embedding 与向量索引承接通用切片和标书业务切片的结果,负责判断哪些内容需要生成向量、组织基础与业务索引数据,并在索引完整后切换为可检索版本。

这里将“通用 Chunk”理解为基础 Chunk(通用切片结果):它按文档结构产生,本身也服务标书业务;业务 Chunk 则是多个基础内容经过业务关联后形成的派生结果。

flowchart TD
    A["基础 Chunk(通用切片结果)"] --> B{"是否具有可检索内容"}
    B -->|"否:空内容、装饰或无效重复"| X["不生成向量,仅保留必要解析记录"]
    B -->|"是"| C{"基础 Chunk 的业务状态"}

    C -->|"完整业务单元"| D["基础 Chunk 增加业务类型和标签"]
    D --> E["作为基础 Chunk 生成一次向量"]

    C -->|"普通基础内容 / 分散业务内容"| V{"是否具有独立检索价值"}
    V -->|"是"| F["基础 Chunk 生成向量"]
    V -->|"否"| Y["不单独生成向量,保留来源数据"]

    C -->|"分散业务内容,同时关联"| G["关联多个基础 Chunk"]
    G --> H["生成业务派生 Chunk"]
    H --> I{"业务内容是否完整且可追溯"}
    I -->|"否"| J["不进入业务索引,记录识别结果或警告"]
    I -->|"是"| K["业务派生 Chunk 单独生成向量"]

    E --> M["统一 Embedding 模型与处理版本"]
    F --> M
    K --> M
    M --> N["写入候选向量索引"]
    N --> O["核对 Chunk、向量和来源关系"]
    O --> P{"索引是否完整"}
    P -->|"否"| Q["候选版本失败,不影响当前活动索引"]
    P -->|"是"| R["切换为活动索引版本"]
    R --> S["进入通用检索与标书业务检索"]
    R --> T["异步清理旧版本和无效向量"]
  1. 进入向量索引的内容范围

  2. 能独立表达正文、条款、列表、表格、图片信息或必要上下文的基础 Chunk,可以进入向量索引。

  3. 已通过完整性检查的业务派生 Chunk,可以进入向量索引。
  4. 空内容、纯装饰图片、无意义重复、解析失败内容和无法追溯来源的业务 Chunk,不进入向量索引。
  5. 只有结构作用、不能独立检索的标题或过渡内容,可以保留在正文或 Block 数据中,用于相邻上下文补充,不必单独生成向量。

  6. 基础 Chunk 的索引方式

  7. 基础 Chunk 是默认的原文检索数据,保留正文、标题路径、内容类型和原文位置后生成向量。

  8. 一个基础 Chunk 如果已经构成完整的资格要求、评分项、参数或合同条款,只需增加 business_type 等业务标签,仍以基础 Chunk 身份生成一次向量。
  9. 基础 Chunk 即使没有业务标签,只要具有独立检索价值,也可以进入索引,用于普通原文问答、相似内容检索和相邻上下文补充。

  10. 业务派生 Chunk 的索引方式

  11. 当一项业务内容分散在多个基础 Chunk、列表项或表格行中时,先关联并生成完整的业务派生 Chunk。

  12. 业务派生 Chunk 通过完整性和来源检查后单独生成向量,并保存业务类型及 source_chunk_ids
  13. 业务派生 Chunk 默认只组合同一文件、同一内容版本中的基础 Chunk;跨文件内容在检索阶段汇总,不在索引阶段拼成一个新 Chunk。
  14. 业务规则变化后可以重新生成业务派生 Chunk,不需要改变基础 Chunk 和原文数据。

  15. 避免重复向量

  16. 业务处理只给基础 Chunk 增加标签时,不再复制正文生成第二条业务向量。

  17. 只有业务派生 Chunk 对多个基础内容进行了有效组合,形成新的完整检索单元时,才单独生成业务向量。
  18. 业务派生 Chunk 与基础 Chunk 内容完全相同或高度重复时,优先复用基础 Chunk,通过业务标签参与业务检索。

  19. 表格与图片的向量化

  20. 表格以保留表头和行列关系的可检索文本生成向量;大型表格按行组产生的 Chunk 分别进入索引。

  21. 图片使用图题、可靠的 OCR 文本和必要的视觉描述生成向量,原图本身作为引用资产保留。
  22. 表格行或图片已经形成评分、参数、证书等完整业务单元时,可以直接增加业务标签;需要关联其他正文时再生成业务派生 Chunk。

  23. Embedding 一致性

  24. 基础 Chunk、业务派生 Chunk 和用户查询需要使用兼容的 Embedding 配置,保证向量可以在同一检索空间比较。

  25. 每次向量化记录模型、向量维度和处理版本;模型或处理规则升级时重新构建候选索引,不直接覆盖当前活动索引。

  26. 候选索引与活动版本

  27. 新文件、文件更新、切片规则变化或 Embedding 模型升级时,先构建候选版本。

  28. 候选版本完成前,当前活动版本继续提供检索,避免 AI 助手读取只处理了一部分的数据。
  29. 候选版本检查通过后再切换为活动版本,切换失败时保留旧活动版本。

  30. 索引完整性与清理

  31. 切换前核对应该索引的基础 Chunk、业务派生 Chunk、成功向量和来源关系是否完整。

  32. 文件删除或版本切换后,检索立即排除旧数据,再异步清理旧 Chunk、旧向量和失败候选。
  33. 定期检查正文数据库与向量数据库是否一致,发现缺失向量时补写,发现孤儿向量时清理。

首期建议将基础 Chunk 和业务派生 Chunk 放在同一逻辑索引中,通过 chunk_category=base/business 和业务类型区分,并采用两路召回后统一去重、Rerank。是否拆分为独立索引,可在数据规模和业务检索效果明确后再决定。

通用检索能力

检索模块负责根据 AI 助手的问题,从通用 Chunk 和业务 Chunk 中找到可靠依据,完成过滤、排序和上下文组装后返回给 tender-service;答案生成仍由上层 AI 助手负责。

通用检索能力主要包括:

flowchart TD
    A["用户问题 + tender-service 检索范围"] --> B["问题规范化、意图识别与查询改写"]
    B --> S["按知识库、标书、文件和业务范围过滤"]
    S --> C{"选择通用 / 业务召回路径"}

    C --> G["通用 Chunk 向量召回"]
    C --> U["业务 Chunk 向量召回"]
    C --> K["关键词 / 稀疏 / 编号 / 参数召回"]

    G --> M["合并多路候选结果"]
    U --> M
    K --> M

    M --> F["候选数量控制与相关度阈值过滤"]
    F --> D["去重与来源多样性控制"]
    D --> R["Rerank 重新排序"]
    R --> J{"是否存在可靠结果"}
    J -->|"否"| X["降级检索;仍无结果返回 no_reliable_context"]
    J -->|"是"| N["补充必要的相邻 Chunk"]
    N --> P["按 Token 预算组装上下文"]
    P --> O["返回 Chunk 正文、分数和引用信息"]

    O -. "检索日志与标注样本" .-> E["检索效果评估与参数调优"]
    X -. "无结果与降级记录" .-> E
  1. 问题理解与查询改写

  2. 识别用户是在查询资格、评分、技术参数、废标条件、合同条款还是普通原文内容。

  3. 对口语化问题补充标书常用表达、同义词和必要关键词,但保留原始问题用于结果判断。

  4. 检索范围控制

  5. 使用 tender-service 传入的知识库、标书、文件和业务范围限制检索内容。

  6. rag-service 只执行范围过滤,不自行判断租户、用户权限和标书归属。

  7. 通用 Chunk 与业务 Chunk 召回策略

  8. 普通文档问答以通用 Chunk 为基础;资格、评分、参数和废标等明确业务问题提高业务 Chunk 的召回权重。

  9. 两类 Chunk 可以并行召回,避免业务识别错误时完全漏掉原文内容。

  10. 向量、关键词与混合检索

  11. 向量检索负责语义相似内容,关键词或稀疏检索补充项目编号、参数值、证书名称、金额和条款原文。

  12. 混合检索用于兼顾自然语言问题和标书中的精确表达。

  13. 候选数量与阈值过滤

  14. 先召回相对充足的候选内容,再根据相关度阈值筛除明显无关结果。

  15. 阈值和候选数量需要按问题类型调整,不能只使用一个固定值覆盖所有标书场景。

  16. 去重、来源与多样性控制

  17. 合并通用 Chunk、业务 Chunk 和不同检索路径中的重复结果。

  18. 避免结果全部集中在一个重复章节,同时不能为了多样性丢弃真正相关的关键条款。

  19. Rerank 排序

  20. 根据“用户问题 + Chunk 内容”对候选结果重新评分,优先保留能够直接回答问题且信息完整的内容。

  21. Rerank 不可用时可以降级使用原始召回分数,保证基础检索仍然可用。

  22. 相邻内容补充

  23. 命中内容缺少标题、前置条件、表头或后续说明时,按来源关系补充必要的相邻 Chunk。

  24. 相邻扩展只补充上下文,不应无条件返回整章内容。

  25. 上下文组装与引用输出

  26. 按总 Token 预算、单个来源占比和最大引用数量组装最终上下文。

  27. 返回正文、Chunk 类型、文件、标题路径、页码或 Sheet、检索分数及原文引用信息。

  28. 无可靠结果与降级处理

  29. 没有结果或结果低于可靠阈值时返回明确的 no_reliable_context,避免 AI 助手把无关内容当作标书依据。

  30. 查询改写、业务召回或 Rerank 失败时,可逐级降级到通用向量检索。

  31. 检索效果评估

  32. 使用真实标书问题建立评测集,分别观察资格、评分、参数、废标、合同和普通问答的召回效果。

  33. 重点评估是否找到正确原文、前几条结果是否相关、引用是否完整,以及无答案问题是否被正确拒绝。

以上为检索能力的设计角度,具体采用纯向量还是混合检索、两类 Chunk 的权重、Rerank 模型和阈值,需要通过实际标书评测后确定。

标书业务检索(待确认)

标书业务检索建立在通用检索能力之上,主要服务标书正文写作。用户输入当前章节、写作要求或已有正文后,系统查找可参考的相似条款、政策标准、技术方案、商务内容和资格材料,并返回原文及可靠引用。

flowchart TD
    A["当前章节 + 已有正文 + 写作要求 + 项目信息"] --> B["识别写作任务与所需参考资料"]
    B --> C{"选择业务检索场景"}

    C --> T["相似条款与历史写法"]
    C --> P["政策法规与行业标准"]
    C --> S["技术方案与产品能力"]
    C --> BZ["商务、合同与服务条款"]
    C --> Q["资格要求与证明材料"]

    T --> R["调用通用检索进行多路召回"]
    P --> R
    S --> R
    BZ --> R
    Q --> R

    R --> F["按行业、地区、项目类型、时间和资料类型过滤"]
    F --> K["按相似度、适用性、完整性和来源可靠性排序"]
    K --> D["识别重复、冲突和可能失效的参考资料"]
    D --> O["分类返回可引用原文、参考写法和政策依据"]
    O --> I["附带来源文件、原文位置和适用性提示"]
  1. 写作上下文输入

  2. 检索输入不只包含用户的一句话,还可以包含当前章节标题、相邻正文、招标要求、项目行业、地区和项目类型。

  3. tender-service 负责提供当前写作场景和允许检索的资料范围,rag-service 负责据此检索。

  4. 相似条款与历史写法

  5. 根据当前条款或写作要求,查找历史标书中语义相近、结构完整的正文内容。

  6. 优先返回包含完整适用条件、要求和结果的条款,避免只返回相似短句或脱离上下文的段落。

  7. 政策法规与行业标准参考

  8. 根据行业、地区、采购类型和写作主题检索相关政策、法规、规范和标准原文。

  9. 结果应展示发布单位、文件名称、文号、发布日期、实施日期和知识库记录的有效状态;知识库未维护有效状态时,不应声称政策仍然有效或最新。

  10. 技术方案与产品能力参考

  11. 根据技术要求、设备名称、系统模块和功能目标,查找相似项目中的技术方案、实施方法和产品能力说明。

  12. 返回内容需要保留适用项目和前置条件,避免把其他行业或其他产品的方案直接作为当前项目结论。

  13. 商务、合同与服务条款参考

  14. 检索交付、工期、付款、验收、质保、售后、违约和风险分担等相似条款。

  15. 重点保留比例、时间、地点、触发条件和责任主体,避免只召回笼统的商务描述。

  16. 资格要求与证明材料参考

  17. 根据资格条件查找相似项目要求的证书、业绩、人员、财务和信用证明材料。

  18. 区分招标方的资格要求与历史投标文件中的响应材料,避免将响应内容误认为当前项目要求。

  19. 适用范围过滤

  20. 支持按资料类型、行业、地区、项目类型、采购方式、时间范围和业务章节过滤参考材料。

  21. 政策和标准优先匹配适用地区及有效时间,历史写法优先匹配相近项目场景。

  22. 业务价值排序

  23. 除语义相似度外,同时考虑业务类型匹配度、适用范围、内容完整性、来源可靠性和资料时间。

  24. 对相似条款优先完整可参考的内容,对政策依据优先权威来源和知识库中状态明确的内容。

  25. 重复与冲突提示

  26. 对多个文件中的重复条款合并展示,但保留各自来源。

  27. 当不同资料的金额、时间、参数或要求存在冲突时,不自动合成单一结论,应同时返回并标记差异。

  28. 写作参考结果组织

  29. 结果可以按“可引用原文、历史参考写法、政策或标准依据、相关技术与商务材料”分类返回。

  30. 每条结果附带来源文件、标题路径、页码或 Sheet、内容类型和适用性提示,方便 AI 助手选择和引用。

  31. 无结果与使用边界

  32. 没有可靠参考资料时明确返回无结果,不通过大模型补造条款、政策名称或标准编号。

  33. 业务检索只提供写作材料和依据,不判断最终条款是否合法、政策是否仍有效,也不直接替代 AI 助手生成正文。

以上是面向标书正文写作的初始检索方案,后续需要结合实际写作入口、知识库资料分类和典型检索问题进一步完善业务类型、排序规则和结果展示方式。

外部能力接入候选(待调研)

rag-service 保留文档处理、切片、索引和检索等核心流程,以下能力通过统一 Provider 接口接入。这里仅列举候选方案,具体产品需要结合标书效果、成本、性能、数据安全和部署方式进一步调研。

  1. OCR 与文档识别

  2. 国内云服务:阿里云 OCR/文档智能、百度智能云 OCR、腾讯云 OCR、华为云 OCR、火山引擎 OCR。

  3. 开源或自部署:PaddleOCR、MinerU、Tesseract、Surya、Docling、Unstructured。
  4. 主要用途:扫描 PDF、图片文字、表格、印章、证书和复杂版面的识别。

  5. 视觉理解模型

  6. 国内模型:通义千问 VL、豆包视觉模型、文心多模态模型、腾讯混元视觉模型、盘古多模态模型、智谱 GLM 视觉模型。

  7. 海外模型:OpenAI 视觉模型、Google Gemini、Anthropic Claude Vision。
  8. 开源或自部署:Qwen-VL、InternVL、LLaVA、MiniCPM-V 等视觉模型。
  9. 主要用途:理解流程图、技术架构图、证书、产品图片和无法只靠 OCR 表达的图像内容。

  10. Embedding 模型

  11. 国内云服务:阿里云百炼 Embedding、火山方舟 Embedding、百度智能云 Embedding、腾讯混元 Embedding、智谱 Embedding。

  12. 海外服务:OpenAI Embedding、Cohere Embed、Voyage AI Embedding、Jina Embeddings。
  13. 开源或自部署:BGE/BGE-M3、E5、GTE、M3E、Jina Embeddings 开源模型。
  14. 主要用途:生成正文、表格、图片描述和用户问题的语义向量。

  15. Rerank 模型

  16. 国内云服务:阿里云百炼 Qwen Rerank、百度智能云 Reranker、火山方舟 Rerank、智谱 Rerank。

  17. 海外服务:Cohere Rerank、Jina Reranker、Voyage AI Rerank。
  18. 开源或自部署:BGE Reranker、Qwen Reranker、Jina Reranker 开源模型。
  19. 主要用途:对初步召回的候选 Chunk 重新排序,提高最终上下文相关度。

  20. 向量数据库与检索引擎

  21. 当前及自部署方案:Qdrant、Milvus、PostgreSQL + pgvector、Elasticsearch、OpenSearch、Weaviate。

  22. 阿里云托管方案:DashVector、OSS Vectors、阿里云 Elasticsearch、OpenSearch 向量检索版。
  23. 其他托管方案:Zilliz Cloud、Pinecone、Qdrant Cloud、Weaviate Cloud。
  24. 主要用途:保存 Chunk 向量和检索元数据,提供向量召回、条件过滤及混合检索能力。

  25. 大语言模型

  26. 国内模型平台:阿里云百炼/通义千问、火山方舟/豆包、百度千帆/文心、腾讯混元、华为盘古、智谱、DeepSeek、月之暗面、MiniMax、零一万物。

  27. 海外模型平台:OpenAI、Anthropic Claude、Google Gemini、Mistral AI、Cohere。
  28. 自部署方案:通过 vLLM、SGLang、Ollama 等运行 Qwen、DeepSeek、Llama、Mistral 等开源模型。
  29. 主要用途:查询改写、业务内容识别、答案生成和引用组织;不负责替代 RAG 的基础索引与检索流程。

  30. AI 应用与工作流编排

  31. 平台方案:Dify、阿里云百炼应用与工作流、FastGPT、Coze/扣子、Flowise、n8n。

  32. 开发框架:LangGraph、LangChain、LlamaIndex、Haystack、Semantic Kernel。
  33. 主要用途:编排模型调用、检索工具、Prompt、对话状态和 AI 助手工作流;rag-service 仍作为独立检索能力被调用。

后续选型时分别验证中文标书效果、表格与图片能力、接口稳定性、调用限额、延迟、费用、数据保存策略、私有化能力和供应商锁定风险。

二、正常流程技术细节

序号 功能点 基本说明
1 文件接收 接收 tender-service 提供的文件地址、文件名、类型、大小、checksum 和业务来源信息
2 文件完整性校验 校验文件是否存在、大小是否一致、checksum 是否匹配
3 文件格式识别 通过扩展名、MIME 和文件头判断 PDF、Word、Excel 等真实格式
4 文档下载 从对象存储获取文件,限制下载超时和最大文件大小
5 结构化解析 提取标题、段落、列表、表格、页码等文档结构
6 Markdown 标准化 将不同格式文档转换为统一 Markdown,作为后续处理的标准正文
7 原文位置映射 记录 Markdown 内容与原始页码、段落、表格位置的对应关系
8 解析质量检查 检查空内容、乱码、内容过少、重复页和结构异常
9 Markdown 正文落库 保存标准 Markdown、内容 hash、页数、解析器版本和解析元数据
10 标题感知切块 优先按标题、段落和语义边界切块,长内容再按句子拆分
11 Chunk overlap 在相邻 Chunk 之间保留适量重叠,避免语义从边界断开
12 Chunk 去重 去除重复页眉页脚、模板内容和完全相同的 Chunk
13 Chunk 元数据生成 生成 Chunk index、标题路径、页码、字符位置、Token 数和内容 hash
14 候选 Chunk 落库 新内容先写入候选版本,不覆盖当前活动版本
15 Embedding 配置选择 根据 Embedding profile 确定 provider、model、dimension 和 normalization
16 Embedding 批处理 按批次、并发限制生成所有 Chunk 的向量
17 向量合法性校验 校验向量数量、维度、空向量、NaN 和模型版本
18 确定向量 ID 根据 source、内容版本和 Chunk 生成稳定且可重试的 point ID
19 候选向量写入 将向量和轻量过滤字段写入 Qdrant 候选版本
20 索引完整性检查 核对候选 Chunk 数、成功向量数和 Qdrant point 数
21 活动版本切换 候选版本完整后,原子切换为当前可检索版本
22 旧版本清理 异步清理旧版本 Chunk、向量和无用解析产物
23 查询向量化 将 AI 助手的问题使用相同 Embedding profile 转换为查询向量
24 检索范围过滤 根据 tender-service 提供的知识库、文件和 metadata scope 限定检索范围
25 向量候选召回 使用 recall_k 从 Qdrant 召回较多候选 Chunk
26 相似度阈值过滤 过滤低于 min_score 的候选,避免无关内容进入 AI 上下文
27 检索结果去重 按内容 hash 和相似度删除重复或高度相似结果
28 相邻 Chunk 合并 合并同文件、同版本且连续命中的相邻 Chunk
29 来源多样性控制 防止最终结果全部来自同一文件或同一章节
30 Rerank 根据“用户问题 + Chunk 正文”重新评分并排序
31 最终 TopK 选择 从 Rerank 结果中选择最终少量高质量材料
32 Context Packing 按总 Token、单 Chunk 长度和最大引用数量组装 AI 上下文
33 引用元数据组装 返回文件名、标题路径、页码、source、版本、Chunk 和检索分数
34 检索结果返回 tender-service 返回 Chunk 正文、结构化引用、策略版本和检索状态

三、异常、重试与补偿技术细节

序号 异常场景 处理方式
1 重复提交同一文件 根据 idempotency key、checksum 和处理版本返回已有任务,避免重复解析和写向量
2 同一文件并发处理 同一个 source 只允许一个活动摄入任务,其他请求复用或返回冲突
3 文件不存在或下载失败 标记下载失败;瞬时网络错误自动重试,永久不存在直接终止
4 下载超时 按指数退避重试,超过最大次数进入失败或死信状态
5 文件过大 在下载或解析前拒绝处理,返回明确错误码
6 文件格式不匹配 以文件头检测结果为准;无法识别时终止任务,不进入切块和 Embedding
7 文件损坏 记录解析错误和解析器信息,终止候选版本,保留旧活动版本
8 解析结果为空 视为解析失败,不生成 Chunk,不切换活动版本
9 解析质量过低 标记质量警告或进入人工复核状态,不直接覆盖当前版本
10 Worker 意外退出 通过 heartbeat 和任务租约识别超时任务,再由新 Worker 恢复
11 旧 Worker 延迟写回 使用 fencing token/CAS version 拒绝旧 Worker 更新任务和活动版本
12 切块失败 删除当前候选 Chunk,记录阶段错误,旧活动版本继续使用
13 Chunk 数量异常 例如正文非空但 Chunk 为零时终止任务,避免生成空索引
14 Embedding 请求超时 对失败批次自动重试,不重复处理已经成功的批次
15 Embedding 限流 识别 429,按服务端提示或指数退避降低并发后重试
16 Embedding 鉴权或配置错误 直接失败,不做无意义重试,输出明确配置错误码
17 Embedding 数量不一致 不写入活动版本,清理候选向量并终止任务
18 Embedding 维度不一致 阻止写入原 collection,要求使用匹配的 Embedding profile 或新 collection
19 Qdrant 部分写入失败 使用确定性 point ID 幂等重试,避免产生重复向量
20 Qdrant 完全不可用 保留候选 Chunk,重试向量写入;超过次数后将候选版本标记失败
21 候选版本处理失败 只删除失败候选的 Chunk 和向量,当前活动版本继续提供检索
22 活动版本切换冲突 使用数据库锁和 CAS 重试;发现任务已过期则停止旧任务
23 切换成功但旧向量清理失败 保持新版本活动,任务进入 cleaning,由后台巡检继续清理
24 删除文件时 Qdrant 不可用 先写删除标记,使检索立即排除,再异步重试物理清理
25 检索时 Qdrant 超时 短暂重试;仍失败则向 tender-service 返回明确的检索不可用状态
26 查询 Embedding 失败 不调用 LLM,返回检索失败,避免助手在无知识上下文时自由回答
27 检索结果低于阈值 返回 no_reliable_context,由 AI 助手提示当前知识库没有可靠依据
28 Rerank 超时或失败 降级使用向量召回排序,不影响基础检索可用性
29 Context 超出 Token 预算 按最终分数和来源优先级裁剪,在段落边界截断
30 引用对应 Chunk 已失效 回表校验活动版本,丢弃失效结果;必要时扩大候选重新检索
31 PostgreSQL 与 Qdrant 不一致 定时核对活动 Chunk 与 point,清理孤儿向量或重新补写缺失向量
32 多次自动重试仍失败 进入 dead letter,保留任务阶段、错误码、最后异常和人工重试入口
33 服务重启后存在未完成任务 扫描 running/cleaning 任务,根据 heartbeat 和活动版本恢复或补偿
34 旧版本清理误操作风险 所有删除必须附带 source 和 version 条件,禁止仅按文件名或外部 ID 模糊删除
35 模型或切块策略升级 创建新候选版本重新索引,验证成功后切换,禁止直接覆盖原活动索引