链载Ai

标题: 数据工程:RAG系统的基石 [打印本页]

作者: 链载Ai    时间: 1 小时前
标题: 数据工程:RAG系统的基石

前言

检索增强生成(Retrieval-Augmented Generation, RAG)系统通过结合外部知识源与大型语言模型(LLM)的生成能力,旨在提供更准确、更具上下文感知能力的回答。我们在之前的“Agentic RAG”文章中详细介绍了RAG从Naive RAG到Agentic RAG的发展过程。

一个优秀的RAG系统必定是个复杂的系统,这涉及到诸多层面的因素考量,宏观层面,从索引、检索、到增强,最后大模型进行输出,每一个环节都非常重要。每个环节都有对应的技术选型,如Embedding模型、向量数据库、Rerank模型、到最后的LLM。搭建一个简单的RAG问答系统很简单,借助AI,一句话就可以帮你生成:

importosfromlangchain_community.document_loadersimportTextLoaderfromlangchain_text_splittersimportRecursiveCharacterTextSplitterfromlangchain_openaiimportOpenAIEmbeddings,ChatOpenAIfromlangchain_community.vectorstoresimportFAISSfromlangchain_core.promptsimportChatPromptTemplatefromlangchain_core.runnablesimportRunnablePassthroughfromlangchain_core.output_parsersimportStrOutputParser#---1.设置OpenAIAPI密钥---#确保你已经设置了环境变量OPENAI_API_KEY#或者直接在这里设置:#os.environ["OPENAI_API_KEY"]="YOUR_API_KEY"#---2.准备并加载文档---#假设你有一个名为my_document.txt的文件#你可以手动创建这个文件并添加一些文本内容withopen("my_document.txt","w",encoding="utf-8")asf:f.write("Langchain是一个强大的框架,用于构建基于大语言模型的应用程序。\n")f.write("RAG系统结合了检索和生成的能力。\n")f.write("FAISS是一个高效的相似性搜索库。\n")f.write("OpenAI提供了先进的语言模型和嵌入模型。\n")loader=TextLoader("my_document.txt",encoding="utf-8")documents=loader.load()#---3.分割文档---text_splitter=RecursiveCharacterTextSplitter(chunk_size=500,chunk_overlap=50)texts=text_splitter.split_documents(documents)#---4.创建文本嵌入模型---#确保你的OPENAI_API_KEY环境变量已设置try:embeddings=OpenAIEmbeddings()exceptImportError:print("OpenAIEmbeddings未找到。请确保已安装langchain-openai并且OPENAI_API_KEY已设置。")exit()#---5.创建向量存储---#FAISS是一个内存中的向量数据库,你也可以选择其他的,比如Chroma,Pinecone等try:vectorstore=FAISS.from_documents(texts,embeddings)exceptExceptionase:print(f"创建向量存储时出错:{e}")print("这可能是因为OpenAIAPI密钥无效或网络问题。")exit()#---6.创建检索器---retriever=vectorstore.as_retriever(search_kwargs={"k":2})#检索最相关的2个文档块#---7.创建Prompt模板---template="""基于以下检索到的上下文来回答问题。如果你不知道答案,就说你不知道,不要试图编造答案。最多使用三句话,并保持回答简洁。上下文:{context}问题:{question}有用的回答:"""prompt=ChatPromptTemplate.from_template(template)#---8.创建大语言模型---llm=ChatOpenAI(model_name="gpt-3.5-turbo",temperature=0.7)#---9.创建RAG链---#LCEL(LangchainExpressionLanguage)的写法rag_chain=({"context":retriever,"question":RunnablePassthrough()}|prompt|llm|StrOutputParser())#---10.运行RAG链并提问---if__name__=="__main__":print("RAG系统已准备就绪。请输入你的问题:")whileTrue:user_question=input("你:")ifuser_question.lower()in["退出","exit","quit"]:breakifuser_question:try:response=rag_chain.invoke(user_question)print(f"AI:{response}")#如果想查看检索到的上下文内容,可以这样做:#retrieved_docs=retriever.invoke(user_question)#print("\n---检索到的上下文---")#fori,docinenumerate(retrieved_docs):#print(f"文档{i+1}:\n{doc.page_content}\n")exceptExceptionase:print(f"处理请求时发生错误:{e}")else:print("请输入一个问题。")

然而,这个简单RAG系统仅限于demo,真实的个人场景、企业场景,信息、数据、知识的处理和AI赋能要远比这复杂得多。LLM在做最后的输出时,本质上就是利用参考的知识片段作为提示词的一部分。数据的质量和组织方式直接决定了后续检索信息的关联性和准确性,进而对LLM生成内容的质量产生决定性影响。今天我们就来详细拆解下RAG的第一步,也是最关键的一步:数据工程。

一、数据加载

RAG 索引流程的第一步是从各种来源加载数据,这些数据可能是非结构化、半结构化或结构化的,确保数据准确、完整地被摄取,对于 RAG 的性能至关重要。

非结构化数据的挑战。对于非结构化数据格式,“数据加载”这一术语往往掩盖了一个复杂的、针对特定格式的子流程,该流程涉及多种专用工具(如 OCR、布局分析、表格提取、图像字幕生成)。此处的工程工作量不容小觑,一个通用的“加载器”不足以应对这些挑战:

处理半结构化与结构化数据。对于结构化/半结构化数据,核心困难不在于解析格式本身,而在于将其固有的结构(行、列、键、嵌套)转换为线性的文本表示(切片),同时保留语义含义,且不丢失关键的关系信息,以便 LLM 理解,这些数据格式及其特点:

二、数据清洗

数据清洗并非一次性的通用步骤,而是一个迭代过程,必须根据具体的数据源和 RAG 系统的目标进行调整。过度激进的清洗可能会移除重要的上下文线索。不同的数据类型和来源会有不同的“噪声”特征,数据清洗主要包含以下几个部分:

三、数据分块

大语言模型(LLM)存在上下文窗口限制,而更小、更集中的切片能提高检索精度,数据分块至关重要,切分策略的选择深刻影响检索效果和生成质量。

基本切分方法。基础切分方法易于实现,但它们往往是在计算效率和语义完整性之间进行权衡,主要缺点是可能导致语义碎片化:

高级与上下文感知切分方法。高级切分技术反映了从依赖表层句法线索(固定长度、句子终止符)到更深层次内容语义理解的根本转变。这需要更复杂的数据工程(将嵌入模型、NLP 库甚至 LLM 集成到切分流程中),但有望产生更高质量的切片:

切片与精度的权衡。不存在通用的“最佳”切片大小或重叠。具体方法必须根据数据特性、嵌入模型、检索策略、LLM 上下文窗口和特定任务需求进行调整,通常通过迭代评估来完成,主要的考量因素:

四、数据增强

除了基本的切分之外,还可以采用多种技术来丰富数据,以提高检索准确性并为 LLM 提供更好的上下文。这些技术通常涉及从切片本身或关于切片生成额外信息,缺点是增加了预处理成本。

丰富元数据。元数据是描述文档/切片的附加信息,例如来源、作者、创建/修改日期、关键词、主题、章节标题、页码、URL、内容类型标签。可以通过手动、基于规则或使用 NLP 技术(如命名实体识别 NER、主题建模)自动提取元数据;

语义增强。为每个切片生成简洁的摘要、为切片生成假设性问答对,语义增强旨在创建更丰富、更符合查询意图的数据表示,从而可能改善对细微信息或以非典型查询方式表达的信息的检索。

知识图谱。将信息表示为实体和关系,识别文本切片中提及的实体(人物、地点、组织、概念)、关系构成的图网络,允许查询针对特定实体来提高检索的精确性。

上下文检索。将特定于切片的解释性上下文,预置到每个切片,保留了切片与其更广泛的文档上下文之间的关系。

这些高级技术代表了从将切片视为孤立的词袋/词元串,转向将其表示为更大、结构化的知识网络中的组件的转变。这允许基于关系和规范实体进行更细致和精确的检索,而不仅仅是基于关键字或表面的语义相似性。

五、系统考量

RAG 数据工程并非静态的一次性构建。它们是“活的系统”,必须适应新的数据、不断变化的数据格式以及扩展需求。这从一开始就需要一种优先考虑适应性和演进式设计的架构方法。知识库很少是静态的;新文档会不断添加,现有文档会更新或过时。

许多核心索引步骤(如嵌入质量或切分策略的“可检索性”)的“黑箱”特性,使得必须通过间接评估来衡量其有效性。它们的有效性通常通过下游检索任务的性能来推断。这使得评估变得复杂且具有迭代性。建立一个监控、评估和迭代优化数据工程的框架也很关键:

六、总结

许多RAG系统挑战的根源在于将数据预处理视为简单的步骤序列,而不是一个复杂的软件工程和数据管理问题,后者需要严格的设计、测试和维护。识别并规避 RAG 索引设计与执行中的常见陷阱是有必要的:

最后,回到索引这个模块,RAG 索引的未来趋势是更加动态、多模态和智能化。当前的 RAG 索引主要是一个离线的批处理过程。未来的趋势指向“实时 RAG”,需要对索引进行动态更新。“多模态内容”意味着索引需要处理图像、视频、音频,而不仅仅是文本。结合了关键字、语义和图搜索的“混合模型”意味着更复杂、多层面的索引。这些趋势共同指向一个与检索甚至生成阶段更深度集成、更自动化,并且能够处理数据类型和语义关系方面更大复杂性的索引阶段。这将进一步放大 RAG 中数据工程的重要性和难度。

END






欢迎光临 链载Ai (https://www.lianzai.com/) Powered by Discuz! X3.5