Prompt Engineering 经验分享

我这大半年来都在围绕 ChatGPT API 做事,积累了一些 Prompt 相关的经验,大部分跟编程有关。即拿到结果后,我们不直接输出,而是使用代码处理这些结果,然后再输出。Functional Calling 对编程当然有用,不过有时候,配合文中的一些方法,可以得到更好用的结果。

ChatGPT 的基本原理

ChatGPT 是一个生成式大语言模型,它由海量的数据训练而来。所以当我们输入一些内容作为启动数据之后,它就会计算出来最可能最合理的新内容。比如,输入“白日依山尽”,那么最合理的接续多半是“黄河入海流”。当然,由于 ChatGPT 已经针对“聊天”这个场景做过优化,所以,他可能会多说一些过渡性的内容。

通常来说,我们发给 ChatGPT 的内容不会这么好预期,所以它会产出的结果也存在很大变数。这对我们来说有好处也有坏处。好处是,多变的结果,会让我们有更多期待,也更有机会拿到想要的结果;坏处是,结果质量可能忽高忽低,格式也飘忽不定,难以在程序里使用。

Prompt 入门

要写出好的、有效的 Prompt,第一步应该去认真阅读 OpenAI 官方的 GPT最佳实践(GPT best practices)。这里我简单总结一下:

请求里包含必要的信息

比如我家孩子想让 GPT 帮他写作文,如果只说:“帮我写一篇作文”,效果就不好。因为作文有很多可能,不同的阶段、不同的文体、不同的主题,写出来的作文可能完全不同。

这时候就要耐心跟 GPT 讲清楚:“我是一名小学五年级的学生,请帮我写一篇作文,大约 300 字,记录我们家过中秋节的故事,我们吃了月饼,看了晚会;我们本来想出去旅游,但是爸爸妈妈猜到处都是人,就没有出去。”

让 GPT 扮演一个角色

GPT 已把成千上万的角色融于一身。还是上面的例子,我家孩子如果只让 GPT 帮他写作文,能写,但是未必敢交给老师。所以此时就要让 GPT 扮演同样的小学五年级的学生来写作文。

给 GPT 提供周边信息的时候,要把边界标清楚

没有格式的文字,无论是人还是机器都无法理解。所以我们可以使用各种 XML 标记,或者三连引号,让 GPT 知道哪些是我们的请求、哪些是我们给它的参考资料。

提前帮 GPT 分解任务

GPT 目前的逻辑能力有限,如果我们有更靠谱的解法,直接教给它会更有效率。

提供例子让 GPT 参考

这个策略在二次开发领域会大量使用,我觉得比 functional calling 更常用。

指定输出内容的长度

我们知道,语言都存在信息密度,想把一件事情说清楚,可能需要很多文字;而过多的文字,也可能存在一些“废话”。所以限制输出长度往往也可以行之有效地改进结果。

不过实际上,内容长度会跟很多因素有关,往往不能简单一限了之;如果篇幅限制,实在说不清楚,GPT 也可能会忽略我们的某个要求,大量文字一吐为快。

我的经验

对编程来说,稳定性非常重要,因为我们的代码无法适配各种各样千奇百怪的输出。这些输出在 ChatGPT 的聊天界面里,面向使用自然语言的普通人,其表达能力没有问题,但是对我们的程序来说,一些微微的差异也可能破坏代码功能。

总则:把 GPT 当成态度超好但能力一般的实习生

GPT 拥有海量的知识,但是缺少足够的逻辑思维能力去组织、架构这些知识。于是我们不能指望 GPT 能够很好的利用这些知识帮我们做事情。更多的时候,我们要先想清楚怎么做,拆解出来步骤,再把任务逐一分配给 GPT,让它尽量简单地做执行工作。

但是 GPT 态度绝对好,绝对耐心,它可以不厌其烦的反复尝试我们交代的工作,毫无怨言。真是一个能力平平的社畜……

如果你不知道下一步该怎么做,不妨把 ChatGPT 当成一位无法独立处理工作的实习生,尝试带领它工作,而不是期待他能解决你都不知道该怎么解决的问题。

减少歧义,尤其是隐含的歧义

有时候,我们的表达会有一些隐含的歧义。比如,我们去吃饭,想点一份不辣的鱼香肉丝或者回锅肉,这里面就包含歧义——按照川菜里的标准定义,鱼香肉丝和回锅肉都有辣。如果是在不常吃辣的地方,厨师可能可以试一试;如果实在巴蜀本地,那多半厨师要谢绝接待了。

我们向 ChatGPT 提要求的时候也要注意。举个例子,我厂的产品会要求 ChatGPT 帮忙写一封信,这封信需要遵循一定格式,我们才好解析它并重新格式化。但是我们发现,GPT 在写开头(intro)的时候,经常会只写:Dear Meathill,即问候语(greetings),然后漏掉我们希望有的第一段。反复换模型也没有效果。后来我把要求改成

intro: greetings, then one paragraph of introduction about 50 words,终于解决了问题。

因为对于 GPT 来说,一句 greeting 也可以是 intro,只要求写 intro,它搞不清我们的目的,输出就远不如后面准确。

使用 YAML 传递格式化数据

JSON 格式要求很严格,很容易出错,而且在得到完整结果前,也很难解析。所以我建议大家如果需要格式化数据,不要用 JSON,用 YAML。YAML 格式更简单,不容易出错;而且 YAML 在流式传播的时候,不耽误我们实时解析并且输出,效果更好。

比如这样:

Please, as a Christian minister, help me choose a thought-provoking verse from the Bible, tell me why you chose it, and then write a prayer for me. Please write to me in the following YAML formats. No other content.

“`yaml
verse: the verse content
reference: the verse you select for me
thought: teach me about this verse, about 80 words
prayer: use it to lead me to prayer, about 80 words
“`

控制 Prompt 的长度

正如前面所说:

  1. ChatGPT 的推理能力并没有传说中那么强;
  2. 自然语言里难免会存在前后矛盾之处

所以过长的 prompt 很容易导致得到不稳定、不可靠的结果。网上能找到各种洋洋洒洒一大篇的超长 Prompt,实际上以我的经验,这些 Prompt 要么实际效果一般,要么有许多限制条件并不必要。尤其是那些限制 ChatGPT 应该说这个不应该说那个的,多半因为前后矛盾实际上并未生效。

我建议大家保证遵守上面最佳实践的六点之后,尽量用简短无歧义的语言提出要求,得到的结果会更加可靠。

(案例待补充)

Embedding + Searching 中文一般,英文略好

经我们测试,中文 Embedding 的结果差强人意,检索匹配度很差,感觉跟传统关键词搜索的效果差不多,自然语言与原文表达相似的意思,但是词汇完全不同的时候,经常搜不出结果。

英文略好一些,不过也好不到哪儿去,事实搜索强于表意搜索,做知识库知识管理的话,问题不大;期待做回复系统的话,我认为并不可行。实际上,我体验那些所谓名人聊天工具时,感觉也是如此。

比如,类似 trickle.com 这样的知识管理工具,存进去一些统计数据,如股票价格、销量等,然后基于自然语言进行检索:“苹果股价最高时是多少?”一般来说没有问题。但是如果写日记,然后搜索:“我那天特别开心,是怎么了来着?”,就基本没有结果。

解决方案当然也是有的,在 Embedding 存入数据库时,预设一些搜索场景,然后让 ChatGPT 帮助生成搜索辅助内容,最后一起 Embedding 存入数据库,这样搜索的时候就有更大概率能找到。比如:

这是我的日记,请分析我日记中所表述的心情、印象、态度,概括为 10~20 个形容词。请只用 TypeScript `string[]` 的格式输出。No more other content.

“””长假期间天气好热,想出去玩,但想到这么热人又多就懒得走了……”””。

总结

ChatGPT 非常强,但要让他发挥全部战力,我们开发者的努力也不可或缺。以上是我这几个月来学习总结得到的经验,希望对大家有用。也期待看到更多开发者从编程角度,分享二次开发的经验。

如果您觉得文章内容对您有用,不妨支持我创作更多有价值的分享:


已发布

分类

来自

评论

《 “Prompt Engineering 经验分享” 》 有 2 条评论

  1. d 的头像
    d

    私以为yaml格式的输出更容易出错,因为ai经常控制不好空格的位数,或者空格和tab混用,导致我解析不出来

    1. meathill 的头像

      我没遇到过。我会尽量控制yaml结构的复杂度,目前最多3层,效果还可以,没出过问题。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据