构建LangChain应用程序的示例代码:38、自主RAG的概念及其实现方法,使用LangChain和OpenAI工具从头开始构建一个结合检索和生成的系统

# 安装必要的库
! pip install langchain_community tiktoken langchain-openai langchainhub chromadb langchain langgraph

自主RAG (Self-RAG)

自主RAG是最近的一篇论文,介绍了一种用于主动RAG的有趣方法。

该框架训练单个任意的语言模型(如LLaMA2-7b, 13b)来生成控制RAG过程的标记:

  1. 是否从检索器检索 - Retrieve

    • 标记:Retrieve
    • 输入:x (问题)x (问题), y (生成的回答)
    • 决定何时使用R检索D个片段
    • 输出:yes, no, continue
  2. 检索到的片段D是否与问题x相关 - ISREL

    • 标记:ISREL
    • 输入:(x (问题), d (片段)) 对于每个dD
    • d提供解决x的有用信息
    • 输出:relevant, irrelevant
  3. 每个片段D生成的LLM回答是否与片段相关(如幻觉等) - ISSUP

    • 标记:ISSUP
    • 输入:x (问题), d (片段), y (生成的回答) 对于每个dD
    • y (生成的回答)中所有需要验证的陈述都由d支持
    • 输出:fully supported, partially supported, no support
  4. 每个片段D生成的LLM回答是否对x (问题)有用 - ISUSE

    • 标记:ISUSE
    • 输入:x (问题), y (生成的回答) 对于每个dD
    • y (生成的回答)是否对x (问题)有用
    • 输出:{5, 4, 3, 2, 1}

我们可以将其表示为一个图:

在这里插入图片描述

论文链接:https://arxiv.org/abs/2310.11511


让我们使用LangGraph从头开始实现这个过程。

检索器 (Retriever)

让我们索引三个博客文章。

from langchain.text_splitter import RecursiveCharacterTextSplitter  # 从LangChain导入递归字符文本分割器
from langchain_community.document_loaders import WebBaseLoader      # 从LangChain Community导入网页基础加载器
from langchain_community.vectorstores import Chroma                # 从LangChain Community导入Chroma向量存储
from langchain_openai import OpenAIEmbeddings                      # 从LangChain OpenAI导入OpenAI嵌入# 定义需要索引的博客文章URL列表
urls = ["https://lilianweng.github.io/posts/2023-06-23-agent/","https://lilianweng.github.io/posts/2023-03-15-prompt-engineering/","https://lilianweng.github.io/posts/2023-10-25-adv-attack-llm/",
]# 加载每个URL的文档内容
docs = [WebBaseLoader(url).load() for url in urls]
# 将嵌套的文档列表展开为单个列表
docs_list = [item for sublist in docs for item in sublist]# 使用递归字符文本分割器将文档分割成大小为250字符的块,且块之间没有重叠
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(chunk_size=250, chunk_overlap=0
)
doc_splits = text_splitter.split_documents(docs_list)# 将分割后的文档添加到向量数据库
vectorstore = Chroma.from_documents(documents=doc_splits,            # 输入分割后的文档collection_name="rag-chroma",    # 指定集合名称embedding=OpenAIEmbeddings(),    # 使用OpenAI嵌入
)# 将向量存储转化为检索器
retriever = vectorstore.as_retriever()

状态

我们将定义一个图。

我们的状态将是一个字典。

我们可以从任何图节点访问它,使用 state[‘keys’]。

from typing import Dict, TypedDictfrom langchain_core.messages import BaseMessageclass GraphState(TypedDict):"""Represents the state of an agent in the conversation.Attributes:keys: A dictionary where each key is a string and the value is expected to be a list or another structurethat supports addition with `operator.add`. This could be used, for instance, to accumulate messagesor other pieces of data throughout the graph."""keys: Dict[str, any]

节点和边

每个节点将简单地修改状态。

每条边将选择下一个要调用的节点。

我们可以将自助RAG表示为一个图:
在这里插入图片描述

import json
import operator
from typing import Annotated, Sequence, TypedDictfrom langchain import hub
from langchain.output_parsers import PydanticOutputParser
from langchain.output_parsers.openai_tools import PydanticToolsParser
from langchain.prompts import PromptTemplate
from langchain_community.vectorstores import Chroma
from langchain_core.messages import BaseMessage, FunctionMessage
from langchain_core.output_parsers import StrOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.runnables import RunnablePassthrough
from langchain_core.utils.function_calling import convert_to_openai_tool
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langgraph.prebuilt import ToolInvocation### 节点 ###def retrieve(state):"""检索文档参数:state (dict): 代理当前的状态,包括所有键。返回:dict: 向状态添加新键,documents,包含检索到的文档。"""print("---RETRIEVE---")state_dict = state["keys"]question = state_dict["question"]documents = retriever.invoke(question)return {"keys": {"documents": documents, "question": question}}def generate(state):"""生成答案参数:state (dict): 代理当前的状态,包括所有键。返回:dict: 向状态添加新键,generation,包含生成的答案。"""print("---GENERATE---")state_dict = state["keys"]question = state_dict["question"]documents = state_dict["documents"]# 提示模板prompt = hub.pull("rlm/rag-prompt")# LLM模型llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)# 后处理def format_docs(docs):return "\n\n".join(doc.page_content for doc in docs)# 链rag_chain = prompt | llm | StrOutputParser()# 运行generation = rag_chain.invoke({"context": documents, "question": question})return {"keys": {"documents": documents, "question": question, "generation": generation}}def grade_documents(state):"""确定检索到的文档是否与问题相关。参数:state (dict): 代理当前的状态,包括所有键。返回:dict: 向状态添加新键,filtered_documents,包含相关文档。"""print("---CHECK RELEVANCE---")state_dict = state["keys"]question = state_dict["question"]documents = state_dict["documents"]# 数据模型class grade(BaseModel):"""相关性检查的二进制评分。"""binary_score: str = Field(description="相关性评分 'yes' 或 'no'")# LLM模型model = ChatOpenAI(temperature=0, model="gpt-4-0125-preview", streaming=True)# 工具grade_tool_oai = convert_to_openai_tool(grade)# LLM与工具绑定并强制调用llm_with_tool = model.bind(tools=[convert_to_openai_tool(grade_tool_oai)],tool_choice={"type": "function", "function": {"name": "grade"}},)# 解析器parser_tool = PydanticToolsParser(tools=[grade])# 提示模板prompt = PromptTemplate(template="""你是一个评估员,正在评估检索到的文档与用户问题的相关性。\n 这是检索到的文档:\n\n {context} \n\n这是用户问题:{question} \n如果文档包含与用户问题相关的关键词或语义,请将其评为相关。\n给出一个二进制评分 'yes' 或 'no',表示文档是否与问题相关。""",input_variables=["context", "question"],)# 链chain = prompt | llm_with_tool | parser_tool# 评分filtered_docs = []for d in documents:score = chain.invoke({"question": question, "context": d.page_content})grade = score[0].binary_scoreif grade == "yes":print("---GRADE: DOCUMENT RELEVANT---")filtered_docs.append(d)else:print("---GRADE: DOCUMENT NOT RELEVANT---")continuereturn {"keys": {"documents": filtered_docs, "question": question}}def transform_query(state):"""转换查询以生成更好的问题。参数:state (dict): 代理当前的状态,包括所有键。返回:dict: 保存新问题到state。"""print("---TRANSFORM QUERY---")state_dict = state["keys"]question = state_dict["question"]documents = state_dict["documents"]# 创建一个包含格式指令和查询的提示模板prompt = PromptTemplate(template="""你正在生成针对检索进行优化的问题。\n 查看输入并尝试推理其潜在的语义意图。\n 这是初始问题:\n ------- \n{question} \n ------- \n形成一个改进的问题:""",input_variables=["question"],)# 评分模型model = ChatOpenAI(temperature=0, model="gpt-4-0125-preview", streaming=True)# 提示模板chain = prompt | model | StrOutputParser()better_question = chain.invoke({"question": question})return {"keys": {"documents": documents, "question": better_question}}def prepare_for_final_grade(state):"""准备进行最终评分,状态透传。参数:state (dict): 代理当前的状态,包括所有键。返回:state (dict): 代理当前的状态,包括所有键。"""print("---FINAL GRADE---")state_dict = state["keys"]question = state_dict["question"]documents = state_dict["documents"]generation = state_dict["generation"]return {"keys": {"documents": documents, "question": question, "generation": generation}}### 边 ###def decide_to_generate(state):"""决定是生成答案还是重新生成问题。参数:state (dict): 代理当前的状态,包括所有键。返回:dict: 向状态添加新键,filtered_documents,包含相关文档。"""print("---DECIDE TO GENERATE---")state_dict = state["keys"]question = state_dict["question"]filtered_documents = state_dict["documents"]if not filtered_documents:# 所有文档在检查相关性时都被过滤掉了# 我们将重新生成一个新查询print("---DECISION: TRANSFORM QUERY---")return "transform_query"else:# 我们有相关文档,所以生成答案print("---DECISION: GENERATE---")return "generate"def grade_generation_v_documents(state):"""确定生成的回答是否基于文档。参数:state (dict): 代理当前的状态,包括所有键。返回:str: 二进制决策评分。"""print("---GRADE GENERATION vs DOCUMENTS---")state_dict = state["keys"]question = state_dict["question"]documents = state_dict["documents"]generation = state_dict["generation"]# 数据模型class grade(BaseModel):"""相关性检查的二进制评分。"""binary_score: str = Field(description="支持评分 'yes' 或 'no'")# LLM模型model = ChatOpenAI(temperature=0, model="gpt-4-0125-preview", streaming=True)# 工具grade_tool_oai = convert_to_openai_tool(grade)# LLM与工具绑定并强制调用llm_with_tool = model.bind(tools=[convert_to_openai_tool(grade_tool_oai)],tool_choice={"type": "function", "function": {"name": "grade"}},)# 解析器parser_tool = PydanticToolsParser(tools=[grade])# 提示模板prompt = PromptTemplate(template="""你是一个评估员,正在评估答案是否基于/支持一组事实。\n 这里是事实:\n ------- \n{documents} \n ------- \n这是答案:{generation}给出一个二进制评分 'yes' 或 'no',表示答案是否基于/支持一组事实。""",input_variables=["generation", "documents"],)# 链chain = prompt | llm_with_tool | parser_toolscore = chain.invoke({"generation": generation, "documents": documents})grade = score[0].binary_scoreif grade == "yes":print("---DECISION: SUPPORTED, MOVE TO FINAL GRADE---")return "supported"else:print("---DECISION: NOT SUPPORTED, GENERATE AGAIN---")return "not supported"def grade_generation_v_question(state):"""确定生成的回答是否解决了问题。参数:state (dict): 代理当前的状态,包括所有键。返回:str: 二进制决策评分。"""print("---GRADE GENERATION vs QUESTION---")state_dict = state["keys"]question = state_dict["question"]documents = state_dict["documents"]generation = state_dict["generation"]# 数据模型class grade(BaseModel):"""相关性检查的二进制评分。"""binary_score: str = Field(description="有用评分 'yes' 或 'no'")# LLM模型model = ChatOpenAI(temperature=0, model="gpt-4-0125-preview", streaming=True)# 工具grade_tool_oai = convert_to_openai_tool(grade)# LLM与工具绑定并强制调用llm_with_tool = model.bind(tools=[convert_to_openai_tool(grade_tool_oai)],tool_choice={"type": "function", "function": {"name": "grade"}},)# 解析器parser_tool = PydanticToolsParser(tools=[grade])# 提示模板prompt = PromptTemplate(template="""你是一个评估员,正在评估答案是否有助于解决问题。\n 这是答案:\n ------- \n{generation} \n ------- \n这是问题:{question}给出一个二进制评分 'yes' 或 'no',表示答案是否有助于解决问题。""",input_variables=["generation", "question"],)# 提示模板chain = prompt | llm_with_tool | parser_toolscore = chain.invoke({"generation": generation, "question": question})grade = score[0].binary_scoreif grade == "yes":print("---DECISION: USEFUL---")return "useful"else:print("---DECISION: NOT USEFUL---")return "not useful"

Graph

import pprintfrom langgraph.graph import END, StateGraph# 定义工作流状态图
workflow = StateGraph(GraphState)# 添加节点
workflow.add_node("retrieve", retrieve)  # 检索
workflow.add_node("grade_documents", grade_documents)  # 评估文档
workflow.add_node("generate", generate)  # 生成答案
workflow.add_node("transform_query", transform_query)  # 转换查询
workflow.add_node("prepare_for_final_grade", prepare_for_final_grade)  # 准备最终评分,透传状态# 构建图
workflow.set_entry_point("retrieve")  # 设置入口点为检索节点
workflow.add_edge("retrieve", "grade_documents")  # 检索后接评估文档节点
workflow.add_conditional_edges("grade_documents",decide_to_generate,{"transform_query": "transform_query",  # 评估文档后,根据决定转到转换查询或生成答案节点"generate": "generate",},
)
workflow.add_edge("transform_query", "retrieve")  # 转换查询后返回检索节点
workflow.add_conditional_edges("generate",grade_generation_v_documents,{"supported": "prepare_for_final_grade",  # 生成答案后,根据决定转到准备最终评分或重新生成答案"not supported": "generate",},
)
workflow.add_conditional_edges("prepare_for_final_grade",grade_generation_v_question,{"useful": END,  # 准备最终评分后,根据决定结束或返回转换查询"not useful": "transform_query",},
)# 编译工作流
app = workflow.compile()
# 导入 pprint 模块,用于美化打印输出
import pprint# 定义输入,包含一个问题
inputs = {"keys": {"question": "Explain how the different types of agent memory work?"}}# 运行编译好的工作流应用
for output in app.stream(inputs):# 遍历每个节点的输出for key, value in output.items():# 打印节点名称pprint.pprint(f"Output from node '{key}':")pprint.pprint("---")# 打印输出的详细信息pprint.pprint(value["keys"], indent=2, width=80, depth=None)# 打印分隔符,区分不同节点的输出pprint.pprint("\n---\n")
import pprint# 定义输入,包含一个问题
inputs = {"keys": {"question": "Explain how chain of thought prompting works?"}}# 运行编译好的工作流应用
for output in app.stream(inputs):# 遍历每个节点的输出for key, value in output.items():# 打印节点名称pprint.pprint(f"Output from node '{key}':")pprint.pprint("---")# 打印输出的详细信息pprint.pprint(value["keys"], indent=2, width=80, depth=None)# 打印分隔符,区分不同节点的输出pprint.pprint("\n---\n")

扩展知识

1. RAG (Retrieval-Augmented Generation)

RAG是一种结合了检索和生成的技术,首先从一个大型文档集合中检索相关内容,然后使用生成模型基于这些内容生成回答。这种方法能够有效结合外部知识库和生成模型的能力,提高回答的准确性和信息丰富性。

2. LangChain

LangChain是一个用于构建语言模型应用的框架,支持多种文档加载、文本分割、嵌入计算和向量存储方式。它简化了从数据准备到模型应用的整个流程。

3. OpenAI

OpenAI提供了强大的语言模型如GPT-3和GPT-4,这些模型能够理解和生成自然语言文本,广泛应用于各种NLP任务,如问答、翻译、文本生成等。

4. Chroma

Chroma是一个高效的向量数据库,支持快速的向量检索,常用于结合嵌入技术进行相似性搜索。它在处理大型文档集合时表现出色。

总结

在本文中,我们介绍了自主RAG的概念及其实现方法,使用LangChain和OpenAI工具从头开始构建一个结合检索和生成的系统。通过对多个博客文章进行索引和处理,我们展示了如何利用这些工具进行高效的信息检索和回答生成。本文还补充了相关的技术知识,帮助读者更好地理解和应用这些技术。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/859584.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高清录屏软件哪个好用?分享这3款录屏软件

在我们的日常生活和工作中,视频录制是我们经常需要使用到的功能。不仅可以帮助我们录制网课内容方便后期复习,还可以录制视频会议,记录上级指示,甚至可以通过录制一些视频教程或游戏视频上传网络进行分享。 对电脑屏幕进行录制&a…

【GD32F303红枫派使用手册】第二十四节 DHT11温湿度传感器检测实验

24.1 实验内容 通过本实验主要学习以下内容: DHT11操作原理 单总线GPIO模拟操作原理 24.2 实验原理 HT11是一款已校准数字信号输出的温湿度一体化数字传感器。该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点信号,传输距离可达20米以…

Codeforces Round 954 (Div. 3) (A~F)(不会数学)

A - X Axis 暴力枚举一下所有可能 void solve() {int a , b , c;cin >> a >> b >> c;int ans 100;for(int i 0 ; i < 10 ; i ){ans min(ans , abs(i - a) abs(i - b) abs(i - c));} cout << ans << endl; } B - Matrix Stabiliz…

【数据分享】2006-2023《中国贸易外经统计年鉴》

公众号新功能 目前公众号新增以下等功能 1、处理GIS出图、Python制图、区位图、土地利用现状图、土地利用动态度和重心迁移图等等 2、核密度分析、网络od分析、地形分析、空间分析等等 3、地理加权回归、地理探测器、生态环境质量指数、地理加权回归模型影响因素分析、计算…

硬件开发笔记(二十):AD21导入外部下载的元器件原理图库、封装库和3D模型

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/139707771 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

webpack【实用教程】

基础配置 配置的拆分和合并 通常 webpack 的配置文件会有3个 webpack.common.js 公共配置&#xff08;会被另外两个配置文件导入并合并&#xff09;webpack.dev.js 开发环境的配置webpack.prod.js 生产环境的配置 开发环境的本地服务 在 webpack.dev.js 中配置 devServer:…

使用鸿蒙HarmonyOs NEXT 开发b站的卡片效果 手把手教学

资源准备&#xff1a; 需要4张图片&#xff1a;分别是页面图&#xff0c;播放图标&#xff0c;评论图标&#xff0c;更多图标 1.实现效果显示&#xff1a; 2.教学视频&#xff1a; 使用鸿蒙HarmonyOs NEXT 开发b站卡片_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1…

Huffman树——AcWing 148. 合并果子

目录 Huffman树 定义 运用情况 注意事项 解题思路 AcWing 148. 合并果子 题目描述 运行代码 代码思路 其它代码 代码思路 Huffman树 定义 它是一种最优二叉树。通过构建带权路径长度最小的二叉树&#xff0c;经常用于数据压缩等领域。 运用情况 在数据压缩中&a…

【机器学习】半监督学习可以实现什么功能?

目录 一、什么是机器学习二、半监督学习算法介绍三、半监督学习算法的应用场景四、半监督学习可以实现什么功能&#xff1f; 一、什么是机器学习 机器学习是一种人工智能技术&#xff0c;它使计算机系统能够从数据中学习并做出预测或决策&#xff0c;而无需明确编程。它涉及到…

Java研学-RBAC权限控制(八)

九 登录登出 1 登录作用 判断员工是否有权限访问&#xff0c;首先得知道现在操作的人是谁&#xff0c;所以必须先实现登录功能 2 登录流程 ① 提供登录页面&#xff0c;可输入用户名与密码信息&#xff0c;并添加执行登录的按钮。&#xff08;登录页面不能被拦截&#xff09;…

意识清晰,对答如流,但手脚活动受限 是脊髓损伤?

在医学领域&#xff0c;有一种情况常常令人困惑&#xff1a;患者意识清醒&#xff0c;交流无碍&#xff0c;但手脚的活动却受到限制。这种情况可能源于多种原因&#xff0c;其中之一就是脊髓损伤。本文将对脊髓损伤进行科普&#xff0c;帮助大家更好地理解这一复杂的医学问题。…

AIGC技术的发展现状与未来趋势探讨

AIGC技术的发展现状与未来趋势探讨 随着人工智能&#xff08;AI&#xff09;技术的迅猛发展&#xff0c;AI生成内容&#xff08;AI-Generated Content&#xff0c;AIGC&#xff09;成为了一项颠覆性的技术&#xff0c;它能够自动生成文本、图像、音频和视频等多种内容。本文将…

示例:推荐一个基于第三方QRCoder.Xaml封装的二维码显示控件

一、目的&#xff1a;基于第三方QRCoder.Xaml封装的二维码控件&#xff0c;为了方便WPF调用 二、效果如下 功能包括&#xff1a;背景色&#xff0c;前景色&#xff0c;中心图片设置和修改大小&#xff0c;二维码设置等 三、环境 VS2022 四、使用方式 1、安装nuget包&#xf…

数据可视化期末总结

期末考试重点&#xff08;世界上最没意义的事情&#xff09; 选择 p8 数据可视化的标准&#xff1a; 实用、完整、真实、艺术、交互&#xff08;性&#xff09; p21 色彩三属性 色相、饱和度、亮度 p23 视觉通道的类型&#xff1a; 记得色调是定性 p39 散点图&#xff08;二维…

Kotlin 运行代码片段多种方式

目录 场景描述 一、Scratch files and worksheets in the IDE 1、Scratch files(草稿文件) 特点&#xff1a; Scratch files文件创建步骤&#xff1a; 功能解释&#xff1a; Scratch Buffer笔记文件&#xff1a; 2、Worksheets(工单) 1&#xff09;、创建方式不同。 …

国内有哪些比较优秀的wordpress主题?

WordPress作为全球最受欢迎的开源内容管理系统之一&#xff0c;拥有众多优质的主题供用户选择。那么国内有哪些比较优秀的wordpress主题呢&#xff1f;下面小编就和大家分享国内功能比较完善比较受欢迎的wordpress主题。 wordpress主题合集&#xff1a;WP主题-办公人导航https:…

浅析缓存技术

缓存技术的原理 缓存技术通过在内存中存储数据副本来加速数据访问。当应用程序需要数据时&#xff0c;首先检查缓存是否存在数据副本&#xff0c;如果有则直接返回&#xff0c;否则再从原始数据源获取。这种机制大大减少了访问时间&#xff0c;提升了系统的响应速度和整体性能。…

利用Frp实现内网穿透(docker实现)

文章目录 1、WSL子系统配置2、腾讯云服务器安装frps2.1、创建配置文件2.2 、创建frps容器 3、WSL2子系统Centos服务器安装frpc服务3.1、安装docker3.2、创建配置文件3.3 、创建frpc容器 4、WSL2子系统Centos服务器安装nginx服务 环境配置&#xff1a;一台公网服务器&#xff08…

centos7 根目录扩容

1、先检查一下磁盘空间 [rootlocalhost ~]# lsblk 二、使用fdisk创建新分区 [rootlocalhost ~]# fdisk /dev/vdb 1、输入 p &#xff0c;查看当前分区表&#xff1b; 2、输入 n &#xff0c;新建一个分区&#xff1b; 3、再输入 p &#xff0c;选择分区类型为主分区&#x…

智能化改造助力企业高质量发展

引言 背景介绍 在当今全球经济环境中&#xff0c;变化和不确定性已成为常态。企业面临的竞争压力不断增加&#xff0c;市场竞争日益激烈。新兴市场的崛起、技术进步和消费者需求的快速变化&#xff0c;使得传统的商业模式和生产方式面临巨大挑战。为了在这样的环境中保持竞争力…