AI知识库

53AI知识库

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


Llamaindex最佳实践:18.OpenAI检索API基准测试(通过助手代理)
发布日期:2024-06-12 20:32:25 浏览次数: 1865 来源:barry的异想世界


本指南通过使用我们的OpenAIAssistantAgent基准测试OpenAI Assistant API中的检索工具。我们对Llama 2论文进行测试,并与简单的RAG管道的生成质量进行比较。

%pip install llama-index-readers-file pymupdf
%pip install llama-index-agent-openai
%pip install llama-index-llms-openai
!pip install llama-index
import nest_asyncio

nest_asyncio.apply()

数据设置

这里我们加载 Llama 2 论文并将其分块。

!mkdir -p 'data/'
!wget --user-agent "Mozilla" "https://arxiv.org/pdf/2307.09288.pdf" -O "data/llama2.pdf"
--2023-11-08 21:53:52--https://arxiv.org/pdf/2307.09288.pdf
正在解析 arxiv.org (arxiv.org)... 128.84.21.199
正在连接 arxiv.org (arxiv.org)|128.84.21.199|:443... 已连接。
已发送 HTTP 请求,正在等待响应... 200 OK
长度:13661300 (13M) [application/pdf]
正在保存至: ‘data/llama2.pdf’

data/llama2.pdf 100%[===================>]13.03M 141KB/s用时 1m 48s

2023-11-08 21:55:42 (123 KB/s) - ‘data/llama2.pdf’ 已保存 [13661300/13661300]
from pathlib import Path
from llama_index.core import Document, VectorStoreIndex
from llama_index.readers.file import PyMuPDFReader
from llama_index.core.node_parser import SimpleNodeParser
from llama_index.llms.openai import OpenAI
loader = PyMuPDFReader()
docs0 = loader.load(file_path=Path("./data/llama2.pdf"))

doc_text = "\n\n".join([d.get_content() for d in docs0])
docs = [Document(text=doc_text)]
node_parser = SimpleNodeParser.from_defaults()
nodes = node_parser.get_nodes_from_documents(docs)
len(nodes)
89

定义评估模块

我们设置评估模块,包括数据集和评估器。

设置“黄金数据集”

这里我们加载一个“黄金”数据集。

选项1:加载现有数据集

注意:我们从Dropbox中拉取。有关如何生成数据集的详细信息,请参阅我们的DatasetGenerator模块。

!wget "https://www.dropbox.com/scl/fi/fh9vsmmm8vu0j50l3ss38/llama2_eval_qr_dataset.json?rlkey=kkoaez7aqeb4z25gzc06ak6kb&dl=1" -O data/llama2_eval_qr_dataset.json
from llama_index.core.evaluation import QueryResponseDataset

# 可选
eval_dataset = QueryResponseDataset.from_json(
"data/llama2_eval_qr_dataset.json"
)

选项2:生成新数据集

如果您选择此选项,您可以从头开始生成新数据集。这使您可以调整DatasetGenerator设置,以确保满足您的需求。

from llama_index.core.evaluation import DatasetGenerator, QueryResponseDataset
from llama_index.llms.openai import OpenAI
# 注意:如果数据集尚未保存,请运行此代码
# 注意:我们仅从前20个节点生成,因为其余节点是引用
llm = OpenAI(model="gpt-4-1106-preview")
dataset_generator = DatasetGenerator(
nodes[:20],
llm=llm,
show_progress=True,
num_questions_per_chunk=3,
)
eval_dataset = await dataset_generator.agenerate_dataset_from_nodes(num=60)
eval_dataset.save_json("data/llama2_eval_qr_dataset.json")
# 可选
eval_dataset = QueryResponseDataset.from_json(
"data/llama2_eval_qr_dataset.json"
)

评估模块

我们定义了两个评估模块:正确性和语义相似性 - 两者都比较预测响应与实际响应的质量。

from llama_index.core.evaluation.eval_utils import (
get_responses,
get_results_df,
)
from llama_index.core.evaluation import (
CorrectnessEvaluator,
SemanticSimilarityEvaluator,
BatchEvalRunner,
)
from llama_index.llms.openai import OpenAI
eval_llm = OpenAI(model="gpt-4-1106-preview")
evaluator_c = CorrectnessEvaluator(llm=eval_llm)
evaluator_s = SemanticSimilarityEvaluator(llm=eval_llm)
evaluator_dict = {
"correctness": evaluator_c,
"semantic_similarity": evaluator_s,
}
batch_runner = BatchEvalRunner(evaluator_dict, workers=2, show_progress=True)
import numpy as np
import time
import os
import pickle
from tqdm import tqdm


def get_responses_sync(
eval_qs, query_engine, show_progress=True, save_path=None
):
if show_progress:
eval_qs_iter = tqdm(eval_qs)
else:
eval_qs_iter = eval_qs
pred_responses = []
start_time = time.time()
for eval_q in eval_qs_iter:
print(f"eval q: {eval_q}")
pred_response = agent.query(eval_q)
print(f"predicted response: {pred_response}")
pred_responses.append(pred_response)
if save_path is not None:
# 保存中间响应(作为缓存,以防出现异常)
avg_time = (time.time() - start_time) / len(pred_responses)
pickle.dump(
{"pred_responses": pred_responses, "avg_time": avg_time},
open(save_path, "wb"),
)
return pred_responses


async def run_evals(
query_engine,
eval_qa_pairs,
batch_runner,
disable_async_for_preds=False,
save_path=None,
):
# 然后进行评估
# TODO: 评估生成结果的样本
eval_qs = [q for q, _ in eval_qa_pairs]
eval_answers = [a for _, a in eval_qa_pairs]

if save_path is not None:
if not os.path.exists(save_path):
start_time = time.time()
if disable_async_for_preds:
pred_responses = get_responses_sync(
eval_qs,
query_engine,
show_progress=True,
save_path=save_path,
)
else:
pred_responses = get_responses(
eval_qs, query_engine, show_progress=True
)
avg_time = (time.time() - start_time) / len(eval_qs)
pickle.dump(
{"pred_responses": pred_responses, "avg_time": avg_time},
open(save_path, "wb"),
)
else:
# [可选] 加载
pickled_dict = pickle.load(open(save_path, "rb"))
pred_responses = pickled_dict["pred_responses"]
avg_time = pickled_dict["avg_time"]
else:
start_time = time.time()
pred_responses = get_responses(
eval_qs, query_engine, show_progress=True
)
avg_time = (time.time() - start_time) / len(eval_qs)

eval_results = await batch_runner.aevaluate_responses(
eval_qs, responses=pred_responses, reference=eval_answers
)
return eval_results, {"avg_time": avg_time}

构建内置检索的助手

我们将通过传递内置的OpenAI检索工具来构建助手。

在这里,我们上传并在创建助手时传入文件。

from llama_index.agent.openai import OpenAIAssistantAgent
agent = OpenAIAssistantAgent.from_new(
name="SEC 分析师",
instructions="你是一个设计用来分析SEC文件的QA助手。",
openai_tools=[{"type": "retrieval"}],
instructions_prefix="请以Jerry称呼用户。",
files=["data/llama2.pdf"],
verbose=True,
)
response = agent.query(
"Llama 2 和 Llama 2-Chat 的主要区别是什么?"
)
print(str(response))
根据文档,Llama 2 和 Llama 2-Chat 的主要区别在于它们在安全评估中的表现,特别是在对抗性提示测试中。Llama 2-Chat 的安全评估部分突出显示了以下一些差异:

...

基准测试

我们在评估数据集上运行代理。我们使用标准的 top-k RAG 管道(k=2)与 gpt-4-turbo 进行基准对比。

注意:在我们测试的时期(2023年11月),助手API的速率限制非常严格,对60个数据点生成响应可能需要约1-2小时。

定义基线索引 + RAG 管道

llm = OpenAI(model="gpt-4-1106-preview")
base_index = VectorStoreIndex(nodes)
base_query_engine = base_index.as_query_engine(similarity_top_k=2, llm=llm)

在基线运行评估

base_eval_results, base_extra_info = await run_evals(
base_query_engine,
eval_dataset.qr_pairs,
batch_runner,
save_path="data/llama2_preds_base.pkl",
)
results_df = get_results_df(
[base_eval_results],
["基线查询引擎"],
["正确性", "语义相似度"],
)
display(results_df)

namescorrectnesssemantic_similarity
0基线查询引擎4.050.964245

在助手API上运行评估

assistant_eval_results, assistant_extra_info = await run_evals(
agent,
eval_dataset.qr_pairs[:55],
batch_runner,
save_path="data/llama2_preds_assistant.pkl",
disable_async_for_preds=True,
)

获取结果

我们看到...我们的基本 RAG 管道表现更好。

对这些数字持保留态度。这里的目标是提供一个脚本,以便您可以在自己的数据上运行。

尽管如此,检索API没有立即提供开箱即用的更好性能,这还是令人惊讶的。

results_df = get_results_df(
[assistant_eval_results, base_eval_results],
["检索API", "基线查询引擎"],
["正确性", "语义相似度"],
)
display(results_df)
print(f"基线平均时间: {base_extra_info['avg_time']}")
print(f"助手平均时间: {assistant_extra_info['avg_time']}")

namescorrectnesssemantic_similarity
0检索API3.5363640.952647
1基线查询引擎4.0500000.964245
基线平均时间: 0.25683316787083943
助手平均时间: 75.43605598536405



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

产品:大模型应用平台+智能体定制开发+落地咨询服务

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

联系我们

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

微信扫码

与创始人交个朋友

回到顶部

 
扫码咨询