【提示工程】向AI发出高质量的指令(实战篇)
引言
通过上一篇提示工程的理论学习,相信都已经很清楚我们应该向AI发出怎样的提示从而得到更为准确的回答。本篇内容将进行实战,通过一个简单的实例演示从零示例、单示例到多轮对话、智能机器人对话的优化过程。
示例
下面基于千问大模型API实现一个推荐流量包的智能客服。
调用千问API:
import dashscopedef get_completion(prompt):message = [{'role': 'user','content': prompt}]response = dashscope.Generation.call(# 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",api_key="sk-****",#os.getenv('DASHSCOPE_API_KEY'),model="qwen-plus", # 此处以qwen-plus为例,可按需更换模型名称。模型列表:https://help.aliyun.com/zh/model-studio/getting-started/modelsmessages=message,result_format='message')print(response)print(response.output.choices[0]['message']['content'])
1、无示例提示
提示仅包含任务描述和用户输入的内容。
import promptapi
# 最简版:零示例提示
#任务描述
instruction = """
你的任务是识别用户对手机流量套餐产品的选择条件每种流量套餐产品包含三个属性:名称,月费价格,月流量。根据用户输入,识别用户在上述三种属性上的倾向。
"""
#用户输入
input_text = """
办个100G的套餐
"""#prompt模版
prompt = f"""
{instruction}用户输入:
{input_text}
"""print(prompt)
response = promptapi.get_completion(prompt)# 输出结果:
# 根据用户输入的“办个100G的套餐”,可以识别出用户对手机流量套餐产品的选择条件如下:
#
# - **月流量**:明确倾向为 **100G**,用户对流量需求有明确要求。
# - **名称**:未提及,**无倾向**。
# - **月费价格**:未提及,**无倾向**。
#
# 总结:用户主要关注的是**月流量为100G**,对套餐名称和月费价格没有具体要求。
2、指定输出格式提示
在上面的基础上,增加了指定结果输出json格式
import promptapi
# 优化1:指定精细化json格式输出
# 输出格式
output_format = """
以json格式输出
1. name字段的取值为string类型,取值必须为以下之一:经济套餐、畅游套餐、无限套餐、校园套餐、或null
2. price字段取值为一个结构体或null,包含两个字段:
(1)operator,string类型,取值范围:'<='(小于等于),'>='(大于等于),'=='(等于)
(2)value,int类型
3. data字段取值为一个结构体或null,包含两个字段:
(1)operator,string类型,取值范围:'<='(小于等于),'>='(大于等于),'=='(等于)
(2)value,int类型或string类型,string类型只能是无上限
4. 用户意图可以包含按price或data排序,以sort字段标识,取值为一个结构体
(1)结构体中以“ordering"="descend"表示按降序排序,以value字段存储待排序的字段
(2)结构体中以“ordering"="ascend"表示按升序排序,以value字段存储待排序的字段
输出中只包含用户提及的字段,不要猜测任务用户未直接提及的字段,不输出为null的字段
"""
#任务描述
instruction = """
你的任务是识别用户对手机流量套餐产品的选择条件每种流量套餐产品包含三个属性:名称(name),月费价格(price),月流量(data)。根据用户输入,识别用户在上述三种属性上的倾向。
"""
#用户输入
input_text = """
办个100G的套餐
"""
#用户输入2
# input_text = """
# 有没有便宜的套餐
# """#prompt模版
prompt = f"""
{instruction}用户输入:
{input_text}{output_format}
"""print(prompt)
response = promptapi.get_completion(prompt)#输出结果:
# ```json
# {
# "data": {
# "operator": ">=",
# "value": 100
# }
# }
# ```
3、单示例提示
在提示中增加了一个例子,有示例,输出的结果会更加精准。
import promptapi
# 优化2:给个例子
#例子
examples = """
便宜的套餐:{"sort":{"ordering"="ascend","value"="price"}}
有没有不限流量的:{“data":{"operator":"==","“"value":“无上限"}}
流量大的:{"sort":{"ordering"="descend","value"="data"}}
月费不超过200的:{"price":operator":"<=","value":200}}
就要月费180那个套餐:{"price":{"operator":"==""value":180}}
经济套餐:{'name":“经济套餐"}
"""
# 输出格式
output_format = """
以json格式输出
1. name字段的取值为string类型,取值必须为以下之一:经济套餐、畅游套餐、无限套餐、校园套餐、或null
2. price字段取值为一个结构体或null,包含两个字段:
(1)operator,string类型,取值范围:'<='(小于等于),'>='(大于等于),'=='(等于)
(2)value,int类型
3. data字段取值为一个结构体或null,包含两个字段:
(1)operator,string类型,取值范围:'<='(小于等于),'>='(大于等于),'=='(等于)
(2)value,int类型或string类型,string类型只能是无上限
4. 用户意图可以包含按price或data排序,以sort字段标识,取值为一个结构体
(1)结构体中以“ordering"="descend"表示按降序排序,以value字段存储待排序的字段
(2)结构体中以“ordering"="ascend"表示按升序排序,以value字段存储待排序的字段
输出中只包含用户提及的字段,不要猜测任务用户未直接提及的字段,不输出为null的字段
"""
#任务描述
instruction = """
你的任务是识别用户对手机流量套餐产品的选择条件每种流量套餐产品包含三个属性:名称(name),月费价格(price),月流量(data)。根据用户输入,识别用户在上述三种属性上的倾向。
"""
#用户输入
input_text = """
有没有不限流量的
"""#prompt模版
prompt = f"""
{instruction}{output_format}例如:
{examples}用户输入:
{input_text}"""print(prompt)
response = promptapi.get_completion(prompt)#输出结果:
# ```json
# {
# "data": {
# "operator": ">=",
# "value": 100
# }
# }
# ```
4、多轮对话
上面是单个示例,下面是增加了用户与客服之间对话的多个示例,结果都是基于该示例输出的。
import promptapi
# 优化3:多轮对话
#例子
examples = """
客服:有什么可以帮您
用户:100G套餐有什么
{"data" : {"operator" :">=","value":100}}客服:有什么可以帮您
用户:100G套餐有什么
客服:我们现在有无限套餐,不限流量,月费300元用户:太贵了,有200元以内的不
{"data" : {"operator" :">=","value":100}, "price" :{"<=","value":200}}客服:有什么可以帮您
用户:便宜的套餐有什么
客服::我们现在有经济套餐,每月50元,10G流量
用户:100G以上的有什么
{"data": {"operator":">=","value":100},"sort":{"ordering"="ascend","value"="price"}}客服:有什么可以帮您
用户:100G以上的套餐有什么
客服:我们现在有畅游套餐,流量100G,月费180元
用户:流量最多的呢
{"sort" : {"ordering"="descend" , "value"="data" } ,"data" : {"operator" :">=" "value":100}}"""
# 输出格式
output_format = """
以json格式输出
1. name字段的取值为string类型,取值必须为以下之一:经济套餐、畅游套餐、无限套餐、校园套餐、或null
2. price字段取值为一个结构体或null,包含两个字段:
(1)operator,string类型,取值范围:'<='(小于等于),'>='(大于等于),'=='(等于)
(2)value,int类型
3. data字段取值为一个结构体或null,包含两个字段:
(1)operator,string类型,取值范围:'<='(小于等于),'>='(大于等于),'=='(等于)
(2)value,int类型或string类型,string类型只能是无上限
4. 用户意图可以包含按price或data排序,以sort字段标识,取值为一个结构体
(1)结构体中以“ordering"="descend"表示按降序排序,以value字段存储待排序的字段
(2)结构体中以“ordering"="ascend"表示按升序排序,以value字段存储待排序的字段
输出中只包含用户提及的字段,不要猜测任务用户未直接提及的字段,不输出为null的字段
"""
#任务描述
instruction = """
你的任务是识别用户对手机流量套餐产品的选择条件每种流量套餐产品包含三个属性:名称(name),月费价格(price),月流量(data)。根据用户输入,识别用户在上述三种属性上的倾向。
"""
#用户输入
input_text = """
哪个便宜
"""
#多轮对话上下文
context = f"""
客服:有什么可以帮您
用户:有什么100G以上的套餐推荐
客服:我们现在有畅游套餐和无限套餐,你有什么价格倾向吗?
用户:{input_text}
"""#prompt模版
prompt = f"""
{instruction}{output_format}{examples}{context}
"""print(prompt)
response = promptapi.get_completion(prompt)#输出结果:
# ```json
# {
# "price": {"operator": "<=", "value": 200},
# "data": {"operator": ">=", "value": 100},
# "sort": {"ordering": "ascend", "value": "price"}
# }
# ```
5、智能机器人
增加交互式聊天
import json
import re
from typing import Dict, Any, Optional
from prompt import promptapiclass FlowPackageIntentRecognizer:def __init__(self):# 定义流量包套餐信息self.packages = [{"name": "经济套餐", "data": 10, "price": 50},{"name": "畅游套餐", "data": 100, "price": 180},{"name": "无限套餐", "data": 1000, "price": 300},{"name": "校园套餐", "data": 200, "price": 150}]# 构建prompt模板self.instruction = """你的任务是识别用户对手机流量套餐产品的选择条件。每种流量套餐产品包含三个属性:名称(name),月费价格(price),月流量(data)。根据用户输入,识别用户在上述三种属性上的倾向。"""self.output_format = """以json格式输出1. name字段的取值为string类型,取值必须为以下之一:经济套餐、畅游套餐、无限套餐、校园套餐、或null2. price字段取值为一个结构体或null,包含两个字段:(1)operator,string类型,取值范围:'<='(小于等于),'>='(大于等于),'=='(等于)(2)value,int类型3. data字段取值为一个结构体或null,包含两个字段:(1)operator,string类型,取值范围:'<='(小于等于),'>='(大于等于),'=='(等于)(2)value,int类型或string类型,string类型只能是无上限4. 用户意图可以包含按price或data排序,以sort字段标识,取值为一个结构体(1)结构体中以"ordering"="descend"表示按降序排序,以value字段存储待排序的字段(2)结构体中以"ordering"="ascend"表示按升序排序,以value字段存储待排序的字段输出中只包含用户提及的字段,不要猜测任务用户未直接提及的字段,不输出为null的字段"""self.examples = """客服:有什么可以帮您用户:100G套餐有什么{"data" : {"operator" :">=","value":100}}客服:有什么可以帮您用户:100G套餐有什么客服:我们现在有无限套餐,不限流量,月费300元用户:太贵了,有200元以内的不{"data" : {"operator" :">=","value":100}, "price" :{"operator":"<=","value":200}}客服:有什么可以帮您用户:便宜的套餐有什么客服::我们现在有经济套餐,每月50元,10G流量用户:100G以上的有什么{"data": {"operator":">=","value":100},"sort":{"ordering":"ascend","value":"price"}}客服:有什么可以帮您用户:100G以上的套餐有什么客服:我们现在有畅游套餐,流量100G,月费180元用户:流量最多的呢{"sort" : {"ordering":"descend" , "value":"data"} ,"data" : {"operator":">=", "value":100}}"""def build_prompt(self, context: str, input_text: str) -> str:"""构建多轮对话的prompt"""context_with_input = f"""客服:有什么可以帮您用户:有什么100G以上的套餐推荐客服:我们现在有畅游套餐和无限套餐,你有什么价格倾向吗?用户:{input_text}"""prompt = f"""{self.instruction}{self.output_format}{self.examples}{context_with_input}"""return promptdef parse_intent_response(self, response: str) -> Dict[str, Any]:"""解析API返回的意图识别结果"""try:# 提取JSON部分json_match = re.search(r'\{[\s\S]*\}', response)if json_match:json_str = json_match.group()return json.loads(json_str)return {}except json.JSONDecodeError:print("JSON解析错误")return {}def recommend_packages(self, intent: Dict[str, Any]) -> list:"""根据识别到的意图推荐套餐"""filtered_packages = self.packages.copy()# 根据data条件过滤if 'data' in intent:data_cond = intent['data']operator = data_cond['operator']value = data_cond['value']if operator == '>=':filtered_packages = [p for p in filtered_packages if p['data'] >= value]elif operator == '<=':filtered_packages = [p for p in filtered_packages if p['data'] <= value]elif operator == '==':filtered_packages = [p for p in filtered_packages if p['data'] == value]# 根据price条件过滤if 'price' in intent:price_cond = intent['price']operator = price_cond['operator']value = price_cond['value']if operator == '>=':filtered_packages = [p for p in filtered_packages if p['price'] >= value]elif operator == '<=':filtered_packages = [p for p in filtered_packages if p['price'] <= value]elif operator == '==':filtered_packages = [p for p in filtered_packages if p['price'] == value]# 根据名称过滤if 'name' in intent and intent['name']:filtered_packages = [p for p in filtered_packages if p['name'] == intent['name']]# 排序if 'sort' in intent:sort_cond = intent['sort']field = sort_cond['value']ordering = sort_cond['ordering']reverse = (ordering == 'descend')filtered_packages.sort(key=lambda x: x[field], reverse=reverse)return filtered_packagesdef format_recommendation(self, packages: list) -> str:"""格式化推荐结果"""if not packages:return "抱歉,没有找到符合您条件的套餐。"result = "为您推荐以下套餐:\n"for pkg in packages:result += f"📦 {pkg['name']}: {pkg['data']}G流量,{pkg['price']}元/月\n"return resultdef process_user_input(self, input_text: str, context: str = None) -> str:"""处理用户输入并返回推荐结果"""# 构建promptprompt = self.build_prompt(context or "", input_text)# 调用APIresponse = promptapi.get_completion(prompt)# 模拟API响应(根据不同的输入返回不同的结果)if "便宜" in input_text or "实惠" in input_text:mock_response = '{"sort": {"ordering": "ascend", "value": "price"}}'elif "流量多" in input_text or "流量大" in input_text:mock_response = '{"sort": {"ordering": "descend", "value": "data"}}'elif "200" in input_text and "以内" in input_text:mock_response = '{"price": {"operator": "<=", "value": 200}}'else:mock_response = '{}'# 解析意图intent = self.parse_intent_response(mock_response)print(f"识别到的意图: {intent}")# 推荐套餐recommended_packages = self.recommend_packages(intent)# 格式化结果return self.format_recommendation(recommended_packages)def run_chatbot(self):"""运行多轮对话客服"""print("🤖 欢迎使用流量包智能客服!")print("输入'退出'或'quit'结束对话\n")context = ""while True:user_input = input("用户: ").strip()if user_input.lower() in ['退出', 'quit', 'exit']:print("客服: 感谢使用,再见!")break# 处理用户输入response = self.process_user_input(user_input, context)print(f"客服: {response}")# 更新上下文(简化处理)context += f"用户: {user_input}\n客服: {response}\n"# 使用示例
if __name__ == "__main__":recognizer = FlowPackageIntentRecognizer()# 测试单个输入# test_inputs = [# "我是一名大学生,能帮我推荐一下流量多且经济实惠的套餐吗?"# ]## for test_input in test_inputs:# print(f"\n测试输入: {test_input}")# result = recognizer.process_user_input(test_input)# print(f"推荐结果: {result}")# 运行交互式聊天recognizer.run_chatbot()
以上只是一个用于学习的例子,主要是在脑海中构建一个提示工程的实现框架,并且通过实战也发现了prompt的重要性。