实践篇:利用ragas在自己RAG上实现LLM评估②

文章目录

    • 使用ragas做评估
      • 在自己的数据集上评估
        • 完整代码
        • 代码讲解
          • 1. RAG系统构建
            • 核心组件初始化
            • 文档处理流程
          • 2. 评估数据集构建
          • 3. RAGAS评估实现
            • 1. 评估数据集创建
            • 2. 评估器配置
            • 3. 执行评估

本系列阅读:
理论篇:RAG评估指标,检索指标与生成指标①
实践篇:利用ragas在自己RAG上实现LLM评估②

首先我们可以共识LLM的评估最好/最高效的方式就是再利用LLM的强大能力,而不是用传统指标。
假设我们不用LLM评估我们只有两条方式可实现:

  1. 传统指标,如Bleu。需输入标准答案(通常也是人工审核答案是不是标准的,或者是人工制造标准答案),缺点是效果有限,用了都知道效果惨不忍睹。
  2. 纯人工打分。缺点是耗时,带有主观性。

使用ragas做评估

推荐一个包ragas。但是它的教程文档确实写得不太好,可能是jupyter格式,直接在py中运行,总是会报少变量之类。我这边都改动了下,确保我们py文件可以运行。
在这里插入图片描述
ragas(Retrieval Augmented Generation Assessment)是社区最著名的评估方案,内置了我们常见的评估指标。
在这里插入图片描述
利用了LLM评估,因此不需要人工打标。其出名是因为封装了LLM做评估,简单易用(当然其实这些也是我们可以造轮子实现的~)。

代码链接https://github.com/blackinkkkxi/RAG_langchain/blob/main/learn/evaluation/RAGAS-langchian.ipynb

在自己的数据集上评估

完整可运行的代码见本文的完整代码小节,代码可运行。而1~3我们会拆开完整代码讲解,代码主要用于讲解完整代码,可能不能运行。

完整代码

在使用我的代码你只需要把deepseekapi换成你自己的即可。

import os
import re
from langchain_community.document_loaders import WebBaseLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.prompts import PromptTemplate
from langchain.chains import RetrievalQA
from langchain.chat_models import init_chat_model
from ragas import evaluate
from ragas.llms import LangchainLLMWrapper
from ragas import EvaluationDataset
from ragas.metrics import LLMContextRecall, Faithfulness, FactualCorrectnessclass RAG:def __init__(self, api_key=None):"""使用DeepSeek模型和BGE嵌入初始化RAG系统"""# 设置环境变量os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'# 初始化对话模型self.llm = init_chat_model(model="deepseek-chat",api_key=api_key,api_base="https://api.deepseek.com/",temperature=0,model_provider="deepseek",)# 初始化嵌入模型self.embedding_model = HuggingFaceEmbeddings(model_name="BAAI/bge-large-zh-v1.5")# 初始化文本分割器self.text_splitter = RecursiveCharacterTextSplitter(chunk_size=500,chunk_overlap=50)# 初始化向量存储和检索器self.vectorstore = Noneself.retriever = Noneself.qa_chain = None# 设置提示模板self.template = """根据以下已知信息,简洁并专业地回答用户问题。如果无法从中得到答案,请说"我无法从已知信息中找到答案"。已知信息:{context}用户问题:{question}回答:"""self.prompt = PromptTemplate(template=self.template,input_variables=["context", "question"])def load_documents_from_url(self, url, persist_directory="./chroma_db"):"""从网页URL加载文档并创建向量存储"""# 从网页加载文档loader = WebBaseLoader(url)documents = loader.load()# 将文档分割成块chunks = self.text_splitter.split_documents(documents)# 创建向量存储self.vectorstore = Chroma.from_documents(documents=chunks,embedding=self.embedding_model,persist_directory=persist_directory)# 创建检索器self.retriever = self.vectorstore.as_retriever()# 创建问答链self.qa_chain = RetrievalQA.from_chain_type(llm=self.llm,chain_type="stuff",retriever=self.retriever,chain_type_kwargs={"prompt": self.prompt})print(f"成功从 {url} 加载并处理文档")def ask(self, question):"""便捷的提问方法"""result = self.qa_chain.invoke({"query": question})return result["result"]def relevant_docs_with_scores(self, query, k=1):"""计算相关文档及其相似度分数,返回处理后的文档信息"""docs_with_scores = self.vectorstore.similarity_search_with_score(query, k=k)# 处理文档内容processed_docs = []for i, (doc, score) in enumerate(docs_with_scores, 1):# 清理文档内容content = doc.page_content.strip()# 去除回车符、换行符和多余的空白字符content = content.replace('\n', ' ').replace('\r', ' ').replace('\t', ' ')# 合并多个连续空格为单个空格content = re.sub(r'\s+', ' ', content)processed_docs.append({'index': i,'score': score,'content': content})return processed_docs# 使用示例
if __name__ == "__main__":api_key = "X"queries = ["为什么Transformer需要位置编码?","QKV矩阵是怎么得到的?","注意力机制的本质是什么?","对于序列长度为n的输入,注意力机制的计算复杂度是多少?","在注意力分数计算中,为什么要除以√d?","多头注意力机制的主要作用是什么?","解码器中的掩码自注意力是为了什么?","编码器-解码器注意力中,Query来自哪里?","GPT系列模型使用的是哪种架构?","BERT模型适合哪类任务?"]# 初始化RAGrag = RAG(api_key)# 从URL加载文档rag.load_documents_from_url("https://blog.csdn.net/ngadminq/article/details/147687050")expected_responses = ["Transformer的输入是并行处理的,不像RNN有天然的序列关系,因此需要位置编码来为模型提供词元在序列中的位置信息,确保模型能理解词的先后顺序。","QKV矩阵通过将输入向量分别与三个不同的权重矩阵W_q、W_k、W_v进行线性投影得到,这三个权重矩阵是模型的可学习参数,在训练过程中不断优化。","注意力机制的本质是为序列中的每个词找到重要的上下文信息,通过计算词与词之间的相关性分数,实现对重要信息的聚焦和整合。","注意力机制的计算复杂度是O(n²),因为序列中每个词都需要与所有其他词计算注意力分数,形成n×n的注意力矩阵。","除以√d是为了提升训练稳定性,防止注意力分数过大导致softmax函数进入饱和区,确保梯度能够有效传播。","多头注意力机制可以从多个角度捕捉不同类型的词间关联,比如语义关系、句法关系等,增强了模型的表达能力和理解能力。","解码器中的掩码自注意力是为了防止当前位置关注未来位置的信息,确保在自回归生成过程中每个位置只能看到当前及之前的信息。","在编码器-解码器注意力中,Query来自解码器的前一层输出,而Key和Value来自编码器的最终输出,这样解码器就能利用编码器处理的源序列信息。","GPT系列模型使用仅解码器架构,专门针对文本生成任务设计,通过掩码自注意力机制实现从左到右的序列生成。","BERT模型适合分类和理解类任务,如文本分类、命名实体识别、情感分析、问答等,因为它使用双向编码器可以同时关注上下文信息。"]dataset = []for query, reference in zip(queries, expected_responses):# 获取相关文档及分数并打印relevant_docs = rag.relevant_docs_with_scores(query)relevant_docs = relevant_docs[0]['content']response = rag.ask(query)dataset.append({"user_input": query,"retrieved_contexts": [relevant_docs],"response": response,"reference": reference})evaluation_dataset = EvaluationDataset.from_list(dataset)llm = init_chat_model(model="deepseek-chat",api_key=api_key,api_base="https://api.deepseek.com/",temperature=0,model_provider="deepseek",)evaluator_llm = LangchainLLMWrapper(llm)result = evaluate(dataset=evaluation_dataset, metrics=[LLMContextRecall(), Faithfulness(), FactualCorrectness()],llm=evaluator_llm)print(result)

以下是运行的结果:
在这里插入图片描述
根据我们的结果指标可以针对指标有优化方向

代码讲解
1. RAG系统构建
核心组件初始化
class RAG:def __init__(self, api_key=None):# DeepSeek聊天模型self.llm = init_chat_model(model="deepseek-chat",api_key=api_key,api_base="https://api.deepseek.com/",temperature=0,model_provider="deepseek",)# BGE中文嵌入模型self.embedding_model = HuggingFaceEmbeddings(model_name="BAAI/bge-large-zh-v1.5")# 文本分割器self.text_splitter = RecursiveCharacterTextSplitter(chunk_size=500,chunk_overlap=50)

技术要点:

  • 使用DeepSeek作为生成模型,temperature=0确保输出稳定性
  • BGE-large-zh-v1.5是目前中文嵌入效果较好的开源模型
  • 文本分块策略:500字符块大小,50字符重叠防止信息丢失
文档处理流程
def load_documents_from_url(self, url, persist_directory="./chroma_db"):# 1. 网页内容加载loader = WebBaseLoader(url)documents = loader.load()# 2. 文档分块chunks = self.text_splitter.split_documents(documents)# 3. 向量化存储self.vectorstore = Chroma.from_documents(documents=chunks,embedding=self.embedding_model,persist_directory=persist_directory)# 4. 构建检索链self.qa_chain = RetrievalQA.from_chain_type(llm=self.llm,chain_type="stuff",retriever=self.retriever,chain_type_kwargs={"prompt": self.prompt})
2. 评估数据集构建

数据集需要包含四个核心要求

dataset.append({"user_input": str,                # 用户查询,即我们备好的一系列问题"retrieved_contexts": [strstr], # 检索到的上下文,list格式"response": str,               # 系统回答"reference": str             # 标准答案,人工制造,我这里使用cluade生成的
})
3. RAGAS评估实现
1. 评估数据集创建
from ragas import EvaluationDataset
evaluation_dataset = EvaluationDataset.from_list(dataset)
2. 评估器配置
from ragas.llms import LangchainLLMWrapper
evaluator_llm = LangchainLLMWrapper(llm)

关键点: RAGAS使用LLM作为评估器,需要将LangChain模型包装成RAGAS兼容格式

3. 执行评估

代码使用了三个核心评估指标:

LLMContextRecall(上下文召回率)

  • 作用: 评估检索到的上下文是否包含回答问题所需的信息
  • 计算方式: 通过LLM判断标准答案中的信息有多少能在检索上下文中找到
  • 公式: Context Recall = 可在上下文中找到的标准答案句子数 / 标准答案总句子数

Faithfulness(忠实度)

  • 作用: 衡量生成回答与检索上下文的一致性,防止幻觉
  • 计算方式: 检查回答中的每个声明是否能在提供的上下文中得到支持
  • 公式: Faithfulness = 有上下文支持的声明数 / 总声明数

FactualCorrectness(事实正确性)

  • 作用: 评估生成回答的事实准确性
  • 计算方式: 将生成回答与标准答案进行事实层面的比较
  • 评估维度: 包括事实的正确性、完整性和相关性
from ragas.metrics import LLMContextRecall, Faithfulness, FactualCorrectnessresult = evaluate(dataset=evaluation_dataset, metrics=[LLMContextRecall(), Faithfulness(), FactualCorrectness()],llm=evaluator_llm
)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/86575.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…

PostgreSQL 安装与配置全指南(适用于 Windows、macOS 与主流 Linux 发行版)

PostgreSQL 是一个功能强大、开源、稳定的对象关系数据库系统,广泛用于后端开发、数据处理与分布式架构中。本指南将手把手教你如何在 Windows、macOS 以及主流 Linux 发行版 上安装 PostgreSQL,并附上安装验证命令与基础配置方法。 一、Windows 安装与配…

WordPress博客文章SEO的优化技巧

在数字时代,博客不仅用于表达观点,也能提升品牌影响力并吸引潜在客户。许多服务器提供商(如 Hostease)支持 WordPress 一键安装功能,方便新手快速完成安装,专注于内容创作和 SEO 优化。然而,写出…

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…

雨季智慧交通:从车辆盲区到客流统计的算法全覆盖

雨季智慧交通中的视觉分析技术应用 一、背景:雨季交通的复杂挑战 雨季是城市交通管理的关键考验期。以济南为例,强对流天气伴随的短时强降水、雷雨大风及冰雹,不仅导致道路积水、能见度骤降,还加剧了大型车辆(如渣土…

安全生产管理是什么?安全生产管理系统都有哪些核心功能?

随着法律法规的日益严格和公众对安全意识的提升,企业面临的安全生产压力也越来越大。无论是大型企业还是中小型企业,安全生产管理不仅关系到企业的生存与发展,更直接关系到员工的生命安全和企业的社会形象。因此,理解并实施有效的…

【PyCharm必会基础】正确移除解释器及虚拟环境(以 Poetry 为例 )

#工作记录 【PyCharm使用基础】 当遇到虚拟环境难以修复的场景,我们需要删除当前解释器和虚拟环境然后再重新创建虚拟环境,以下是在PyCharm中正确移除的步骤。 一、进入解释器设置 在 PyCharm 界面右下角,点击Poetry (suna0),选…

day028-Shell自动化编程-判断进阶

文章目录 1. 特殊变量补充2. 变量扩展-变量子串2.1 获取变量字符的长度2.2 给变量设置默认值 3. 命令3.1 dirname3.2 basename3.3 cut 4. 条件测试命令:[]4.1 逻辑运算符4.2 文件测试4.3 案例:书写脚本-检查文件类型4.4 逻辑运算4.5 案例:书写…

oracle sql 语句 优化方法

1、表尽量使用别名,字段尽量使用别名.字段名,这样子,可以减少oracle数据库解析字段名。而且把 不需要的字段名剔除掉,只保留有用的字段名,不要一直使用 select *。 2、关联查询时,选择好主表 。oracle解析…

【Java】Ajax 技术详解

文章目录 1. Filter 过滤器1.1 Filter 概述1.2 Filter 快速入门开发步骤:1.3 Filter 执行流程1.4 Filter 拦截路径配置1.5 过滤器链2. Listener 监听器2.1 Listener 概述2.2 ServletContextListener3. Ajax 技术3.1 Ajax 概述3.2 Ajax 快速入门服务端实现:客户端实现:4. Axi…

07 APP 自动化- appium+pytest+allure框架封装

文章目录 一、PO二、代码简单实现项目框架预览:base_page.pydir_config.pyget_data.pylogger.pystart_session.pyconfig.yamlkey_code.yamllaunch_page_loc.pylogin_page_loc.pylaunch_page.pylogin_page.pytest_login.pypytest.inirun.py APP 自动化代码总和 一、P…

用户体验升级:表单失焦调用接口验证,错误信息即时可视化

现代前端应用中,表单交互是用户体验的重要组成部分。而表单验证作为其中的核心环节,不仅需要前端的即时反馈,还需要与后端接口联动进行数据合法性校验。本文将详细介绍如何在Vue3中实现表单输入与接口验证的无缝联动,并优雅地展示…

Vue 插槽(Slot)用法详解

插槽(Slot)是Vue中一种强大的内容分发机制,它允许你在组件中定义可替换的内容区域,为组件提供了更高的灵活性和可复用性。本文将全面介绍Vue插槽的各种用法。 1. 基本插槽 基本插槽是最简单的插槽形式,它允许父组件向子组件插入内容。 子组…

C++ 标准模板库(STL)详解文档

C 标准模板库(STL)详解文档 1 前言2 常用容器2.1 内容总览2.2 向量 vector2.2.1 概述2.2.2 常用方法2.2.3 适用场景2.2.4 注意事项 2.3 栈 stack2.3.1 概述2.3.2 常用方法2.3.3 注意事项 2.4 队列 queue2.4.1 概述2.4.2 常用方法2.4.3 注意事项 2.5 优先…

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…

Redis(02)Win系统如何将Redis配置为开机自启的服务

一、引言 Redis 是一款高性能的键值对存储数据库,在众多项目中被广泛应用。在 Windows 环境下,为了让 Redis 能更稳定、便捷地运行,将其设置为系统服务并实现自动启动是很有必要的。这样一来,系统开机时 Redis 可自动加载&#xf…

apex新版貌似移除了amp从源码安装方式装的话会在from apex import amp时报错

问题: 安装完apex结果 from apex import amp会报错 解决方法: # apex git clone https://github.com/NVIDIA/apex cd apex # https://github.com/modelscope/ms-swift/issues/4176 git checkout e13873debc4699d39c6861074b9a3b2a02327f92 pip insta…

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…

【AI学习】三、AI算法中的向量

在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…