当前位置: 首页 > news >正文

RAG架构原理和LangChain方式实现RAG

文章目录

  • 参考文档
  • 一 RAG
  • 二 LangChain方式实现RAG
    • 2.1 环境准备
    • 2.2 整体思路
    • 2.3 代码实践
      • 2.3.1 milvus
      • 2.3.2 详细步骤和完整代码

参考文档

  • Agentic RAG 架构的基本原理与应用入门

一 RAG

  • Retrieval-Augmented Generation (RAG\检索增强生成) 是帮助大模型更好地回答问题的一种方式。RAG旨在为大模型灵活的提供外部知识库支持,以拓展大模型知识边界。
  • RAG(检索增强生成)技术就能派上用场。它的作用就是从这些文档中找到最相关的信息,然后利用大模型生成精准的回答。简单来说,RAG 就是帮助大模型‘找到’并‘利用’最相关的信息来回答你的问题,就像一个聪明的助手快速翻阅资料给你最合适的答案。

在这里插入图片描述

  • RAG能够实现的原因是实验论文证明,当为大模型提供一定的上下文信息后,其输出会变得更稳定。传统RAG的方法是将知识库中的信息或掌握的信息先输送给大模型,再由大模型服务用户。
  • 传统的对话系统、搜索引擎等核心依赖于检索技术,如果将这一检索过程融入大模型应用的构建中,既可以充分利用大模型在内容生成上的能力,也能通过引入的上下文信息显著约束大模型的输出范围和结果,同时还实现了将私有数据融入大模型中的目的,达到了双赢的效果。
  • 从技术实现细节上,RAG的实现是包括两个阶段的:检索阶段和生成阶段。在检索阶段,从知识库中找出与问题最相关的知识,为后续的答案生成提供素材。在生成阶段,RAG会将检索到的知识内容作为输入,与问题一起输入到语言模型中进行生成。
    在这里插入图片描述
  • 将外部文本相关信息作为Prompt的一部分输入给大模型的原因:
  1. 如果用户提出的问题,其对应的答案出现在一篇文章中,但是将检索到的这整篇文章直接放入Prompt中并不是最优的选择,因为其中包含非常多无关的信息,而无效信息越多,对大模型后续的推理影响越大。
  2. 任何一个大模型都存在最大输入的Token限制,如果将一整个文本去全部传入大模型,无法容纳如此多的信息。

  • RAG构建的关键,则是由检索组件(通常由Embedding模型和向量数据库组成)和生成组件( 大模型 )组成。在推理时,用户查询用于对索引文档运行相似性搜索,以检索与查询最相似的文档,并为大模型提供额外的上下文。
  • 实现RAG系统主要有三种方式:手动实现、框架实现和手动+框架结合的方式。通常,90%以上开发者会选择灵活性和高效的手动+框架结合的方式。
    在这里插入图片描述

二 LangChain方式实现RAG

2.1 环境准备

  1. OpenAI中转 API Key
  2. Python环境
  3. 正常网络环境
  4. LangChain框架
  5. milvus

2.2 整体思路

  • 简易RAG实现思路。
    在这里插入图片描述

2.3 代码实践

  1. 安装langchain框架
pip install langchain langchain_community PyPDF2 langchain_milvus langgraph

2.3.1 milvus

  • 打开milvus,正常注册登录,创建向量库。
  • 详细操作文档参看2.3 存入向量数据库小节
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 注意复制连接用户名称、密钥、网址、向量库名称。例如。上图中的重要信息如下:
向量库名称:langChainRag
网址:https://in03-3eff8663c0e2d4d.serverless.aws-eu-central-1.cloud.zilliz.com
用户名称:xxx
密钥:xxx

2.3.2 详细步骤和完整代码

  1. 在构建 RAG系统的过程中,第一步是从文档中提取有用的信息。通过使用 PyPDF2 库的 PdfReader 类来实现从 PDF 文件中提取文本。
  2. 加载Embedding模型,对文本进行切分和向量化。
  3. 使用向量化数据库存储向量化后的切分文本。
  4. 构建Prompt和接入大语言模型,完成完整的问答流程。
from PyPDF2 import PdfReader
from langchain_core.documents import Document
from langchain_text_splitters import RecursiveCharacterTextSplitterdef pdf_read(pdf_doc):text = ""for pdf in pdf_doc:pdf_reader = PdfReader(pdf)for page in pdf_reader.pages:text += page.extract_text()return text
# 返回值content将包含该 PDF 文件的所有文本内容。
content = pdf_read(['./data/凡人修仙传第一章.pdf'])
# Document 对象,其属性 page_content 被设置为之前从 PDF 文件中提取的文本 content。
documents = [Document(page_content=content)]chunk_size = 600
chunk_overlap = 200
# 使用 LangChain 的 RecursiveCharacterTextSplitter根据指定的块大小和重叠部分将文档文本分割成多个较小的部分,完成文本切分。
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap
)# 切分
splits = text_splitter.split_documents(documents)
# print(splits)from langchain_openai import OpenAIEmbeddings
import os
os.environ["USER_AGENT"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
API_KEY = "hk-xxx";
BASE_URL = "https://api.openai-hk.com/v1";
os.environ["OPENAI_API_KEY"] = API_KEY
os.environ["OPENAI_API_BASE"] = BASE_URLembeddings = OpenAIEmbeddings(model="text-embedding-3-small",
)text = "第一章山边小村 \n 二愣子睁大着双眼,直直望着茅草和烂泥糊成的黑屋顶,身上盖着的旧棉被,已呈深黄色。"single_vector = embeddings.embed_query(text)
# print(str(single_vector))  # 显示前词向量的表示 1536维度from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import WebBaseLoader
from langchain_milvus import Milvus# 添加到向量数据中
vectorstore = Milvus.from_documents(documents=splits,collection_name="langChainRag",embedding=embeddings,connection_args={"uri": "https://xxx.serverless.aws-eu-central-1.cloud.zilliz.com","user": "db_xxx","password": "xxx",}
)# 接入LLM测试
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessagefrom langchain.prompts import PromptTemplate
from langchain import hub
from langchain_core.output_parsers import StrOutputParsermodel = ChatOpenAI(model="gpt-4o-mini")# 提示词模板
prompt = PromptTemplate(template="""你是一个智能问答助手. 使用以下检索到的上下文片段来回答问题。 如果你不知道答案,直接说不知道即可。最多用三句话,回答要简明扼要:问题: {question} 内容: {context} 回答: """,input_variables=["question", "documents"],
)# 构建传统的RAG Chain
rag_chain = prompt | model | StrOutputParser()
# 问题
question = "韩立是的名字是谁起的?"
# 构建检索器
retriever = vectorstore.as_retriever(search_kwargs={"k": 1})# 执行检索
docs = retriever.invoke("question")
print(docs)
  • 运行结果:
    韩立的名字是他的父亲求村里老张叔给起的。老张叔是村里唯一的读书人,曾经认识几个字。韩立被朋友们称为“二愣子”,但这只是个绰号。
    
http://www.dtcms.com/a/298532.html

相关文章:

  • 【正点原子K210连载】第二十一章 machine.UART类实验摘自【正点原子】DNK210使用指南-CanMV版指南
  • MyBatis-Plus 指南
  • 网络安全入门第一课:信息收集实战手册(3)
  • @ControllerAdvice相关知识点,和@Controller有什么区别
  • “八卦”简读
  • 手语式映射:Kinova Gen3 力控机械臂自适应控制的研究与应用
  • Python HTML模块详解:从基础到实战
  • 率先通过自动制冰性能认证,容声冰箱推动行业品质升级
  • TDengine 转化函数 TO_TIMESTAMP 用户手册
  • 原创-大型嵌入式软件架构设计指南:从理论到实践的完整方法论
  • WinUI3开发_过渡动画
  • 数据结构(3)单链表
  • 机器学习之knn算法保姆级教学
  • (三)Python基础入门-流程控制结构
  • 航段导航计算机 (Segment_Navigator) 设计与实现
  • 深入解析 ArkUI 触摸事件机制:从点击到滑动的开发全流程
  • 协作机器人掀起工厂革命:码垛场景如何用数据重塑制造业命脉?
  • SEO实战派白杨SEO:SEO中说的框计算、知心搜索(知识图谱)是什么?有什么用处?
  • SpringBoot配置外部Servlet
  • TQZC706开发板教程:创建PCIE项目
  • LoRA、ControlNet与T2I Adapter的区别
  • HTTP 请求方法有哪些?
  • 如何用豆包一键P图,一键生成装修图
  • Qt 与 C++11/14/17 新特性结合应用
  • 深入理解Linux底层文件操作:write、read、open、close、lseek和ioctl命令详解
  • OpenCV摄像头打开及预览
  • 告别文件传输焦虑,FileLink 让数据流转更简单
  • [MMU] Table walk flow详解
  • ‌通向数字孪生的大门:掌握RVT到3DTiles的关键转换流程
  • 函数-变量的作用域和生命周期