LangChain大型语言模型(LLM)应用开发(五):评估

LangChain是一个基于大语言模型(如ChatGPT)用于构建端到端语言模型应用的 Python 框架。它提供了一套工具、组件和接口,可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互,将多个组件链接在一起,以便在不同的应用程序中使用。

今天我们来学习DeepLearning.AI的在线课程:LangChain for LLM Application Development的第五门课:Evaluation(评估),所谓评估是指检验LLM回答的问题是否正确的方法,在上一篇博客Q&A over Documents中我们解释了如何通过langchain来实现对文档的问答功能,在文档的问答过程中LLM会就用户提出的关于文档内容的相关问题进行回答,那么今天我们需要研究的就是如何来检验LLM的回答是否正确?

要评估LLM回答问题的准确性大致需要下面几个步骤:

  1. 需要创建一组关于相关的问答测试集(包含了问题和标准答案)
  2. 让LLM回答测试集中的所有问题,并收集LLM给出的所有答案
  3. 将LLM的答案与问答测试集中的标准答案做比对,并给LLM的表现评分

下面我们就开始来讨论评估LLM表现吧!

创建基于文档问答的Q/A应用

首先我们还是要做一些基础性工作,比如设置openai的api key,导入一些langchain的基础库:

import pandas as pd
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
from langchain.document_loaders import CSVLoader
from langchain.indexes import VectorstoreIndexCreator
from langchain.vectorstores import DocArrayInMemorySearch
import os

from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file

接下来我们需要导入一个csv文件,该文档主要包含2列,name和description,其中name表示商品的名称,description表示该商品的说明信息,我们需要对改文档的产品信息进行问答。

df=pd.read_csv("OutdoorClothingCatalog_1000.csv")
 
df

 下面我们查看一下其中的某个商品信息:

print(df[:1].name.values[0])
print('------------------------')
print(df[:1].description.values[0])

 下面我们将该商品的信息翻译成中文,这样便于大家理解:

 接下来我们要创建一个用于回答文档内容的chain:RetrievalQA, 创建RetrievalQA需要包含以下几个步骤:

  1. 创建一个文档加载器CSVLoad实例
  2. 创建向量数据库索引index
  3. 创建llm
  4. 创建文档问答chain,RetrievalQA
#1.创建文档加载器
file = 'OutdoorClothingCatalog_1000.csv'
loader = CSVLoader(file_path=file)
data = loader.load()

#2.创建向量数据库索引
index = VectorstoreIndexCreator(
    vectorstore_cls=DocArrayInMemorySearch
).from_loaders([loader])

#3.创建llm
llm= ChatOpenAI(temperature = 0.0)

#4.创建文档问答chain
qa = RetrievalQA.from_chain_type(
    llm=llm, 
    chain_type="stuff", 
    retriever=index.vectorstore.as_retriever(), 
    verbose=True,
    chain_type_kwargs = {
        "document_separator": "<<<<>>>>>"
    }
)

上述代码的主要功能及作用在LangChain大型语言模型(LLM)应用开发(四):Q&A over Documents这篇博客中都已说明,这里不再赘述。

设置测试的数据

下面我们查看一下经过档加载器CSVLoad加载后生成的data内的信息,这里我们抽取data中的第九和第十条数据看看它们的主要内容:

手动创建测试集 

需要说明的是这里我们的文档是csv文件,所以我们使用的是文档加载器是CSVLoader,CSVLoader会对csv文件中的每一行数据进行分割,所以这里看到的data[10],data[11]的内容则是csv文件中的第10,第11条数据的内容。下面我们根据这两条数据手动设置两条“问答对”,每一个“问答对”中包含一个query,一个answer:

examples = [
    {
        "query": "Do the Cozy Comfort Pullover Set\
        have side pockets?",
        "answer": "Yes"
    },
    {
        "query": "What collection is the Ultra-Lofty \
        850 Stretch Down Hooded Jacket from?",
        "answer": "The DownTek collection"
    }
]

让LLM生成Q/A测试用例

在我以前写的两篇博客中(使用大型语言模(LLM)构建系统(七):评估1,与 使用大型语言模(LLM)构建系统(七):评估2)我们使用的方法都是通过手动的方法来构建测试数据集,比如说我们可以手动创建10个问题和10个答案,然后让LLM回答这10个问题,再将LLM给出的答案与我们准备好的答案做比较,最后再给LLM打分。评估的流程大概就是这样,但是这里有一个问题,就是我们需要手动去创建所有的问题集和答案集,那会是一个非常耗费人力和时间的成本。那有没有一种可以自动创建大量问题集和答案集的方法呢?那当然是有的,今天我们就来介绍Langchain提供的方法:QAGenerateChain,我们可以通过QAGenerateChain来为我们的文档自动创建问答集:

from langchain.evaluation.qa import QAGenerateChain

example_gen_chain = QAGenerateChain.from_llm(ChatOpenAI())

new_examples = example_gen_chain.apply([{"doc": t} for t in data[:5]])
print(new_examples)

 这里我们对上述代码做个简单说明,我们创建了一个QAGenerateChain,然后我们应用了QAGenerateChain的apply方法对data中的前5条数据创建了5个“问答对”,由于创建问答集是由LLM来自动完成的,因此会涉及到token成本的问题,所以我们这里出于演示的目的,只对data中的前5条数据创建问答集。

那QAGenerateChain是如何自动创建问题集的,一个简单的apply方法似乎隐藏了很多的细节,如果你对这个隐藏的细节感兴趣,那我们可以尝试用debug的方式来打开这个潘多拉魔盒:

import langchain

#打开debug
langchain.debug = True

new_examples = example_gen_chain.apply([{"doc": t} for t in data[:5]])

#关闭debug
langchain.debug = False

 从上面展现的细节中我们可以看到,原来在QAGenerateChain中有一个内置的prompt,在这个内置的prompt的前缀信息中,以"Human"的角色要求LLM对给与它的文档产生一个question和answer。这个prompt的前缀信息大概就长这个样子:

 QAGenerateChain会在data中的每一条数据中都运用这个prompt模板,因此data中的每一条数据都会产生一条“问答对”。有了问答集以后,我们还需要对问答集进行解析,从中过滤出真正有用的信息,不过我们首先需要创建一个解析函数parse_strings:

def parse_strings(strings_list):
    parsed_list = []
    
    for s in strings_list:
        s = s.replace('\n\n','\n')
        split_s = s.split('\n')
        
        # Ensure there are 2 parts in the split string
        if len(split_s) != 2:
            continue
        
        question_part, answer_part = split_s
        
        # Ensure each part has the correct prefix
        if not question_part.startswith('QUESTION: ') or not answer_part.startswith('ANSWER: '):
            continue
        
        # Remove the prefixes and strip leading/trailing whitespace
        question = question_part.replace('QUESTION: ', '').strip()
        answer = answer_part.replace('ANSWER: ', '').strip()
        
        parsed_list.append({"query": question, "answer": answer})
    
    return parsed_list

#对问答集进行解析
new_examples = parse_strings([t['text'] for t in new_examples])
print(new_examples)

 这里经过解析以后我们的new_examples 中只包含了5个query和5个answer,没有其他多余的信息,这正是我们想要的测试集。

组合测试集

还记得我们前面手动创建的两个问答集吗?现在我们需要将之前手动创建的问答集合并到QAGenerateChain创建的问答集中,这样在答集中既有手动创建的例子又有llm自动创建的例子,这会使我们的测试集更加完善:

examples += new_examples

examples 

 这里我们看到examples 的前两条数据就是我们先前手动创建的,接下来我们就需要让之前创建的文档问答chain来回答这个测试集里的问题,来看看LLM是怎么回答的吧:

qa.run(examples[0]["query"])

 

 这里我们看到qa回答了第0个问题:“Yes, the Cozy Comfort Pullover Set does have side pockets.” ,这里的第0个问题就是先前我们手动创建的第一个问题,并且我们手动创建的answer是 :"Yes", 这里我们发现问答chain qa回答的也是“Yes”,只是它比我们的答案还多了一段说明:“the Cozy Comfort Pullover Set does have side pockets.”。

你想知道问答chain qa是怎么找到问题的答案的吗?魔鬼往往隐藏在细节中,下面让我们打开debug,看看问答chain qa是如何找到问题的答案!

langchain.debug = True

qa.run(examples[0]["query"])

langchain.debug = False

 这里我们稍微对问答chain qa寻找答案的过程进行一些说明,首先qa拿到问题,然后根据问题去向量数据库中搜索和问题相关的产品信息(会在全部产品中搜索),由于向量数据库中可能会存在多条产品信息和问题相关,因此这里会用“<<<<>>>>>”来分隔搜索到的多个产品信息,这里所谓的搜索是指向量间的相似度计算和比较,首先将问题转换成向量,再计算问题向量和数据库中每个向量的相似度,获取相似度最高的n条向量,然后再将这些相似的向量再转换成对应的文本即可。当这些步骤完成以后我们就看到了上述的结果,其中罗列了question和content,question是我们提出的问题,而“content”则是搜索到的多个相关产品信息,它们被用“<<<<>>>>>”分隔。这里需要加入一个我的个人判断:在搜索相关文档的时候应该是没有llm参与的,因此不会产生token成本的问题。在有了问题和相关产品信息后,接下来就需要LLM登场了,这里就会有一个prompt,在这个prompt中有一个System前缀信息,它告诉llm需要做什么,紧接着前缀信息的是多个产品信息,它们被用<<<<>>>>>进行分隔,最后是我们的问题,这里用Human来标识我们的问题。

 

 下面是输出部分,LLM会根据给它的prompt输出一个内容较多的json格式的结果,其中包含了问题的答案:

 

 最后经过过滤,得到了最终的答案:

前面我们让问答chain qa回答了测试集中的一个问题,下面我们要做的是让qa来回答测试集中的所有问题:

predictions = qa.apply(examples)

  

 基于LLM的自我评估

让我们来理一下思路,首先我们让LLM自动创建了问答测试集,接着我们又让LLM回答了测试集中所有的问题并得到了所有问题的回复信息。接下来我们要做的就是将这些问题的回复信息与测试集里的答案进行比对,更其妙的是这个比对过程也将是由LLM自己来完成,也就是说我们的LLM既当球员,又当裁判,最后再由“裁判”给出比对的结果,不过我需要指出的这里既当球员,又当裁判的LLM并非是同一个chain构成的,它们来自于不同的chain,也就是说这些chain的职能是不同的:

from langchain.evaluation.qa import QAEvalChain

#创建LLM
llm = ChatOpenAI(temperature=0)

#创建评估chain
eval_chain = QAEvalChain.from_llm(llm)

#生成评估结果
graded_outputs = eval_chain.evaluate(examples, predictions)

#统计评估结果
for i, eg in enumerate(examples):
    print(f"Example {i}:")
    print("Question: " + predictions[i]['query'])
    print("Real Answer: " + predictions[i]['answer'])
    print("Predicted Answer: " + predictions[i]['result'])
    print("Predicted Grade: " + graded_outputs[i]['text'])
    print()

 从上面的返回结果中我们看到,每一个问题中都包含了Question,Real Answer,Predicted Anser和Predicted Grade 四组内容,其中Real Answer是有先前的QAGenerateChain创建的问答测试集中的答案,而Predicted Answer则是由我们的问答chain qa回答的问题,最后的Predicted Grade则是由上面代码中的QAEvalChain回答的。

总结

今天我们学习了如何利用Langchain来评估LLM的表现,和以前评估openai模型的方法不同的是,这里我们使用的是全自动方式,即全自动方式生成测试集,然后全自动的给出问题的预测结果,最好全自动的评估预测结果的准确性,通过这种全自动的方式解放了我们的双手,使我们不需要因为没有测试数据集而苦恼,大大提高了生产率。

参考资料

QA Generation | 🦜️🔗 Langchain

Question Answering | 🦜️🔗 Langchain

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【每日一题】——C - Standings(AtCoder Beginner Contest 308 )

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;每日一题 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日反刍 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓称…

ArcGIS、ENVI、InVEST、FRAGSTATS等多技术融合提升环境、生态、水文、土地、土壤、农业、大气等领域的数据分析

一、 空间数据获取与制图 1.1 软件安装与应用讲解 1.2 空间数据介绍 1.3海量空间数据下载 1.4 ArcGIS软件快速入门 1.5 Geodatabase地理数据库 二、 ArcGIS专题地图制作 2.1专题地图制作规范 2.2 空间数据的准备与处理 2.3 空间数据可视化&#xff1a;地图符号与注记 …

十一、正则表达式详解:掌握强大的文本处理工具(三)

文章目录 &#x1f340;贪婪模式&#x1f340;应用的场景&#x1f340;总结 &#x1f340;非贪婪模式&#x1f340;应用的场景&#x1f340;总结 &#x1f340;贪婪模式与非贪婪模式在爬虫的应用&#x1f340;转义字符&#x1f340;正则表达式常见函数 &#x1f340;贪婪模式 在…

如何查看小程序的APPID和AppSecret

小程序APPID可以在手机上打开小程序后&#xff0c;点击右上角三点&#xff1a; 然后点击中间位置的小程序名称&#xff0c;进入小程序介绍页面&#xff1a; 点击“更多资料”后&#xff0c;进入页面就可以看到上方有APPID&#xff1a; 另一种方法&#xff1a; 在微信公众平台登…

【iOS】CALayer的理解与简单使用

文章目录 前言一、UIView与CALayer的关系二、CALayer的简单使用1.圆角与裁剪2.contents3.边框属性 总结 前言 在实现网易云音乐demo开发的过程中&#xff0c;通过查阅网上资料&#xff0c;发现了我们可以对我们的视图进行裁剪来实现美观的体现&#xff0c;例如这样&#xff1a…

Vue--》打造个性化医疗服务的医院预约系统(三)

今天开始使用 vue3 + ts 搭建一个医院预约系统的前台页面,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关…

C语言程序运行需要的两大环境《C语言进阶》

目录 程序的翻译环境和执行环境 翻译环境分为两部分&#xff0c;编译链接 第一步&#xff1a;预编译&#xff08;预处理&#xff09; 第二步&#xff0c;编译 第三步&#xff1a;汇编 关于运行环境分为四点&#xff1a; 关于链接库 程序的翻译环境和执行环境 在 ANSI C(标…

C语言第七课----------函数的定义及使用--------C语言重要一笔

作者前言 个人主页::小小页面 gitee页面:秦大大 一个爱分享的小博主 欢迎小可爱们前来借鉴 __________________________________________________________ 目录 1.函数是什么 2. 库函数 3. 自定义函数 4. 函数参数 5. 函数调用 6. 函数的嵌套调用和链式访问 7. 函数的声…

海康摄像头开发笔记(一):连接防爆摄像头、配置摄像头网段、设置rtsp码流、播放rtsp流、获取rtsp流、调优rtsp流播放延迟以及录像存储

文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/131679108 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结…

物联网如何为智慧城市提供动力

智慧城市可以创造一个基础设施顺畅、效率提升的乌托邦&#xff0c;改善城市地区的生活质量&#xff0c;促进当地经济发展。 其影响意义重大&#xff0c;预计到 2024 年智慧城市基础设施的收入将超过 1000 亿美元。 从改善公共交通到解决犯罪问题和提高能源效率——应有尽有&am…

Fatdog64 Linux 814发布

导读Fatdog64 Linux是一个小型、桌面、64位的Linux发行版。 最初是作为Puppy Linux的衍生品&#xff0c;并增加了一些应用程序。该项目最新的版本&#xff0c;Fatdog64 814&#xff0c;是8xx系列的最后一个版本&#xff0c;未来的版本将转向9xx基础。 尽管它是该系列的最后一个…

【Ranking】50 Matplotlib Visualizations, Python实现,源码可复现

详情请参考博客: Top 50 matplotlib Visualizations 因编译更新问题&#xff0c;本文将稍作更改&#xff0c;以便能够顺利运行。 1 Ordered Bar Chart 有序条形图有效地传达项目的排名顺序。但是&#xff0c;将图表上方的指标值相加&#xff0c;用户将从图表本身获得准确的信息…

网络安全合规与标准的主要发展方向

网络安全合规就是避免违反网络安全有关的法律、法规、规章、合同义务以及任何安全要求&#xff0c;标准在网络安全合规工作中扮演着重要的角色。 一、标准在网络安全合规体系中的地位作用 网络安全合规体系包括网络安全有关的法律、法规、规章、其他规范性文件、及合同义务等…

[java安全]TemplatesImpl在Shiro550反序列化

文章目录 【java安全】TemplatesImpl在Shiro550反序列化Shiro的原理Shiro反序列化产生演示攻击过程payload使用key加密 构造不含数组的GadGets简单调用链 改造cc6为CommonsCollctionsShiro完整POC触发Shiro550漏洞进阶POC总结 【java安全】TemplatesImpl在Shiro550反序列化 Sh…

24.实现线性拟合和相关系数(matlab程序)

1.简述 1. 基本语法 1.1 corr函数基本语法 语法 说明 rho corr(X) 返回输入矩阵X中每对列之间的两两线性相关系数矩阵。 rho corr(X, Y) 返回输入矩阵X和Y中每对列之间的两两相关系数矩阵。 [rho, pval] corr(X, Y) 返回pval&#xff0c;一个p值矩阵&#xff0c…

OceanBase 压测时为什么冻结阈值在变化?

本文从源码角度分析了 OceanBase 压测中冻结阈值动态变化的原因&#xff0c;并给出运维建议。 作者&#xff1a;张乾 外星人2号&#xff0c;兼任五位喵星人的铲屎官。 本文来源&#xff1a;原创投稿 爱可生开源社区出品&#xff0c;原创内容未经授权不得随意使用&#xff0c;转…

Vue3组合式API+TypeScript写法入门

文章目录 前言1.reactive2.ref3.props4.computed5.emit6.watch总结 前言 参考Vue3官网. 本篇以组合式API为例, 但不包含setup语法糖式写法. 原本打算结合class-component, Vue3不推荐就不用了: OverView|Vue Class Component. 而且是不再推荐基于类的组件写法, 推荐单文件组件…

NetSuite ERP顾问的进阶之路

目录 1.修养篇 1.1“道”是什么&#xff1f;“器”是什么&#xff1f; 1.2 读书这件事儿 1.3 十年计划的力量 1.3.1 一日三省 1.3.2 顾问损益表 1.3.3 阶段课题 2.行为篇 2.1协作 2.2交流 2.3文档管理 2.4时间管理 3.成长篇 3.1概念能力 3.1.1顾问的知识结构 …

【idea】idea全局设置Maven配置

Idea版本&#xff1a;2021.1.1 1、点击File->Close project 2、点击Customize->All settings 3、设置Maven

Vue 项目增加版本号输出, 可用于验证是否更新成功

webpack 1. vue.config.js 中增加以下配置, 此处以增加一个日期时间字符串为例, 具体内容可以根据自己需求自定义 // vue.config.js module.exports {chainWebpack(config) {config.plugin(define).tap(args > {args[0][process.env].APP_VERSION ${JSON.stringify(new …