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

2024-07-04 16:15:48 浏览数 (2)

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

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

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复制
<我>: 没事,只是随便开个玩笑而已。享受你的洗澡时间!


	

0 人点赞