本地大模型编程实战(19)RAG(Retrieval Augmented Generation,检索增强生成)(3)

上一篇文章我们演练了一个 langgraph 实现的 RAG(Retrieval Augmented Generation,检索增强生成) 系统。本文将要创建的系统将更加智能:如果在知识库中未找到靠谱的文档,则用 LLM(大语言模型) 自身的能力弥补。
另外,检索和生成部分增加了更多的细节控制。本次构建的 LangGraph 链如下图:
langgraph 链

如上图,query_or_respond 是一个条件节点,它通过能否根据用户的问题生成 工具调用(tool_calls) ,来判断是否需要检索矢量知识库:如果 工具调用 为空,则直接由大语言模型处理;否则通过 工具调用 调用 tools 进行检索。

使用 qwen2.5deepseek 以及 llama3.1 做实验,用 shaw/dmeta-embedding-zh 做中文嵌入和检索。

准备

在正式开始撸代码之前,需要准备一下编程环境。

  1. 计算机
    本文涉及的所有代码可以在没有显存的环境中执行。 我使用的机器配置为:

    • CPU: Intel i5-8400 2.80GHz
    • 内存: 16GB
  2. Visual Studio Code 和 venv
    这是很受欢迎的开发工具,相关文章的代码可以在 Visual Studio Code 中开发和调试。 我们用 pythonvenv 创建虚拟环境, 详见:
    在Visual Studio Code中配置venv

  3. Ollama
    Ollama 平台上部署本地大模型非常方便,基于此平台,我们可以让 langchain 使用 llama3.1qwen2.5deepseek 等各种本地大模型。详见:
    在langchian中使用本地部署的llama3.1大模型

创建矢量数据库对象

我们直接使用之前使用 chroma 创建好的本地嵌入数据库,它的数据源是一个 csv 文件,每一行包含了一种动物的信息,例如:

名称,学名,特点,作用
狗,Canis lupus familiaris,忠诚、聪明、社交性强,看家护院、导盲、搜救、警务、情感陪伴
猫,Felis catus,独立、高冷、善于捕鼠,消灭害鼠、陪伴、缓解压力

详细的创建过程可参见:本地大模型编程实战(14)初探智能体Agent(1)

embed_model_name = "shaw/dmeta-embedding-zh"
vector_store = Chroma(persist_directory=get_persist_directory(embed_model_name),embedding_function=OllamaEmbeddings(model=embed_model_name))

创建 LangGraph 链

在上一篇文章 RAG(Retrieval Augmented Generation,检索增强生成)(2) 中,我们将用户输入、检索到的上下文和生成的答案表示为状态对象中的单独键。
除了来自用户和AI的消息之外,还可以通过工具消息将检索到的文档内容合并到消息序列中,这样我们可以使用一系列消息来表示 RAG 应用程序的状态。具体来说,我们将:

  • 把用户输入作为 HumanMessage;
  • 把向量存储查询作为带有工具调用的 AIMessage;
  • 把检索到的文档作为 ToolMessage;
  • 最终响应作为 AIMessage。
    这种状态模型非常通用,因此 LangGraph 提供了一个内置版本以方便使用:
from langgraph.graph import MessagesState, StateGraph
graph_builder = StateGraph(MessagesState)

将检索步骤转化为工具

利用工具调用与检索步骤交互还有另一个好处,即检索查询由我们的大语言模型生成。这在对话环境中尤其重要,因为用户查询可能需要基于聊天记录进行情境化。例如,考虑以下交流:

Human:“什么是任务分解?”
AI:“任务分解涉及将复杂任务分解为更小、更简单的步骤,以使代理或模型更易于管理。”
Human:“常见的做法是什么?”

在这种情况下,模型可以生成查询,例如:任务分解的常见方法。
由于大语言模型在生成工具调用时会智能的生成查询,那么它将会明显提升查询的准确性。它还可以生成不涉及检索步骤的直接响应(例如,响应用户的一般问候),也可以自动进行指代消解:根据上下文自动修改问题,把问题中的代词替换成上下文中的内容。

下面我们基于 检索 生成一个 工具:

@tool(response_format="content_and_artifact",parse_docstring=True)      # docstring的内容对agent自动推理影响比较大
def retrieve(query: str):
    """检索与 query参数内容 相关的信息

    Args:
        query: 要搜索的字符串。 
    """

    print(f"start retrieve:{
     query}")

    # 定义相似度阈值。因为这种相似性检索并不考虑相似性大小,如果不限制可能会返回相似性不大的文档, 可能会影响问答效果。
    similarity_threshold = 0.8
    retrieved_docs = vector_store.similarity_search_with_score(query, k=3)

    # 根据相似度分数过滤结果
    filtered_docs = [
        doc for doc, score in retrieved_docs if score <= similarity_threshold
    ]

    serialized = "\n\n".join(
        (f"Source: {
     doc.metadata}\n" f"Content: {
     doc.page_content}")
        for doc in filtered_docs
    )

    if not serialized:
        return "抱歉,我找不到任何相关信息。", None
    else:
        <
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值