吾日三省吾身。
单元测验是一种软件测验办法,它验证程序中的单独的代码单元是否按预期作业。代码单元是软件的最小可测验部分。在面向目标编程中,这通常是一个办法,无论是在基类(超类)、抽象类仍是派生类(子类)中。单元测验通常由软件开发人员编写,用于确保他们所写的代码契合软件需求和遵循开发目标。
AI时代单元测验或许会由Github Copilot和Cursor之类的东西主动生成。
运用LLM构建杂乱的运用程序时,咱们也会碰到相似的问题:怎么评价运用程序的体现,运用程序是否达到了咱们的检验标准,是否按预期作业?这一步很重要有时还有点扎手。别的,假如咱们决定换一种完成方法,如切换到不同的LLM(这个很有或许,LLM自身在不断升级,不同版本的差异比较大;也或许由于不可抗力的原因,从国外的LLM切换到国内的LLM)、更改怎么运用向量数据库的战略或许选用不同的向量数据库、选用其他方法检索数据或许修改了体系的其他参数等等,怎样才能知道成果更好了仍是更糟糕了?
在本篇中,咱们会评论怎么评价依据LLM的运用程序,一起介绍一些帮助评价的东西,终究还介绍了开发中的评价渠道。
假如运用LangChain来开发运用,运用实际上便是许多不同的链和序列,那么首要任务便是了解每个过程的输入和输出究竟是什么,咱们会用一些可视化东西和调试东西辅佐。运用很多不同的数据集来测验模型,这有助于咱们全面了解模型的体现。
调查事物的一种办法是直接用咱们的肉眼看,还有一个很自然的主意便是运用大言语模型和链来评价其他言语模型、链和运用程序。
预备
同样,先经过.env文件初始化环境变量,记住咱们用的是微软Azure的GPT,详细内容参阅本专栏的第一篇。
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
deployment = "gpt-4"
model = "gpt-3.5-turbo"
咱们运用上一篇文章中的文档问答程序来评价。为了阅览便利,这里列出对应的源代码,详细解说请参阅专栏的上一篇文章。
from langchain.chains import RetrievalQA
# from langchain.chat_models import ChatOpenAI
from langchain.chat_models import AzureChatOpenAI
from langchain.document_loaders import CSVLoader
from langchain.indexes import VectorstoreIndexCreator
from langchain.vectorstores import DocArrayInMemorySearch
file = 'OutdoorClothingCatalog_1000.csv'
loader = CSVLoader(file_path=file)
data = loader.load()
index = VectorstoreIndexCreator(
vectorstore_cls=DocArrayInMemorySearch
).from_loaders([loader])
# llm = ChatOpenAI(temperature = 0.0, model=llm_model)
llm = AzureChatOpenAI(temperature=0, model_name=model, deployment_name=deployment)
qa = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=index.vectorstore.as_retriever(),
verbose=True,
chain_type_kwargs = {
"document_separator": "<<<<>>>>>"
}
)
生成数据集
要评价,首要要搞清楚要用什么样的数据集。
手艺生成数据集
第一种方法是咱们自己手艺生成一些好的示例数据集。由于大言语模型仍是简略呈现幻觉,我以为当前这是必不可少的,手艺创立一些数据集感觉底气更足一点。
检查csv文档的两行数据:
Document(page_content=”shirt id: 10nname: Cozy Comfort Pullover Set, Stripendescription: Perfect for lounging, this striped knit set lives up to its name. We used ultrasoft fabric and an easy design that’s as comfortable at bedtime as it is when we have to make a quick run out.nnSize & Fitn- Pants are Favorite Fit: Sits lower on the waist.n- Relaxed Fit: Our most generous fit sits farthest from the body.nnFabric & Caren- In the softest blend of 63% polyester, 35% rayon and 2% spandex.nnAdditional Featuresn- Relaxed fit top with raglan sleeves and rounded hem.n- Pull-on pants have a wide elastic waistband and drawstring, side pockets and a modern slim leg.nnImported.”, metadata={‘source’: ‘OutdoorClothingCatalog_1000.csv’, ‘row’: 10})
Document(page_content=’shirt id: 11nname: Ultra-Lofty 850 Stretch Down Hooded Jacketndescription: This technical stretch down jacket from our DownTek collection is sure to keep you warm and comfortable with its full-stretch construction providing exceptional range of motion. With a slightly fitted style that falls at the hip and best with a midweight layer, this jacket is suitable for light activity up to 20 and moderate activity up to -30. The soft and durable 100% polyester shell offers complete windproof protection and is insulated with warm, lofty goose down. Other features include welded baffles for a no-stitch construction and excellent stretch, an adjustable hood, an interior media port and mesh stash pocket and a hem drawcord. Machine wash and dry. Imported.’, metadata={‘source’: ‘OutdoorClothingCatalog_1000.csv’, ‘row’: 11})
针对这两行数据,能够写出下面的问题和答案。
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"
}
]
这种方法不简略扩展,需要花时间来检查文档,了解文档的详细内容,AI时代应该更多的Automatic,不是吗?
下面咱们来看一下怎么主动生成测验数据集。
主动生成测验数据集
LangChain有一个QAGenerateChain链,能够读取文档并且从每个文档中生成一组问题和答案。
from langchain.evaluation.qa import QAGenerateChain
example_gen_chain = QAGenerateChain.from_llm(AzureChatOpenAI(deployment_name=deployment))
new_examples = example_gen_chain.apply_and_parse(
[{"doc": t} for t in data[:3]]
)
for example in new_examples:
print(example)
上面的程序运用了apply_and_parse办法来解析运转的成果,意图是得到Python的词典目标,便利后续处理。
运转程序能够得到下面的成果:
{‘qa_pairs’: {‘query’: “What is the approximate weight of the Women’s Campside Oxfords?”, ‘answer’: ‘The approximate weight is 1 lb.1 oz. per pair.’}} {‘qa_pairs’: {‘query’: ‘What are the dimensions of the small and medium Recycled Waterhog Dog Mat?’, ‘answer’: ‘The small Recycled Waterhog Dog Mat measures 18″ x 28″, while the medium one measures 22.5″ x 34.5″.’}} {‘qa_pairs’: {‘query’: ‘What is the name of the shirt with id: 2?’, ‘answer’: “Infant and Toddler Girls’ Coastal Chill Swimsuit, Two-Piece”}}
主动生成的数据集也一起加到手艺生成的数据集。
examples.extend([example["qa_pairs"] for example in new_examples])
评价
现在有了数据集,怎么评价呢?
跟踪单次调用
先来调查一个比如:
qa.run(examples[0]["query"])
把数据集的第一个问答传进去,运转会得到成果:
‘Yes, the Cozy Comfort Pullover Set does have side pockets. The pull-on pants in the set feature a wide elastic waistband, drawstring, side pockets, and a modern slim leg.’
可是咱们无法调查链的内部细节:如传给大言语模型的Prompt是什么,向量数据库检索到哪些文档?对于一个包含多个过程的杂乱链,每一步的中间成果是什么?所以只看到终究成果是远远不够的。(能够对比程序出错的时分看不到Stack Trace或许微服务调用看不到调用链)
针对这一问题,LangChain供给了“langchain debug”的小东西。经过 langchain.debug = True 开启调试形式履行qa.run(examples[0][“query”])。用完记得用langchain.debug = False封闭调试形式,不然就等着调试信息刷屏。
import langchain
langchain.debug = True
qa.run(examples[0]["query"])
# Turn off the debug mode
langchain.debug = False
从下面的图能够看到,调用的每一步都显示出来了:先调用RetrievalQA链,再调用StuffDocumentsChain(构建RetrievalQA链的时分,咱们传入了chain_type=”stuff”),终究来到LLMChain(能够看到传入的问题:Do the Cozy Comfort Pullover Set have side pockets? 和 上下文:shirt id: 10nname…… ,上下文是依据问题检索到的4个文档块:shirt id: 10、shirt id: 73、shirt id: 419、shirt id: 632内容拼接成的。文档块之间用<<<<>>>>>分隔开,这个是在前面经过chain_type_kwargs = {“document_separator”: “<<<<>>>>>”}配置的。)
在做文档问答体系时要注意,回来过错的成果,纷歧定是大言语模型自身的问题,或许在检索那一步就现已错了。检查检索回来的上下文有助于找出问题所在。
记住,咱们现在本质上便是在做依据Prompt的编程,所以咱们要继续往下,检查传给LLM的Prompt。这个也是咱们跟AI专家学习的好机会。 看一下咱们给体系的“人设”:Use the following pieces of context to answer the user’s question. nIf you don’t know the answer, just say that you don’t know, don’t try to make up an answer. 完成问答体系,这个很重要,确保了LLM不要胡编乱造,知之为知之,不知为不知,不知道直接答复不知道就好。
不知道有没有同学发现,整个调用链,为什么是1、3、4、5?这个估计是新版LangChain的bug, 吴恩达教师的视频中是1、2、3、4的。 [1:chain:RetrievalQA > 3:chain:StuffDocumentsChain > 4:chain:LLMChain > 5:llm:AzureChatOpenAI]
批量检查
咱们现在知道了怎么检查单次调用的状况,那么对于咱们手动和主动创立的一切examples,怎么批量检查是否正确呢?
LangChain供给了QAEvalChain链来协助判别问答体系的成果是否契合测验数据集的答案,便是做了普通程序单元测验里assertEqual的作业。
predictions = qa.apply(examples)
from langchain.evaluation.qa import QAEvalChain
llm = AzureChatOpenAI(temperature=0, model_name=model, deployment_name=deployment)
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("Predicted Grade: " + graded_outputs[i]['results'])
print()
首要履行检索链:predictions = qa.apply(examples),生成predictions,predictions是下面这样的结构(以第一个元素为例):query是问题,answer是答案,result是咱们的问答体系得到的成果。
{‘query’: ‘Do the Cozy Comfort Pullover Set have side pockets?’, ‘answer’: ‘Yes’, ‘result’: ‘Yes, the Cozy Comfort Pullover Set does have side pockets.’}
然后创立eval_chain,eval_chain.evaluate(examples, predictions)进行评价(传入examples有点多余,predictions现已包含了问题、答案),评价成果放在graded_outputs[i][‘results’]:CORRECT或许INCORRECT。
Example 0: Question: Do the Cozy Comfort Pullover Set have side pockets? Real Answer: Yes Predicted Answer: Yes, the Cozy Comfort Pullover Set does have side pockets. Predicted Grade: CORRECT
评价渠道
上面是在本地履行的,LangChain还在开发一个在线的评价渠道,原来的网址是:www.langchain.plus/ 现在变成 smith.langchain.com/ 黑客帝国的奸细Smith?
评价渠道目前需要约请码才能注册,能够用这个约请码试试:lang_learners_2023 在写本文的时分这个约请码还能够用。
评价渠道很简略运用:只需要简略设置一下环境变量,履行用LangChain开发的运用,就能够在渠道上看到调用链,界面还挺赏心悦意图。
注意会上传相当多的信息,假如是敏感项目,不要开启这个。