Lazy loaded image
🤹创建一个拥有上下文记忆的RAG 链和agent应用 | 🦜️🔗 LangChain
Words 5506Read Time 14 min
2024-12-31
2024-12-31
type
status
date
slug
summary
tags
category
icon
password
comment
Status
创建一个拥有上下文记忆的RAG 链和agent应用_哔哩哔哩_bilibili
本视频中在RAG链式调用的基础上添加了整合历史消息的逻辑。然后构建了一个能够自主决定是否调用知识库查询工具的agent智能体。相关文档https://capricious-sesame-e56.notion.site/RAG-agent-LangChain-5bee3a6c760b4c5c818f76f12c2976b4?pvs=4代码仓库https://gitee.com/hi_tom/huia, 视频播放量 3204、弹幕量 0、点赞数 109、投硬币枚数 64、收藏人数 341、转发人数 37, 视频作者 小灰的AI笔记, 作者简介 探索AI的无限可能,相关视频:【2025大模型电影教程】桥本有菜(新有菜) 大模型学习路线 LLM+GPTo3+RAG+LangChain+Agent+Qwen,跟电脑F盘的女神一起操练—9,【全748集】目前B站最全最细的AI大模型零基础全套教程,2025最新版,包含所有干货!七天就能从小白到大神!少走99%的弯路!存下吧!很难找全的!,【2025大模型电影教程】桥本有菜(新有菜) 大模型学习路线 LLM+GPTo3+RAG+LangChain+Agent+Qwen,跟F盘的女神一起操练—11,【GraphRAG RAG LLM 小白电影教程——二部曲】三上悠亚大模型学习路线+langchain+Agent+Qwen,跟电脑F盘的女神一起操练起来—11,居然有比LangChain还好用的多Agent应用开发框架?,AI Agent教程2024年最新版,手把手带你从0→1构建一个独属于你的智能体!,第一个智能体|Coze AI|2025扣子手把手教程,基于LLamaindex轻松实现RAG多知识库智能问答,2025 年将是智能体(agent)爆发之年,扣子保姆级教程|超详细的AI应用搭建教程
创建一个拥有上下文记忆的RAG 链和agent应用_哔哩哔哩_bilibili
 
在许多问答形式的应用程序中,允许用户进行多轮对话,这意味着应用程序需要记忆过去问题和答案,并且按照一定的方法将它们整合到当前对话中。
在本指南中,我们着重添加整合历史消息的逻辑。有关聊天历史管理的更多细节,请参阅这里
我们将介绍两种方法:
  1. 链式方法,其中我们总是执行检索步骤;
  1. agent方法,在这种方法中,我们让LLM自行决定是否以及如何执行检索步骤(或多个步骤)。
对于外部知识来源,我们将使用同一篇文章,来自Lilian Weng的LLM动力自主代理博客,来自RAG教程

设置

依赖

我们将在本教程中使用OpenAI嵌入模型和Chroma矢量存储,但这里演示的所有内容都可以使用langchain提供的任何嵌入模型,VectorStore向量存储或Retriever检索器。
我们需要设置环境变量OPENAI_API_KEY,可以直接设置,也可以从.env文件中加载,方法如下:

LangSmith

使用LangChain构建的许多应用程序将都包含多个步骤和多次调用LLM调用。随着这些应用程序变得越来越复杂,能够检查chain或agent内部发生的细节变得至关重要。我们可以使用LangSmith查看应用程序的内部细节。
请注意,LangSmith并非必需,它只是在我们开发调试应用的时候非常有用。如果想使用可以在官网注册后申请秘钥,每个月都会有一定的免费使用额度,足够我们学习和测试,将key设置在的环境变量中就可以轻松使用LangSmith,

Chains

首先让我们看一下上一讲提到的问答应用,本地知识库的文章还是使用LLM Powered Autonomous Agents 这篇文章。
我们使用了内置的chain构造函数create_stuff_documents_chaincreate_retrieval_chainrag_chain 的组成成员:
  1. retriever检索器;
  1. prompt提示词模板;
  1. LLM。
这将简化合并聊天记录的过程。

添加历史对话

上面我们构建的链是使用输入问题来检索知识库相关的上下文,但在对话环境中,用户的问题可能是基于对话的上下文才。例如:
Human: "What is Task Decomposition?"
AI: "Task decomposition involves breaking down complex tasks into smaller and simpler steps to make them more manageable for an agent or model."
Human: "What are common ways of doing it?"
为了理解第二个问题,我们的应用需要理解 "it" 代指的是 "Task Decomposition."
We'll need to update two things about our existing app:
在我们现有的应用代码中我们需要更改两块内容:
  1. Prompt: 更新我们的提示词模板,去支持历史消息作为输入。
  1. Contextualizing questions(将问题放在上下文中重新表述): 添加一个子链,它获取最新的用户问题,并将其放在聊天记录的上下文中重新表述。这可以简单地被看作是构建一个新的“历史对话”的检索器。
之前的流程:
  • query -> retriever
之后的流程:
  • (query, conversation history) -> LLM -> rephrased query -> retriever

将问题放在上下文中重新表述

首先,我们需要定义一个子链,它接收历史消息和最新用户问题,并且如果问题中涉及历史信息,就重新表述问题。
我们将需要传入一个包含名为“chat_history”的 MessagesPlaceholder 提示词模板变量。这样,我们可以使用“chat_history”输入键将消息列表传递给提示词模板,并且插入这些消息在系统消息之后和最新问题之前。
我们在代码中使用了 create_history_aware_retriever 函数,组成的retriever链会依次调用 prompt | llm | StrOutputParser() | retriever。调用链需要传入 inputchat_history 参数,他的输出形式与retriever相同。
这个链中,在执行本地知识库检索器的前面,添加根据历史对话重新生成的问题表述,以便检索过程能够整合对话的上下文。
现在我们可以建立完整的问答链。只需要更新检索器为我们的新history_aware_retriever
我们还是使用 create_stuff_documents_chain 来生成一个 question_answer_chain,这个链其实只需要关注模型输入输出的内容,关于知识库具体的查询逻辑并不关心。需要传入的参数:知识库检索上下文 context, 历史对话chat_history 和输入问题 input
我们使用 create_retrieval_chain 方法构建最终的 rag_chain。构建方法需要传入history_aware_retrieverquestion_answer_chain 。调用rag_chain 时需要传入:问题input和历史对话chat_history,输出包括:问题input、历史对话chat_history、知识库检索到的上下文context和最终回答 answer
让我们尝试调用一下。下面我们提出一个问题和一个需要上下文的后续问题,看看是否能够返回正确的回答。
langsmith

聊天记录状态管理

上面我们介绍了如何向 rag_chain 中加入历史输出中,但我们仍然是手动更新聊天记录。在一个真正的问答应用程序中,我们希望有一种持久化聊天记录的方式,并且有一种自动插入和更新它的方式。
这里我们可以使用:
  • RunnableWithMessageHistory: 将 BaseChatMessageHistory 包装成可以加入rag_chain 链中的对象,实现自动将聊天记录注入到提示词模板,并在每次调用后更新聊天记录。
要详细了解如何添加的历史消息并加入链中的,可以查看具体的官方文档How to add message history (memory)
以下,我们使用将聊天记录存储在一个简单的字典 store 中。LangChain 也支持与Redis和其他技术的内存集成。
接下来,我们定义一个RunnableWithMessageHistory的实例来帮助管理聊天记录。他需要一个配置参数,使用一个键(默认为“session_id”)来指定要获取的对话历史,并将其添加到输入的问题之前,同时将模型的输出追加到相同的对话历史中。
我们可以查询一下字典:

整合

notion image
为了方便查看,我们整合一下上面的代码:
上面我们搭建好了一个拥有记忆功能并检索本地知识库的应用,但是这个问答应用不管我们询问什么问题都会检索本地知识库,其实我们在实际的使用过程中可能只有某几个相关的问题才有必要使用本地知识库检索,那我们能不能让大模型自己判断回答我们的问题是不是需要执行检索?

Agents 智能体

Agents智能体 可以利用LLM的推理能力在执行过程中做出决策。使用智能体可以让我们在检索过程中由大模型自主判断是否需要检索。尽管大模型的行为与定义好的链相比更加不可预测,但是这也提供了一些优势。
  • Agents智能体直接生成输入以供检索器使用,而不一定需要我们明确构建上下文;
  • 智能体可以根据情况查询执行多个检索步骤,或完全不执行检索步骤(例如,响应用户的问候语)。

Retrieval tool 检索器工具

Agents 可以访问并使用工具,我们将上面的本地知识库检索器 retriever 封装成智能体可以使用的工具。
定义好的工具实现了 Runnables 相关的接口,可以直接使用 invoke 等方法调用

构造 Agent智能体

现在我们已经定义了工具和大型语言模型(LLM),可以创建智能体。我们使用LangGraph来构建这个代理。目前,我们直接使用一个高级接口来构建智能体,但LangGraph的优势在于,这个高级接口背后有一个低级的、高度可控制的API,以便在需要时可以修改代理的逻辑。
LangGraph自带持久性功能,所以不需要使用 ChatMessageHistory 。我们可以直接将一个检查点器( checkpointer)传递给我们的LangGraph代理。
我们尝试执行一下agent,如果我们输入的查询不需要执行检索步骤,那么智能体就不会执行检索步骤。
此外,如果我们输入的查询需要执行检索步骤,agent将生成输入到工具中。
在上面的例子中,agent 并没有直接将我们的查询原封不动地插入到工具中,而是去除了像“what”和“is”这样的不必要的词汇。
这一相同的原则允许代理在需要时利用对话的上下文。
请注意,agent能够推断出我们查询中的“它”指的是“任务分解”,并因此生成了一个合理的搜索查询——在这个例子中是“任务分解的常见方法”。
langsmith

整合

总结

在本文中,在RAG链式调用的基础上添加了整合历史消息的逻辑。然后构建了一个能够自主决定是否调用知识库查询工具的agent智能体。
 
官网地址:
上一篇
创建检索增强生成(RAG)应用 | 🦜️🔗 LangChain
下一篇
构建一个基于SQL数据的问答系统 | 🦜️🔗 LangChain