2 文档、网页、数据库、代码库有什么区别
P0 · rag
🏷 标签:rag, data-sources, preprocessing, parsing
1️⃣ 考察意图
面试官想看你是否真正理解RAG系统的数据工程基础,而非只背概念。这是一道系统设计+工程取舍题,刁钻点在于:候选人常只回答“文档是文本、网页要清洗”这种表面区别,但面试官真正想听的是——不同数据源在解析复杂度、语义表示、检索策略上的根本差异,以及如何统一接入知识库。答好了能展示你对数据预处理、chunking策略、embedding适配的实战理解,证明你不是只会调API的“胶水工程师”。
2️⃣ 标准答
从RAG数据管线的视角,四种数据源的核心区别在于结构化程度、噪声类型、语义粒度,需要定制预处理和检索策略。
文档(PDF/Word/PPT)
- 特性:非结构化文本,含排版、表格、图片、页眉页脚等“伪结构”。
- 预处理:用PyMuPDF或pdfplumber提取文本,注意表格用camelot或tabula转为Markdown;Word用python-docx保留段落结构。坑:PDF常见“文本顺序错乱”(如多栏布局),解法是先用OCR(如Tesseract)做版面分析,再按阅读顺序重组。
- Chunking:按段落或语义边界(如章节标题)切分,用LangChain的RecursiveCharacterTextSplitter,chunk_size=500-1000,overlap=10-20%。取舍:小chunk提升检索精度但丢失上下文,大chunk保留语义但增加噪声——需根据下游任务调参。
- 检索:用BM25(k1=1.5, b=0.75)做稀疏检索,配合dense embedding(如bge-large)做混合检索,因为文档中专业术语多,BM25对精确匹配更鲁棒。
网页
- 特性:半结构化HTML,含导航、广告、评论等噪声,动态内容需JS渲染。
- 预处理:用BeautifulSoup或Readability提取正文,移除
<script>、<style>、<nav>标签;动态页面用Selenium或Playwright渲染后抓取。坑:单页应用(SPA)的URL不变但内容变,需监听DOM变化或使用API接口。 - Chunking:按
<h1>、<h2>等标题分割,保留层级结构(如Markdown标题语法),因为网页内容常是“主题-子主题”树状结构。 - 检索:优先用dense embedding,因为网页语言更口语化,稀疏检索易受停用词干扰;对新闻类网页,可加时间戳作为元数据过滤。
数据库
- 特性:结构化表格,数据精确但缺乏自然语言描述。
- 预处理:核心是Schema-to-Text映射——将表名、列名、外键关系转为自然语言描述(如“用户表包含用户ID、姓名、注册日期”)。坑:SQL查询结果需转成文本块,但直接拼接会丢失语义(如“SELECT *”返回1000行,不能全塞进embedding)。解法:用NL2SQL(如SQLCoder)先转查询,再对结果做摘要(如“最近10个订单的总金额为5000元”)。
- 检索:不直接embedding整表,而是用查询改写:用户问题→SQL→结果摘要→embedding。取舍:SQL查询精确但灵活度低,适合“事实型”问题(如“昨天销售额”),不适合“模糊搜索”(如“相关产品”)。
代码库
- 特性:结构化文本,含语法、缩进、注释,语义依赖函数名和变量名。
- 预处理:用tree-sitter解析AST(抽象语法树),提取函数、类、模块的签名和文档字符串;保留缩进和注释,因为Python的缩进有语义。坑:代码中变量名(如
x)无意义,需用docstring或类型注解补充语义。解法:对无注释代码,用CodeBERT生成摘要。 - Chunking:按函数或类切分,每个chunk包含签名+docstring+实现(约50-200行),因为检索时用户常问“如何实现某个功能”。
- 检索:用代码专用embedding模型(如CodeBERT、UniXCoder),因为通用模型对代码语义(如
for循环和while循环的等价性)理解差。取舍:代码检索需平衡“精确匹配”(如函数名)和“语义相似”(如“排序算法”匹配“quicksort”),建议用BM25+CodeBERT混合。
总结:四种数据源在解析复杂度(网页>文档>代码>数据库)、噪声类型(网页广告、文档排版、代码注释、数据库空值)、语义粒度(代码精确、文档模糊)上差异显著,需定制预处理和检索策略,但最终都需统一为“文本块+元数据”格式接入知识库。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从数据特性、预处理策略、检索适配三个层面回答。数据特性上,文档是非结构化文本,网页是半结构化含噪声,数据库是结构化表格,代码是语法结构化文本。预处理上,文档需解析格式和分块,网页要清洗HTML和渲染动态内容,数据库要Schema-to-Text映射,代码要AST解析和保留缩进。检索适配上,文档用BM25+混合检索,网页优先dense embedding,数据库用查询改写+摘要,代码用CodeBERT。总结一句:不同数据源在解析复杂度、噪声类型、语义粒度上差异显著,需定制管线但最终统一为文本块+元数据。”
4️⃣ 高频追问 & 应对
追问 1:如果用户同时查询文档和数据库,如何融合结果?
用多源检索融合:对文档用BM25+embedding得到top-k,对数据库用NL2SQL得到精确结果,然后统一排序。具体做法:将数据库结果转为文本块(如“订单#123:金额500元”),与文档块一起输入reranker(如Cohere rerank v3),按相关性分数排序。取舍:数据库结果精确但可能不相关(如用户问“推荐产品”,SQL返回“库存列表”),需加语义过滤;文档结果模糊但覆盖广。实际落地中,对“事实型”问题(如“价格”)优先数据库,对“探索型”问题(如“趋势”)优先文档。
追问 2:代码库中函数名是驼峰式(如getUserInfo),如何提升检索效果?
用代码语义增强:首先,对函数名做camelCase分词(如
getUserInfo→get user info),作为额外文本字段。其次,用CodeBERT的tokenizer保留代码语法(如def、return),但embedding时对变量名做mask(因为变量名常无意义)。坑:直接分词可能破坏语义(如getUserInfo和get_user_info等价),解法是用tree-sitter提取函数签名,再对签名做归一化(如统一为下划线命名)。实际中,对Python代码,用inspect模块获取函数注释,比纯函数名更鲁棒。
追问 3:网页中图片和表格如何处理?
图片用多模态模型(如GPT-4V或CLIP)生成描述文本(如“柱状图显示2023年销售额增长20%”),作为额外chunk嵌入;表格用camelot或pandas读取,转为Markdown格式(如“| 年份 | 销售额 |\n| 2022 | 100 |”),因为Markdown对embedding模型更友好。取舍:多模态模型成本高,只对关键图片(如数据图表)处理,装饰性图片(如logo)直接丢弃;表格转Markdown会丢失样式(如合并单元格),但语义保留足够。
5️⃣ 避坑 · 常见错误答法
- ❌ 说“文档用PDF解析器,网页用BeautifulSoup,数据库用SQL,代码用Git”这种工具罗列,无深度分析。✅ 正确切入:强调不同数据源在语义粒度上的差异(如代码的精确语义 vs 文档的模糊语义),以及对应的检索策略(代码用CodeBERT,文档用BM25+embedding)。
- ❌ 说“所有数据源都统一用embedding模型,因为向量检索最通用”。✅ 正确切入:指出embedding模型对代码和数据库的局限性(如代码变量名无意义、数据库数值字段无法embedding),需要混合检索或查询改写。
- ❌ 说“网页动态内容用requests就能抓,因为大多数网站是静态的”。✅ 正确切入:指出SPA(如React/Vue)和反爬机制(如Cloudflare)的坑,必须用Selenium或Playwright渲染,且需处理无限滚动和懒加载。
6️⃣ 简历呼应
- 如果你有RAG项目:从“多源知识库统一接入”角度切入,强调你如何设计数据管线处理PDF、网页、数据库,并对比不同chunking策略对检索效果的影响(如用RAGAS评估)。
- 如果你只做过传统NLP:用“文本分类 vs 数据预处理”类比迁移,强调你对不同文本结构(如HTML标签、代码语法)的解析经验,以及如何用规则+模型处理噪声。
- 如果你是校招无项目:聚焦论文复现,如引用“Dense Passage Retrieval”中关于文档分块和embedding的讨论,或“CodeBERT”中代码语义表示的方法,展示你对数据源差异的理论理解。
- Dense Passage Retrieval (Karpukhin et al., 2020) – 文档分块与检索基础
- CodeBERT: A Pre-Trained Model for Programming and Natural Languages (Feng et al., 2020)
- WebSight: A Large-Scale Web Page Dataset for Visual Understanding (2023) – 网页预处理
- SQLCoder: Open-Source Text-to-SQL Model (Defog.ai, 2023)
- LangChain Document Loaders 文档 – 多数据源解析实战