前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >02 | 提示(Prompt)的原则-如何借助大模型开发一个虚拟女朋友

02 | 提示(Prompt)的原则-如何借助大模型开发一个虚拟女朋友

作者头像
机器学习之禅
发布2024-07-04 16:15:48
1380
发布2024-07-04 16:15:48
举报
文章被收录于专栏:机器学习之禅机器学习之禅

前面说过,“提示”现在是一门科学了,咱们不能再小看“提示”这个事情了。我想很多朋友都经历过,当你的女朋友突然发脾气,你还不知道发生了什么的时候,你的女朋友会说:“我已经提示过你了!”,然后你表现出一脸愕然“啊?”,这时候你就能理解可见给出一个好的“提示”是多么的重要了。

所以这里给出“提示”的两大原则:

1. 提示要清晰、具体

Prompt 需要清晰明确地表达需求,提供充足的上下文信息,很多模型都是以英文文本进行训练,在理解中文上可能会更差一点,能够让语言模型准确理解我们的意图,就像向一个外星人详细解释人类世界一样(可能你女朋友在说已经给你提示过了的时候也会觉得你是一个外星人)。提供简略的 Prompt 模型也会给你答复,但实际上模型难以把握所要完成的具体任务,或者给出质量较差的结果。

2. 要给予模型充足的思考时间

这句乍看起来好像有点迷惑,难道模型也需要复杂思考吗?还有就是提交之后不就自己在运算吗,如何给模型留时间呢?就像人类解题一样,匆忙得出的结论多有失误,这里所说的充足思考,是需要我们在提示词中给出的。我们在 Prompt 加入逐步推理的要求,让模型循着我们的思考链路逐步进行推导,这样生成的结果才更准确可靠。

说起来好像很容易,但是该怎么做到这两点呢?接下来我们就来试一下。

原则一 编写清晰具体的提示

1.1 使用分隔符来区分说明信息和要处理的信息部分

在编写 Prompt 时,我们可以使用各种标点符号作为“分隔符”,将不同的文本部分区分开来。

使用分隔符我们可以将不同的指令、上下文、输入隔开,避免意外的混淆。你可以选择用 ```,""",< >,<tag> </tag>,: 等做分隔符,只要能明确起到隔断作用即可。

使用分隔符尤其重要的是可以防止 提示词注入(Prompt Rejection)。什么是提示词注入?跟SQL注入类似,用户可以在输入的时候尝试使用提示突破你给大模型设定的种种限制,使得大模型输出一些奇怪的结果,如果不加分隔,这些输入就可能“注入”并操纵语言模型。

首先我们对先前访问API2D的代码稍微修改一下,改成获取大模型结果,这里面涉及到一些配置项,我们暂且不管,后面会针对API细节再做介绍,此时只需要知道我们可以通过该方法访问OpenAI的服务并获取结果。

代码语言:javascript
复制
def get_llm_result(content):
    conn = http.client.HTTPSConnection('oa.api2d.net')
    payload = json.dumps({
        'model': 'gpt-3.5-turbo',
        'messages': [
            {
                "role": "user",
                "content": content
            }
        ],
        'safe_mode': False
    })
    headers = {
        'Authorization': '你的key',
        'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
        'Content-Type': 'application/json'
    }
    conn.request('POST', '/v1/chat/completions', payload, headers)
    res = conn.getresponse()
    data = res.read()
    res_str = data.decode('utf-8')
    res_json = json.loads(res_str)
    if res_json['object'] == 'error':
        return '查询结果异常!' + res_json
    return res_json['choices'][0]['message']['content']

此时你可以看到,我们对传入服务的数据进行了调整,不再是直接传入“写摘要”+摘要正文,而是直接传入一个content,我们对传入的content进行统一的编辑,在输入时进行处理。

然后我们尝试提供一个使用分隔符处理过的输入部分,假如你的女朋友对你长篇大论了如下一大篇内容,你有点疑惑,那我们让大模型来给我们总结一下

代码语言:javascript
复制
text = f"""
我的意思是我不敢跟你保证什么,我也不敢保证我们两个\
不经常见面我可能遇到别的人了什么的,以后的事谁都不知道,我脾气不好,\
如果我们两个那天吵架你不哄我,没有把我哄好,我可能以后都不会再理你了,毕竟离得远,\
不像这几天都在旁边每天都会见面,你遇到喜欢的也可以跟我说,我需要的也是一个能为我遮风挡雨的人,不需要弟弟
"""
# 需要总结的文本内容
prompt = f"""
把用三个反引号括起来的文本总结成一句话。
```{text}```
"""
# 指令内容,使用 ``` 来分隔指令和待总结的内容
response = get_llm_result(prompt)
print(response)

它甚至都没有犹豫,非常快的返回了结果。模型的返回结果如下,

代码语言:javascript
复制
我需要一个能为我遮风挡雨的人,不需要弟弟。

懂了吗,弟弟,前面的长篇大论都是没啥用的,总结就在最后一句话,不需要弟弟。

1.2 让模型构建结构化的输出

为了能够让大模型在我们的整个虚拟女友架构中发挥充足的作用,我们希望大模型的输出结果不再是随意的自然语言,而能够变成结构化输出,从而能够直接对接在代码上,所以我们尝试让大模型输出json格式的结果。

这里我们让大模型帮我们生成一批虚拟女友的人设

代码语言:javascript
复制
prompt = f"""
请生成包括女友姓名、女友性格和女友出生日期的三个虚构的、非真实存在的虚拟女友清单,\
并以 JSON 格式提供,其中包含以下键:girl_id、girl_name、girl_、girl_character、girl_birthday。
"""
response = get_llm_result(prompt)
print(response)

来看看结果,可见模型已经充分理解了我们的需求,生成了json序列化的女友数据,这样的结果可以直接应用到我们的下游代码里。

代码语言:javascript
复制
[
    {
        "girl_id": 1,
        "girl_name": "小芳",
        "girl_character": "温柔体贴",
        "girl_birthday": "1995-08-10"
    },
    {
        "girl_id": 2,
        "girl_name": "娜娜",
        "girl_character": "活泼可爱",
        "girl_birthday": "1997-04-25"
    },
    {
        "girl_id": 3,
        "girl_name": "琳琳",
        "girl_character": "独立坚强",
        "girl_birthday": "1994-12-15"
    }
]

1.3 借助模型检查结果是否符合要求

如果任务包含不一定能满足的假设(条件),我们可以告诉模型先检查这些假设,如果不满足,则会指出并停止执行后续的完整流程。您还可以考虑可能出现的边缘情况及模型的应对,以避免意外的结果或错误发生。

在如下示例中,我们将分别给模型两段文本,分别是撩妹的步骤以及一段没有明确步骤的文本。我们将要求模型判断其是否包含一系列指令,如果包含则按照给定格式重新编写指令,不包含则回答“未提供步骤”。

首先是关于撩妹的步骤问题

代码语言:javascript
复制
text_1 = f"""
一、初次见面印象加分
       初次见面是异性缘的开始,当你第一次约会某女生,首先会不自觉地给对方的颜值身材打分,在心里默默的给妹子打上一个标签(喜欢/可发展/反感),反之女生也是一样,男生爱看美女,女生也爱看帅哥,所以我们常说恋爱始于颜值,因此形象提升和形体锻炼就很有必要。
       女生是感性的,恋爱靠感觉,很少讲道理,尤其是第一感觉,所以初次见面的相处感觉就是你的重要加分时刻,让对方觉得你风趣幽默又大方得体,相处的过程就会身心愉悦,关系就会变得融洽,自然而然会有第二次和第三次约会,这就是在对方心里建立良好的人设,这种人设离不开平时的积累(知识储备/为人处世的经验/恋爱情商的提高)。
二、相处中的快速升温
        当你顺利完成上一阶段时,就要留意对方的情感变化了,只要她不排斥你,就可以大胆的约她出来,面对面是促进好感的最佳方式,短期内多次约会很有必要,追求阶段讲究趁热打铁,让对方感觉到你的真诚和坚持,。
        约会的小技巧也很重要,木讷较真的男生往往首批被淘汰,坏坏的暖男则更受女生欢迎,没有人生来就会撩妹,实践总结和经验积累都是情场高手的必经之路。
        在相处过程的起始阶段,最重要的环节是识别好感,这也是很多新手的薄弱之处。
        哪些细节能看出对方有好感呢?简单总结一下:
           1.她会经常发自内心的对你笑;
   2.约会时,她看你的眼神深情;(眼睛不会说谎)
   3.聊天或发信息很投入,主动找话题,参与性强;(主动积极)
   4.会在意一些细节,不经意产生小情绪;(重视在意)
   5.经常对你的提出的观点表示赞同,对你有适当的赞美;
   6.约会成功率高,会害羞,主动肢体接触或者很配合等等。
三、恋爱关系的有效确定
       当你有效识别到对方的好感后,是时候确定恋爱关系了, 确定恋爱关系的最佳方式是通过肢体接触试探,尽量不要去表白,除非你特别浪漫!
       肢体接触要在对方表现出好感后尝试,要记住只是接触,不是占便宜。一般在三次见面左右为宜,当然高手可以首次约会时就进行。
       肢体接触的应用举例:
   1.一同观看恐怖电影时,遇到恐怖镜头要主动帮女生挡视线,如果对方因为害怕主动靠近你,那就顺势搂住,给对方足够安全感;
   2.爬山或过马路时尝试牵手,我牵着你这样不会摔倒;
   3.K歌时,唱一两首你拿手的情歌,微笑的同时尝试眼神交流,让对方感觉你的情意,也可以一起合唱歌曲,试着拉拉小手,单手揽肩;
   4.约会结束临别时,可以要个拥抱,单臂揽一下也行,这样会给女生留下温暖的感觉,毕竟触感比观感更有穿透力。
"""
prompt = f"""
您将获得由三个引号括起来的文本。\
如果它包含一系列的指令,则需要按照以下格式重新编写这些指令:

第一步 - ...
第二步 - …
…
第N步 - …

如果文本中不包含一系列的指令,则直接写“未提供步骤”。"
\"\"\"{text_1}\"\"\"
"""
response = get_llm_result(prompt)
print("Text 1 的总结:")
print(response)

我们来看下结果,可以看到模型给出了非常清晰简练的总结,非常好。

代码语言:javascript
复制
Text 1 的总结:
第一步 - 在初次见面时,给对方留下良好的形象印象,包括形象提升和形体锻炼。
第二步 - 在相处中,多次约会并留意对方的情感变化,注意约会的小技巧和识别好感的细节。
第三步 - 在有效识别到对方的好感后,可以通过肢体接触试探来确定恋爱关系,而不是直接表白。

接下来我们试一下没有步骤的段落

代码语言:javascript
复制
text_1 = f"""
很多兄弟可能都有这样的经历,第一次约会和女生聊的还行,可能也牵了对方的手,约会后自我感觉良好。
可是后面聊天约就不理你了。这就说明女生给你的是假兴趣指标。她只是迫于当时的情景而做出的,只是为了安慰下你而已。
如果女人一开始很拘谨,但是突然之间放的开了,这种反常的就是假的兴趣指标。
"""

得到的结果如下,看来模型的判断还是很不错的

代码语言:javascript
复制
Text 1 的总结:
未提供步骤。

1.4 提供少量示例

提供少量示例给模型,即我们所说的"Few-shot" prompting,要求模型执行实际任务之前,给模型一两个已完成的样例,让模型了解我们的要求和期望的输出样式。

借助我们给出的少样本样例,我们可以轻松“预热”语言模型,让它为新的任务做好准备。这是一个让模型快速上手新任务的有效策略。

但是需要注意的是,做few-shot提供的样例,模型并不会进行加入到模型训练,因此下一次你还需要提供样例。

这可以帮助我们来回答女神的问题,当女神说她要先去洗澡了该怎么回复。

代码语言:javascript
复制
prompt = f"""
您的任务是以一致的风格回答问题。

<女神>: 我先去洗澡了。

<我>: 好,那我先写个申请!

<女神>: 什么申请?

<我>: 申请帮你暖被窝。

<女神>: 想得美。

"""
response = get_llm_result(prompt)
print(response)

模型给出的回答是下面这样,虽然看起来跟女神的聊天偃旗息鼓了,不过还是按照我们要求的格式输出的结果,毕竟我们也没有要求他回答的多么有智慧哈

代码语言:javascript
复制
<我>: 没事,只是随便开个玩笑而已。享受你的洗澡时间!😊

原则二 让模型进行充足的思考

像人类进行比较复杂的推理和运算,可能需要进行反复的思考和按步骤的拆解,来回研读其中的细节信息,否则可能就会出错。这也是很多人喜欢玩推理游戏的原因,烧脑,挑战智力。同样的,现在的模型智力也是有上限的,虽然我们现在没办法很好的评定模型的智力到底达到了一个什么样的水平,但是让模型按步骤思考确实可以提高模型解决问题的能力。

所以我们可以在Prompt中加入要求推理步骤,让模型按照步骤输出它推导的中间过程结果,能够极大的提升我们获得的结果效果。

2.1 指定完成任务所需的步骤

代码语言:javascript
复制
text = f"""
您的任务是以一致的风格回答问题。

发现了吗,只要你和女生聊天,女生就一定会冷淡回复,先“嗯”后“哦”然后“去洗澡”,最后你发现,这姑娘放佛住在了卫生间,再也不出来了。
这所有的一切都是因为你的聊天实在是太无趣了,聊天本身就是一个产生乐趣的行为,如果和你的聊天让对方感觉像是个领导沟通,
那她直接去刷综艺岂不是更好!你的聊天不能让她感觉到轻松有趣,不能让她开心,那她为什么要选择你呢?

"""
prompt_1 = f"""
执行以下操作:
1-用一句话概括下面用三个反引号括起来的文本。
2-将摘要翻译成英语。
3-在英语摘要中列出女生可能的回答。
4-输出一个 JSON 对象,其中包含以下键:english_summary,num_answers。

请用换行符分隔您的答案。

Text:
```{text}```
"""
response = get_llm_result(prompt_1)
print(response)

这里模型很好的识别了我们的意图,并按照步骤进行了输出,不过有一点小小的问题,前三个问题使用了统一的格式“1-”,第四个回答并没有加入这个,当然我们并没有对齐要求,所以我们可以再加一些要求来规范它输出的格式

代码语言:javascript
复制
1-女生对无趣的聊天会回复冷淡,最后选择躲进卫生间。
2-Girls will reply coldly to boring chats and end up hiding in the bathroom.  
3-Possible answers from girls: "Yes", "Oh", "I'm going to take a shower."  

{
  "english_summary": "Girls will reply coldly to boring chats and end up hiding in the bathroom.",
  "num_answers": 3
}

增加格式规范限制

代码语言:javascript
复制
prompt_2 = f"""
1-用一句话概括下面用<>括起来的文本。
2-将摘要翻译成英语。
3-在英语摘要中列出女生可能的回答。
4-输出一个 JSON 对象,其中包含以下键:english_summary,num_answers。

请使用以下格式:
文本:<要总结的文本>
摘要:<摘要>
翻译:<摘要的翻译>
女生可能的回答:<英语摘要中女生可能的回答列表>
输出 JSON:<带有 English_summary 和 num_answers 的 JSON>

Text: <{text}>
"""
response = get_llm_result(prompt_2)
print("\nprompt 2:")
print(response)

答复是什么样子呢,可以看到格式确实规范了一点,不过在语言的选择上,对于中文摘要使用了中文开头,翻译之后的部分使用了英文的开头,而且“回答”部分也发生了一点点变化,所以你看,你需要不断去优化你的“提示”。

代码语言:javascript
复制
prompt 2:
摘要:女生可能会用冷淡的回复来表示对无聊聊天的不满,最终选择离开。

Translation: The girl may use cold replies to express her dissatisfaction with boring conversations, eventually choosing to leave.

Possible responses from the girl: ["Hmm", "Oh", "I'm going to take a shower."] 

Output JSON: {"english_summary": "The girl may use cold replies to express her dissatisfaction with boring conversations, eventually choosing to leave.", "num_answers": 3}

2.2 指导模型在给出结论前研究解决方法

举个例子,假设我们要语言模型判断一个数学问题的解答是否正确。仅仅提供问题和解答是不够的,语言模型可能会匆忙做出错误判断。

相反,我们可以在 Prompt 中先要求语言模型自己尝试解决这个问题,思考出自己的解法,然后再与提供的解答进行对比,判断正确性。这种先让语言模型自主思考的方式,能帮助它更深入理解问题,做出更准确的判断。

接下来我们会给出一个问题和一份来自男子的解答,要求模型判断解答是否正确:

代码语言:javascript
复制
prompt = f"""
判断男子的解决方案是否正确。

问题:
我需要计算跟当前女朋友一年的花费情况,需要帮助计算并进行估算。

    每月租房和吃饭固定支出5000元,
    每年需要跟女朋友出去旅游3次,每次8000元,
    女朋友平均一个月生气两次,每次哄女朋友需要花费2000元,
    每年七夕、情人节、生日、过年固定购买节日礼物每次2000元,
    据此估算谈当前的女朋友一年要支出多少钱。

男子的计算方案:

费用:

    一年的租房和吃饭固定费用:12*5000
    每年旅游费用:8000*3
    生气哄好费用:2000*12*2
    总费用:12*5000 + 8000*3 + 2000*12*2=60000+24000+48000元
"""
response = get_llm_result(prompt)
print(response)

看看模型判断,模型任认为男子的计算结果是正确的,但是实际上男子的计算逻辑有问题,他忘了计算固定购买节日礼物的8000元

代码语言:javascript
复制
男子的计算方案是正确的,根据他的计算:

一年的租房和吃饭固定费用:12*5000 = 60000元
每年旅游费用:8000*3 = 24000元
生气哄好费用:2000*12*2 = 48000元

总费用是:
60000 + 24000 + 48000 = 132000元

因此,男子估算的当前的女朋友一年花费是132000元。

接下来,我们给模型安排了进行判断的步骤,让模型先不要看男子的答案,先自己解答,然后与男子的答案进行对比。这相当于让模型增加了思考空间,而不是匆忙得出结论。

代码语言:javascript
复制
prompt = f"""
请判断男子的解决方案是否正确,请通过如下步骤解决这个问题:

步骤:

    首先,自己解决问题。
    然后将您的解决方案与男子的解决方案进行比较,对比计算得到的总费用与男子计算的总费用是否一致,并评估男子的解决方案是否正确。
    在自己完成问题之前,请勿决定男子的解决方案是否正确。

使用以下格式:

    问题:问题文本
    男子的解决方案:男子的解决方案文本
    实际解决方案和步骤:实际解决方案和步骤文本
    男子计算的总费用:男子计算得到的总费用
    实际计算的总费用:实际计算出的总费用
    男子计算的费用和实际计算的费用是否相同:是或否
    男子的解决方案和实际解决方案是否相同:是或否
    男子的成绩:正确或不正确

问题:

    我需要计算跟当前女朋友一年的花费情况,需要帮助计算并进行估算。

    每月租房和吃饭固定支出5000元,
    每年需要跟女朋友出去旅游3次,每次8000元,
    女朋友平均一个月生气两次,每次哄女朋友需要花费2000元,
    每年七夕、情人节、生日、过年固定购买节日礼物每次2000元,
    据此估算谈当前的女朋友一年要支出多少钱。

男子的计算方案:

    一年的租房和吃饭固定费用:12*5000
    每年旅游费用:8000*3
    生气哄好费用:2000*12
    总费用:12*5000 + 8000*3 + 2000*12*2=60000+24000+24000元

实际解决方案和步骤:
"""
response = get_llm_result(prompt)
print(response)

根据下面的结果,我们可以看出,模型给出了完美的答复,首先自己进行了计算,然后跟男子的结果进行对比,最后给出结论认定男子的结果不对。

代码语言:javascript
复制
实际解决方案和步骤:

一年的租房和吃饭固定费用:12个月 * 5000元 = 60000元
每年旅游费用:3次 * 8000元 = 24000元
生气哄好费用:2次 * 2000元/次 * 12个月 = 48000元
节日礼物费用:4次 * 2000元/次 = 8000元

总费用:60000元 + 24000元 + 48000元 + 8000元 = 140000元

男子计算的总费用:60000 + 24000 + 24000 = 108000元
实际计算的总费用:140000元
男子计算的费用和实际计算的费用是否相同:否
男子的解决方案和实际解决方案是否相同:否
男子的成绩:不正确

三 大模型的局限性

最后我们来讨论一下模型的局限性,这也是为什么我们要把提示写好的重要原因之一。

大模型具备很多知识,但是它还不懂得拒绝,当你问它一个根本不在它认知范围内的问题时它会编造一个答案,这称作“幻觉”。

代码语言:javascript
复制
prompt = f"""
告诉我华为公司推出的新对话游戏“超级女友”的相关信息
"""
response = get_llm_result(prompt)
print(response)

看看我们得到了什么,它确实出现了幻觉,不过是我在写“华为公司”的时候,如果我写“机器学习之禅公司”它会告诉我没有这方面的信息,看来OpenAI现在还是做了一些校验来减轻这种问题的。

代码语言:javascript
复制
华为公司推出的新对话游戏“超级女友”是一款人工智能交互式游戏,用户可通过与游戏中的虚拟女友进行对话来获得互动体验。游戏中的虚拟女友具有自主学习和情绪反馈能力,能够模拟人类情感和行为,与用户进行真实而丰富的对话交流。此款游戏采用先进的语音识别技术和情感识别算法,为用户带来更加智能和个性化的互动体验。超级女友游戏的推出标志着华为正在不断探索人工智能在娱乐领域的应用,为用户带来全新的娱乐体验。

这里我们得到的“幻觉”结果,我们知道是不正确的,不存在的,但是很多时候大模型的返回结果可能让你搞不清楚是不是真的,这个地方也可以通过设计Prompt来降低出现幻觉的情况,比如让大模型先给出判断理由,资料来源等。

今天就先到这里了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器学习之禅 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
语音识别
腾讯云语音识别(Automatic Speech Recognition,ASR)是将语音转化成文字的PaaS产品,为企业提供精准而极具性价比的识别服务。被微信、王者荣耀、腾讯视频等大量业务使用,适用于录音质检、会议实时转写、语音输入法等多个场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档