做RAG项目做得越多,我越觉得一个容易被忽略但是决定成败的问题是:你的数据到底长什么样。很多团队上来就选框架、配向量库、调Embedding模型,折腾半天发现效果很差,回头一看,问题出在数据形态没盘清楚。RAG的全称是Retrieval-Augmented Generation,检索增强生成,听到“检索”两个字,人很容易默认想到向量检索,但实际上不同类型的业务数据,对应的检索方式、存储结构、解析策略甚至评估口径完全不一样。所以我想从“数据类型”这个最底层的视角,把RAG从头到尾重新拆一遍。
这篇文章适合正在做RAG落地、被知识库效果困扰的工程师,也适合刚入门RAG,想建立整体认知的人。我会从数据形态出发,讲清楚为什么数据类型会决定RAG方案架构,再结合检索、解析、切分、评测这些实操环节,补上我在项目里踩过的坑和总结出来的经验。内容尽量不绕弯子,能直接落到代码和配置层面的,我都会写清楚。
1. RAG 的真正起点:先认清你的数据长什么样
1.1 数据类型决定 RAG 的架构选型
我在很多分享里反复强调过一个观点:RAG难点从来不在大模型的调用上,而在数据侧。数据侧的第一步,不是清洗、不是切分,而是先做类型识别。很多团队拿到的数据是几百个PDF和Word文档,以为这就是全部,结果做完了才发现,真正高频被问到的数据在Excel里,或者在内部系统的数据库里。数据形态不同,RAG的方案几乎是完全不同的技术栈。
从数据结构维度,我习惯把RAG的数据分成四类:非结构化文本数据,比如文档、PDF、网页正文;结构化表格数据,比如Excel、CSV、关系型数据库里的表;图结构数据,强调实体与关系的知识图谱;以及代码类数据,比如源码、API文档、配置文件。这四类数据,检索逻辑完全不一样。非结构化文本靠语义召回,靠切块和Embedding;表格数据靠自然语言转SQL或者转查询表达式;图数据靠图遍历,靠Cypher、SPARQL这类图查询语言;代码数据则要兼顾语法树结构和符号之间的引用关系。
所以当我听到有人说“我用RAG做了一个知识库”的时候,我第一反应永远是反问一句:你知识库里的数据,主要是哪一种类型?这个问题的答案,决定了你后面80%的技术决策。这也是为什么我认为“从数据类型出发理解RAG”不是一句空话,而是整个项目规划的原点。
1.2 非结构化文本数据:TextRAG 的典型通路
最常见的RAG形态是非结构化文本RAG,通常被称为TextRAG或VectorRAG。这类RAG的处理对象是自然语言文本。整个链路是:文档解析、段落切分、向量化、存储、召回、重排、拼接上下文、交给大模型生成答案。这条链路里最容易出问题的点是切分,很多人直接按固定长度暴力切分,比如每500个token切一块,结果把一个完整的意思拦腰截断,召回时上下文碎片化,答案质量断崖式下降。
更好的做法是结构感知切分,Markdown按标题切,PDF按章节标题和段落边界切,HTML按DOM结构切。市面上很多RAG框架,比如LlamaIndex和LangChain,都内置了这类NodeParser策略。但框架给的只是通用方案,真实项目里必须针对自己的文档结构做定制。我在一个法律合同项目中,把合同按“条款编号+条款标题”做递归切分,每一块尽量保持法律语义的完整性,召回准确率比纯按字数切要高很多。
1.3 结构化表格与数据库:TableRAG 与 NL2SQL 的战场
非结构化文本只是RAG的第一层。真实业务里大量高价值信息躺在表格和数据库里。比如财务数据、销售明细、用户表、订单表。表格数据跑了普通的文本切分,后果很惨:表头被切到一个chunk里,数值被切到另一个chunk里,检索时拿到的是断裂的单元格,大模型根本拼不出完整语义。
针对表格数据,行业里有几条主流路线。一类是TableRAG思路,把表格先做序列化描述,也就是把表头和示例行转成文本描述,再做向量化召回,最后把命中的表格片段交给模型生成回答。另一类是NL2SQL路线,也是我在这类项目里更推荐的做法:让大模型把用户问题转成SQL或查询表达式,直接在数据库里执行查询,拿到精确结果后,再让大模型组织自然语言回答。后者避免了把表拆碎的问题,因为它压根不切表,而是切“查询逻辑”。
这两种方案怎么选?如果表格本身不大、行数少、适合直接塞进上下文,用TableRAG序列化描述就够了;如果表格在真正的数据库里,数据量大、实时性要求高,那我建议直接上NL2SQL。这个时候你真正需要的是一个好的Schema设计和一个严格的SQL校验机制,防止生成非法查询。
1.4 图数据:Graph RAG 与 Ontology RAG 的进阶路线
当数据的价值更多体现在实体关系和多跳推理上时,比如“A公司和B公司之间通过C项目产生了什么关联”,纯向量检索的表现会非常吃力。因为向量检索擅长做相似匹配,不擅长做关系推理。这种情况下,Graph RAG开始发挥作用。
Graph RAG和TextRAG最大的区别在于,它先把非结构化文本中的实体和关系抽取出来,构建成知识图谱,存入图数据库,比如Neo4j、NebulaGraph,然后用图查询来回答问题。搜索热词里的ontology rag本质上是Graph RAG的进阶版:先定义好本体层,也就是实体类型、属性、关系类型,再按照本体去抽取和入库,保证知识图谱的schema一致性。
我自己做过一个企业供应链项目,数据散落在几百份供应商合同和审计报告里。业务方的问题经常跨多个实体,比如“某供应商的所有下游客户里,有多少家同时是我们的竞争对手”。这种问题用普通向量检索做,大模型只能凭上下文猜,但建了供应商、合同、客户、竞争对手四类实体和五类关系的图谱之后,一条Cypher查询就能精确回答。这类需求在实际业务里非常普遍,也是Graph RAG在目前RAG落地中最受关注的原因之一。
2. 从数据类型倒推检索与存储选型
2.1 Dense Vector Search 与密集向量检索的本质
RAG的主流召回方式是dense vector search,也就是密集向量检索。所谓密集向量,是Embedding模型把文本转换成几百甚至上千维的浮点向量,语义相近的文本在向量空间里距离更近。Vector Search做的是近似最近邻搜索,常用HNSW算法,用图索引加速查询。
提到dense vector,核心关键词是“语义相似度”。好处是能解决同义改写的问题,比如用户问“怎么退货款”,文档里写的是“退款流程”,两者字面完全不同,但语义接近,向量检索能匹配到。代价是Embedding模型分不清精确数值和逻辑条件。你问“去年销售额超过100万的客户有哪些”,向量检索根本没法做大于小于比较,这种查询必须走结构化检索。
这是我在项目里反复强调的边界:dense vector search适合“找相关内容”,不适合“算精确结果”。一旦问题里出现数值比较、条件过滤、聚合统计,就要考虑混合检索或NL2SQL方案了。很多RAG项目翻车,就是拿向量检索干结构化查询的活。
2.2 稀疏检索、BM25 与混合检索的配合逻辑
虽然向量检索是RAG的代名词,但我实际项目中几乎不会只跑向量检索。关键词精确匹配在很多场景里依然不可替代,尤其是人名、产品型号、合同编号、法律条文号这类专有名词。Embedding模型在这类精确标识符上经常表现不稳定,稍微改写一下就可能召不回。
所以我在生产环境里通常用混合检索:BM25稀疏检索加向量密集检索并行,再用RRF(Reciprocal Rank Fusion)或Rerank模型做结果融合。BM25是传统的词频统计检索算法,对精确词匹配非常友好;向量检索负责语义泛化。两者互补之后,召回率会比单一检索高出一大截。
热词里的embedding rerank就是这条链路的关键环节。Embedding负责初筛,Rerank模型负责精排。初筛阶段召回100条候选,Rerank阶段根据用户query与候选文档的相关性打分,拿出前5条。很多队伍到这一步就收工了,但我想多说一句:Rerank模型一定要和Embedding模型分家,不要用同一个模型既做召回又做排序。因为召回模型追求宽泛召回,排序模型追求精排区分度,两者目标不同,混用会两头不讨好。
2.3 图存储与向量检索的协同
在Graph RAG体系里,存储选型更复杂。图数据库负责存实体和关系,向量索引负责存实体的语义描述,两者之间需要协同。比较常见的做法是:图数据库里每个节点绑定一个embedding属性,用图数据库的向量索引插件做近邻搜索,或者把向量放到外部向量库,然后通过实体ID关联。
比如Neo4j从5.x版本开始内置了向量索引功能,可以把节点属性的embedding直接存入,然后跑kNN查询。实际项目中我更喜欢把向量索引和图形遍历分开,各司其职。第一步用向量召回实体种子节点,第二步沿着图结构做多跳扩展,第三步把扩展结果作为上下文。这种“先向量召回种子,再图遍历扩展”的混合方案,比纯粹依赖向量检索或纯粹依赖图查询都更稳健。
在这个架构里,还有一个索引一致性问题。业务系统的数据在变,图谱在变,向量索引也要跟着变。很多项目初期效果很好,跑了一个月后越来越差,就是因为增量更新没做好。所以从设计第一天,就必须把“哪个字段变化时需要更新哪个索引”这个映射关系定清楚。
2.4 不同类型数据映射到存储组件的实践思路
不同数据类型对应的存储组件,我列一个对照表,方便做技术选型的时候直接参考。
| 数据类型 | 检索方式 | 典型存储 | 适用场景 |
|---|---|---|---|
| 长文本/文档 | 向量检索+BM25混合 | Milvus、Qdrant、Elasticsearch | 合同、政策、FAQ知识库 |
| 短文本/问答对 | 向量检索 | 上述任意向量库 | 客服FAQ、操作手册 |
| 表格/数据库 | NL2SQL/查询表达式 | MySQL、PostgreSQL、DuckDB | 经营分析、财务数据查询 |
| 关系密集型文本 | 图遍历+向量召回 | Neo4j、NebulaGraph | 供应链风控、舆情分析 |
| 代码仓库 | AST解析+符号索引 | 自建索引+向量库 | 代码问答、API检索 |
Redis这类缓存型数据库在RAG里也在承担新角色,比如热词里的redis数据类型。很多团队用Redis存用户的会话上下文、缓存检索结果、管理rerank后的临时结果集。Redis的String、Hash、JSON等数据类型,与RAG的缓存策略结合得比较紧密,但要注意它不是主力存储,主检索还是得交给专业向量库。
3. 核心细节:类型转换、解析与切分的那些坑
3.1 文档解析中的“类型劫持”
很多人在做RAG项目时,会忽略一个前置问题:从文件里读出来的数据,真的是你以为的那个类型吗?以PDF为例,一个看起来是表格的PDF,可能实际上是由绝对坐标拼出来的文本框,并没有真正的表格结构。用普通的文本抽取工具,会把表格顺序完全打乱。热词里的“pandas 数据类型转换”和“python变量和数据类型”恰恰点出了这个问题的本质:数据从一种介质转换到另一种介质时,类型信息会发生丢失或畸变,必须做显式转换和校验。
我的处理惯例如下:PDF到文本,优先用PyMuPDF或paddleocr;表格抽取优先用Camelot或pdfplumber,抽取完后用pandas检查列数是否一致、缺失值比例是否异常,再做字段类型推断。数据库从MySQL同步到数据湖时,时间字段经常从datetime类型变成字符串,金额字段可能从decimal变成float,这些类型变化如果不提前识别,到RAG检索阶段就会出各种脏数据。
还有乱码问题。很多扫描版PDF没有文本层,直接抽出来的文本全是乱码,这种就必须走OCR,OCR完再做一次校对,否则会带着大量识别错误进入向量库,严重影响检索质量。这个过程费时费力,但它是RAG数据质量的生命线。
3.2 代码数据的类型意识与代码 RAG
代码类数据是RAG里比较特殊的一类。代码的语义高度结构化,依赖包导入、函数定义、变量作用域、类型声明。普通文档的切分策略用在代码上基本失效。把一份完整的Java类文件按固定长度切成几块,结果就是每个chunk里都是不完整的语法片段,检索出来根本没法直接用。
针对代码数据,我的建议是尽量用语法解析器生成AST(抽象语法树),以函数、类、方法为最小单元切分,保留文件路径、类名、函数签名等元信息。拿Java举例,用tree-sitter或JavaParser把源文件解析成语法树,按方法块与类块组织索引。这样用户问“某个REST接口的入参校验逻辑在哪里”,检索系统能准确定位到对应方法,而不是返回一大段无关代码。
热词里出现“codesys里_uxint是什么数据类型”“sv中的数据类型转换“java基本数据类型”这类问题,说明开发者群体对数据类型本身就有强烈的问答需求。代码RAG的落地方向之一,就是把这些数据类型、函数库、API文档做成一个可检索的开发者知识库,让大模型直接回答类型定义、转换规则这类开发问题。这种场景下,数据的“类型意识”从字面意义上就变得非常重要。
3.3 数据类型规范化:打通检索与推理的边界
做完解析,下一步就是数据规范化。数据规范化的核心是统一字段类型和命名规则。例如客户ID在合同文档里是字符串,在数据库里是bigint,在Excel里可能被读成了float,因为有缺失值,pandas会把整列推断为float。如果不做统一转换,后续检索和查询会遇到大量类型不匹配的报错,或者更隐蔽的,查询结果出现偏差。
我在项目里通常建一个数据字典,统一记录每个字段的物理类型、逻辑类型、取值范围和示例值。这个数据字典本身也是知识库的一部分,喂给大模型,可以让NL2SQL生成的查询更稳定。比如字段名叫created_at,我就不会让模型把它当成普通字符串去过滤。实际上,NL2SQL方案中很多生成SQL的报错,都是字段名或类型理解错误引起的,提前给模型一份清晰的Schema和数据字典,能大幅减少这类问题。
此外,热词里的agentic rag提示我们,新一代RAG不再是单次检索后直接回答,而是让大模型像Agent一样,根据问题自主规划检索步骤,必要时调用多个工具。这个过程中,数据类型的理解能力更加关键,因为Agent一旦误解了某个字段的类型或含义,后续的规划和工具调用全都是错的。所以在Agentic RAG项目中,我更强调先把数据类型和字段语义定义清楚,再让Agent去编排。
4. 实操过程:一个混合数据 RAG 项目的完整链路
4.1 项目需求与数据摸底
这里我拿一个做过的真实项目作为案例来讲。项目背景是某企业需要搭建一个内部采购制度问答系统,数据来源包括:几百份采购管理制度文档、一套ERP系统的物料主数据表、以及一份供应商风险等级的评分表。业务方希望员工用自然语言提问,系统能回答制度流程问题,也能查询物料的库存与供应商风险情况,典型的需求包括“某某物料的当前库存是多少”“采购金额超过50万的流程需要哪些审批节点”。
项目启动后,我做的第一件事就是数据摸底。我把所有数据源列成了清单,逐个标注数据格式、规模、更新频率、有没有结构化字段、文本里有没有图片或表格,然后按照前面说的四个数据类型做分类。结果发现,制度文档属于非结构化文本,物料主数据和评分表属于结构化表格。不同数据对应着完全不同的技术路线。
4.2 数据预处理与类型规范化
摸底之后,是繁琐但决定成败的预处理阶段。制度文档的预处理重点是清洗与切分。我用PyMuPDF抽取文本,过滤页眉页脚和重复的目录信息,再按章节结构切分,每段保留来源和章节号。针对文档中的表格,单独抽取出来转成文本描述,附在对应章节后面。
物料主数据的处理就不一样了。我先用pandas读取数据库表,检查字段类型。常见的问题是物料编码被Excel识别成科学计数法,导致精度丢失;部分日期字段是字符串格式,需要统一转换成datetime类型。我把物料编码统一降级成字符串,并加前导零补齐;金额字段统一转成decimal,避免浮点数比较误差。这一步做完之后,我对每一张表都生成了字段描述表,包括字段名、类型、单位、取值含义,这些后续都要交给大模型使用。
4.3 索引构建与检索链路配置
结构化数据和非结构化文本分开建立索引。制度文档的章节块,我用embedding模型(这里我们用的是bge-large-zh)转成向量,存入Milvus,同时把文本原文同步到Elasticsearch,做BM25索引,双路召回。物料数据和评分表,没有做向量化,而是保留在MySQL里,通过NL2SQL方式查询。
检索链路配置为:用户提问后,先经过一个查询分类器,判断是文档查询还是数据查询。文档查询走混合检索:向量与BM25同时召回,再用RRF融合,送入Rerank模型精排,最后把Top5拼进Prompt。数据查询则走NL2SQL:大模型根据表结构生成SQL,先做语法校验,再执行查询,把结果拼接成自然语言回答返回给用户。对于混合型问题,比如“某某物料的库存和采购制度是什么”,系统会同时触发两条链路,把结果合并后再回答。
4.4 回答合成与引用约束
最后一步是回答合成。这里有个我踩过很多次的坑:大模型很容易一本正经地编造引用。解决方案是做引用约束,要求模型在输出答案时,必须从上下文中摘取原始片段作为依据,如果没有找到对应内容,必须直接说“未找到相关信息”,而不能自行发挥。
我会在Prompt里明确给出格式约定,要求回答中每个关键结论后跟一个方括号引用标记,标记对应检索结果的编号。系统在最终展示时,根据编号把原文链接附在后面。这一步极大提升了业务方对系统的信任度。对数据查询类回答,我还会在Prompt后面附上一句提醒:如果数据查询结果为空,模型只能回答“查询无结果”,不允许猜测。这类约束写得越细,生产表现越稳。
5. 从数据类型视角看 RAG 失败模式与评估
5.1 RAG 测评怎么做:别只看最终答案对不对
热词里有“rag测评怎么做”“rag评估方案”,说明大家都在重视评估,但很多团队的评估方法太简陋。单纯让大模型对最终答案打一个分,完全不够。一套完整的RAG评估,至少应该分成检索评估和生成评估两层。
检索评估看召回质量,常用指标是Recall@K、MRR、命中率。我习惯的做法是维护一个标准问题集,每个问题标注正确的文档片段ID,然后测试在不同K值下系统能召回多少个正确片段。生成评估看端到端回答质量,用RAGAS这类框架做忠实度、相关性和答案正确性评分。此外我还会人工抽检bad case,尤其是推理型问题和多跳问题,因为这类问题最容易暴露出数据链路的缺陷。
在评估数据集构建上,有一个容易被忽视的点:必须按数据类型分层设计评测问题。文本类问题测语义召回,表格类问题测数值查询准确性,图类问题测多跳推理能力。如果混合在一起评估,某个环节的缺陷会被其他环节的成绩掩盖。
5.2 类型错位导致的典型 bad case
我在项目里整理过一批高频bad case,基本都是数据类型错位引起的。
第一种是文本和数值混用。用户问“上个月的采购总金额是多少”,系统误把这个问题交给了文档检索,结果回答了一段关于采购流程的文字,根本没有具体金额。这就是典型的query类型识别失败。
第二种是数值精度丢失。物料编码从Excel读入时被转成了科学计数法,导致下游匹配全部失效。或者是金额字段被转成float以后出现0.1加0.2不等于0.3的问题。这种问题在开发环境很难发现,因为数据量小,一旦上生产,匹配错误率和查询偏差就会集中爆发。
第三种是关系型问题被误判为相似性问题。用户问“A项目影响了哪些供应商”,如果系统只在文档片段里做向量检索,得到的一定是语义相似的内容,而不是真正的关联实体集合。正确答案应该通过图查询或结构化关联查询获得。这类问题的判定,需要跟业务方充分对齐,我会在项目一开始就建立类型判定清单,把常见的“关系型问题”模板识别出来。
5.3 常见问题速查与避坑记录
结合多个项目的经验,我把RAG中与数据类型相关的高频问题整理成一张速查表:
| 问题现象 | 根因 | 排查方向 |
|---|---|---|
| 检索结果语义对但数值错 | 数值被切分或类型转换异常 | 检查chunk切分边界,检查Excel/数据库字段类型 |
| 专有名词召回不到 | 向量检索对精确词不敏感 | 改用混合检索,加BM25 |
| 表格内容乱序 | PDF表格解析失败 | 换Camelot/pdfplumber做表格抽取,保留行列结构 |
| 查询SQL频繁报错 | Schema信息和数据类型未提供给模型 | 提供字段字典和示例SQL |
| 多跳推理答案零散 | 实体关系未建图 | 评估是否需要Graph RAG,构建实体关系抽取管线 |
| Rerank后效果反而变差 | 检索引擎分到了不同文本粒度 | 统一检索结果粒度,确保Rerank输入格式一致 |
这张表我建议参数团队在项目上线前逐条对照检查。很多时候RAG效果不好,不是大模型不够聪明,而是数据侧的隐性问题没暴露出来。从数据类型出发做一次系统体检,能少走很多弯路。
我个人在实际操作中还有一个比较深的体会:数据类型的梳理不是一次性的工作,而是需要持续维护的资产。随着业务扩展,新的数据源不断接入,类型体系必须同步演进。那些告诉我RAG项目上线后基本不用管了的团队,我基本都会劝一句,检索层的指标和bad case还是要有持续的监控机制,数据形态一变,整个链路的稳定性就得重新校准。这是我做了这么多项目之后最想留下的一个经验。