支持私有化部署
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


如何创建具有自我评估机制的Agent RAG

发布日期:2025-06-15 08:51:34 浏览次数: 1528
作者:AI大模型观察站

微信搜一搜,关注“AI大模型观察站”

推荐语

探索下一代RAG系统:如何让AI具备自我评估能力,解决复杂信息检索难题。

核心内容:
1. 传统RAG系统的三大组件与核心局限性
2. Agentic RAG如何通过自主决策链突破检索瓶颈
3. 基于GPT-4的自我评估机制实现路径与案例演示

杨芳贤
53A创始人/腾讯云(TVP)最具价值专家

随着大语言模型(LLMs)的发展,模型已经能够理解大量数据并进行逻辑推理。这些发展带来的最重要成果之一是检索增强生成(Retrieval-Augmented Generation,简称RAG)系统。

LLMs 在非常大的数据集上进行训练,但它们受限于训练数据的范围。

假设您拥有一家公司,并有一些政策文档。为了让员工找到正确的答案,他们要么需要非常熟悉这些文档,要么需要在文档中搜索答案。您希望通过一个聊天机器人简化这个系统。随着 LLMs 的发展,您可以使用它们,但 LLM 并不了解您的公司数据。当您询问与这些主题相关的问题时,LLM 很可能会出现“幻觉”(hallucinate)。您需要通过微调(fine-tuning)来教导模型您的数据,这是一个漫长且昂贵的过程,或者您可以使用 RAG 系统。得益于 RAG 系统,LLM 可以在您的文档中搜索,并根据这些文档提供答案。

听起来很棒,对吧?当然,事情并非那么简单。传统 RAG 系统根据用户查询检索相关文档或信息片段,并将这些信息传递给 LLM 以生成答案。然而,这种方法对于复杂的信息需求或模糊的查询可能不足以应对。这就是“代理RAG”(Agentic RAG)概念的用武之地。

代理RAG 是一种高级系统,它在传统 RAG 系统的基础上增加了自主决策、规划和自我评估能力,使信息检索过程更加智能和灵活。这些系统可以重新表述用户的查询,评估不同的信息来源,并衡量自身答案的准确性和质量。

在本文中,我们将通过一个代理RAG系统的示例,展示如何基于特定文章为用户的问题提供全面且准确的答案。在我们的示例中,我们使用 OpenAI 的 GPT-4 模型,它能够理解给定的文章,在必要时进行网络搜索,重新表述查询并评估自己的答案。我准备这个示例是为了让大家对代理RAG 有一些概念和方法的了解。它可以进一步改进或添加不同的方法。

RAG 系统基础

检索增强生成(RAG)是一种方法,允许 LLMs 访问除训练数据之外的其他信息来源。传统 RAG 系统由三个基本组件组成:

检索器(Retriever):根据用户查询从数据库中检索相关文档或信息片段的组件。生成器(Generator):通常是一个 LLM,使用检索到的文档和用户查询生成答案。索引器(Indexer):预处理文档并将它们存储在向量数据库中以实现高效访问。

传统 RAG 系统的局限性

正如我们在开头提到的,RAG 系统有许多优点和缺点:

它们直接使用用户的查询,无法进行改进,因此可能难以获得答案。对于复杂问题可能表现不足。无法控制生成答案的质量或准确性。

代理(Agents)基础

代理是能够自主决策、执行这些决策并评估其正确性的系统。

它们可以自主决策。它们可以进行规划。它们可以为不同任务使用不同的工具,并选择使用哪些工具。它们逐步解决问题,并在必要时可以改变策略。

代理RAG 基础

代理RAG 使用代理来消除传统 RAG 系统的局限性。

更准确的答案:通过多次验证和自我评估,降低幻觉风险。全面的信息访问:通过结合不同来源和策略,访问更全面的信息。适应性:根据用户查询的质量或复杂性调整方法。透明度:能够清晰说明思考过程和信息来源。

实践项目

在之前的章节中,我们讨论了代理RAG的基础。现在是时候将它们付诸实践了。

系统架构

LLM 引擎:基于 GPT-4 的语言模型。文档访问链:从文章数据库中检索相关内容的 RetrievalQA 链。网络搜索工具:使用 Tavily API 执行网络搜索的组件。查询重新表述模块:将模糊查询变得更具体的函数。自我评估机制:评估生成答案质量的模块。代理协调器:协调不同工具使用的 LangChain 代理。内存系统:存储对话历史的 ConversationBufferMemory。

数据准备与索引

首先,让我们导入将使用的所有库。

import fitz  from langchain.embeddings importOpenAIEmbeddingsfrom langchain.vectorstores import FAISSfrom langchain.text_splitter importRecursiveCharacterTextSplitterfrom langchain.tools importToolfrom langchain.chains importRetrievalQAfrom langchain.chat_models importChatOpenAIfrom langchain.agents import initialize_agent,Tool,AgentTypefrom langchain_community.tools.tavily_search importTavilySearchResultsfrom langchain.memory importConversationBufferMemoryimport os
os.environ["TAVILY_API_KEY"]="your-api-key"

我们代理RAG 示例的基础是一个准确且高效的数据准备和索引过程。此过程包括处理、分割和将我们的 PDF 文章转换为向量数据库。

首先,我们将使用 PyMuPDF 库从 PDF 格式文档中提取内容。

def extract_text_from_pdf(pdf_path):    doc = fitz.open(pdf_path)    text ="\n".join([page.get_text()for page in doc])return text
text = extract_text_from_pdf("pdf_files/article_2.pdf")

此函数提取并合并给定 PDF 文件所有页面中的文本。

PDF 中的文本可能非常长,整体处理如此长的数据效率低下。因此,我们使用 LangChain 的 RecursiveCharacterTextSplitter 类将文本分割成更小、更易管理的片段:

text_splitter =RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)docs = text_splitter.create_documents([text])

这里:

chunk_size=500:确保每个文本片段最多包含 500 个字符。chunk_overlap=50:通过确保连续部分之间有 50 个字符的重叠,防止因分割句子或段落而丢失意义。

我们还使用 OpenAIEmbeddings() 类将文本转换为嵌入(embeddings)。

embeddings =OpenAIEmbeddings()

在完成所有这些步骤后,我们通过将每个文本片段转换为向量表示,创建了 FAISS 向量数据库,以便高效查询分段文本:

vectorstore = FAISS.from_documents(docs, embeddings)vectorstore.save_local("faiss_index")

FAISS(Facebook AI Similarity Search)是一个为高维向量执行高效相似性搜索设计的库。

在应用程序运行时,我们按如下方式加载之前创建的 FAISS 索引:

vectorstore = FAISS.load_local("faiss_index", embeddings, allow_dangerous_deserialization=True)retriever = vectorstore.as_retriever()

通过将加载的向量数据库转换为检索器对象,我们可以高效地找到与用户查询相关的文本片段。

这个数据准备和索引过程构成了我们代理RAG 系统的信息检索基础。

代理RAG

首先,我们初始化所选的 LLM 模型。在我们的示例中,它是 GPT-4。

llm =ChatOpenAI(model="gpt-4")

接下来,我们需要创建 RetrievalQA 链以便从文章数据库中检索信息。

retrieval_qa_chain =RetrievalQA.from_chain_type(    llm=llm,    retriever=retriever,    return_source_documents=True)

此链接受用户查询,提取相关文档,并通过 LLM 生成响应。

我们还使用 TavilySearchResults 来搜索文章中未找到的信息。此工具与 Tavily API 集成,每个查询返回两个最相关的结果。为此,您必须先访问 Tavily 网站,创建账户并获取 API 密钥,否则会报错。

search =TavilySearchResults(max_results=2)

接下来,我们添加一个自定义函数,用于重写模糊或笼统的输入,使其更具体。

def query_reformulation(query):    response = llm.predict("Rewrite this query to be more specific: "+ query)return response

此函数向 LLM 发送请求以优化查询。例如,它可以将像“什么是人工智能?”这样的笼统查询转换为更具体的查询,如“文章中描述的人工智能技术的主要特点和应用是什么?”

我们还有另一个函数,用于让系统评估其生成的答案。

def self_evaluate(input_text):    parts = input_text.split("|||")    query = parts[0]    response = parts[1]    sources = parts[2]if len(parts)>2else""
    evaluation_prompt = f"""评估以下对查询的响应:
查询:{query}响应:{response}来源:{sources}
基于以下标准评估:1.事实准确性(是否与来源匹配?)2.完整性(是否涵盖查询的所有方面?)3.相关性(信息是否与查询相关?)4.幻觉(是否包含来源不支持的信息?)
返回0-10的置信度评分和解释。"""
    evaluation = llm.predict(evaluation_prompt)return evaluation

此函数评估答案的准确性、全面性、相关性和幻觉情况。评估包括 0-10 的置信度评分和解释。

现在我们已经定义了所有函数,可以将工具整合在一起。

tools =[Tool(        name="Article Retrieval",        func=lambda q: retrieval_qa_chain({"query": q})["result"],        description="从文章数据库中检索知识。"),
Tool(        name="Web search",        func=search,        description="如果在文档中找不到请求的信息,则说明这一点并执行网络搜索。"),Tool(        name="Query reformulation",        func=query_reformulation,        description="将查询重新表述为更具体和针对性更强的形式。")]

我们的工具包括文章检索、网络搜索和查询重新表述。代理将决定在何种情况下使用哪种工具。

我们还从 LangChain 库中添加了 ConversationBufferMemory,以保存与用户的聊天历史。

memory =ConversationBufferMemory(memory_key="chat_history", return_messages=True)

现在我们已经创建了所有组件,是时候启动代理了。

agent = initialize_agent(    tools=tools,    llm=llm,    agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,    verbose=True,    memory=memory)

这里的代理类型 STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION 创建了一个能够逐步推理并根据情况使用工具的代理。

现在是运行代理的时候了。为此,我们编写了一个可用于自我评估的函数。

def get_evaluated_response(query):    response = agent.run(query)
try:        result = retrieval_qa_chain({"query": query})        sources =[doc.page_content for doc in result.get("source_documents",[])]        sources_text ="\n".join(sources)exceptExceptionas e:        sources_text ="无可用来源"
    evaluation = self_evaluate(f"{query}|||{response}|||{sources_text}")
return{"query": query,"response": response,"evaluation": evaluation,"sources": sources_text}

此函数获取代理的响应并进行评估,然后返回结果。

我们可以通过以下函数查看自我评估的响应和代理的响应。

def transparent_response(query):    result = get_evaluated_response(query)
return f"""响应:{result['response']}
置信度评估:{result['evaluation']}"""

现在让我们试一试。

我给出的文章是一篇关于多代理系统的调查。

print(transparent_response("什么是多代理系统?"))

当我们如上运行系统时,会得到以下输出。由于输出内容太长,我无法在这里展示所有内容,但代理理解了需要从文章中回答我们的问题,并为此使用了“Article Retrieval”工具。然后,它为我们创建了一个最终答案。自我评估对生成的结果进行了评估,并给出了 9.75 分(满分 10 分)。

让我们尝试一个文章中没有的例子。

print(transparent_response("伊斯坦布尔当前的天气如何?"))

正如您所见,这次代理理解了需要使用网络工具,并从中为我们带来了答案。但由于未共享资源,我们的置信度评分较低。这是需要优化的部分。

现在让我们问一些 LLM 已经知道的内容。

print(transparent_response("YouTube 是什么时候创立的?"))

系统告诉我们它已经知道这个信息,并直接给出了答案,无需使用任何工具。我们的置信度评分相当高。

最后一个例子是尝试查询重新表述。为此,我输入了一个非常模糊的内容。

print(transparent_response("烤蛋糕"))

代理通过重写输入使其更高效,然后使用网络搜索工具。


53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询