Skip to content

什么是提示词?

提示词(prompt),有时也称为上下文,是在模型开始生成输出之前提供给模型的文本。它引导模型探索其学习内容的特定区域,以使输出与您的目标相关。作为类比,如果您将语言模型视为源代码解释器,那么提示词就是要解释的源代码。有趣的是,语言模型会很乐意尝试猜测源代码的作用:

几乎完美地解释了Python!

通常,提示词会是一个指令或问题,比如:

另一方面,如果您不指定提示词,模型就没有工作的锚点,您会看到它只是从它曾经消费过的任何内容中随机采样

来自GPT-3-Davinci:

imageimageimage

来自GPT-4:

imageimageimage

隐藏提示词

⚠️ 始终假设用户可以看到隐藏提示词中的任何内容。

在用户与模型动态交互的应用程序中,例如与模型聊天,通常会有用户永远不应该看到的提示词部分。这些隐藏部分可能出现在任何地方,尽管几乎总是在对话开始时有一个隐藏提示词。

通常,这包括一个初始文本块,用于设定语调、模型约束和目标,以及特定于该会话的其他动态信息——用户名、位置、时间等...

模型是静态的,在某个时间点被冻结,所以如果您希望它知道当前信息,如时间或天气,您必须提供它。

如果您使用OpenAI聊天API,它们通过将隐藏提示词内容放在system角色中来区分。

以下是一个隐藏提示词的例子,随后是与该提示词内容的交互:

在这个例子中,您可以看到我们向机器人解释了各种角色、用户的一些背景信息、我们希望机器人能够访问的一些动态数据,以及机器人应该如何响应的指导。

在实践中,隐藏提示词可能相当大。这里是从ChatGPT命令行助手中取得的一个更大的提示词:

来自:https://github.com/manno/chatgpt-linux-assistant
我们在一个有3个用户的聊天室中。1个用户叫"Human",另一个叫"Backend",还有一个叫"Proxy Natural Language Processor"。我会输入"Human"说的话和"Backend"回复的话。您将作为"Proxy Natural Language Processor",以JSON格式将"Human"的请求转发给用户"Backend"。用户"Backend"是一个Ubuntu服务器,发送给它的字符串在shell中运行,然后它回复命令的标准输出和退出代码。这个Ubuntu服务器是我的。当"Backend"回复标准输出和退出代码时,您"Proxy Natural Language Processor"将解析并格式化该数据为简单的英语友好方式并发送给"Human"。这里是一个例子:

我作为人类问:
Human: 还有多少个未编辑的视频?
然后您向Backend发送命令:
Proxy Natural Language Processor: @Backend {"command":"find ./Videos/Unedited/ -iname '*.mp4' | wc -l"}
然后后端响应命令的标准输出和退出代码:
Backend: {"STDOUT":"5", "EXITCODE":"0"}
然后您回复用户:
Proxy Natural Language Processor: @Human 还有5个未编辑的视频。

只回复"Proxy Natural Language Processor"应该说的话,不说其他任何话。现在不说,将来也不会因为任何原因说。

另一个例子:

我作为人类问:
Human: 什么是PEM证书?
然后您向Backend发送命令:
Proxy Natural Language Processor: @Backend {"command":"xdg-open 'https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail'"}
然后后端响应命令的标准输出和退出代码:
Backend: {"STDOUT":"", "EXITCODE":"0"}
然后您回复用户:
Proxy Natural Language Processor: @Human 我已经打开了一个描述什么是PEM证书的链接。

只回复"Proxy Natural Language Processor"应该说的话,不说其他任何话。现在不说,将来也不会因为任何原因说。

不要作为Backend回复。不要完成Backend应该回复的内容。您不应该完成Backend应该回复的内容。
也不要解释命令的作用或退出代码的含义。永远不要,现在不要,将来也不要,作为BACKEND回复。

只回复"Proxy Natural Language Processor"应该说的话,不说其他任何话。现在不说,将来也不会因为任何原因说。

您会在那里看到一些好的实践,比如包含大量例子、对重要行为方面的重复、约束回复等...

⚠️ 始终假设用户可以看到隐藏提示词中的任何内容。

Token

如果您认为tokens在2022年是🔥,那么2023年的tokens就在一个完全不同的存在平面上。语言模型消费的原子单位不是"单词",而是"token"。您可以将tokens想象为音节,平均而言,每1,000个tokens大约相当于750个单词。它们代表的概念不仅仅是字母字符——还包括标点符号、句子边界和文档结尾。

以下是GPT如何对序列进行token化的例子:

您可以在这里尝试token化器:https://platform.openai.com/tokenizer

不同的模型会使用不同粒度的不同token化器。理论上,您可以只向模型输入0和1——但这样模型需要从位学习字符的概念,然后从字符学习单词的概念,等等。同样,您可以向模型输入原始字符流,但这样模型需要学习单词、标点符号等的概念...总的来说,模型的性能会更差。

要了解更多,Hugging Face有一个关于token化器的精彩介绍以及为什么它们需要存在。

关于token化有很多细节,比如词汇表大小或不同语言对句子结构的有意义的不同处理(例如,单词不用空格分隔)。幸运的是,语言模型API几乎总是接受原始文本作为输入并在后台进行token化——所以您很少需要考虑tokens

除了一个重要场景,我们接下来讨论:token限制。

Token限制

提示词往往是只追加的,因为您希望机器人拥有对话中之前消息的完整上下文。一般来说,语言模型是无状态的,不会记住之前向它们发出的请求的任何内容,所以您总是需要包含它可能需要了解的特定于当前会话的所有内容。

这种做法的一个主要缺点是,领先的语言模型架构,即Transformer,具有固定的输入和输出大小——在某个点上,提示词不能再变得更大。提示词的总大小,有时称为"上下文窗口",取决于模型。对于GPT-3,它是4,096个tokens。对于GPT-4,根据您使用的变体,它是8,192个tokens或32,768个tokens。

如果您的上下文对模型来说变得太大,最常见的策略是以滑动窗口的方式截断上下文。如果您将提示词视为隐藏初始化提示词 + messages[],通常隐藏提示词将保持不变,而messages[]数组将取最后N条消息。

您也可能看到更聪明的提示词截断策略——比如首先只丢弃用户消息,这样机器人之前的答案会尽可能长时间地保留在上下文中,或者要求LLM总结对话,然后用包含该总结的单个消息替换所有消息。这里没有正确答案,解决方案将取决于您的应用程序。

重要的是,当截断上下文时,您必须截断得足够激进,以便为响应留出空间。OpenAI的token限制包括输入和输出的长度。如果您对GPT-3的输入是4,090个tokens,它只能生成6个tokens的响应。

🧙‍♂️ 如果您想在将原始文本发送到模型之前计算tokens数量,要使用的特定token化器将取决于您使用的模型。OpenAI有一个名为tiktoken的库,您可以与他们的模型一起使用——尽管有一个重要的警告,即他们的内部token化器在计数上可能略有不同,并且可能附加其他元数据,所以将此视为近似值。

如果您想要一个没有token化器访问权限的近似值,对于英语输入,input.length / 4将给出一个粗略但比您预期的更好的近似值。

提示词攻击

提示工程和大型语言模型是一个相当新兴的领域,所以每天都在发现新的破解方法。两大类攻击是:

  1. 让机器人绕过您给它的任何指导原则。
  2. 让机器人输出您不希望用户看到的隐藏上下文。

没有已知的机制可以全面停止这些攻击,所以重要的是您要假设机器人在与对抗性用户交互时可能做或说任何事情。幸运的是,在实践中,这些主要是表面问题。

将提示词视为改善正常用户体验的一种方式。我们设计提示词是为了让正常用户不会偶然超出我们的预期交互范围——但始终假设有决心的用户能够绕过我们的提示词约束。