大模型实战:使用LangGraph实现CRAG,CRAG比传统RAG强多少?

为了提高RAG的性能,结合大模型的RAG技术涌现出很多的改进方案SELF-RAG,Adaptive RAG,CRAG等技术相继被提出,今天笔者就来介绍CRAG这个技术,并采用langchain全家桶中的LangGraph框架实现CRAG。看看CRAG比传统RAG强多少。

纠正性检索增强生成——CRAG

纠正性检索增强生成(Corrective Retrieval-Augmented Generation,CRAG)是一种先进的自然语言处理技术,旨在提高基于检索的生成(Retrieval-Augmented Generation,RAG)方法的鲁棒性和准确性。CRAG通过引入一个轻量级的检索评估器来评估检索到的文档的质量,并根据评估结果触发不同的知识检索动作,以确保生成结果的准确性和可靠性。

在这里插入图片描述

CRAG(纠正性检索增强生成)的工作流程如上方图所示主要包括以下几个步骤:

检索文档:首先,基于用户的查询,系统执行检索操作以获取相关的文档或信息。

评估检索质量:CRAG使用一个轻量级的检索评估器对检索到的每个文档进行质量评估,计算出一个量化的置信度分数。

触发知识检索动作:根据置信度分数,CRAG将触发以下三种动作之一:

  • 正确:如果评估器认为文档与查询高度相关,将采用该文档进行知识精炼。
  • 错误:如果文档被评估为不相关或误导性,CRAG将利用网络搜索寻找更多知识来源。
  • 模糊:对于相关性不确定的文档,CRAG会结合正确和错误的处理策略,以提高检索的鲁棒性。

知识精炼:对于评估为正确的文档,CRAG将进行知识精炼,抽取关键信息并过滤掉无关信息。

网络搜索:在需要时,CRAG会执行网络搜索以寻找更多高质量的知识来源,以纠正或补充检索结果。

分解-重组:CRAG采用一种分解-重组算法,将检索到的文档解构为关键信息块,筛选重要信息,并重新组织成结构化知识。

生成文本:最后,利用经过优化和校正的知识,提高了生成文本的准确性和鲁棒性。

LangGraph简介

LangGraph 是 LangChain 的一个重要扩展库,它允许开发者构建基于大型语言模型(LLMs)的复杂应用,特别是那些需要循环或多个智能体(agents)协作的应用。以下是 LangGraph 的一些关键特性和概念:

  1. 状态图(StateGraph):LangGraph 使用状态图来表示整个应用的状态,图中的节点和边定义了应用的流程和逻辑4。
  2. 节点(Nodes):在 LangGraph 中,节点可以是任何可调用的 Python 函数,也可以是 LangChain 中的可运行组件,如链(Chains)或智能体(Agents)。每个节点执行特定的任务,如推理、调用工具或生成响应。
  3. 边(Edges):边定义了节点之间的连接和数据流。LangGraph 支持不同类型的边,包括:
  • 起始边(Starting Edge):定义任务的起始节点。
  • 普通边(Normal Edge):表示一个节点完成后立即跳转到下一个节点。
  • 条件边(Conditional Edge):基于条件函数的结果决定跳转到哪个节点4。
  1. 循环和多智能体支持:LangGraph 支持构建循环图,允许智能体在循环中被调用,直到任务完成。这对于需要迭代或多步骤交互的应用非常有用。
  2. 状态管理:LangGraph 允许开发者定义和维护一个中央状态对象,该对象会根据节点的跳转不断更新。状态对象的属性可以自定义,以适应不同的应用需求。

LangGraph 设计为与框架无关,这意味着每个节点都是一个常规的 Python 函数,可以轻松地与现有的 Python 生态系统集成。LangGraph 扩展了 LangChain 表达式语言(LCEL),允许协调多个链或智能体,提供了一种高级的 LCEL 语言,使得逻辑更清晰。通过 LangGraph,开发者可以创建出能够处理更复杂交互和循环逻辑的智能体应用,从而推动基于大型语言模型的应用开发向更高级别的自动化和智能化发展。

实战部分

当然本次实现的不是完整版的CRAG,相比于原论文,简化了评估检索质量这一步和省掉了知识精炼和分解-重组这两个步骤。

在这里插入图片描述

代码主要参考下方,但是在llm模型,embeding模型,以及prompt上做了一些修改。

https://github.com/langchain-ai/langgraph/blob/main/examples/rag/langgraph_crag.ipynb

初始化知识库和大模型LLM

这里的向量服务器是采用xinference 本地部署的bge-base-zhv1.5,大模型部分采用的glm4免费送的一些token

from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_community.embeddings import XinferenceEmbeddings
###向量服务
xinference = XinferenceEmbeddings(
    server_url="*******", model_uid="bge-base-zhv15"
)

###知识收集和预处理
urls = [
    "https://spaces.ac.cn/archives/9907", 
    "https://spaces.ac.cn/archives/9920"
]

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)

# 向量入库
vectorstore = Chroma.from_documents(
    documents=doc_splits,
    collection_name="rag-chroma",
    embedding=xinference,
)
retriever = vectorstore.as_retriever()

### 初始化llm
llm = ChatOpenAI(
    temperature=0.95,
    model="glm-4",
    openai_api_key="*******",
    openai_api_base="https://open.bigmodel.cn/api/paas/v4/"
)

搜索结果评价 agent的定义

# 搜索结果评价 agent
system = """
    请扮演是一位评估检索文档与用户问题相关性的评分员。
    如果文档包含与问题相关的关键词或语义,请将其评为yes,否则评为no
    直接给出"yes" 和 "no" .\\n"""
grade_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system),
        ("human", "以下是:\\n 检索文档: \\n\\n {document} \\n\\n 用户问题: {question}"),
    ]
)
retrieval_grader = grade_prompt | llm | StrOutputParser()

##测试搜索结果评价 agent
question = "什么是cool paper"
docs = retriever.get_relevant_documents(question)
doc_txt = docs[0].page_content
print(retrieval_grader.invoke({"question":question, "document": doc_txt}))
## 评价结果: yes

图片
在这里插入图片描述

RAG agent的定义

#RAG agent
from langchain import hub
from langchain_core.output_parsers import StrOutputParser
prompt = hub.pull("rlm/rag-prompt")
# Post-processing
def format_docs(docs):
    return "\\n\\n".join(doc.page_content for doc in docs)
rag_chain = prompt | llm | StrOutputParser()
generation = rag_chain.invoke({"context": docs, "question": question})
print(generation)
## rag结果: Cool Papers是一个辅助科研人员刷论文的网站,它逐日收录论文并提供了站内检索系统。该网站还引入了venue分支,收录了如ICLR、IC等会议历年的论文集。Cool Papers的开发得到了GPT4和Kimi等人工智能模型的支持,可以帮助用户快速了解论文内容。

搜索query优化agent定义

#搜索query 优化agent
system = """您是一位搜索query优化专家,负责将搜索输入的问题转换成一个更优的版本,一定不要改变原义,更适合网络搜索,尽量精简一点"""
re_write_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system),
        (
            "human",
            "这是用户的问题:: \\n\\n {question} \\n 请直接输出优化后的问题:",
        ),
    ]
)
question_rewriter = re_write_prompt | llm | StrOutputParser()
question_rewriter.invoke({"question": question})

##优化结果: "cool paper 定义及特点"

搜索工具定义

### web Search 工具
from langchain_community.tools.tavily_search import TavilySearchResults
import os
os.environ["TAVILY_API_KEY"] = "******"
web_search_tool = TavilySearchResults(k=3)

web_search_tool.invoke({"query": "如何有效缩小毛孔?"})

搜索结果如下:

[{‘url’: ‘https://beautyfoomall.com/blogs/news/毛孔大怎么办什么可以收缩毛孔’, ‘content’: ‘Dec 8, 2021 — Dec 8, 2021… 毛孔粗大。缩小面部毛孔可根据皮肤的不同种类进行治疗,利用护肤品补水、射频、激光、食疗等方法是可以延缓皮肤衰老,缩小面部毛孔 … 有效!Cellreturn\xa0…’}, {‘url’: ‘https://zhuanlan.zhihu.com/p/281404233’, ‘content’: ‘12种有效方法收缩毛孔的教你怎么样让毛孔变小 · 1、化妆前,可以用冰凉的毛巾收缩紧致毛孔 · 2、使用化妆棉创造水嫩豆腐肌 · 3、多喝水,从内到外让肌肤水水 · 4、用饭团搓\xa0…’}, {‘url’: ‘https://fashion.sina.cn/zl/2016-06-23/detail-ifxtmses0755122.d.html’, ‘content’: ‘Jun 22, 2016 — Jun 22, 2016鸡蛋+橄榄油鸡蛋打散,加入橄榄油,搅匀,敷脸15分钟,洗干净。如果蛋液能放在冰箱里冰镇,效果更好,不仅可以收缩毛孔,还可以美白。’}, {‘url’: ‘https://www.zhihu.com/question/40366369’, ‘content’: ‘Feb 14, 2016 — Feb 14, 2016从目前来看,用护肤品把毛孔“彻底缩小”的确有难度,不过要让毛孔暂时一段时间内“视觉上缩小”还是有办法的。 反对那种一谈毛孔粗大就建议别人去医美的言论\xa0…’}, {‘url’: ‘https://skintypesolutions.com/zh/blogs/皮肤护理/皮肤科医生建议如何收缩毛孔’, ‘content’: ‘Nov 14, 2023 — Nov 14, 2023在这篇文章中,我将解释导致毛孔扩大的原因,并提供基于证据的策略来帮助缩小毛孔并使其不那么明显。 我将帮助您找到最好的毛孔缩小剂产品和美容程序。’}]

流程图的定义

###定义agent graph
from langchain.schema import Document
from typing_extensions import TypedDict
from typing import List

class GraphState(TypedDict):
    """
    Represents the state of our graph.

    Attributes:
        question: question
        generation: LLM generation
        web_search: whether to add search
        documents: list of documents
    """

    question: str
    generation: str
    web_search: str
    documents: List[str]

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)
    print(documents[0])
    return {"documents": documents, "question": question}

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}

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 = []
    web_search = "No"
    for d in documents:
        score = retrieval_grader.invoke(
            {"question": question, "document": d.page_content}
        )
      
        if"yes"in score:
            print("---GRADE: DOCUMENT RELEVANT---")
            filtered_docs.append(d)
        else:
            print("---GRADE: DOCUMENT NOT RELEVANT---")
            web_search = "Yes"
            continue
    return {"documents": filtered_docs, "question": question, "web_search": web_search}

def transform_query(state):
    """
    Transform the query to produce a better question.

    Args:
        state (dict): The current graph state

    Returns:
        state (dict): Updates question key with a re-phrased question
    """

    print("---TRANSFORM QUERY---")
    question = state["question"]
    documents = state["documents"]

    # Re-write question
    better_question = question_rewriter.invoke({"question": question})
    print("优化后的qurey是:" + better_question)
    return {"documents": documents, "question": better_question}

def web_search(state):
    """
    Web search based on the re-phrased question.

    Args:
        state (dict): The current graph state

    Returns:
        state (dict): Updates documents key with appended web results
    """

    print("---WEB SEARCH---")
    question = state["question"]
    documents = state["documents"]

    # Web search
    docs = web_search_tool.invoke({"query": question})

    web_results = "\\n".join([d["content"] for d in docs])
    print("搜索结果是:" + web_results)
    web_results = Document(page_content=web_results)
    documents.append(web_results)
    return {"documents": documents, "question": question}

### Edges
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---")
    question = state["question"]
    web_search = state["web_search"]
    filtered_documents = state["documents"]

    if web_search == "Yes":
        # 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"



from langgraph.graph import END, StateGraph

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
workflow.add_node("web_search_node", web_search)  # web search

# Build graph
workflow.set_entry_point("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", "web_search_node")
workflow.add_edge("web_search_node", "generate")
workflow.add_edge("generate", END)

# Compile
app = workflow.compile()

流程图的可视化

from IPython.display import Image, display

try:
    display(Image(app.get_graph(xray=True).draw_mermaid_png()))
except:
    # This requires some extra dependencies and is optional
    pass

流程图可视化结果

图片

开始问问题

第一个是知识库有的问题,所以走的是左边的路线,直接本地rag后,检索质量评估结果不错,最终生成结果。

:Cool Papers是一个用于刷论文的辅助网站,开发者曾在博客中分享其开发体验和更新进度。该网站逐日收录论文,并经历了几次较大的变化,如引入venue分支,收录了一些会议历年的论文集。随着时间的积累,Cool Papers还增加了一个站内检索系统以提高检索效率。

from pprint import pprint

# Run
inputs = {"question": "Cool Papers 是什么"}
for output in app.stream(inputs):
    for key, value in output.items():
        # Node
        pprint(f"Node '{key}':")
        # Optional: print full state at each node
        # pprint.pprint(value["keys"], indent=2, width=80, depth=None)
    pprint("---------------------------------")

# Final generation
pprint(value["generation"])

图片

第一个是知识库没有的问题,所以走的是右边的路线,直接本地rag后,检索质量评估结果很差,然后走web搜索rag 生成结果:有效缩小毛孔的方法包括:1. 使用鸡蛋和橄榄油自制面膜敷脸,冰镇后效果更佳;2. 化妆前用冰凉的毛巾敷脸,帮助收缩毛孔;3.多喝水,保持肌肤水润。此外,还可以根据皮肤类型选择合适的护肤品和美容程序进行毛孔缩小治疗

from pprint import pprint

# Run
inputs = {"question": "如何缩小毛孔?"}
for output in app.stream(inputs):
    for key, value in output.items():
        # Node
        pprint(f"Node '{key}':")
        # Optional: print full state at each node
        # pprint.pprint(value["keys"], indent=2, width=80, depth=None)
    pprint("---------------------------------")

# Final generation
pprint(value["generation"])

图片

普通人如何抓住AI大模型的风口?

领取方式在文末

为什么要学习大模型?

目前AI大模型的技术岗位与能力培养随着人工智能技术的迅速发展和应用 , 大模型作为其中的重要组成部分 , 正逐渐成为推动人工智能发展的重要引擎 。大模型以其强大的数据处理和模式识别能力, 广泛应用于自然语言处理 、计算机视觉 、 智能推荐等领域 ,为各行各业带来了革命性的改变和机遇 。

目前,开源人工智能大模型已应用于医疗、政务、法律、汽车、娱乐、金融、互联网、教育、制造业、企业服务等多个场景,其中,应用于金融、企业服务、制造业和法律领域的大模型在本次调研中占比超过 30%。
在这里插入图片描述

随着AI大模型技术的迅速发展,相关岗位的需求也日益增加。大模型产业链催生了一批高薪新职业:

在这里插入图片描述

人工智能大潮已来,不加入就可能被淘汰。如果你是技术人,尤其是互联网从业者,现在就开始学习AI大模型技术,真的是给你的人生一个重要建议!

最后

如果你真的想学习大模型,请不要去网上找那些零零碎碎的教程,真的很难学懂!你可以根据我这个学习路线和系统资料,制定一套学习计划,只要你肯花时间沉下心去学习,它们一定能帮到你!

大模型全套学习资料领取

这里我整理了一份AI大模型入门到进阶全套学习包,包含学习路线+实战案例+视频+书籍PDF+面试题+DeepSeek部署包和技巧,需要的小伙伴文在下方免费领取哦,真诚无偿分享!!!
vx扫描下方二维码即可
加上后会一个个给大家发

在这里插入图片描述

部分资料展示

一、 AI大模型学习路线图

整个学习分为7个阶段
在这里插入图片描述
在这里插入图片描述

二、AI大模型实战案例

涵盖AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,皆可用。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

三、视频和书籍PDF合集

从入门到进阶这里都有,跟着老师学习事半功倍。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

四、LLM面试题

在这里插入图片描述
在这里插入图片描述

五、AI产品经理面试题

在这里插入图片描述

六、deepseek部署包+技巧大全

在这里插入图片描述

😝朋友们如果有需要的话,可以V扫描下方二维码联系领取~
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值