第六、七章
前言
【在线阅读地址】https://datawhalechina.github.io/llm-universe/
【项目仓库地址】https://github.com/datawhalechina/llm-universe
【用户反馈地址】https://emoumcwvfx.feishu.cn/share/base/form/shrcnWBh2a9gl3HhW5ww736B64f
【小程序使用手册】
https://mp.weixin.qq.com/s/iPmzb72Yk0mhIA2NYezXDg
第六章 验证迭代
一、验证迭代的一般思路
使用LLM构建应用程序时,首先在小样本集上调整Prompt,测试系统性能。当遇到棘手例子时,将其添加到测试集合中,逐步扩大开发集。当手动运行例子变得不便时,开发用于衡量性能的指标,如平均准确度。如果系统性能足够好,可以随时停止改进。在实际应用中,许多已部署的应用程序在第一步或第二步就停止了,并且运行良好。
二、解决Bad Case
初始化的的 Prompt :
template_v1 = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
案。最多使用三句话。尽量使答案简明扼要。总是在回答的最后说“谢谢你的提问!”。
{context}
问题: {question}
有用的回答:"""
1、提升回答的质量
修改 Prompt 模板,加入要求其回答具体,并去掉“谢谢你的提问”的部分:
template_v2 = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
案。你应该使答案尽可能详细具体,但不要偏题。如果答案比较长,请酌情进行分段,以提高答案的阅读体验。
{context}
问题: {question}
有用的回答:"""
改进 Prompt,要求其对有几点的答案进行分点标号,让答案清晰具体:
template_v3 = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
案。你应该使答案尽可能详细具体,但不要偏题。如果答案比较长,请酌情进行分段,以提高答案的阅读体验。
如果答案有几点,你应该分点标号回答,让答案清晰具体
{context}
问题: {question}
有用的回答:"""
2、标明知识来源,提高可信度
由于大模型存在幻觉问题,有时我们会怀疑模型回答并非源于已有知识库内容。
template_v4 = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
案。你应该使答案尽可能详细具体,但不要偏题。如果答案比较长,请酌情进行分段,以提高答案的阅读体验。
如果答案有几点,你应该分点标号回答,让答案清晰具体。
请你附上回答的来源原文,以保证回答的正确性。
{context}
问题: {question}
有用的回答:"""
3、构造思维链
大模型往往可以很好地理解并执行指令,但模型本身还存在一些能力的限制,例如大模型的幻觉、无法理解较为复杂的指令、无法执行复杂步骤等。我们可以通过构造思维链,将 Prompt 构造成一系列步骤来尽量减少其能力限制。
template_v4 = """
请你依次执行以下步骤:
① 使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答案。
你应该使答案尽可能详细具体,但不要偏题。如果答案比较长,请酌情进行分段,以提高答案的阅读体验。
如果答案有几点,你应该分点标号回答,让答案清晰具体。
上下文:
{context}
问题:
{question}
有用的回答:
② 基于提供的上下文,反思回答中有没有不正确或不是基于上下文得到的内容,如果有,修改回答"""
4、增加一个指令解析
我们往往会面临一个需求,即我们需要模型以我们指定的格式进行输出。但是,由于我们使用了 Prompt Template 来填充用户问题,用户问题中存在的格式要求往往会被忽略。
针对该问题,一个存在的解决方案是,在我们的检索 LLM 之前,增加一层 LLM 来实现指令的解析,将用户问题的格式要求和问题内容拆分开来。
prompt_input = '''
请判断以下问题中是否包含对输出的格式要求,并按以下要求输出:
请返回给我一个可解析的Python列表,列表第一个元素是对输出的格式要求,应该是一个指令;第二个元素是去掉格式要求的问题原文
如果没有格式要求,请将第一个元素置为空
需要判断的问题:
{}
'''
三、大模型评估方法
1、人工评估的一般思路
量化评估、多维评估
2、简单自动评估
构造客观题、计算答案相似度(NLP 一般对生成问题采用人工构造标准答案并计算回答与标准答案相似度的方法来实现自动评估)
3、使用大模型进行评估
以下为使用智谱GLM进行评估的步骤:
zhipuai_embedding.py和zhipuai_llm.py请自行下载:https://github.com/datawhalechina/llm-universe
构建数据库:
#构建数据库:
from langchain.vectorstores import Chroma
from langchain.document_loaders import PyMuPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.document_loaders import UnstructuredMarkdownLoader
from langchain.document_loaders import UnstructuredFileLoader
#from langchain.embeddings.openai import OpenAIEmbeddings
#from langchain.embeddings.huggingface import HuggingFaceEmbeddings
from zhipuai_embedding import ZhipuAIEmbeddings
#from langchain.llms import OpenAI
#from langchain.llms import HuggingFacePipeline
from zhipuai_llm import ZhipuAILLM
import zhipuai
import os
os.environ['ZHIPUAI_API_KEY']="***" #填写控制台中获取的 APIKey 信息
zhipuai.api_key = os.environ['ZHIPUAI_API_KEY']
# 加载 PDF
loaders = [
PyMuPDFLoader("knowledge_db/pumkin_book/pumpkin_book.pdf") # 机器学习
]
docs = []
for loader in loaders:
docs.extend(loader.load())
# 切分文档
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=150)
split_docs = text_splitter.split_documents(docs)
# 定义 Embeddings
#embedding = OpenAIEmbeddings()
# embedding = HuggingFaceEmbeddings(model_name=model_name, model_kwargs=model_kwargs)
embedding = ZhipuAIEmbeddings()
persist_directory = 'vector_db/chroma'
vectordb = Chroma.from_documents(
documents=split_docs[:100], # 为了速度,只选择了前 100 个切分的 doc 进行生成。
embedding=embedding,
persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上
)
vectordb.persist()
加载数据库:
#加载数据库:
from langchain.vectorstores import Chroma
from zhipuai_embedding import ZhipuAIEmbeddings
# 定义 Embeddings
embedding = ZhipuAIEmbeddings()
# 向量数据库持久化路径
persist_directory = 'vector_db/chroma'
vectordb = Chroma(
persist_directory=persist_directory,
embedding_function=embedding
)
print(f"向量库中存储的数量:{vectordb._collection.count()}")
使用LangChain调用智谱LLM:
import zhipuai
from zhipuai_llm import ZhipuAILLM
llm = ZhipuAILLM(model="chatglm_turbo", temperature=0, zhipuai_api_key=zhipuai.api_key)
#llm.generate(['你好,请介绍一下你自己'])
#构建 prompt
from langchain.prompts import PromptTemplate
#定义一个提示模板
template_v1 = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
案。你应该使答案尽可能详细具体,但不要偏题。如果答案比较长,请酌情进行分段,以提高答案的阅读体验。
{context}
问题: {question}
有用的回答:"""
QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],
template=template_v1)
#创建一个基于模板的检索链
from langchain.chains import RetrievalQA #导入检索式问答链
qa_chain = RetrievalQA.from_chain_type(llm,
retriever=vectordb.as_retriever(),
return_source_documents=True,
chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})
构造Prompt Engineering:
#构造如下的 Prompt Engineering
prompt = '''
你是一个模型回答评估员。
接下来,我将给你一个问题、对应的知识片段以及模型根据知识片段对问题的回答。
请你依次评估以下维度模型回答的表现,分别给出打分:
① 知识查找正确性。评估系统给定的知识片段是否能够对问题做出回答。如果知识片段不能做出回答,打分为0;如果知识片段可以做出回答,打分为1。
② 回答一致性。评估系统的回答是否针对用户问题展开,是否有偏题、错误理解题意的情况,打分分值在0~1之间,0为完全偏题,1为完全切题。
③ 回答幻觉比例。该维度需要综合系统回答与查找到的知识片段,评估系统的回答是否出现幻觉,打分分值在0~1之间,0为全部是模型幻觉,1为没有任何幻觉。
④ 回答正确性。该维度评估系统回答是否正确,是否充分解答了用户问题,打分分值在0~1之间,0为完全不正确,1为完全正确。
⑤ 逻辑性。该维度评估系统回答是否逻辑连贯,是否出现前后冲突、逻辑混乱的情况。打分分值在0~1之间,0为逻辑完全混乱,1为完全没有逻辑问题。
⑥ 通顺性。该维度评估系统回答是否通顺、合乎语法。打分分值在0~1之间,0为语句完全不通顺,1为语句完全通顺没有任何语法问题。
⑦ 智能性。该维度评估系统回答是否拟人化、智能化,是否能充分让用户混淆人工回答与智能回答。打分分值在0~1之间,0为非常明显的模型回答,1为与人工回答高度一致。
你应该是比较严苛的评估员,很少给出满分的高评估。
用户问题:
```
{}
```
待评估的回答:
```
{}
```
给定的知识片段:
```
{}
```
你应该返回给我一个可直接解析的 Python 字典,字典的键是如上维度,值是每一个维度对应的评估打分。
不要输出任何其他内容。
'''
#要得到用户问题、待评估的回答(基于检索式问答链得到)、给定的知识片段(基于检索式问答链得到)
question = "应该如何使用南瓜书?"
result = qa_chain({"query": question})
answer = result["result"]
knowledge = result["source_documents"]
调用智谱LLM输出评估结果:
#封装好messages,里面包括role和content
def getText(role, content, text = []):
# role 是指定角色,content 是 prompt 内容
jsoncon = {}
jsoncon["role"] = role
jsoncon["content"] = content
text.append(jsoncon)
return text
messages = getText("user", prompt.format(question, answer, knowledge))
#调用智谱LLM进行回答
# 请求模型
response = zhipuai.model_api.invoke(
model="chatglm_turbo",
prompt=messages
)
print(response)
4、混合评估
客观正确性、主观正确性、智能性、知识查找正确性
第七章 前后端搭建
待续。。。