我们接着上面的例子继续
上面的例子是用纯Prompt实现的,本讲中我们用OpenAI API 实现完整上述功能
import json
from openai import OpenAI
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
# 一个辅助函数,只为演示方便,不必关注细节
def print_json(data):
"""
打印参数。如果参数是有结构的(如字典或列表),则以格式化的 JSON 形式打印;
否则,直接打印该值。
"""
if hasattr(data, 'model_dump_json'):
data = json.loads(data.model_dump_json())
if (isinstance(data, (list, dict))):
print(json.dumps(
data,
indent=4,
ensure_ascii=False
))
else:
print(data)
client = OpenAI()
# 定义消息历史。先加入 system 消息,里面放入对话内容以外的 prompt
messages = [
{
"role": "system", # system message 只能有一条,且是第一条,对后续对话产生全局影响。LLM 对其遵从性有可能更高。一般用于放置背景信息、行为要求等。
"content": """
你是一个手机流量套餐的客服代表,你叫小瓜。可以帮助用户选择最合适的流量套餐产品。可以选择的套餐包括:
经济套餐,月费50元,10G流量;
畅游套餐,月费180元,100G流量;
无限套餐,月费300元,1000G流量;
校园套餐,月费150元,200G流量,仅限在校生。
"""
}
]
def get_completion(prompt, model="gpt-4o-mini"):
# 把用户输入加入消息历史
messages.append({"role": "user", "content": prompt})
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=0.7,
)
msg = response.choices[0].message.content
# 把模型生成的回复加入消息历史。很重要,否则下次调用模型时,模型不知道上下文
messages.append({"role": "assistant", "content": msg})
return msg
# 连续调用模型,进行多轮对话
get_completion("流量最大的套餐是什么?")
get_completion("多少钱?")
get_completion("给我办一个")
print_json(messages)
这里是把各种套餐放到Mesage中,当做背景.也就是角色system,在调用get_completion时要把用户的Prompt和AI返回的信息都要加入到Messages中,为什么呢?因为大模型没有记忆功能.我们平常用的文心或Gpt或千问都是一个逻辑,每次问大模型时,都是把界面前面的的交互的所有信息全部传给大模型的.
增加思维链
增加这样的检查,也叫质检项
- 当向用户介绍流量套餐产品时,客服人员必须准确提及产品名称、月费价格、月流量总量、适用条件(如有)
- 上述信息缺失一项或多项,或信息与事实不符,都算信息不准确
我们把这两条要求放到Prompt中.让大模型自己思考一下,例如直接告诉大模型请一步一步的分析对话.
from openai import OpenAI
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
client = OpenAI()
def get_completion(prompt, model="gpt-4o-mini"):
messages = [{"role": "user", "content": prompt}]
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=0,
)
return response.choices[0].message.content
instruction = """
给定一段用户与手机流量套餐客服的对话,。
你的任务是判断客服的回答是否符合下面的规范:
- 必须有礼貌
- 必须用官方口吻,不能使用网络用语
- 介绍套餐时,必须准确提及产品名称、月费价格和月流量总量。上述信息缺失一项或多项,或信息与事实不符,都算信息不准确
- 不可以是话题终结者
已知产品包括:
经济套餐:月费50元,月流量10G
畅游套餐:月费180元,月流量100G
无限套餐:月费300元,月流量1000G
校园套餐:月费150元,月流量200G,限在校学生办理
"""
# 输出描述
output_format = """
如果符合规范,输出:Y
如果不符合规范,输出:N
"""
context = """
用户:你们有什么流量大的套餐
客服:亲,我们现在正在推广无限套餐,每月300元就可以享受1000G流量,您感兴趣吗?
"""
cot = ""
# cot = "请一步一步分析对话"
prompt = f"""
# 目标
{instruction}
{cot}
# 输出格式
{output_format}
# 对话上下文
{context}
"""
response = get_completion(prompt)
print(response)
把上述代码中的# cot = "请一步一步分析对话"这行代码放开和屏蔽模型给出了不同的结果.
防止 Prompt 攻击
大家可以在网上锁一下"奶奶漏洞".
防范措施一般是在System的背景角色消息中增加要求,也可以在用户输入中增加防御
这里就不多讲了
提示工程经验总结
- 别急着上代码,先尝试用 prompt 解决,往往有四两拨千斤的效果
- 但别迷信 prompt,合理组合传统方法提升确定性,减少幻觉
- 定义角色、给例子是最常用的技巧
- 必要时上思维链,结果更准确
- 防御 prompt 攻击非常重要,但很难
另外下面的大模型参数,可以有需要了看一下
def get_chat_completion(session, user_prompt, model="gpt-4o-mini"):
session.append({"role": "user", "content": user_prompt})
response = client.chat.completions.create(
model=model,
messages=session,
# 以下默认值都是官方默认值
temperature=1, # 生成结果的多样性。取值 0~2 之间,越大越发散,越小越收敛
seed=None, # 随机数种子。指定具体值后,temperature 为 0 时,每次生成的结果都一样
stream=False, # 数据流模式,一个字一个字地接收
response_format={"type": "text"}, # 返回结果的格式,可以是 text、json_object 或 json_schema
top_p=1, # 随机采样时,只考虑概率前百分之多少的 token。不建议和 temperature 一起使用
n=1, # 一次返回 n 条结果
max_tokens=None, # 每条结果最多几个 token(超过截断)
presence_penalty=0, # 对出现过的 token 的概率进行降权
frequency_penalty=0, # 对出现过的 token 根据其出现过的频次,对其的概率进行降权
logit_bias={}, # 对指定 token 的采样概率手工加/降权,不常用
)
msg = response.choices[0].message.content
return msg
提示词到这也就唠叨完了,作为开发人员主要是了解一下代码,找一下感觉.虽然老师当时说意思不需要熟悉代码.我还是不认同的.
以上代码都是可以执行的.