代理 RAG 系列:探索 LangGraph 高级工作流程

介绍

在上一篇文章中,我们介绍了Agentic RAG的概念,强调了它如何通过集成自主代理能力来扩展传统的检索增强生成(RAG)框架。在本期中,我们深入探讨LangGraph,一个用于协调逻辑工作流的创新框架。LangGraph使得创建具有复杂推理能力的多代理系统成为可能,是构建Agentic RAG架构的理想工具。

图片

图片

为什么选择 LangGraph 用于 Agentic RAG?

LangGraph 提供了一个强大的环境,用于创建有状态的工作流,在这里,代理可以在节点、工具和任务之间智能地互动。它与 LangChain 及其他先进的 AI 框架的兼容性,使得与检索和生成管道的无缝集成成为可能,这使其非常适合 Agentic RAG 的动态需求。

主要优势:

  1. \1. 工作流编排: 定义和管理具有条件逻辑和状态管理的多步骤工作流。
  2. \2. 工具集成: 轻松集成外部工具、API 和检索系统。
  3. \3. 可扩展性: 以最小的开销处理复杂的多代理工作流。
  4. \4. 灵活性: 设计能够动态适应上下文和输入的工作流。

LangGraph 架构用于 Agentic RAG

一个典型的 LangGraph 工作流用于 Agentic RAG 可能包括查询重写、文档检索、相关性评分和生成响应的组件。

流程图:Agentic RAG 中的 LangGraph 工作流程

[Start Query]
   |
   v
[Agent Node: Rewrite or Process Query]
   |
   +--> [Retrieve Documents: Knowledge Sources]
   |
   +--> [Grade Relevance]
   |
   +--> [Generate Response]
   |
   v
[End]
  • Start Query: 接收用户输入的查询。
  • Agent Node: 根据上下文和条件确定下一步。
  • Retrieve Documents: 从知识库中获取相关文档。
  • Grade Relevance: 对文档进行评分,以评估其与查询的上下文相关性。
  • Generate Response: 使用检索和处理的数据生成最终输出。

使用Agentic RAG对LangGraph进行基准测试

实验设置

  • 数据集: 研究论文、文章和常见问题的混合。
  • 评估指标: 相关性、准确性、响应时间和工作流程效率。
  • 基准: 传统 RAG 与使用 LangGraph 的 Agentic RAG。

结果:

图片

代码解释:

该代码定义了一个 文档问答助手,允许用户上传 PDF 文件、提供 URL 或两者兼而有之,然后询问有关这些文档内容的问题。它利用了 LangChain 框架LangGraphOllama API 进行嵌入和基于聊天的响应。助手是使用 Gradio 库 构建的,提供了一个易于使用的界面以与系统进行交互。

代码解析:

1. 导入

代码首先导入必要的模块:

  • LangChain 和 LangGraph:用于文档加载、向量存储创建、嵌入、消息处理和基于图的工作流程。
  • Gradio:用于构建用户友好的界面。
  • Pydantic:帮助定义和验证数据结构。
  • Validators:用于检查 URL 的有效性。
  • Tempfile:创建临时文件以处理 PDF 上传。
from langchain_community.document_loaders import WebBaseLoader, PyPDFLoader
from langchain_community.vectorstores import Chroma
from langchain_ollama import OllamaEmbeddings, ChatOllama
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.tools.retriever import create_retriever_tool
from typing import Annotated, Sequence, Literal
from typing_extensions import TypedDict
from langchain_core.messages import BaseMessage, HumanMessage
from langgraph.graph.message import add_messages
from langchain import hub
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langgraph.graph import END, StateGraph, START
from langgraph.prebuilt import ToolNode, tools_condition
from pydantic import BaseModel, Field
import gradio as gr
import tempfile
import validators
from io import StringIO

2. 数据结构

  • AgentState: 一个 TypedDict,用于跟踪代理的状态,特别是一系列消息。这用于在交互过程中维护对话上下文。
class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]

3. 处理来源

  • process_sources(urls=None, pdf_files=None):
  • • 接受 URL 和/或 PDF 文件作为输入。
  • • 对于 URL:
  • • 验证格式。
  • • 使用 WebBaseLoader 从网络加载文档。
  • • 对于 PDF:
  • • 暂时保存上传的文件。
  • • 使用 PyPDFLoader 将 PDF 解析为文档。
  • • 返回处理后的文档列表。
def process_sources(urls=None, pdf_files=None):
    """Process both URLs and PDF files"""
    docs_list = []

    # Handle URLs
    if urls and urls.strip():
        url_list = [url.strip() for url in urls.split(",")]
        for url in url_list:
            if validators.url(url):
                try:
                    url_docs = WebBaseLoader(url).load()
                    docs_list.extend(url_docs)
                except Exception as e:
                    print(f"Error loading URL {url}: {e}")

    # Handle PDFs
    if pdf_files:
        for pdf in pdf_files:
            try:
                with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp:
                    tmp.write(pdf.read())
                    loader = PyPDFLoader(tmp.name)
                    docs_list.extend(loader.load())
            except Exception as e:
                print(f"Error loading PDF: {e}")

4. 评分文档相关性

  • grade_documents(state):
  • • 确定文档是否与用户的查询相关。
  • • 使用 ChatOllama 和特定提示将文档评分为 yesno
  • • 提示要求模型评估文档内容是否与用户的问题一致。
def grade_documents(state) -> Literal["generate", "rewrite"]:
    print("---CHECK RELEVANCE---")

    classgrade(BaseModel):
        binary_score: str = Field(description="Relevance score 'yes' or 'no'")

    model = ChatOllama(temperature=0, model="llama3.2", streaming=True)
    llm_with_tool = model.with_structured_output(grade)

    prompt = PromptTemplate(
        template="""You are a grader assessing relevance of a retrieved document to a user question.
        Document: {context}
        Question: {question}
        If the document contains keyword(s) or semantic meaning related to the user question, grade it as relevant.
        Give a binary score 'yes' or 'no' score to indicate whether the document is relevant to the question.""",
        input_variables=["context", "question"],
    )

    chain = prompt | llm_with_tool

    messages = state["messages"]
    question = messages[0].content
    docs = messages[-1].content

    scored_result = chain.invoke({"question": question, "context": docs})
    return"generate"if scored_result.binary_score == "yes"else "rewrite"

5. 核心代理功能:

agent(state):

  • • 通过调用代理的 LLM 能力与提供的工具处理一般查询。
def agent(state):
    print("---CALL AGENT---")
    messages = state["messages"]
    model = ChatOllama(temperature=0, streaming=True, model="llama3.2")
    model = model.bind_tools(tools)
    response = model.invoke(messages)
    return {"messages": [response]}

rewrite(state):

  • • 使用语义推理重新表述用户的查询,以提高精确度。
def rewrite(state):
    print("---TRANSFORM QUERY---")
    messages = state["messages"]
    question = messages[0].content
  
    msg = [HumanMessage(content=f"""
    Look at the input and try to reason about the underlying semantic intent / meaning.
    Initial question: {question}
    Formulate an improved question:""")]
  
    model = ChatOllama(temperature=0, model="llama3.2", streaming=True)
    response = model.invoke(msg)
    return {"messages": [response]}

generate(state):

  • • 利用相关文档内容,通过预构建的 RAG(检索与生成)提示回答用户的查询。
def generate(state):
    print("---GENERATE---")
    messages = state["messages"]
    question = messages[0].content
    docs = messages[-1].content
  
    prompt = hub.pull("rlm/rag-prompt")
    llm = ChatOllama(temperature=0, streaming=True, model="llama3.2")
    rag_chain = prompt | llm | StrOutputParser()
  
    response = rag_chain.invoke({"context": docs, "question": question})
    return {"messages": [HumanMessage(content=response)]}

6. 查询处理工作流程

process_query(urls, pdf_files, query):

  • • 首先,将提供的URLs和PDF处理成文档列表。
  • • 使用RecursiveCharacterTextSplitter将这些文档拆分成更小的块。
  • • 使用OllamaEmbeddings对这些块进行嵌入,并将其存储在Chroma向量存储中。
  • • 创建一个检索工具以在向量存储中进行搜索。
  • • 定义一个基于LangGraph的工作流程,包含节点:
  • agent: 管理对话流程。
  • retrieve: 搜索相关文档。
  • rewrite: 重新表述查询。
  • generate: 生成最终答案。
  • • 工作流程边缘根据条件定义这些节点之间的转换。
  • • 执行图形以向用户提供其查询的响应。
def process_query(urls, pdf_files, query):
    docs_list = process_sources(urls, pdf_files)
    ifnot docs_list:
        return"No valid documents provided. Please input URLs or upload PDFs."

    text_splitter = RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=50)
    doc_splits = text_splitter.split_documents(docs_list)

    vectorstore = Chroma.from_documents(
        documents=doc_splits,
        collection_name="rag-chroma",
        embedding=OllamaEmbeddings(model="nomic-embed-text"),
    )
    retriever = vectorstore.as_retriever()

    global tools
    tools = [create_retriever_tool(
        retriever,
        "retrieve_documents",
        "Search and return information from the provided documents."
    )]

    workflow = StateGraph(AgentState)
    workflow.add_node("agent", agent)
    workflow.add_node("retrieve", ToolNode(tools))
    workflow.add_node("rewrite", rewrite)
    workflow.add_node("generate", generate)

    workflow.add_edge(START, "agent")
    workflow.add_conditional_edges(
        "agent",
        tools_condition,
        {"tools": "retrieve", END: END},
    )
    workflow.add_conditional_edges(
        "retrieve",
        grade_documents,
        {"generate": "generate", "rewrite": "rewrite"},
    )
    workflow.add_edge("generate", END)
    workflow.add_edge("rewrite", "agent")

    graph = workflow.compile()

    inputs = {"messages": [HumanMessage(content=query)]}
    response = ""
    for output in graph.stream(inputs):
        for key, value in output.items():
            if value.get("messages"):
                response = value["messages"][-1].content

    return response

7. Gradio 界面

create_interface():

  • • 构建一个包含两个选项卡的 Gradio 界面:

上传文档

  • • 用于输入 URL 的文本框。
  • • 用于上传 PDF 的文件上传器。
  • • 处理文档的按钮。
  • • 显示处理结果的状态框。

聊天

  • • 用户查询的文本框。
  • • 启动查询的按钮。
  • • 显示响应的文本框。
def create_interface():
    with gr.Blocks(title="Document Q&A Assistant") as interface:
        gr.Markdown("# Document Q&A Assistant")
        gr.Markdown("*You can provide URLs, PDF files, or both*")
      
        with gr.Tab("Upload Documents"):
            urls = gr.Textbox(label="Enter URLs (comma separated)", placeholder="https://example1.com, https://example2.com")
            pdfs = gr.File(file_count="multiple", label="Upload PDF files", file_types=[".pdf"])
            upload_btn = gr.Button("Process Documents")
            upload_status = gr.Textbox(label="Upload Status")
          
            defhandle_upload(urls, pdfs):
                ifnot urls andnot pdfs:
                    return"Please provide either URLs, PDF files, or both"
                docs = process_sources(urls, pdfs)
                if docs:
                    return"Documents processed successfully!"
                return"No valid documents provided. Please input valid URLs or PDF files"
          
            upload_btn.click(
                fn=handle_upload,
                inputs=[urls, pdfs],
                outputs=upload_status
            )
      
        with gr.Tab("Chat"):
            query = gr.Textbox(label="Ask a question about the documents")
            chat_btn = gr.Button("Ask")
            response = gr.Textbox(label="Response")
          
            chat_btn.click(
                fn=process_query,
                inputs=[urls, pdfs, query],
                outputs=response
            )
          
    return interface

8. 应用程序启动

  • • 当脚本被执行时,Gradio 界面被启动。
interface = create_interface()

if __name__ == "__main__":
    interface.launch()

关键特性概述:

多模态文档支持

  • • 同时支持 URL 和 PDF。

图片

图片

相关性评分

  • • 确保响应基于最相关的文档。

工作流图

  • • 利用 StateGraph 动态决定行动(例如,重写、检索、生成)。

嵌入和向量搜索

  • • 使用 OllamaEmbeddingsChroma 向量存储 进行高效的文档检索。

交互式用户界面

  • • 使用 Gradio 提供一个可访问的无代码界面。

结论

LangGraph 是推动 Agentic RAG 发展的关键工具,它能够实现动态的多代理工作流程,以适应复杂场景。它与 LangChain、Chroma 和 ChatOllama 等工具的无缝集成确保开发者能够高效构建可扩展和智能的检索增强系统。

如何学习大模型

下面这些都是我当初辛苦整理和花钱购买的资料,现在我已将重要的AI大模型资料包括市面上AI大模型各大白皮书、AGI大模型系统学习路线、AI大模型视频教程、实战学习,等录播视频免费分享出来,需要的小伙伴可以扫取。

现在社会上大模型越来越普及了,已经有很多人都想往这里面扎,但是却找不到适合的方法去学习。

作为一名资深码农,初入大模型时也吃了很多亏,踩了无数坑。现在我想把我的经验和知识分享给你们,帮助你们学习AI大模型,能够解决你们学习中的困难。

一、AGI大模型系统学习路线

很多人学习大模型的时候没有方向,东学一点西学一点,像只无头苍蝇乱撞,我下面分享的这个学习路线希望能够帮助到你们学习AI大模型。

在这里插入图片描述

二、AI大模型视频教程

在这里插入图片描述

三、AI大模型各大学习书籍!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

四、AI大模型各大场景实战案例

在这里插入图片描述

五、AI大模型面试题库

在这里插入图片描述

五、结束语

学习AI大模型是当前科技发展的趋势,它不仅能够为我们提供更多的机会和挑战,还能够让我们更好地理解和应用人工智能技术。通过学习AI大模型,我们可以深入了解深度学习、神经网络等核心概念,并将其应用于自然语言处理、计算机视觉、语音识别等领域。同时,掌握AI大模型还能够为我们的职业发展增添竞争力,成为未来技术领域的领导者。

再者,学习AI大模型也能为我们自己创造更多的价值,提供更多的岗位以及副业创收,让自己的生活更上一层楼。

因此,学习AI大模型是一项有前景且值得投入的时间和精力的重要选择。

### LangGraph RAG 的相关介绍 LangGraph RAG(Retrieval-Augmented Generation)是一种结合检索增强生成技术的方法,旨在通过高效的数据检索和模型生成能力提升自然语言处理任务的效果。以下是关于 LangGraph RAG 的详细介绍: #### 自定义本地驱动的 RAG 代理 LangGraph 提供了一种基于自定义本地 Llama 3 驱动的 RAG 代理实现方式[^1]。这种代理利用了多种策略和技术来优化数据检索和生成过程。 #### 自适应 RAG 策略 自适应 RAGLangGraph 中的一种核心策略,它融合了查询分析和主动/自校正机制两种方法[^2]。具体来说,自适应 RAG 可以分为以下几个阶段: - **No Retrieval**: 不执行任何检索操作,直接依赖于预训练的语言模型进行生成。 - **Single-shot RAG**: 执行一次性的检索操作,在生成过程中仅使用单一的检索结果集。 - **Iterative RAG**: 进行多次迭代式的检索操作,逐步改进检索结果的质量并动态调整生成的内容。 这些不同模式的选择取决于具体的场景需求以及输入查询的特点。 #### 工作流构建示例 为了更好地理解如何实际应用 LangGraph 来创建工作流程,可以参考以下 Python 示例代码片段[^3]: ```python from langgraph import StateGraph, MessagesState, START, END # 初始化状态图对象 builder = StateGraph(MessagesState) # 添加节点表示调用工具链中的LLM组件 builder.add_node("tool_calling_llm", tool_calling_llm) # 定义起始与结束边的关系 builder.add_edge(START, "tool_calling_llm") builder.add_edge("tool_calling_llm", END) # 编译整个图形结构得到最终的工作流实例 graph = builder.compile() ``` 上述代码展示了如何通过 `StateGraph` 类型的对象一步步搭建复杂的工作流逻辑,并将其编译成可运行的形式用于后续的任务自动化管理当中去。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值