本章摘要 构建一个能够进行“深度研究”的智能体,远比搭建一个简单的问答机器人复杂。它需要处理长达数百页的非结构化 PDF(包含双栏排版、跨页表格、复杂图表),需要在海量噪声中提取“原子级证据”,更需要像人类分析师一样处理相互冲突的信息,并生成带有精确引用的专业报告。 核心差异:
- Search (搜索):找到包含关键词的片段。
- Research (研究):阅读 理解 关联 验证 综合 撰写。
学习目标
- 构建一套视觉优先(Vision-First)的多模态文档解析流水线,解决 PDF “解析即损失”的难题。
- 掌握分层索引(Hierarchical Indexing)与假设性问题(Hypothetical Questions)嵌入策略。
- 设计多智能体协作流:规划员(Planner)、搜集员(Collector)与主笔者(Writer)。
- 实现零幻觉引用系统:确保生成的每一句话都能通过超链接回溯到原始 PDF 的具体坐标。
DeepResearch 任务通常始于一个宏大的、非结构化的问题,终于一份结构化的、可验证的交付物。
| 维度 | 普通 RAG (Q&A) | DeepResearch Agent |
|---|---|---|
| 输入 | “Model Y 的续航是多少?” | “分析 2024 年固态电池技术突破及其对电动车成本结构的影响。” |
| 数据源 | 单一文档或短文本 | 20+ 份 PDF(财报、白皮书、论文),混合图与数据表。 |
| 推理深度 | 单步检索(Single-hop) | 多步推理(Multi-hop)、跨文档比较、时序分析。 |
| 输出 | 一段话答案 | 包含摘要、目录、数据图表、带有精确引用的 3000 字报告。 |
| 容错率 | 容忍少量概括 | 零容忍:数据必须与原始报表一致,引用不可造假。 |
PDF 是为打印而生的格式,不是为机器阅读而生的。
为了解决上述挑战,不能仅依赖 PyPDF2 或 LangChain 的默认 Loader。我们需要构建一个像人类一样“看文档的流水线。
graph TD;
A[原始 PDF] --> B{视觉版面分析 VLA};
B -- 文本区域 --> C[OCR / 文本提取];
B -- 表格区域 --> D[表格结构化处理];
B -- 图表区域 --> E[多模态图表摘要];
B -- 标题/页码 --> F[元数据过滤];
C & D & E --> G[逻辑重组器];
G --> H[多模态分块 (Chunks)];
(注:此处使用文字描述逻辑,实际文档中可使用上述逻辑)
处理流程详解:
Header, Footer, Text, Title, Table, Figure, Caption。Caption(图注)与对应的 Figure(图片)绑定,否则图片将失去语境。工程陷阱 (Gotcha): 页眉页脚的干扰。每一页重复出现的 “Confidential - Project X” 会严重干扰向量检索(Retriever 认为所有页面都高度相关)。 解决方案:用版面分析的 BBox 坐标,物理剔除页面顶部和底部的 10% 区域,或通过正则去重。
简单的 Chunk size = 500 切分策略在 DeepResearch 中是灾难性的。我们需要保留语境。
我们需要建立三层索引:
Original Text + Augmented Data。在 Agent 的工作记忆中,不要存储大段文本,而是存储标准化的“证据原子”。
{
"evidence_id": "ev_8a7b2c",
"content": "2023年Q4,公司毛利率下降至18.5%,主要受锂价波动影响。",
"source_doc": "financial_report_2023.pdf",
"page_num": 42,
"bbox": [100, 200, 500, 300], // 在原图上的坐标,用于高亮显示
"timestamp": "2023-12-31", // 用于时序冲突仲裁
"confidence": "high" // 来源于官方财报 vs 第三方博客
}
DeepResearch 任务过于复杂,单一 Prompt 容易导致上下文溢出或逻辑混乱。推荐采用 Map-Reduce 变体架构。
vector_search, keyword_search, read_full_page。timestamp 和 source_reliability,决定采信哪一个,或在报告中注明差异。如何保证 [1] 真的对应那一句话?
[ID: doc1_p5] content...
[ID: doc2_p8] content...Generated: 2023年销量创新高 [doc1_p5],但利润率有所下滑 [doc2_p8]。[doc1_p5] 替换为可点击的数字 [1],并生成对应的悬浮窗或侧边栏链接。DeepResearch 经常遇到新旧数据打架的问题。
Data_Timestamp 排序,取最新。Date。如果 PDF 没有明确日期,尝试从文件名或第一页提取。Q1. 版面感知的 Token 优化
场景:你有 100 份 PDF,全部转图片喂给 GPT-4o 极其昂贵。但是你又不想放弃图表信息。 问题:设计一个具体的过滤算法,在进入 VLM 之前,筛选出真正“值得看”的页面或区域。
点击查看提示
提示:大多数 PDF 页面是纯文字。纯文字用 OCR 就够了,不需要 VLM。你需要一个轻量级分类器。 </details>
点击查看参考答案
策略:分级漏斗 (Tiered Funnel)
- L0 (Layout Detection): 使用轻量级模型 (如 YOLOv8-nano, CPU 可运行) 扫描页面。
- 判别逻辑:
- 如果页面只包含
Text类:走 OCR 通道(成本 0)。- 如果页面包含
Chart,Table类将该区域(BBox)裁剪出来。- L1 (Vision Processing): 仅将裁剪下来的
Chart/Table图片发送给 VLM。- 效益:通常 PDF 中图表区域仅占总面积的 5%-10%,此法可节省 90% 的 Vision Token 成本。
</details>
Q2. 表格的 Markdown 还原
场景:OCR 提取的表格变成了乱序的字符串。 问题:请写出一段 Prompt,指导 VLM 将一张表格截图转换为结构完美的 Markdown,并处理“合并单元格”这一棘手情况。
点击查看提示
提示:你需要显式地告诉模型如何处理空缺值,以及当一个单元格跨越多行时该怎么做。 </details>
点击查看参考答案
Prompt 示例: “You are a data entry expert. Convert the provided table image into a Markdown table. Rules:
- Preserve all headers exactly as shown.
- Handling Merged Cells: If a cell spans multiple rows (vertically merged), repeat the value in each row. Do not leave it empty.
- If a cell is visually empty but implies a value from above (ditto), fill it.
- If the image is blurry, output
[UNREADABLE]for that cell.- Output ONLY the markdown text.”
</details>
Q3. 引用 ID 的持久化
场景:Writer Agent 生成了初稿,包含
[doc_id_123]。然后 Editor Agent 进行了润色,删减了一些段落。 问题:如何确保最终输出的参考文献列表(Bibliography)只包含正文中实际保留下来的那些引用?点击查看提示
提示:这类似于编程中的“垃圾回收(GC)”机制。 </details>
点击查看参考答案
流程:
- 全集维护:在 Context 中维护一个字典
Reference_Dict = {id: metadata},包含所有检索到的证据。- 正则扫描:在 Editor Agent 输出最终文本后运行正则匹配
\[doc_id_([a-z0-9]+)\]。- 重构列表:提取所有命中的 ID,从
Reference_Dict中取出对应条目,生成最终的参考文献列表。- 重编号:将正文中的 UUID
[doc_id_123]替换为阅读顺序的[1],[2]…,同时更新底部的列表。</details>
Q4. 跨页表格的“缝合手术”
场景:一个长表格从第 10 页底部延伸到第 11 页顶部。第 11 页的部分没有表头(Headers),只有数据。单独看第 11 页无法理解每一列的含义。 问题:设计一个算法逻辑,自动检测并修复这种跨页表格。
点击查看提示
提示:你需要关注页面底部的 Layout 元素和下一页顶部的 Layout 元素。 </details>
点击查看参考答案
逻辑流程:
- 检测断裂:若 Page N 的最后一个元素是
Table且未合(没有底部边框或 Footer 阻隔),且 Page N+1 的第一个元素是Table且没有Header。- 上下文注入 (Context Injection):
- 提取 Page N 表格的 Header 区域图片。
- 在处理 Page N+1 的表格截图时,将 Page N 的 Header 图片拼接在顶部(Vision 层面拼接),或者在 Prompt 中输入提取出的 Header 文本。
- 合并输出:告诉模型“这是上一页表格的延续,请使用相同的列结构解析数据”。
</details>
Q5. “幻觉引用”的红队测试 (Red Teaming)
场景:你需要构建一个自动评测脚本,专门抓包 Agent 瞎编引用的情况。 问题:给定 (生成的句子 S, 引用来源原文 P),如何判断 S 是否忠实于 P?请描述这个验证器的逻辑。
点击查看提示
提示:这本质上是一个自然语言推理(NLI)任务。 </details>
点击查看参考答
验证器设计 (Verifier):
- 原子化:提取句子 S 中的核心主张 (Claim)。
- 召回原文:根据引用 ID 获取原始片段 P (Ground Truth)。
- NLI 判别:调用一个小模型(如 GPT-4o-mini),Prompt 为: “Premise: {P} Hypothesis: {S} Does the premise entail the hypothesis? Options: [Entailment (支持), Contradiction (矛盾), Neutral (无关)]”
- 判定:
- Entailment: 通过。
- Contradiction: 严重错误(篡改数据)。
- Neutral: 幻觉(原文没提这事)。
</details>
Q6. 开放思考:多模态“大海捞针”
场景:用户问:“这款发动机的扭矩曲线在多少转达到峰值?” 答案不在文字里,而在第 50 页的一张无标题的图片曲线图中。 问题:普通的 RAG 根本检索不到这张图(因为没有文本匹配)。如何设计索引让 Agent 能找到它?
点击查看提示
提示:你不能检索像素。你必须把“视觉特征”翻译成“可检索的文本”。 </details>
点击查看参考答案
方案:Dense Captioning + Hypothetical Questions
- 预处理:对文档中所有 Chart 运行 VLM。
- 提取内容:不仅生成 Caption,还要提取数据特征。
- Caption: “Engine torque vs RPM curve chart.”
- Data Features: “Peak torque approx 400Nm at 3500 RPM. Drops to 300Nm at 6000 RPM.”
- 假设性提问:让 LLM 基于图表内容生成问题:”What is the peak torque RPM?”
- 索引:将 “Peak torque 3500 RPM” 和生成的“问题”存入向量库。
- 检索:用户的提问将直接匹配到这些隐式生成的文本,从而“捞”出这张图。
</details>
1,000 经常被 OCR 识别为 l,000 或 I,000。