感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

用LLaMA3和LangChain搭建本地检索增强生成(RAG)代理

慕姐4208626
关注TA
已关注
手记 232
粉丝 5
获赞 38

使用LLaMA3构建本地RAG代理,展示RAG概念的示意图,由DALL·E 3提供。

在人工智能和机器学习的领域中,检索增强生成(RAG)获得了显著的关注和影响力,用于增强语言模型的能力。我们将使用LLaMA3和LangChain构建一个本地RAG代理,利用来自不同RAG论文的先进概念,创建一个灵活且能自我纠正的系统。我们将详细探讨技术细节,实施步骤,并提供示例来解释每一步骤。

背景与概览

检索增强生成(RAG)涉及通过从知识库检索相关信息来增强语言模型的响应。该过程结合了检索系统和生成模型的优点,以提供更准确和上下文合适回答。本教程结合了几篇 RAG 研究论文中的想法,构建了一个功能强大的 RAG 代理,具有以下特点:

1. 自适应路由: 根据问题的特点,将问题分配给不同的检索策略。

2. 纠正性回退: 如果初始文档检索未满足相关性要求,就转而使用网络搜索。

3.自我校正:调整并修正答案,避免胡说,确保答案准确相关。

搭建环境

首先,我们需要安装一些必要的库和工具。以下命令用于安装LangChain及其他依赖项:

pip install langchain
pip install -U langchain-nomic langchain_community tiktoken langchainhub chromadb langchain langgraph tavily-python nomic[local] langchain-text-splitters
设置本地模型

我们将使用LLaMA3作为我们的本地语言模型(LLM),并结合GPT4All的嵌入模型。通过运行以下命令来确保你已经安装了所需的模型:

    ollama pull llama3  # 拉取llama3模型  
    pip install langchain-nomic  # 安装langchain-nomic库
文档加载及索引

我们将从特定的URL加载文档,并把它们拆分成可管理的小块,以实现高效获取。

from langchain_community.document_loaders import WebBaseLoader  
from langchain_text_splitters import RecursiveCharacterTextSplitter  
from langchain_community.vectorstores import Chroma  
from langchain_nomic.embeddings import NomicEmbeddings  

urls = [  
    "https://example.com/post1",  
    "https://example.com/post2",  
    "https://example.com/post3",  
]  

docs = [WebBaseLoader(url).load() for url in urls] # 加载URL列表中的每个网页  
docs_list = [item for sublist in docs for item in sublist] # 将多维列表展平为一维列表  

text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(chunk_size=250, chunk_overlap=0) # 创建一个字符分割器,将文本分割成大约250字符的块  
doc_splits = text_splitter.split_documents(docs_list)  

vectorstore = Chroma.from_documents(  
    documents=doc_splits,  
    collection_name="rag-chroma",  
    embedding=NomicEmbeddings(model="nomic-embed-text-v1.5", inference_mode="local"),  
) # 创建一个Chroma向量存储  
retriever = vectorstore.as_retriever() # 获取检索器对象  
实施检索分级

我们确保找到的文档与查询相关,为此我们实现了一个检索评分系统:

    from langchain_community.chat_models import ChatOllama  
    from langchain_core.prompts import PromptTemplate  
    from langchain_core.output_parsers import JsonOutputParser  

    llm = ChatOllama(model="llama3", format="json", temperature=0)  

    prompt = PromptTemplate(  
        template="""system  
    你是一个评判检索文档与用户问题相关性的评委。若文档中出现与用户问题相关的关键词,则将其评为相关。这不需要是一个严格的测试。目标是筛选掉错误的检索结果。  
    请提供一个二进制评分 '是' 或 '否',以表示文档是否与问题相关。  
    请以一个只包含键 'score' 的 JSON 格式输出,无需任何额外说明。  
    user  
    这里是检索到的文档:\n\n {document} \n\n  
    这里是用户的问题:{question} \n assistant""",  
        input_variables=["question", "document"],  
    )  

    retrieval_grader = prompt | llm | JsonOutputParser()
自适应问题分配

系统根据问题内容决定是否使用向量存储查找或转而使用网页搜索。

    prompt = PromptTemplate(  
        模板为"""系统 你擅长将用户问题导向向量数据库或网络搜索。对于涉及LLM代理、提示工程和对抗性攻击的问题,请使用向量数据库。你不必严格匹配问题中的关键词。对于其他问题,请使用网络搜索。根据问题,给出二元选择 'web_search' 或 'vectorstore'。返回仅包含键 'datasource' 的JSON,无需前言或解释。问题:{question}""",  
        input_variables=["question"],  
    )  

    question_router = prompt | llm | JsonOutputParser()

生成并验证答案的有效性

一旦找到文档,系统就会生成答案并进行验证,以避免出错。

    prompt = PromptTemplate(  
        template="""系统 你是一个用于回答问题的任务助手。使用以下检索到的上下文来回答问题。如果你不知道答案,就说你不知道。最多三句话,保持简洁。  
        问题: {question}  
        上下文: {context}  
        回复: 助理""",  
        input_variables=["question", "context"],  
    )  

    rag_chain = prompt | llm | JsonOutputParser()

这生成的回答然后会被评价是否有幻觉内容,以及与问题的相关性。

    prompt = PromptTemplate(  
        template="""系统,你是一个评估答案是否基于一组事实的评分者。给一个“是”或“否”的二进制分数来表示该答案是否基于一组事实。仅提供一个仅包含一个键'score'的JSON格式的二进制分数,不附加任何说明。user  
        以下是事实:  
        \n ------- \n  
        {documents}  
        \n ------- \n  
        这是答案:{generation} assistant""",  
        input_variables=["generation", "documents"],  
    )  

    hallucination_grader = prompt | llm | JsonOutputParser()

利用LangGraph构建控制流程

最后,我们通过LangGraph把这些组件结合起来,形成一个控制流程。

    from langgraph.graph import END, StateGraph, START  

    class GraphState(TypedDict):  
        question: str  
        generation: str  
        web_search: str  
        documents: List[str]  

    workflow = StateGraph(GraphState)  

    workflow.add_node("websearch", web_search)  
    workflow.add_node("retrieve", retrieve)  
    workflow.add_node("grade_documents", grade_documents)  
    workflow.add_node("generate", generate)  

    workflow.add_conditional_edges(  
        START,  
        route_question,  
        {  
            "websearch": "websearch",  
            "vectorstore": "retrieve",  
        },  
    )  

    workflow.add_edge("retrieve", "grade_documents")  
    workflow.add_conditional_edges(  
        "grade_documents",  
        decide_to_generate,  
        {  
            "websearch": "websearch",  
            "generate": "generate",  
        },  
    )  
    workflow.add_edge("websearch", "generate")  
    workflow.add_conditional_edges(  
        "generate",  
        grade_generation_v_documents_and_question,  
        {  
            "not supported": "generate",  
            "useful": END,  
            "not useful": "websearch",  
        },  
    )  

    app = workflow.compile()

总结

我们这儿提供了一个详细的指南,教你如何用LLaMA3和LangChain来构建本地的RAG代理,整合了先进检索和生成技术。按照这些步骤做,你可以造出一个能准确回答复杂问题的强大系统。

示例查询语句

让我们用一个示例查询来测试系统:“智能代理有哪些类型的记忆?”

inputs = {"question": "什么是代理记忆的类型?"}  
for output in app.stream(inputs):  # app.stream(inputs) is a specific function that processes the inputs
    for key, value in output.items():  
        print(f"完成运行:{key}:")  # "print" is used similarly to "pprint" for displaying output
    print(value["生成"])  # "生成" is used for "generation" in this context

中文:
预期结果:

    根据提供的上下文,提到了几种不同类型的记忆:

1. 感觉记忆:这是记忆的最早阶段,能够保留感觉印象(如视觉、听觉等),即使在原始刺激结束后。

2. 最大内积搜索(MIPS):这是一个长期记忆模块,记录了代理人在自然语言中的全面列表。(最大内积搜索)

通过利用所讨论的概念和实现,你可以将这个框架扩展以适应各种应用场景,从而增强你的人工智能解决方案的能力和可靠性。

参考文献和资源:

简介 | 🦜🔗 LangChain

创建一个代理 | 🦜 LangChain

LangGraph 网站 (langchain-ai.github.io) 官方网站

奥拉玛(Ollama,https://ollama.com/

注意:只有在依赖库和API没有变化的情况下,代码才能正常运行。如果代码未按预期工作,你可能需要做一些必要的调整。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP