【山东大学项目实训】进度汇报11

进行了一些系统测试评估和优化

系统评估和优化从两部分同时入手,分别评估检索部分和优化部分的性能,找出 Bad Case 并针对性进行性能的优化。而具体到生成部分,在已限定使用的大模型基座的情况下,通过优化 Prompt Engineering 来优化生成的回答。

先加载我们的向量数据库与检索链:

import sys
sys.path.append("../C3 搭建知识库") # 将父目录放入系统路径中

# 使用智谱 Embedding API,注意,需要将上一章实现的封装代码下载到本地
from zhipuai_embedding import ZhipuAIEmbeddings

from langchain.vectorstores.chroma import Chroma
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv, find_dotenv
import os

_ = load_dotenv(find_dotenv())    # read local .env file
zhipuai_api_key = os.environ['ZHIPUAI_API_KEY']
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]

# 定义 Embeddings
embedding = ZhipuAIEmbeddings()

# 向量数据库持久化路径
persist_directory = '../../data_base/vector_db/chroma'

# 加载数据库
vectordb = Chroma(
    persist_directory=persist_directory,  # 允许我们将persist_directory目录保存到磁盘上
    embedding_function=embedding
)

# 使用 OpenAI GPT-3.5 模型
llm = ChatOpenAI(model_name = "gpt-3.5-turbo", temperature = 0)

os.environ['HTTPS_PROXY'] = 'http://127.0.0.1:7890'
os.environ["HTTP_PROXY"] = 'http://127.0.0.1:7890'

使用初始化的 Prompt 创建一个基于模板的检索链:

from langchain.prompts import PromptTemplate
from langchain.chains import RetrievalQA


template_v1 = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
案。最多使用三句话。尽量使答案简明扼要。总是在回答的最后说“谢谢你的提问!”。
{context}
问题: {question}
"""

QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],
                                 template=template_v1)



qa_chain = RetrievalQA.from_chain_type(llm,
                                       retriever=vectordb.as_retriever(),
                                       return_source_documents=True,
                                       chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})

测试效果:

question = "什么是南瓜书"
result = qa_chain({"query": question})
print(result["result"])
南瓜书是对《机器学习》(西瓜书)中比较难理解的公式进行解析和补充推导细节的书籍。南瓜书的最佳使用方法是以西瓜书为主线,遇到推导困难或看不懂的公式时再来查阅南瓜书。谢谢你的提问!

针对性地修改 Prompt 模板,加入要求其回答具体,并去掉“谢谢你的提问”的部分:

template_v2 = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
案。你应该使答案尽可能详细具体,但不要偏题。如果答案比较长,请酌情进行分段,以提高答案的阅读体验。
{context}
问题: {question}
有用的回答:"""

QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],
                                 template=template_v2)
qa_chain = RetrievalQA.from_chain_type(llm,
                                       retriever=vectordb.as_retriever(),
                                       return_source_documents=True,
                                       chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})

question = "什么是南瓜书"
result = qa_chain({"query": question})
print(result["result"])
南瓜书是一本针对周志华老师的《机器学习》(西瓜书)的补充解析书籍。它旨在对西瓜书中比较难理解的公式进行解析,并补充具体的推导细节,以帮助读者更好地理解机器学习领域的知识。南瓜书的内容是以西瓜书为前置知识进行表述的,最佳使用方法是在遇到自己推导不出来或者看不懂的公式时来查阅。南瓜书的编写团队致力于帮助读者成为合格的“理工科数学基础扎实点的大二下学生”,并提供了在线阅读地址和最新版PDF获取地址供读者使用。

可以看到,改进后的 v2 版本能够给出更具体、详细的回答,解决了之前的问题。

测试以下问题:

question = "使用大模型时,构造 Prompt 的原则有哪些"
result = qa_chain({"query": question})
print(result["result"])
在使用大型语言模型时,构造Prompt的原则主要包括编写清晰、具体的指令和给予模型充足的思考时间。首先,Prompt需要清晰明确地表达需求,提供足够的上下文信息,以确保语言模型准确理解用户的意图。这就好比向一个对人类世界一无所知的外星人解释事物一样,需要详细而清晰的描述。过于简略的Prompt会导致模型难以准确把握任务要求。

其次,给予语言模型充足的推理时间也是至关重要的。类似于人类解决问题时需要思考的时间,模型也需要时间来推理和生成准确的结果。匆忙的结论往往会导致错误的输出。因此,在设计Prompt时,应该加入逐步推理的要求,让模型有足够的时间进行逻辑思考,从而提高结果的准确性和可靠性。

通过遵循这两个原则,设计优化的Prompt可以帮助语言模型充分发挥潜力,完成复杂的推理和生成任务。掌握这些Prompt设计原则是开发者成功应用语言模型的重要一步。在实际应用中,不断优化和调整Prompt,逐步逼近最佳形式,是构建高效、可靠模型交互的关键策略。

回答使用首先、其次等词开头,同时将整体答案分成了4段,导致答案不是特别重点清晰,不容易阅读。因此,我们构造以下 Bad Case:

问题:使用大模型时,构造 Prompt 的原则有哪些
初始回答:略
存在不足:没有重点,模糊不清

针对该 Bad Case改进 Prompt,要求其对有几点的答案进行分点标号,让答案清晰具体:

template_v3 = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
案。你应该使答案尽可能详细具体,但不要偏题。如果答案比较长,请酌情进行分段,以提高答案的阅读体验。
如果答案有几点,你应该分点标号回答,让答案清晰具体
{context}
问题: {question}
有用的回答:"""

QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],
                                 template=template_v3)
qa_chain = RetrievalQA.from_chain_type(llm,
                                       retriever=vectordb.as_retriever(),
                                       return_source_documents=True,
                                       chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})

question = "使用大模型时,构造 Prompt 的原则有哪些"
result = qa_chain({"query": question})
print(result["result"])
1. 编写清晰、具体的指令是构造 Prompt 的第一原则。Prompt需要明确表达需求,提供充足上下文,使语言模型准确理解意图。过于简略的Prompt会使模型难以完成任务。

2. 给予模型充足思考时间是构造Prompt的第二原则。语言模型需要时间推理和解决复杂问题,匆忙得出的结论可能不准确。因此,Prompt应该包含逐步推理的要求,让模型有足够时间思考,生成更准确的结果。

3. 在设计Prompt时,要指定完成任务所需的步骤。通过给定一个复杂任务,给出完成任务的一系列步骤,可以帮助模型更好地理解任务要求,提高任务完成的效率。

4. 迭代优化是构造Prompt的常用策略。通过不断尝试、分析结果、改进Prompt的过程,逐步逼近最优的Prompt形式。成功的Prompt通常是通过多轮调整得出的。

5. 添加表格描述是优化Prompt的一种方法。要求模型抽取信息并组织成表格,指定表格的列、表名和格式,可以帮助模型更好地理解任务,并生成符合预期的结果。

总之,构造Prompt的原则包括清晰具体的指令、给予模型充足思考时间、指定完成任务所需的步骤、迭代优化和添加表格描述等。这些原则可以帮助开发者设计出高效、可靠的Prompt,发挥语言模型的最大潜力。

增加一个指令解析

需要模型以指定的格式进行输出。但是由于使用了 Prompt Template 来填充用户问题,用户问题中存在的格式要求被忽略:

question = "LLM的分类是什么?给我返回一个 Python List"
result = qa_chain({"query": question})
print(result["result"])
根据上下文提供的信息,LLM(Large Language Model)的分类可以分为两种类型,即基础LLM和指令微调LLM。基础LLM是基于文本训练数据,训练出预测下一个单词能力的模型,通常通过在大量数据上训练来确定最可能的词。指令微调LLM则是对基础LLM进行微调,以更好地适应特定任务或场景,类似于向另一个人提供指令来完成任务。

根据上下文,可以返回一个Python List,其中包含LLM的两种分类:["基础LLM", "指令微调LLM"]。

该输出要求被包裹在 Template 中被模型忽略掉了。针对该问题构造一个 Bad Case:

问题:LLM的分类是什么?给我返回一个 Python List
初始回答:根据提供的上下文,LLM的分类可以分为基础LLM和指令微调LLM。
存在不足:没有按照指令中的要求输出
测试一下该 LLM 分解格式要求的能力:
response = get_completion(prompt_input.format(question))
response

'```\n["给我返回一个 Python List", "LLM的分类是什么?"]\n```'

再设置一个 LLM 根据输出格式要求,对输出内容进行解析:

prompt_output = '''
请根据回答文本和输出格式要求,按照给定的格式要求对问题做出回答
需要回答的问题:
```
{}
```
回答文本:
```
{}
```
输出格式要求:
```
{}
```
'''

 与检索链串联起来:

question = 'LLM的分类是什么?给我返回一个 Python List'
# 首先将格式要求与问题拆分
input_lst_s = get_completion(prompt_input.format(question))
# 找到拆分之后列表的起始和结束字符
start_loc = input_lst_s.find('[')
end_loc = input_lst_s.find(']')
rule, new_question = eval(input_lst_s[start_loc:end_loc+1])
# 接着使用拆分后的问题调用检索链
result = qa_chain({"query": new_question})
result_context = result["result"]
# 接着调用输出格式解析
response = get_completion(prompt_output.format(new_question, result_context, rule))
response
"['基础LLM', '指令微调LLM']"

经过如上步骤成功实现了输出格式的限定。在实践中可以不断发现 Bad Case 并针对性优化 Prompt,从而提升生成部分的性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值