LangGraph之RAG范式-Self-RAG

1. Self-RAG 范式概述

langgraph_self_rag 示例展示了一个 Self-RAG(Self-Reflective Retrieval-Augmented Generation) 工作流程,使用 LangGraph 实现。与传统 RAG 不同,Self-RAG 引入了自反思机制,通过动态评估生成结果和检索文档的相关性来优化答案质量。相比 langgraph_crag_local(Corrective RAG),Self-RAG 更注重生成阶段的自校正,而非仅依赖文档检索的校正。

其核心范式可以总结为:

  • 状态管理:通过 GraphState 管理问题、文档、生成结果等状态。
  • 节点与边:将 Self-RAG 流程分解为检索、生成、评估和校正等节点,通过条件边控制动态流程。
  • 自反思:通过 LLM 评估生成结果的质量和文档相关性,决定是否重新检索或调整生成。
  • 本地化支持:支持本地 LLM 和嵌入模型,适合离线或隐私敏感场景。

2. LangGraph 中 Self-RAG 的实现逻辑

在 LangGraph 的 examples/rag/langgraph_self_rag.ipynb 示例中,Self-RAG 被实现为一个基于 状态图(StateGraph) 的工作流。

LangGraph之RAG范式-Self-RAG

3. LangGraph Self-RAG 示例代码解析

以下结合代码片段说明其工作原理。

3.1 定义图状态(GraphState)

  • 作用:GraphState 定义了工作流程的状态,贯穿所有节点。
  • 字段解析
    • question:用户输入的问题。
    • generation:LLM 生成的答案。
    • documents:检索到的文档列表。
    • is_relevant:文档是否与问题相关(布尔值)。
    • needs_reflection:生成结果是否需要进一步反思或校正(布尔值)。
    • steps:记录执行步骤,便于调试。

与 CRAG 的区别

  • 相比 langgraph_crag_local 的 search 字段(用于触发 Web 搜索),Self-RAG 使用 is_relevant 和 needs_reflection 更聚焦于文档和生成内容的质量评估。
from typing import List
from typing_extensions import TypedDict

class GraphState(TypedDict):
    question: str
    generation: str
    documents: List[str]
    is_relevant: bool
    needs_reflection: bool
    steps: List[str]

3.2 创建索引

示例中使用了 Chroma 向量数据库来存储文档嵌入,并通过 OpenAIEmbeddings 生成文档的向量表示。

在我们的Demo中我们用HuggingFaceEmbeddings代替了OpenAIEmbeddings

需要引用from langchain_huggingface import HuggingFaceEmbeddings。

同时要注意,下述代码中提供的几个URL可能失效或者无法访问,请修改成自己的。

这部分的代码和CRAG一致解释

  • 从指定 URL 加载博客文章并拆分为小块(每块 250 个 token)。
  • 使用 OpenAI 的嵌入模型将文档转化为向量,存储在 Chroma 数据库中。
  • 创建一个检索器,用于根据查询查找相关文档。
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

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/",
]

docs = [WebBaseLoader(url).load() for url in urls]
docs_list = [item for sublist in docs for item in sublist]

text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
    chunk_size=250, chunk_overlap=0
)
doc_splits = text_splitter.split_documents(docs_list)

# Add to vectorDB
vectorstore = Chroma.from_documents(
    documents=doc_splits,
    collection_name="rag-chroma",
    embedding=OpenAIEmbeddings(),
)
retriever = vectorstore.as_retriever()

3.3 定义工作流节点

CRAG 工作流包含以下节点,每个节点处理一个特定任务:

  1. 检索节点(retrieve)

功能:从向量数据库(如 Chroma)检索与问题相关的文档。

输入:用户问题 (state[“question”])。

输出:更新 documents 和 steps 字段。

与 CRAG 相似:两者都使用向量检索,但 Self-RAG 不立即触发 Web 搜索。

def retrieve(state):
    """    Retrieve documents    Args:        state (dict): The current graph state    Returns:        state (dict): New key added to state, documents, that contains retrieved documents    """print("---RETRIEVE---")
    question = state["question"]

    # Retrieval
    documents = retriever.get_relevant_documents(question)
    return {"documents": documents, "question": question}
  1. 文档评分节点(gradeDocuments)

功能:使用 LLM 评估检索到的文档是否与问题相关。

逻辑

  • 对每个文档调用 LLM,生成相关性判断(relevant 或 irrelevant)。
  • 保留相关文档,丢弃不相关文档。
  • 设置 is_relevant 字段,表示是否有相关文档。

输出:更新 documents、is_relevant 和 steps。

与 CRAG 的区别:CRAG 使用 search 字段触发 Web 搜索,而 Self-RAG 使用 is_relevant 决定是否继续生成或调整流程。

def grade_documents(state):
    """    Determines whether the retrieved documents are relevant to the question.    Args:        state (dict): The current graph state    Returns:        state (dict): Updates documents key with only filtered relevant documents    """print("---CHECK DOCUMENT RELEVANCE TO QUESTION---")
    question = state["question"]
    documents = state["documents"]

    # Score each doc
    filtered_docs = []
    for d in documents:
        score = retrieval_grader.invoke(
            {"question": question, "document": d.page_content}
        )
        grade = score.binary_score
        if grade == "yes":
            print("---GRADE: DOCUMENT RELEVANT---")
            filtered_docs.append(d)
        else:
            print("---GRADE: DOCUMENT NOT RELEVANT---")
            continue
    return {"documents": filtered_docs, "question": question}
  1. 生成节点(generate)

功能:根据检索到的文档和问题生成答案。

逻辑:使用预定义的 RAG 提示模板调用 LLM。

输出:更新 generation 和 steps。

与 CRAG 相似:生成逻辑类似,但 Self-RAG 会在后续节点评估生成质量。

def generate(state):
    """    Generate answer    Args:        state (dict): The current graph state    Returns:        state (dict): New key added to state, generation, that contains LLM generation    """print("---GENERATE---")
    question = state["question"]
    documents = state["documents"]

    # RAG generation
    generation = rag_chain.invoke({"context": documents, "question": question})
    return {"documents": documents, "question": question, "generation": generation}
  1. reflect_on_generation(生成结果反思)

功能:使用 LLM 评估生成结果的质量,检查是否包含幻觉或与文档不一致。

逻辑

  • LLM 比较生成结果与文档内容,判断是否需要校正(needs_reflection = True)。
  • 评估可能基于预定义提示,如“生成内容是否准确引用了文档?”。

输出:更新 needs_reflection 和 steps。

与 CRAG 的区别:CRAG 没有生成结果反思节点,Self-RAG 的自反思是其核心特性。

def reflect_on_generation(state):
    question = state["question"]
    documents = state["documents"]
    generation = state["generation"]
    result = llm.invoke([...])  # 使用 LLM 评估生成结果
    needs_reflection = result.content.lower() == "needs_reflection"
    return {
        "needs_reflection": needs_reflection,
        "steps": state["steps"] + ["reflect_on_generation"]
    }
  1. 决定生成

如果 is_relevant = True,进入生成阶段。

否则,重新检索文档。

def decide_to_generate(state):
    """    Determines whether to generate an answer, or re-generate a question.    Args:        state (dict): The current graph state    Returns:        str: Binary decision for next node to call    """print("---ASSESS GRADED DOCUMENTS---")
    state["question"]
    filtered_documents = state["documents"]

    if not filtered_documents:
        # All documents have been filtered check_relevance
        # We will re-generate a new query
        print(
            "---DECISION: ALL DOCUMENTS ARE NOT RELEVANT TO QUESTION, TRANSFORM QUERY---"
        )
        return "transform_query"
    else:
        # We have relevant documents, so generate answer
        print("---DECISION: GENERATE---")
        return "generate"

3.4 构建图结构

流程逻辑

from langgraph.graph import END, StateGraph, START

workflow = StateGraph(GraphState)

# Define the nodes
workflow.add_node("retrieve", retrieve)  # retrieve
workflow.add_node("grade_documents", grade_documents)  # grade documents
workflow.add_node("generate", generate)  # generatae
workflow.add_node("transform_query", transform_query)  # transform_query

# Build graph
workflow.add_edge(START, "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_and_question,
    {
        "not supported": "generate",
        "useful": END,
        "not useful": "transform_query",
    },
)

# Compile
app = workflow.compile()

Self-RAG 设计体现了以下关键范式:

3.1 模块化与状态管理

  • 模块化:每个节点(retrieve、grade_documents、generate、reflect_on_generation)独立,便于维护和扩展。
  • 状态管理:GraphState 确保状态在节点间一致传递,is_relevant 和 needs_reflection 字段支持动态决策。

3.2 自反思机制

  • 文档评估:通过 grade_documents 过滤无关文档,确保生成基于高质量信息。
  • 生成反思:reflect_on_generation 节点是 Self-RAG 的核心,使用 LLM 评估生成结果的准确性和一致性,减少幻觉。
  • 动态调整:通过条件边支持循环(如重新检索或重新生成),实现自校正。

4. langgraph_crag_local 的对比

表格 还在加载中,请等待加载完成后再尝试复制

LangGraph之RAG范式-Self-RAG

附上全部源代码

RA/SD 衍生者AI训练营。发布者:稻草人,转载请注明出处:https://www.shxcj.com/archives/9596

(0)
上一篇 3天前
下一篇 1天前

相关推荐

发表回复

登录后才能评论
本文授权以下站点有原版访问授权 https://www.shxcj.com https://www.2img.ai https://www.2video.cn