📰 来源:Towards Data Science | 📅 翻译日期:2026年5月30日
🔗 原文:查看原文
🤖 翻译:DeepSeek AI · 仅供参考
快速理解RAG的最短路径
快速理解RAG最快的方法就是构建最小可行版本,在真实文档上运行,然后仔细观察整个过程。这便是本文的内容。大约一百行Python代码(没有向量数据库,没有框架,没有智能体)运行在《Attention Is All You Need》论文上,返回带有确切来源高亮的答案。
然后我们回顾每个模块并问出它自然引发的问题,每个问题都是后续文章的主题。最小化流水线是尊重四个砖块并产生可验证答案的最少代码量。后续每篇文章都会在真实文档出现特定失败后添加团队所需的功能,而不是因为架构需要更多层次。
1. 我们构建的内容
流水线由四个砖块(第二部分会详细解释每个砖块)加上一个可选渲染步骤构成。每个砖块说明输入和输出;从一个砖块传递到下一个砖块的内容就是我们要保存的数据。
- 文档解析:接收PDF路径,返回
line_df(每行文本一条记录,包含page_num、line_num、text和边界框)以及page_df。最小化版本将两者保存在内存中;更大系统会持久化它们。 - 问题解析:将用户问题转换为
ParsedQuestion,包含标准化问题和一个简短的检查关键词列表。这个模块刻意保持狭窄:不包含检索逻辑或问题嵌入。 - 检索:接收
ParsedQuestion并输出top-k页码(以及必要时这些页内的匹配行号)。仅传递页码保持模块小巧;下一步从line_df现场重建过滤后的行。问题嵌入在这个砖块内,因为它依赖于语料库索引。 - 生成:将问题、
line_df和检索到的页码整合,生成AnswerWithEvidence:一个类型化的JSON,包含答案、证据范围(start_page、start_line、end_page、end_line)、置信度、理由、来源精确引用以及任何注意事项。完整的JSON值得保存用于评估、审计和重放。 - PDF标注(可选)。给定原始PDF和证据范围,它生成一个标注过的PDF,在引用的行周围绘制矩形。CLI工具、批处理作业或API消费者可以跳过这一步;因为生成后答案和引用已经完整。
前四个是四个砖块。PDF标注是渲染步骤,本身不是砖块。
基线RAG流水线,端到端(作者供图)
输入一个PDF和一个问题。每个砖块将其输入转换为更结构化的形式:文档解析将PDF转换为行,问题解析将问题转换为搜索关键词,检索将行缩减为几个页码,生成产生类型化答案,PDF标注将引用的行绘制回原始PDF。输出的不是聊天气泡,而是一个带来源的JSON答案和一个可以打开核对的高亮PDF。
依赖项极简:
pymupdf:将PDF解析为文本加位置信息;它返回的边界框用于在源页面上高亮答案。openai:LLM客户端;通过base_url,同一个库可以服务于Azure、OpenRouter、Ollama或任何兼容端点。pandas:以DataFrame形式保存文档,这是每个解析和检索步骤使用的格式。pydantic:定义答案模式,强制输出带引用的结构化JSON。
没有向量数据库,没有编排框架,没有专门的RAG库。后续文章会探讨这些库的辅助功能何时变得有用,以及何时会妨碍我们看清原理。
“对于一篇15页的论文,LLM可以通读全文。为什么还要检索?”对于这一篇文档来说确实有道理。我们用这篇论文来教学,而不是为了在这些15页中节省token。这个反对意见常指向大海捞针基准测试(Kamradt, 2023),前沿模型在从1Mtoken上下文中精确检索单个句子的任务中几乎完美得分。
该基准是研究,不是实践。一根针是一个孤立的、逐字匹配的事实,而企业级问题则是聚合(“所有免赔额超过€5,000的合同”)、比较(“这三张保单中的第12条款”)或跨多个段落总结。这些都不是要找到单个句子。
还有两个更实际的原因让检索保留在流水线中。企业文档通常很长:一份300页的保险合同,一份500页的监管申报文件,一卷多卷技术规范。将全部内容发送给LLM,每次提问、每次重跑、每个用户都要花费真实成本,并且会分散它对无关页面的注意力。
而且同一个问题可能同时跨成百上千份文档运行:“找到所有排除地震损坏的合同”、“总结今年所有申报文件中的监管变化”。在这种规模下,“一股脑全扔进去”就不再是策略了。检索正是让流水线能应对这两种变化的关键:从一篇短文到一份长合同,以及从单文档到整个语料库。
2. 四个砖块与PDF高亮
每个步骤声明其输入和输出,且各步骤相互独立。步骤N的输出是步骤N+1的输入,保存为命名的DataFrame,这样任何步骤都可以独立地对前一步的保存输出重新运行。在AI编码时代,当被告知“修复检索”时,一个助手可能会悄悄修改问题解析器,而它本应保持不变。独立的模块让你能放心地修改一个部分而不破坏其余部分。
下面设置了加载这些模块以及OpenAI客户端的代码块。
# 示例代码块(非原文完整代码)
import pymupdf
import openai
import pandas as pd
from pydantic import BaseModel(后续文章将详细展开每个砖块)
评论已关闭