prompt engineering
设计高效的prompt需要遵循两点:编写清晰、具体的指令和给予模型充足思考时间。掌握这两点,对创建可靠的语言模型交互尤为重要。
一、编写清晰具体的指令
首先,Prompt 需要清晰明确地表达需求,提供充足上下文,使语言模型准确理解我们的意图,过于简略的 Prompt 往往使模型难以把握所要完成的具体任务。
1.使用分隔符清晰地表示输入的不同部分
使用各种标点符号作为“分隔符”,将不同的文本部分区分开来。分隔符将不同的指令、上下文、输入隔开,避免意外的混淆。 ```,""",< >,<tag> </tag>都可以
分隔符。
使用分隔符尤其重要的是可以防止 提示词注入:用户输入的文本可能包含与你的预设 Prompt 相冲突的内容,如果不加分隔,这些输入就可能“注入”并操纵语言模型,导致模型产生毫无关联的乱七八糟的输出。
2.寻求结构化的输出
结构化输出即按照某种格式组织的内容,例如JSON、HTML等。这种输出非常适合在代码中进一步解析和处理。因为我们此次的项目是面向金融领域的大模型,所以需要对金融方面的提问和其它领域的提问做出格式化的规定和约束。
3.要求模型检查是否满足条件
如果任务包含不一定能满足的假设(条件),告诉模型先检查这些假设,如果不满足,则会指出并停止执行后续的完整流程。
4.提供少量示例
在要求模型执行实际任务之前,给模型一两个已完成的样例,让模型了解我们的要求和期望的输出样式。
二、给模型时间思考
在设计 Prompt 时,给予语言模型充足的推理时间非常重要。如果让语言模型匆忙给出结论,其结果很可能不准确。通过 Prompt 指引语言模型进行深入思考,要求其先列出对问题的各种看法,说明推理依据,然后再得出最终结论。在 Prompt 中添加逐步推理的要求,能让语言模型投入更多时间逻辑思维,输出结果也将更可靠准确。
1.指定完成任务所需的步骤
通过给定一个复杂任务,给出完成该任务的一系列步骤,来展示这一策略的效果。
2.指导模型在下结论之前找出一个自己的解法
通过明确指导语言模型进行自主思考,来获得更好的效果。先要求语言模型自己尝试解决这个问题,思考出自己的解法,然后再与提供的解答进行对比,判断正确性。
在这两点上都作出优化,使语言模型就能够尽可能发挥潜力,完成复杂的推理和生成任务。
在经过反复修改和迭代测试后,prompt如下:
zhipuai_llm.py:
def gen_glm_params(prompt):
'''
构造 GLM 模型请求参数 messages
请求参数:
prompt: 对应的用户提示词
'''
messages = [{"role": "system", "content": """
- Role: 金融分析师
- Background: 用户需要对金融领域的文本进行深入分析,以回答特定的金融问题。
- Profile: 你是一位经验丰富的金融分析师,具备深厚的金融市场知识、财务报表分析能力以及对金融新闻和数据的敏感度。
- Skills: 金融市场分析、财务报表解读、金融产品知识、数据分析、问题解决。
- Goals: 设计一个流程,帮助用户从金融文本中提取关键信息,并回答相关的金融问题。
- Constrains: 分析必须准确无误,避免误导用户。同时,应遵守金融行业的法律法规和道德标准。
- OutputFormat: 结果应以清晰、条理分明的文本形式呈现,包括关键数据点和分析结论。
- Workflow:
1. 阅读并理解提供的金融文本。
2. 提取文本中的关键金融信息和数据。
3. 分析这些信息,形成对问题的响应。
- Examples:
文本:“2023年第一季度,XYZ公司的净利润增长了15%,主要得益于其新产品线的成功推出。”
问题:“XYZ公司净利润增长的原因是什么?”
回答:XYZ公司净利润增长的原因主要是其新产品线的成功推出。
文本:“最新的市场报告显示,由于全球经济放缓,ABC股票的价格在过去一个月内下跌了10%。”
问题:“ABC股票价格下跌的主要原因是什么?”
回答:ABC股票价格下跌的主要原因是全球经济放缓。
- Initialization: 欢迎使用金融信息检索服务。请提供您需要分析的金融文本,以及您想要了解的具体问题。
"""},
{"role": "user", "content": prompt}]
return messages
测试:
call_llm.py:
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
import openai
import json
import requests
import _thread as thread
from dotenv import load_dotenv, find_dotenv
import os
from langchain.utils import get_from_dict_or_env
import websocket # 使用websocket_client
from zhipuai import ZhipuAI
def get_completion(prompt: str, model: str, temperature=0.1, api_key=None,
max_tokens=2048):
# arguments:
# prompt: 输入提示
# model:模型名
# temperature: 温度系数
# api_key:如名
# max_tokens : 返回最长序列
# return: 模型返回,字符串
if model in ["chatglm_pro", "chatglm_std", "chatglm_lite"]:
return get_completion_glm(prompt, model, temperature, api_key, max_tokens)
else:
return "不正确的模型"
def get_access_token(api_key, secret_key):
"""
使用 API Key,Secret Key 获取access_token,替换下列示例中的应用API Key、应用Secret Key
"""
# 指定网址
url = f"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={api_key}&client_secret={secret_key}"
# 设置 POST 访问
payload = json.dumps("")
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
# 通过 POST 访问获取账户对应的 access_token
response = requests.request("POST", url, headers=headers, data=payload)
return response.json().get("access_token")
def get_completion_glm(prompt: str, model: str, temperature: float, api_key: str, max_tokens: int):
# 获取GLM回答
if api_key == None:
api_key = parse_llm_api_key("zhipuai")
def gen_glm_params(prompt):
'''
构造 GLM 模型请求参数 messages
请求参数:
prompt: 对应的用户提示词
'''
messages = [{"role": "system", "content": "Role: 金融领域专家"
"Background: 用户是金融领域的从业人员,需要一个能够提供专业金融分析、市场趋势预测、投资建议和风险评估的助手。"
"Profile: 你是一位经验丰富的金融分析师,拥有深厚的金融市场知识和专业的金融工具操作能力。"
"Skills: 金融市场分析、投资策略规划、风险管理、财务报告解读、宏观经济趋势预测。"
"Goals: 设计一个能够帮助金融从业人员进行市场分析、投资决策、风险控制和财务规划的提示词。"
"Constrains: 提示词需要专业、准确,同时要符合金融行业的法律法规和道德标准。"
"OutputFormat: 结果可以是文本分析、数据表格、图表展示或直接的建议。"
"Workflow:"
"1. 收集和分析金融市场数据。"
"2. 提供基于当前市场状况的专业分析。"
"3. 根据用户的具体需求,给出投资建议或风险评估。"
"Initialization: 欢迎使用金融助手服务,我是你的专业金融分析师。请告诉我你的需求,我将为你提供专业的金融分析和建议。"},
{"role": "user", "content": prompt}]
return messages
tools = [{
"type": "web_search",
"web_search": {
"enable": True,
#"search_query": "自定义搜索的关键词"
}
}]
messages = gen_glm_params(prompt)
client = ZhipuAI(
api_key=api_key
)
response = client.chat.completions.create(
model="glm-4",
messages=messages,
tools=tools
)
print(messages)
print(response.choices[0].message.content)
return response.choices[0].message.content
# 收到websocket错误的处理
def on_error(ws, error):
print("### error:", error)
# 收到websocket关闭的处理
def on_close(ws, one, two):
print(" ")
# 收到websocket连接建立的处理
def on_open(ws):
thread.start_new_thread(run, (ws,))
def run(ws, *args):
data = json.dumps(gen_params(appid=ws.appid, domain=ws.domain, question=ws.question, temperature=ws.temperature,
max_tokens=ws.max_tokens))
ws.send(data)
# 收到websocket消息的处理
def on_message(ws, message):
# print(message)
data = json.loads(message)
code = data['header']['code']
if code != 0:
print(f'请求错误: {code}, {data}')
ws.close()
else:
choices = data["payload"]["choices"]
status = choices["status"]
content = choices["text"][0]["content"]
print(content, end="")
global answer
answer += content
# print(1)
if status == 2:
ws.close()
def gen_params(appid, domain, question, temperature, max_tokens):
"""
通过appid和用户的提问来生成请参数
"""
data = {
"header": {
"app_id": appid,
"uid": "1234"
},
"parameter": {
"chat": {
"domain": domain,
"random_threshold": 0.5,
"max_tokens": max_tokens,
"temperature": temperature,
"auditing": "default"
}
},
"payload": {
"message": {
"text": question
}
}
}
return data
def parse_llm_api_key(model: str, env_file: dict() = None):
"""
通过 model 和 env_file 的来解析平台参数
"""
if env_file == None:
_ = load_dotenv(find_dotenv())
env_file = os.environ
if model == "zhipuai":
return get_from_dict_or_env(env_file, "zhipuai_api_key", "ZHIPUAI_API_KEY")
# return env_file["ZHIPUAI_API_KEY"]
else:
raise ValueError(f"model{model} not support!!!")