如何使用 DeepEval 优化 Elasticsearch 中的 RAG 检索

news2025/3/19 16:00:55

作者:来自 Elastic Kritin Vongthongsri

学习如何使用 DeepEval 优化 RAG 流水线中的 Elasticsearch 检索器。

LLMs 容易产生幻觉、缺乏特定领域的专业知识,并受限于上下文窗口。检索增强生成(Retrieval-Augmented Generation - RAG)通过使 LLM 访问相关的外部上下文来解决这些问题,从而使其回答更加准确。

多种 RAG 方法(如 GraphRAG 和 AdaptiveRAG)已经出现,以提高检索的准确性。然而,检索性能仍可能因 RAG 应用的领域和具体用例而有所不同。

要针对特定用例优化检索,需要确定能提供最佳质量的超参数,包括嵌入模型的选择、返回的顶部结果数量(top-K)、相似度函数、重排序策略等。

优化检索意味着评估并迭代这些超参数,直到找到性能最佳的组合。在本文中,我们将探讨如何使用 DeepEval 优化 RAG 流水线中的 Elasticsearch 检索器。

我们首先安装 Elasticsearch 和 DeepEval:

pip install deepeval elasticsearch

衡量检索性能

要优化 Elasticsearch 检索器并对每种超参数组合进行基准测试,需要一种评估检索质量的方法。以下是三个关键指标,可用于衡量检索性能:上下文精确度(contextual precision)上下文召回率(contextual recall)上下文相关性(contextual relevancy)

上下文精确度(Contextual Precision):

from deepeval.metrics import ContextualPrecisionMetric
contextual_precision = ContextualPrecisionMetric()

上下文召回率(Contextual Recall):

该指标衡量检索到的上下文中是否包含所有与输入相关的信息块。换句话说,它检查检索器是否遗漏了关键信息,以确保返回的内容尽可能完整。

from deepeval.metrics import ContextualRecallMetric
contextual_precision = ContextualRecallMetric()

上下文相关性(Contextual Relevancy):

该指标衡量检索到的信息块与输入查询的整体相关性。它确保返回的内容不仅包含相关信息,而且整体上对生成高质量 LLM 响应是有意义的。较高的上下文相关性得分表明检索系统能够提供更加精准和有用的上下文支持。

from deepeval.metrics import ContextualRelevancyMetric
contextual_relevancy = ContextualRelevancyMetric()

最终,上下文相关性指标评估检索上下文中的信息与 RAG 应用用户输入的相关性。

这三个指标的结合对于确保检索器获取适量的正确信息、按适当顺序排列,并为 LLM 提供干净、结构良好的数据以生成准确输出至关重要。

理想情况下,应该找到使所有三个指标得分最高的超参数组合。然而,在某些情况下,提高召回率可能会不可避免地降低相关性。因此,在这些因素之间找到平衡点是实现最佳性能的关键。

如果需要针对特定用例的自定义指标,可以考虑使用 G-Eval 和 DAG。这些工具允许你定义具有特定评估标准的精确指标。

以下资源可能有助于更好地理解这些指标的计算方法:

  • 如何计算上下文精度
  • 如何计算上下文召回率
  • 如何计算上下文相关性
  • RAG 应用中的检索评估

Elasticsearch 可优化的超参数

Elasticsearch 在 RAG 管道中的信息检索提供了极大的灵活性,可通过多种超参数调整来优化检索性能。本节将介绍一些关键的超参数。

检索前:

为了在将数据插入 Elasticsearch 向量数据库之前优化其结构,可以调整诸如 chunk 大小chunk 重叠度 等参数。此外,选择合适的 嵌入模型 也至关重要,以确保高效且有意义的向量表示。

检索过程中:
Elasticsearch 允许完全控制检索过程。可以配置 相似度函数,首先确定近似搜索的候选数量,再对 top-K 进行 KNN 计算,最终选出最相关的 top-K 结果。

此外,还可以定义检索策略 —— 语义检索(基于向量嵌入)、文本检索(基于查询规则),或 混合检索(结合两者)。

检索后:

在获取检索结果后,Elasticsearch 允许进一步优化,例如 重排序(reranking)。可以选择 重排序模型、定义 重排序窗口、设置 最低分数阈值 等,以确保优先返回最相关的结果。

不同的超参数会对特定的检索指标影响较大。例如,如果发现 上下文相关性(contextual relevance) 低,可能与 top-K 等参数设置有关。通过将特定超参数映射到各个检索指标,可以更高效地调整 RAG 管道,从而精准优化检索性能。

下面是不同超参数对检索指标影响的映射表:

MetricHyperparameter
上下文精确度重排序模型、重排序窗口、重排序阈值
上下文召回率检索策略(文本 vs 嵌入)、嵌入模型、候选计数、相似度函数、top-K
上下文相关性top-K、块大小、块重叠

在下一节中,我们将通过代码示例演示如何评估和优化我们的 Elasticsearch 检索器。我们将使用 "all-MiniLM-L6-v2" 来嵌入文本文档,将 top-K 设置为 3,并将候选数配置为 10。

设置 RAG 与 Elastic Retriever

首先,连接到本地或基于云的 Elastic 集群:

from elasticsearch import Elasticsearch

# Create the client instance
client = Elasticsearch(
    # For local development
    # hosts=["http://localhost:9200"]
    cloud_id=ELASTIC_CLOUD_ID,
    api_key=ELASTIC_API_KEY,
)

接下来,创建一个 Elasticsearch 索引,并配置适当的类型映射,以存储文本和作为密集向量的嵌入。

if not client.indices.exists(index="knowledge_base"):
    client.indices.create(
        index="knowledge_base",
        mappings={
            "properties": {
                "text": {
                    "type": "text"
                },
                "embedding": {
                    "type": "dense_vector",
                    "dims": 384,
                    "index": "true",
                    "similarity": "cosine"
                }
            }
        }
    )

为了将文档块插入到 Elastic 索引中,首先使用嵌入模型将其编码为向量。在这个例子中,我们使用 "all-MiniLM-L6-v2"。

# Example document chunks
document_chunks = [
    "Elasticsearch is a distributed search engine.",
    "RAG improves AI-generated responses with retrieved context.",
    "Vector search enables high-precision semantic retrieval.",
    "Elasticsearch uses dense vector and sparse vector similarity for semantic search.",
    "Scalable architecture allows Elasticsearch to handle massive volumes of data.",
    "Document chunking can help improve retrieval performance.",
    "Elasticsearch supports a wide range of search features."
    # Add more document chunks as needed...
]
operations = []
for i, chunk in enumerate(document_chunks):
    operations.append({"index": {"_index": "knowledge_base", "_id": i}})
    # Convert the document chunk to an embedding vector
    operations.append({
        "text": chunk,
        "embedding": model.encode(chunk).tolist()
    })

client.bulk(index="knowledge_base", operations=operations, refresh=True)

最后,定义一个检索器函数,从你的 Elasticsearch 客户端中搜索以供 RAG 摄入管道使用。

def search(input, top_k=3):
    # Encode the query using the model
    input_embedding = model.encode(input).tolist()

    # Search the Elasticsearch index using kNN on the "embedding" field
    res = client.search(index="knowledge_base", body={
        "knn": {
            "field": "embedding",
            "query_vector": input_embedding,
            "k": top_k,  # Retrieve the top k matches
            "num_candidates": 10  # Controls search speed vs accuracy
        }
    })

    # Return a list of texts from the hits if available, otherwise an empty list
    return [hit["_source"]["text"] for hit in res["hits"]["hits"]] if res["hits"]["hits"] else []

评估你的 RAG 检索器

在设置好 Elasticsearch 检索器后,你可以开始将其作为 RAG 管道的一部分进行评估。评估过程包括两步:

  1. 准备输入查询及预期的 LLM 响应,并使用该输入生成 RAG 管道的响应,以创建一个 LLMTestCase,其中包含输入、实际输出、预期输出和检索上下文。
  2. 使用一系列检索指标来评估该测试用例。

准备测试用例

在这里,我们准备一个输入问题:“Elasticsearch 是如何工作的?”以及相应的预期输出:“Elasticsearch 使用密集向量和稀疏向量相似度进行语义搜索。”

input = "How does Elasticsearch work?"
expected_output= "Elasticsearch uses dense vector and sparse vector similarity for semantic search."
retrieval_context = search(input)

prompt = """
Answer the user question based on the supporting context

User Question:
{input}

Supporting Context:
{retrieval_context}
"""
actual_output = generate(prompt) # hypothetical function, replace with your own LLM
print(actual_output)

让我们来检查一下我们的 RAG 管道生成的实际输出:

“Elasticsearch indexes document chunks using an inverted index for fast full-text search and retrieval.”

最后,将所有测试用例参数合并为一个单一的 LLM 测试用例。

from deepeval.test_case import LLMTestCase

test_case = LLMTestCase(
    input=”"How does Elasticsearch work?",
    actual_output=actual_output,
    retrieval_context=retrieval_context,
    expected_output=,
)

运行评估

要对你的 Elastic 检索器运行评估,将我们之前定义的测试用例和度量传递给 evaluate 函数。

evaluate(
   [test_case],
   metrics=[contextual_recall, contextual_precision, contextual_relevancy]
)

优化检索器

一旦你评估了测试用例,我们就可以开始分析结果。下面是我们创建的测试用例的示例评估结果,以及用户可能向你的 RAG 系统提出的其他假设性查询。

QueryContextual precisionContextual recallContextual relevancy
"How does Elasticsearch work?"0.630.930.52
"Explain Elasticsearch's indexing method."0.570.870.49
"What makes Elasticsearch efficient for search?"0.650.900.55
  • Contextual precision 较差 → 一些检索到的上下文可能过于泛泛或离题。
  • Contextual recall  较强 → Elasticsearch 检索到了足够相关的文档。
  • Contextual relevancy 不一致 → 检索到的文档质量在不同查询中有所变化。

提高检索质量

如前所述,每个指标受到特定检索超参数的影响。由于上下文精确度较差且上下文相关性不一致,显然需要改进重排器超参数,以及 top-K、块大小和块重叠。

以下是如何使用简单的 for 循环迭代 top-K 的示例。

# Example of running multiple test cases with different retrieval settings
for top_k in ["1", "3", "5", "7"]:
    retrieval_context = search(query, top_k)
    test_case = LLMTestCase(
        input=query,
        actual_output=generate(query, retrieval_context),
        retrieval_context=retrieval_context,
        expected_output="Elasticsearch is an optimized vector database for AI applications.",
    )

    evaluate([test_case], metrics=[contextual_recall, contextual_precision, contextual_relevancy])

这个 for 循环有助于识别产生最佳指标得分的 top-K 值。你应该将这种方法应用于所有影响检索系统相关性和精确度得分的超参数。这样,你就能确定最佳组合!

跟踪改进

DeepEval 是开源的,非常适合如果你想在本地评估检索器。

然而,如果你希望进行更深入的分析并存储评估结果,Confident AI 将你的评估带到云端,并提供强大的分析工具进行广泛的实验。

Confident 允许你:

  • 轻松策划和管理评估数据集。
  • 使用 DeepEval 指标在本地运行评估,同时从 Confident AI 拉取数据集。
  • 查看和分享测试报告,比较提示、模型,并优化你的 LLM 应用。

想要获得 Elastic 认证吗?查看下一期 Elasticsearch 工程师培训的时间!

Elasticsearch 拥有许多新功能,可以帮助你为你的用例构建最佳搜索解决方案。深入了解我们的示例笔记本,开始免费云试用,或者现在就尝试在本地机器上使用 Elastic。

原文:如何在 Linux,MacOS 及 Windows 上进行安装 Elasticsearch_macos安装es-CSDN博客

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

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

相关文章

行为模式---状态模式

概念 状态模式是一种行为模式,用于在内部状态改变的时候改变其行为。它的核心思想就是允许一个对象在其内部状态改变的时候改变它的行为。状态模式通过将对象的状态封装成独立的类,并将其行为委托给当前的状态对象,从而使得对象行为随着状态…

嵌入式裸机设计--MCU常用裸机架构有哪些?

为什么是裸机设计 792125321入群学习更高效! 在MCU(微控制器单元)裸机开发中,我们常见的架构设计主要围绕如何高效管理资源和任务调度。认识这些开发方式,对我们开发一个小型项目来说及有好处! 下面介绍…

【LInux进程六】命令行参数和环境变量

【LInux进程六】命令行参数和环境变量 1.main函数的两个参数2.利用main函数实现一个简单的计算器3.环境变量之一:PATH4.修改PATH5.在命令行解释器bash中查看所有环境变量6.用自己写的程序查看环境变量7.main函数的第三个参数8.本地的环境变量和环境变量9.环境变量具…

激光slam学习笔记10---ubuntu2004部署运行fastlivo2踩坑记录

背景:mars实验室又发福利啦!跑跑效果,验了那句,mars出品,必属精品!本人pc环境ubuntu20.04,基本流程按照readme走就行,sophus和vikit安装有些注意地方。本文做了一些部署踩坑记录&…

织梦DedeCMS优化文章模版里的“顶一下”与“踩一下”样式

测试的版本5.7.1UTF-8 一、插入<head>Js代码 将下面代码插入到文章模版里的<head>标签里 <script language"javascript" type"text/javascript" src"{dede:global.cfg_cmsurl/}/include/dedeajax2.js"></script> <…

IDEA+Docker插件一键部署SpringBoot项目到远程服务器

文章目录 1. 服务端1.1 安装Docker1.2 Docker放开远程连接1.3 重启Docker1.4 开放端口1.4.1 云端1.4.2 服务器内部防火墙指令 2.IntelliJ IDEA2.1 安装IDEA2.2 安装Docker插件2.3 SSH Configurations2.4 Docker选择对应的SSH2.5 Dockerfile2.5.1 Dockerfile2.5.2 Dockerfile Ed…

C++基础 [五] - String的模拟实现

目录 前言 string类的模拟实现 成员函数的实现 构造函数 拷贝构造函数 赋值运算符重载 析构函数 元素访问的实现 operator[ ] Iterator - 迭代器 容量大小的实现 size capacity reserve ​编辑resize 内容修改的实现 push_back append operator(char ch) …

AIAgent有哪些不错的开源平台

AIAgent领域有许多优秀的开源平台和框架&#xff0c;以下是一些值得推荐的开源平台&#xff1a; AutoGPT AutoGPT 是一个基于 OpenAI 的 GPT-4 和 GPT-3.5 大型语言模型的开源框架&#xff0c;能够根据用户给定的目标自动生成所需提示&#xff0c;并利用多种工具 API 执行多步骤…

Python刷题:流程控制(上)

今天刷的是PythonTip的Python 入门挑战中的题&#xff0c;整体难度不高&#xff0c;适合小白练手以及巩固知识点。下面会进行详细讲解。 每日一句 每一个拼命努力的人&#xff0c;都像是独自穿越黑暗森林的行者&#xff0c; 没有并肩的身影&#xff0c;唯有孤独如影随形&…

vulhub/Billu_b0x靶机----练习攻略

1.Billu_b0x靶场下载链接&#xff1a; https://download.vulnhub.com/billu/Billu_b0x.zip 2.下载后&#xff0c;解压出ova文件&#xff0c;直接拖至VMware中&#xff0c;重命名和选择存储位置&#xff0c;点击导入&#xff0c;报错点击重试即可。修改网卡为NAT模式。 打开靶…

【YOLOv8】YOLOv8改进系列(8)----替换主干网络之Swin Transformer

主页&#xff1a;HABUO&#x1f341;主页&#xff1a;HABUO &#x1f341;YOLOv8入门改进专栏&#x1f341; &#x1f341;如果再也不能见到你&#xff0c;祝你早安&#xff0c;午安&#xff0c;晚安&#x1f341; 【YOLOv8改进系列】&#xff1a; 【YOLOv8】YOLOv8结构解读…

Qwen2-Audio:通义千问音频大模型技术解读

引言:从llm到mlm(audio) 大型语言模型(LLM)的发展日新月异,它们在文本理解、生成、推理等方面展现出惊人的能力。然而,交互模态不仅仅依赖于文字,语音、语调、环境音等听觉信息同样承载着丰富的内容。阿里巴巴通义千问团队,推出了 Qwen-Audio 系列模型,这里我们一起…

解决Java多张图合成JPG时出现红色前景及多列自适应适配

目录 前言 一、追本溯源 1、回到最开始 2、合成JPG的异常 二、解决问题 1、关于ImageType 2、TYPE_INT_RGB和TYPE_INT_ARGB 3、问题修复 4、列数自适应的问题 三、总结 前言 在当今数字化信息飞速发展的时代&#xff0c;图像处理技术在各个领域都占据着举足轻重的地位…

SpringBoot实现发邮件功能+邮件内容带模版

发送简单邮件模版邮件 1.pom引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId><version>2.5.13</version></dependency><dependency><groupId&…

npm 报错 unable to resolve dependency tree

如下图&#xff1a; 解决&#xff1a;npm install --legacy-peer-deps 其实提示上有&#xff1a;npm ERR! Fix the upstream dependency conflict, or retry npm ERR! this command with --force, or --legacy-peer-deps

【蓝桥杯每日一题】3.17

&#x1f3dd;️专栏&#xff1a; 【蓝桥杯备篇】 &#x1f305;主页&#xff1a; f狐o狸x 他们说内存泄漏是bug&#xff0c;我说这是系统在逼我进化成SSR级程序员 OK来吧&#xff0c;不多废话&#xff0c;今天来点有难度的&#xff1a;二进制枚举 二进制枚举&#xff0c;就是…

Linux:冯诺依曼体系结构、操作系统、进程概念(一.初识进程)

文章目录 1.冯诺依曼体系结构总线与数据传输通路为什么有内存这个部分计算机存储结构 2.操作系统(Operator System)2.1 概念2.2 设计OS的目的2.3 理解“管理”先描述再组织 2.4 用户使用系统调用和库函数&#xff08;lib&#xff09;概念 总结 3.初识进程3.1 基本事实与引入3.2…

动手学深度学习:CNN和LeNet

前言 该篇文章记述从零如何实现CNN&#xff0c;以及LeNet对于之前数据集分类的提升效果。 从零实现卷积核 import torch def conv2d(X,k):h,wk.shapeYtorch.zeros((X.shape[0]-h1,X.shape[1]-w1))for i in range(Y.shape[0]):for j in range(Y.shape[1]):Y[i,j](X[i:ih,j:jw…

删除排序链表中的重复元素(js实现,LeetCode:83)

看到这道题的第一反应是使用快慢指针&#xff0c;之前做过类似的题&#xff1a;删除有序数组中的重复项&#xff08;js实现&#xff0c;LeetCode&#xff1a;26&#xff09;原理都是一样,区别是这题需要将重复项删除&#xff0c;所以只需要走一遍单循环就可以实现 /*** Defini…

单片机自学总结

自从工作以来&#xff0c;一直努力耕耘单片机&#xff0c;至今&#xff0c;颇有收获。从51单片机&#xff0c;PIC单片机&#xff0c;直到STM32&#xff0c;以及RTOS和Linux&#xff0c;几乎天天在搞:51单片机&#xff0c;STM8S207单片机&#xff0c;PY32F003单片机&#xff0c;…