- 文集信息
- 目录大纲
- 最新文档
- 知识宇宙
文集详情
文集导读
本指南由 Brex 创建,用于内部目的。它基于 从研究和创建大型语言模型 (LLM) 中吸取的经验教训 生产使用案例的提示。它涵盖了 LLM 的历史以及 使用 和 的策略、指南和安全建议 在大型语言模型(如 OpenAI 的 GPT-4 的。
本文档中的示例是使用非确定性语言生成的 model 和相同的示例可能会得到不同的结果。
这是一个动态文档。最先进的最佳实践和策略 围绕 LLM 每天都在迅速发展。讨论和建议 鼓励改进。
目录
什么是大型语言模型 (LLM)?
大型语言模型是采用一系列单词的预测引擎 并尝试预测该序列之后最有可能出现的序列1. 它通过为可能的下一个序列分配一个概率来实现这一点,然后 从中选一个2.该过程重复进行,直到停止 满足条件。
大型语言模型通过在大型语料库上进行训练来学习这些概率 的文本。这样做的结果是,这些模型将迎合某些用例 比其他 URL 更好(例如,如果它是在 GitHub 数据上训练的,它将理解 源代码中序列的概率非常好)。另一个后果是 模型可能会生成看似合理但实际上是 只是随机的,没有立足于现实。
随着语言模型在预测序列方面变得更加准确,许多 令人惊讶的能力 出现。
语言模型的简短、不完整且有点不正确的历史
2000 年代之前
语言模型已经存在了几十年,尽管传统的语言模型(例如 n-gram models)具有许多 状态空间爆炸方面的缺陷( 维数)和 使用他们从未见过的新短语 (sparsity)。显然,年龄较大 语言模型可以生成文本,这些文本与 人工生成的文本,但输出中没有一致性 - 以及 读者很快就会意识到这都是胡言乱语。N-gram 模型也不进行缩放 的 N 值较大,因此本质上受到限制。
2000 年代中期
2007 年,以在 1980 年代推广反向传播而闻名的 Geoffrey Hinton 发表了训练神经的重要进展 解锁很多的网络 更深的网络。将这些简单的深度神经网络应用于语言 建模有助于缓解语言模型的一些问题 – 它们 以有限的空间和连续的方式表示细微的任意概念, 优雅地处理训练语料库中没有的序列。这些简单的 神经网络很好地学习了其训练语料库的概率,但是 输出将在统计上与训练数据匹配,并且通常不会 相对于输入序列的 coherent 进行匹配。
2010 年代初
尽管它们于 1995 年首次推出,但长短期记忆 (LSTM) 网络发现他们的 是时候在 2010 年代大放异彩了。LSTM 允许模型处理任意长度 序列,重要的是,当它们 处理输入以记住他们之前看到的东西。这个小的调整导致了 到显着的改进。2015 年,安德烈·卡尔帕西 (Andrej Karpathy) 写了一篇著名的 创建角色级别 执行 比它任何权利都要好得多。
LSTM 看似具有神奇的能力,但长期难以 依赖。如果你让它完成句子,“在法国,我们 四处旅行,吃了很多糕点,喝了很多酒,......更多文字...... ,但从未学会如何说 _______“,模型可能会遇到困难 预测 “French”。它们还一次处理一个令牌的输入,也是如此 本质上是连续的,训练速度很慢,并且 Token 只知道之前的 Token。Nth``N - 1
2010 年代末
2017 年,谷歌写了一篇论文,《注意力就是你全部》 需要,引入了 Transformer 网络,并掀起了自然语言处理的巨大革命。一 夜 之间 机器可以突然完成诸如在语言之间进行翻译之类的任务,几乎 和人类一样好(有时比人类更好)。变压器高度可并联 并引入一种称为“注意力”的机制,让模型有效地 强调输入的特定部分。变压器分析整个 同时输入所有内容,选择哪些部分是最重要的,并且 有影响。每个输出标记都受每个输入标记的影响。
Transformer 具有高度可并行化、训练和生产效率 惊人的结果。变压器的缺点是它们具有固定的输入 和 output size (上下文窗口) 和 Computation 增加 与此窗口的大小进行二次方分配(在某些情况下,内存会作为 嗯!3.
变压器并不是道路的终点,但绝大多数最近的 自然语言处理的改进让他们参与进来。还有 对实施和应用它们的各种方法进行了大量积极的研究, 例如亚马逊的 AlexaTM 20B 在许多任务中优于 GPT-3,并且是一个数量级 参数数量较少。
2020 年代
虽然从技术上讲从 2018 年开始,但 2020 年代的主题是 生成式预训练模型 – 更广为人知的是 GPT。一 在“Attention Is All You Need”论文发布一年后,OpenAI 发布了 Improving Generative 的语言理解 训练前。 本文确定,您可以在大型 数据集,然后一旦模型学习了 语言的一般方面,您可以针对特定任务对其进行微调,以及 快速获得最先进的结果。
2020 年,OpenAI 跟进了他们的 GPT-3 论文《语言模型是》 Few-Shot (少数镜头) 学习者, 表明,如果您将类似 GPT 的模型再放大 ~10 倍,在 参数的数量和训练数据的数量,你没有 longer 必须针对许多任务对其进行微调。功能自然而然地出现 通过与模型的文本交互,您可以获得最先进的结果。
2022 年,OpenAI 通过发布 InstructGPT 跟进了他们的 GPT-3 成就。意图 这是为了调整模型以遵循说明,同时也更少 其输出有毒且有偏见。这里的关键要素是加固 从人类反馈中学习 (RLHF) 中,一个 2017 年由 Google 和 OpenAI 合著的概念4,它允许人类 在训练循环中微调模型输出,使其更符合 人类的偏好。InstructGPT 是现在著名的 ChatGPT 的前身。
在过去的几年里,OpenAI 一直是大型语言模型的主要贡献者 年,包括最近推出的 GPT-4,但他们并不孤单。元 引入了许多开源大型语言模型,如 OPT、OPT-IML(指令调优)、 和 LLaMa。 Google 发布了 FLAN-T5 和 BERT 等型号。并且有一个巨大的开放 来源研究社区发布 BLOOM 和 StableLM 等模型。
现在进展如此迅速,以至于每隔几周就会出现最先进的技术 更改或以前需要运行集群的模型现在运行 Raspberry PI 的
什么是提示?
提示(有时称为上下文)是提供给 model 开始生成输出。它指导模型探索 它所学到的特定区域,以便输出与您的 目标。打个比方,如果你把语言模型看作一个源代码 interpreter 中,则 prompt 是要解释的源代码。有点 有趣的是,语言模型会很高兴地尝试猜测什么源代码 将执行以下操作:
它_几乎_完美地诠释了 Python!
通常,提示将是说明或问题,例如:
另一方面,如果您未指定提示,则模型没有锚点 work 的 API 中,你会看到它只是从它拥有的任何内容中随机采样 曾经消费过:
来自 GPT-3-Davinci:
![]() |
![]() |
![]() |
|---|
从 GPT-4 开始:
![]() |
![]() |
![]() |
|---|
隐藏的提示
⚠️始终假定用户可以看到隐藏提示中的任何内容。
在用户与模型动态交互的应用程序中,例如 与模型聊天时,通常会有部分提示 绝不打算让用户看到。这些隐藏的部分可能会出现 anywhere,尽管在 谈话。
通常,这包括设置基调的初始文本块,模型 约束条件和目标,以及其他特定的动态信息 到特定会话 – 用户名、位置、一天中的时间等...
该模型是静态的,并在某个时间点冻结,因此,如果您希望它知道 您必须提供当前信息,例如时间或天气。
如果您使用的是 OpenAI Chat API 中,他们 通过将隐藏的提示内容放置在角色中来描述隐藏的提示内容。system
下面是一个隐藏的提示后跟与内容交互的示例 在该提示中:
在此示例中,您可以看到我们向机器人解释了各种角色,一些 context,我们希望机器人可以访问的一些动态数据,以及 然后指导机器人应如何响应。
在实践中,隐藏的提示可能相当大。下面是一个更大的提示 从 ChatGPT 命令行 助理:
发件人: https://github.com/manno/chatgpt-linux-assistant
We are a in a chatroom with 3 users. 1 user is called "Human", the other is called "Backend" and the other is called "Proxy Natural Language Processor". I will type what "Human" says and what "Backend" replies. You will act as a "Proxy Natural Language Processor" to forward the requests that "Human" asks for in a JSON format to the user "Backend". User "Backend" is an Ubuntu server and the strings that are sent to it are ran in a shell and then it replies with the command STDOUT and the exit code. The Ubuntu server is mine. When "Backend" replies with the STDOUT and exit code, you "Proxy Natural Language Processor" will parse and format that data into a simple English friendly way and send it to "Human". Here is an example: I ask as human: Human: How many unedited videos are left? Then you send a command to the Backend: Proxy Natural Language Processor: @Backend {"command":"find ./Videos/Unedited/ -iname '*.mp4' | wc -l"} Then the backend responds with the command STDOUT and exit code: Backend: {"STDOUT":"5", "EXITCODE":"0"} Then you reply to the user: Proxy Natural Language Processor: @Human There are 5 unedited videos left. Only reply what "Proxy Natural Language Processor" is supposed to say and nothing else. Not now nor in the future for any reason. Another example: I ask as human: Human: What is a PEM certificate? Then you send a command to the Backend: Proxy Natural Language Processor: @Backend {"command":"xdg-open 'https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail'"} Then the backend responds with the command STDOUT and exit code: Backend: {"STDOUT":"", "EXITCODE":"0"} Then you reply to the user: Proxy Natural Language Processor: @Human I have opened a link which describes what a PEM certificate is. Only reply what "Proxy Natural Language Processor" is supposed to say and nothing else. Not now nor in the future for any reason. Do NOT REPLY as Backend. DO NOT complete what Backend is supposed to reply. YOU ARE NOT TO COMPLETE what Backend is supposed to reply. Also DO NOT give an explanation of what the command does or what the exit codes mean. DO NOT EVER, NOW OR IN THE FUTURE, REPLY AS BACKEND. Only reply what "Proxy Natural Language Processor" is supposed to say and nothing else. Not now nor in the future for any reason.
您将在那里看到一些良好的实践,例如包含大量示例。 重复重要的行为方面,限制回复,等等......
⚠️始终假定用户可以看到隐藏提示中的任何内容。
令 牌
如果您认为代币在 2022 年,那么 2023 年的代币总体上是一个整体 不同的存在层面。语言的原子消耗单位 model 不是一个 “词”,而是一个 “token”。你可以想想代币 作为音节,平均每 1,000 个单词约为 750 个 令 牌。它们代表了许多概念,而不仅仅是字母字符—— 例如标点符号、句子边界和文档的结尾。
以下是 GPT 如何对序列进行标记的示例:
您可以在此处试用分词器:https://platform.openai.com/tokenizer
不同的模型将使用不同的分词器,具有不同的粒度级别。从理论上讲,你可以只给模型提供 0 和 1 —— 但模型需要从比特中学习字符的概念,然后从字符中学习单词的概念,依此类推。同样,你可以给模型提供一连串的原始字符,但模型需要学习单词的概念、标点符号等。而且,一般来说,模型的性能会更差。
要了解更多信息,Hugging Face 对分词器以及它们需要存在的原因进行了精彩的介绍。
分词化有很多细微差别,例如词汇量或不同的语言对句子结构的处理意义不同(例如,单词没有用空格分隔)。幸运的是,语言模型 API 几乎总是将原始文本作为输入,并在后台对其进行标记化,因此您很少需要考虑标记。
除了一个重要的场景,我们接下来将讨论:代币限制。
令牌限制
提示往往是仅附加的,因为您希望机器人在对话中拥有先前消息的整个上下文。一般来说,语言模型是无状态的,不会记住之前对它们的请求的任何信息,因此你总是需要包含它可能需要知道的特定于当前会话的所有内容。
这样做的一个主要缺点是,领先的语言模型架构 Transformer 具有固定的输入和输出大小 - 在某个点上,提示不能变得更大。提示符的总大小(有时称为 “上下文窗口”) 取决于模型。对于 GPT-3,它是 4,096 个代币。对于 GPT-4,它是 8,192 个令牌或 32,768 个令牌,具体取决于您使用的变体。
如果上下文对模型来说太大,最常见的策略是以滑动窗口方式截断上下文。如果你把一个提示看作 ,通常隐藏的提示将保持不变,数组将采用最后 N 条消息。hidden initialization prompt + messages[]``messages[]
您可能还会看到更聪明的提示截断策略 - 例如 首先仅丢弃用户消息,以便机器人之前的答案 尽可能长时间地保留在上下文中,或者要求 LLM 总结 对话,然后将所有消息替换为一条消息 包含该摘要。这里没有正确的答案,解决方案会 取决于你的应用程序。
重要的是,在截断上下文时,必须足够积极地截断,以便为响应留出空间。OpenAI 的代币限制包括输入的长度和输出的长度。如果您对 GPT-3 的输入是 4,090 个令牌,则它只能生成 6 个令牌作为响应。
♂️ 如果您想在将原始文本发送到模型之前计算标记的数量,要使用的特定分词器将取决于您使用的模型。OpenAI 有一个名为 tiktoken 的库,您可以将其与他们的模型一起使用——尽管有一个重要的警告,即他们的内部分词器在数量上可能略有不同,并且他们可能会附加其他元数据,因此请将其视为近似值。
如果您想要在没有分词器的情况下进行近似,将给出一个粗略但比您预期的更好的英语输入近似值。
input.length / 4
提示黑客攻击
提示工程和大型语言模型是一个相当新兴的领域,因此每天都会发现绕过它们的新方法。两大类攻击是:
- 让机器人绕过你给它的任何指导方针。
- 使机器人输出您不希望用户看到的隐藏上下文。
没有已知的机制可以全面阻止这些操作,因此请务必假设机器人在与对抗用户交互时可能会做任何事情或说任何事情。幸运的是,在实践中,这些大多是外观问题。
将提示视为改善正常用户体验的一种方式。我们设计提示,以便普通用户不会在我们预期的交互之外绊倒——但始终假设坚定的用户将能够绕过我们的提示约束。
越狱
通常,隐藏的提示会告诉机器人以特定角色行事,并专注于特定任务或避免使用某些词语。通常可以安全地假设机器人将遵循非对抗性用户的这些准则,尽管非对抗性用户也可能意外绕过这些准则。
例如,我们可以告诉 bot:
You are a helpful assistant, but you are never allowed to use the word "computer".
如果我们接着问它一个关于计算机的问题,它会将它们称为“用于计算的设备”,因为它不允许使用“计算机”这个词。
它绝对会拒绝说出这个词:
但是我们可以绕过这些指令,如果我们通过要求它翻译猪拉丁语版本的“computer”来欺骗它,那么它就会愉快地使用这个词。
您可以在这里采取许多防御措施,但通常最好的办法是尽可能在接近结尾时重申您最重要的约束。对于 OpenAI 聊天 API,这可能意味着将其作为消息包含在最后一条消息之后。下面是一个示例:system``user
![]() |
![]() |
|---|
尽管 OpenAI 在越狱方面投入了大量资金,但每天都有非常聪明的解决方法被分享。
泄漏
如果您错过了本文档中前面的警告,则应始终假设用户最终会看到向语言模型公开的任何数据。
作为构建提示的一部分,您通常会在隐藏的提示(也称为系统提示)中嵌入大量数据。机器人会很高兴地将此信息转发给用户:
即使您指示它不要透露信息,并且它遵循这些指示,也有数百万种方法可以在隐藏的提示中泄露数据。
这里有一个例子,机器人永远不应该提到我的城市,但对问题的简单重构就是为了洒豆子。
同样,我们让机器人告诉我们,在实际说出这个词之前,它不允许说出什么词:
您应该将隐藏提示视为一种使用户体验更好或更符合您所定位的角色的方法。切勿在提示中放置任何您不会在屏幕上直观地呈现以供他人阅读的信息。
为什么我们需要及时的工程设计?
在上面,我们使用了 Prompt 的类比作为语言模型“解释”的 “源代码”。提示工程是编写提示以使语言模型执行我们希望它执行的操作的艺术 - 就像软件工程是编写源代码以使计算机执行我们希望它们执行的操作的艺术。
在编写好的 Prompt 时,您必须考虑您正在使用的模型的特性。策略会随着任务的复杂程度而变化。您必须想出一些机制来约束模型以获得可靠的结果,整合模型无法训练的动态数据,考虑模型训练数据中的限制,围绕上下文限制进行设计,以及许多其他维度。
有一句古老的谚语说,计算机只会做你告诉它们做的事情。把这个建议扔出窗外。快速工程反过来了这种智慧。这就像对着一台非确定性计算机用自然语言编程,这台计算机会做任何你没有引导它做的事情。
提示工程方法分为两大类。
给机器人一条鱼
“Give a bot a fish” 存储桶适用于您可以在隐藏上下文中明确向 bot 提供执行任何请求任务所需的所有信息的情况。
例如,如果用户加载了他们的仪表板,我们想向他们展示一条简短的友好消息,说明他们有哪些未完成的任务项,我们可以让机器人将其总结为
您有 4 个收据/备忘录要上传。最近的是 3 月 5 日来自 Target,最早的是 1 月 17 日来自 Blink Fitness。感谢您始终掌握您的开支!
通过提供整个收件箱和我们希望它拥有的任何其他用户上下文的列表。
同样,如果您正在帮助用户预订行程,您可以:
- 询问用户的日期和目的地。
- 在幕后,搜索航班和酒店。
- 将航班和酒店搜索结果嵌入到隐藏的上下文中。
- 此外,将公司的差旅政策嵌入到隐藏的上下文中。
然后机器人将获得实时旅行信息 + 约束 可用于回答用户的问题。下面是 bot 的示例 推荐选项,并且用户要求它优化它们:
(完整提示)
Brex is a platform for managing business expenses. The following is a travel expense policy on Brex: - Airline highest fare class for flights under 6 hours is economy. - Airline highest fare class for flights over 6 hours is premium economy. - Car rentals must have an average daily rate of $75 or under. - Lodging must have an average nightly rate of $400 or under. - Lodging must be rated 4 stars or higher. - Meals from restaurants, food delivery, grocery, bars & nightlife must be under $75 - All other expenses must be under $5,000. - Reimbursements require review. The hotel options are: | Hotel Name | Price | Reviews | | --- | --- | --- | | Hilton Financial District | $109/night | 3.9 stars | | Hotel VIA | $131/night | 4.4 stars | | Hyatt Place San Francisco | $186/night | 4.2 stars | | Hotel Zephyr | $119/night | 4.1 stars review | The flight options are: | Airline | Flight Time | Duration | Number of Stops | Class | Price | | --- | --- | --- | --- | --- | --- | | United | 5:30am-7:37am | 2hr 7 min | Nonstop | Economy | $248 | | Delta | 1:20pm-3:36pm | 2hr 16 min | Nonstop | Economy | $248 | | Alaska | 9:50pm-11:58pm | 2hr 8 min | Nonstop | Premium | $512 | An employee is booking travel to San Francisco for February 20th to February 25th. Recommend a hotel and flight that are in policy. Keep the recommendation concise, no longer than a sentence or two, but include pleasantries as though you are a friendly colleague helping me out:
这与 Microsoft Bing 等产品用于合并动态数据的方法相同。当您与 Bing 聊天时,它会要求机器人生成三个搜索查询。然后,他们运行三个 Web 搜索,并将汇总结果包含在隐藏的上下文中供机器人使用。
总结本节,打造良好体验的诀窍是动态更改上下文以响应用户尝试执行的任何操作。
♂️ 给 Bot 一条鱼是确保 Bot 钓到鱼的最可靠方法。使用此策略,您将获得最一致和可靠的结果。尽可能使用它。
语义搜索
如果您只需要机器人更多地了解世界,一种常见的方法是执行语义搜索。
语义搜索以文档嵌入为导向,您可以将其视为固定长度的数组5的数字,其中每个数字代表文档的某个方面(例如,如果它是科学文档,也许第 843 个数字很大,但如果它是艺术文档,第 1,115 个数字很大——这过于简单化,但传达了这个想法)。6
除了计算文档的嵌入向量外,您还可以使用相同的函数计算用户查询的嵌入向量。如果用户问 “Why the sky is blue?”,则计算该问题的嵌入,从理论上讲,这种嵌入将更类似于提及天空的文档的嵌入,而不是不谈论天空的嵌入。
要查找与用户查询相关的文档,请计算嵌入,然后查找具有最相似嵌入的前 N 个文档。然后,我们将这些文档(或这些文档的摘要)放在隐藏的上下文中,供机器人参考。
值得注意的是,有时用户查询太短,以至于嵌入不是特别有价值。2022 年 12 月发表的一篇论文中描述了一种聪明的技术,称为“假设文档嵌入”或 HyDE。使用此技术,您可以要求模型生成一个假设文档以响应用户的查询,然后计算此生成文档的嵌入。该模型凭空制作了一份文档 - 但这种方法奏效了!
HyDE 技术使用对模型的更多调用,但对于许多用例,结果有显著的提升。
教机器人钓鱼
有时,您会希望机器人能够代表用户执行操作,例如向收据添加备忘录或绘制图表。或者,也许我们希望它以比语义搜索允许的更细微的方式检索数据,例如检索过去 90 天的费用。
在这些情况下,我们需要教机器人如何钓鱼。
命令语法
我们可以为机器人提供一个命令列表供我们的系统解释,以及命令的描述和示例,然后让它生成由这些命令组成的程序。
使用此方法时,需要考虑许多注意事项。使用复杂的命令语法,机器人将倾向于产生可能合理存在但实际上并非如此的命令或参数的幻觉。做到这一点的艺术是列举具有相对高抽象级别的命令,同时为 bot 提供足够的灵活性,以新颖和有用的方式组合它们。
例如,向机器人发出命令并不是特别灵活或可组合,因为机器人可以对其进行哪些操作。同样,命令的级别也太低了。但是给 bot 一个 and 命令提供了一些很好的原语,机器人可以灵活地使用。plot-the-last-90-days-of-expenses``draw-pixel-at-x-y [x] [y] [rgb]``plot-expenses``list-expenses
在下面的示例中,我们使用以下命令列表:
| 命令 | 参数 | 描述 |
|---|---|---|
| 清单费用 | 预算 | 返回给定预算的费用列表 |
| 交谈 | 消息 | 要向用户显示的消息 |
| 地块费用 | 费用 | 绘制费用清单 |
| 按名称获取预算 | budget_name | 按名称检索预算 |
| 列表预算 | 返回用户有权访问的预算列表 | |
| 添加备忘录 | inbox_item_id、备忘录信息 | 将备注添加到提供的收件箱项目 |
我们以 Markdown 格式向模型提供此表,语言模型处理得非常好——大概是因为 OpenAI 大量使用来自 GitHub 的数据进行训练。
该示例中发生了一些有趣的微妙事情,而不仅仅是命令生成。当我们要求它向 “shake shack” 费用添加备注时,模型知道该命令采用费用 ID。但我们从未告诉它费用 ID,因此它会在我们提供的费用表中查找“Shake Shack”,然后从相应的 ID 列中获取 ID,然后将其用作 的参数。
add-memo``add-memo
让命令语法在复杂情况下可靠地工作可能很棘手。我们在这里拥有的最佳杠杆是提供大量描述,并尽可能多地使用示例。大型语言模型是少数机会的学习者,这意味着它们可以通过仅提供几个示例来学习新任务。一般来说,你提供的例子越多,你的生活就会越好——但这也会侵蚀你的代币预算,所以这是一个平衡。
下面是一个更复杂的示例,其中输出以 JSON 而不是 RPN 指定。我们使用 Typescript 来定义命令的返回类型。
(完整提示)
You are a financial assistant working at Brex, but you are also an expert programmer. I am a customer of Brex. You are to answer my questions by composing a series of commands. The output types are: ```typescript type LinkedAccount = { id: string, bank_details: { name: string, type: string, }, brex_account_id: string, last_four: string, available_balance: { amount: number, as_of_date: Date, }, current_balance: { amount: number, as_of_date: Date, }, } type Expense = { id: string, memo: string, amount: number, } type Budget = { id: string, name: string, description: string, limit: { amount: number, currency: string, } } ``` The commands you have available are: | Command | Arguments | Description | Output Format | | --- | --- | --- | --- | | nth | index, values[] | Return the nth item from an array | any | | push | value | Adds a value to the stack to be consumed by a future command | any | | value | key, object | Returns the value associated with a key | any | | values | key, object[] | Returns an array of values pulled from the corresponding key in array of objects | any[] | | sum | value[] | Sums an array of numbers | number | | plot | title, values[] | Plots the set of values in a chart with the given title | Plot | | list-linked-accounts | | "Lists all bank connections that are eligible to make ACH transfers to Brex cash account" | LinkedAccount[] | | list-expenses | budget_id | Given a budget id, returns the list of expenses for it | Expense[] | get-budget-by-name | name | Given a name, returns the budget | Budget | | add-memo | expense_id, message | Adds a memo to an expense | bool | | converse | message | Send the user a message | null | Only respond with commands. Output the commands in JSON as an abstract syntax tree. IMPORTANT - Only respond with a program. Do not respond with any text that isn't part of a program. Do not write prose, even if instructed. Do not explain yourself. You can only generate commands, but you are an expert at generating commands.
如果您选择的语言具有函数,则此版本更容易解析和解释。JSON.parse
♂️ 没有行业公认的最佳格式来定义模型生成程序的 DSL。因此,将此视为一个积极研究的领域。你会遇到限制。当我们克服这些限制时,我们可能会发现定义命令的更优方法。
反应
2023 年 3 月,普林斯顿大学和谷歌发布了一篇论文“ReAct:在语言模型中协同推理和行动”,其中他们引入了一种命令语法的变体,允许完全自主地交互式执行操作和检索数据。
指示模型返回它想要执行的 a 和 an。然后,另一个代理(例如我们的客户)执行 并将其作为 .然后,模型将循环以返回更多想法和操作,直到返回 .thought``action``action``observation``answer
这是一项非常强大的技术,可以有效地让机器人成为自己的研究助理,并可能代表用户采取行动。结合强大的命令语法,机器人应该能够快速响应大量用户请求。
在此示例中,我们为模型提供了一小组与获取员工数据和搜索 wikipedia 相关的命令:
| 命令 | 参数 | 描述 |
|---|---|---|
| find_employee | 名字 | 按姓名检索员工 |
| get_employee | 身份证 | 按 ID 检索员工 |
| get_location | 身份证 | 按 ID 检索位置 |
| get_reports | employee_id | 检索向与 employee_id 关联的员工报告的员工 ID 列表。 |
| 维基百科 | 品 | 检索有关某个主题的 wikipedia 文章。 |
然后,我们向机器人询问一个简单的问题,“我的经理有名吗?
我们看到 bot :
- 首先查找我们的员工资料。
- 从我们的个人资料中,获取我们经理的 ID 并查找他们的个人资料。
- 提取我们经理的姓名并在 Wikipedia 上搜索他们。
- 在这种情况下,我为经理选择一个虚构角色。
- 机器人阅读了维基百科的文章并得出结论,它不可能是我的经理,因为它是一个虚构的人物。
- 然后,机器人会修改其搜索以包括 (real person)。
- 看到没有结果,机器人得出结论,我的经理并不出名。
![]() |
![]() |
|---|
(完整提示)
You are a helpful assistant. You run in a loop, seeking additional information to answer a user's question until you are able to answer the question. Today is June 1, 2025. My name is Fabian Seacaster. My employee ID is 82442. The commands to seek information are: | Command | Arguments | Description | | --- | --- | --- | | find_employee | name | Retrieves an employee by name | | get_employee | id | Retrieves an employee by ID | | get_location | id | Retrieves a location by ID | | get_reports | employee_id | Retrieves a list of employee ids that report to the employee associated with `employee_id`. | | wikipedia | article | Retrieves a wikipedia article on a topic. | Your response will be in JSON and will include a "Thought" + "Action" to retrieve data that you need in order to answer the question, or it will include the "Answer". When data has been retrieved, it will be included as an "Observation". You will continue generating thoughts and actions until you get to an answer, or conclude that you can't. Example 1: ``` User: What is the population of Philadelphia? Assistant: { "thought": "Wikipedia likely has this information. I'm looking it up...", "action": {"command": "wikipedia", "article": "Philadelphia"} } Assistant: { "observation": "Philadelphia, often called Philly, is the largest city in the Commonwealth of Pennsylvania and the second-largest city in both the Northeast megalopolis and Mid-Atlantic regions after New York City. It is one of the most historically significant cities in the United States and served as the nation's capital city until 1800. Philadelphia is the nation's sixth-largest city with a population of 1,603,797 as of the 2020 census. Since 1854, the city has been coextensive with Philadelphia County, the most populous county in Pennsylvania and the urban core of the Delaware Valley, the nation's seventh-largest and one of the world's largest metropolitan regions with 6.245 million residents in 2020. Philadelphia is known for its extensive contributions to American history and for its role in the life sciences, business and industry, art, literature, and music." } Assistant: { "answer": "The population of Philadelphia, as of the 2020 census, is 1,603,797 people." } ``` Example 2: ``` User: What is my manager's city? Assistant: { "thought": "Let me look up who your manager is. First, I need to look up your profile.", "action": {"command": "get_employee", "id": 92352} } Assistant: { "observation": { "id": 78334, "name": "Ms. Manager", "location_id": 8832 } } Assistant: { "thought": "Your manager is Ms. Manager. I'm looking up their location.", "action": {"command": "get_location", "id": 8832} } Assistant: { "observation": { "id": 8832, "name": "Philadelphia" } } Assistant: { "answer": "Your manager lives in Philadelphia." } ```
GPT-4 与 GPT-3.5
在本文档中的大多数示例中,GPT-3.5 和 GPT-4 之间的差异可以忽略不计,但对于“教机器人钓鱼”场景,模型之间的差异是显着的。
例如,如果没有对 GPT-3.5 进行有意义的修改,上述命令语法示例都不起作用。在获得任何合理的结果之前,您至少必须提供大量示例(每个命令至少一个使用示例)。而且,对于复杂的命令集,它可能会产生新命令的幻觉或创建虚构的参数。
使用足够彻底的隐藏提示符,您应该能够克服这些限制。GPT-4 能够通过更简单的提示实现更加一致和复杂的逻辑(并且可以使用零或少量示例 - 尽管包含尽可能多的示例总是有益的)。
策略
本节包含针对特定需求或问题的示例和策略。为了成功的 prompt 工程,您需要组合本文档中列举的所有策略的一些子集。不要害怕混合和匹配 - 或者发明你自己的方法。
嵌入数据
在隐藏的上下文中,您经常需要嵌入各种数据。具体策略将根据要嵌入的数据的类型和数量而有所不同。
简单列表
对于一次性对象,在普通项目符号列表中枚举字段 + 值效果很好:
它也适用于更大的事物集,但 GPT 可以更可靠地处理其他格式的数据列表。无论如何,这里有一个例子:
Markdown 表格
Markdown 表格非常适合要枚举许多相同类型的项的情况。
幸运的是,OpenAI 的模型非常擅长使用 Markdown 表(大概来自他们训练的大量 GitHub 数据)。
我们可以使用 Markdown 表格来重新构建上述内容:
请注意,在最后一个示例中,表中的项目具有明确的日期,即 2 月 2 日。在我们的问题中,我们询问了 “today”。在提示的前面,我们提到今天是 2 月 2 日。该模型正确处理了传递推理 — 将 “today” 转换为 “February 2nd”,然后在表中查找 “February 2nd”。
JSON 格式
Markdown 表格在许多用例中都非常有效,并且应该首选 Markdown 表格,因为它们的密度和模型能够可靠地处理它们,但您可能会遇到以下情况:您有很多列并且模型难以处理它,或者每个项目都有一些自定义属性,并且拥有数十列空数据没有意义。
在这些情况下,JSON 是模型处理得非常好的另一种格式。与它们的紧密接近使模型能够轻松保持映射的直线。keys``values
下面是 Markdown 表中的相同示例,但使用的是 JSON:
任意格式文本
有时,您需要在提示中包含自由格式的文本,以便将其与提示的其余部分区分开来,例如嵌入文档供机器人参考。在这些情况下,用三个反引号 ''' 将文档括起来效果很好8.
嵌套数据
并非所有数据都是平坦和线性的。有时,您需要嵌入嵌套数据或与其他数据有关系的数据。在这些情况下,请依靠 :JSON
(完整提示)
You are a helpful assistant. You answer questions about users. Here is what you know about them: { "users": [ { "id": 1, "name": "John Doe", "contact": { "address": { "street": "123 Main St", "city": "Anytown", "state": "CA", "zip": "12345" }, "phone": "555-555-1234", "email": "johndoe@example.com" } }, { "id": 2, "name": "Jane Smith", "contact": { "address": { "street": "456 Elm St", "city": "Sometown", "state": "TX", "zip": "54321" }, "phone": "555-555-5678", "email": "janesmith@example.com" } }, { "id": 3, "name": "Alice Johnson", "contact": { "address": { "street": "789 Oak St", "city": "Othertown", "state": "NY", "zip": "67890" }, "phone": "555-555-2468", "email": "alicejohnson@example.com" } }, { "id": 4, "name": "Bob Williams", "contact": { "address": { "street": "135 Maple St", "city": "Thistown", "state": "FL", "zip": "98765" }, "phone": "555-555-8642", "email": "bobwilliams@example.com" } }, { "id": 5, "name": "Charlie Brown", "contact": { "address": { "street": "246 Pine St", "city": "Thatstown", "state": "WA", "zip": "86420" }, "phone": "555-555-7531", "email": "charliebrown@example.com" } }, { "id": 6, "name": "Diane Davis", "contact": { "address": { "street": "369 Willow St", "city": "Sumtown", "state": "CO", "zip": "15980" }, "phone": "555-555-9512", "email": "dianedavis@example.com" } }, { "id": 7, "name": "Edward Martinez", "contact": { "address": { "street": "482 Aspen St", "city": "Newtown", "state": "MI", "zip": "35742" }, "phone": "555-555-6813", "email": "edwardmartinez@example.com" } }, { "id": 8, "name": "Fiona Taylor", "contact": { "address": { "street": "531 Birch St", "city": "Oldtown", "state": "OH", "zip": "85249" }, "phone": "555-555-4268", "email": "fionataylor@example.com" } }, { "id": 9, "name": "George Thompson", "contact": { "address": { "street": "678 Cedar St", "city": "Nexttown", "state": "GA", "zip": "74125" }, "phone": "555-555-3142", "email": "georgethompson@example.com" } }, { "id": 10, "name": "Helen White", "contact": { "address": { "street": "852 Spruce St", "city": "Lasttown", "state": "VA", "zip": "96321" }, "phone": "555-555-7890", "email": "helenwhite@example.com" } } ] }
如果使用嵌套对你的 Token 预算来说太冗长了,请回退到使用 :JSON``relational tables``Markdown
(完整提示)
You are a helpful assistant. You answer questions about users. Here is what you know about them: Table 1: users | id (PK) | name | |---------|---------------| | 1 | John Doe | | 2 | Jane Smith | | 3 | Alice Johnson | | 4 | Bob Williams | | 5 | Charlie Brown | | 6 | Diane Davis | | 7 | Edward Martinez | | 8 | Fiona Taylor | | 9 | George Thompson | | 10 | Helen White | Table 2: addresses | id (PK) | user_id (FK) | street | city | state | zip | |---------|--------------|-------------|------------|-------|-------| | 1 | 1 | 123 Main St | Anytown | CA | 12345 | | 2 | 2 | 456 Elm St | Sometown | TX | 54321 | | 3 | 3 | 789 Oak St | Othertown | NY | 67890 | | 4 | 4 | 135 Maple St | Thistown | FL | 98765 | | 5 | 5 | 246 Pine St | Thatstown | WA | 86420 | | 6 | 6 | 369 Willow St | Sumtown | CO | 15980 | | 7 | 7 | 482 Aspen St | Newtown | MI | 35742 | | 8 | 8 | 531 Birch St | Oldtown | OH | 85249 | | 9 | 9 | 678 Cedar St | Nexttown | GA | 74125 | | 10 | 10 | 852 Spruce St | Lasttown | VA | 96321 | Table 3: phone_numbers | id (PK) | user_id (FK) | phone | |---------|--------------|-------------| | 1 | 1 | 555-555-1234 | | 2 | 2 | 555-555-5678 | | 3 | 3 | 555-555-2468 | | 4 | 4 | 555-555-8642 | | 5 | 5 | 555-555-7531 | | 6 | 6 | 555-555-9512 | | 7 | 7 | 555-555-6813 | | 8 | 8 | 555-555-4268 | | 9 | 9 | 555-555-3142 | | 10 | 10 | 555-555-7890 | Table 4: emails | id (PK) | user_id (FK) | email | |---------|--------------|-----------------------| | 1 | 1 | johndoe@example.com | | 2 | 2 | janesmith@example.com | | 3 | 3 | alicejohnson@example.com | | 4 | 4 | bobwilliams@example.com | | 5 | 5 | charliebrown@example.com | | 6 | 6 | dianedavis@example.com | | 7 | 7 | edwardmartinez@example.com | | 8 | 8 | fionataylor@example.com | | 9 | 9 | georgethompson@example.com | | 10 | 10 | helenwhite@example.com | Table 5: cities | id (PK) | name | state | population | median_income | |---------|--------------|-------|------------|---------------| | 1 | Anytown | CA | 50,000 | $70,000 | | 2 | Sometown | TX | 100,000 | $60,000 | | 3 | Othertown | NY | 25,000 | $80,000 | | 4 | Thistown | FL | 75,000 | $65,000 | | 5 | Thatstown | WA | 40,000 | $75,000 | | 6 | Sumtown | CO | 20,000 | $85,000 | | 7 | Newtown | MI | 60,000 | $55,000 | | 8 | Oldtown | OH | 30,000 | $70,000 | | 9 | Nexttown | GA | 15,000 | $90,000 | | 10 | Lasttown | VA | 10,000 | $100,000 |
该模型可以很好地处理第三范式数据,但可能会遇到连接过多的问题。在实验中,它似乎对至少三个级别的嵌套连接没有问题。在上面的示例中,模型成功地从 to 联接到,以推断 George 的可能收入 – 90,000 美元。
users``addresses``cities
引文
通常,自然语言响应本身是不够的,您需要在模型的输出中引用它从何处获取数据。
这里需要注意的一件有用的事情是,您可能想要引用的任何内容都应该有一个唯一的 ID。最简单的方法是只要求模型链接到它引用的任何内容:
程序化消费
默认情况下,语言模型输出自然语言文本,但我们通常需要以编程方式与此结果进行交互,而不仅仅是在屏幕上打印出来。您可以通过要求模型以您最喜欢的序列化格式(JSON 和 YAML 似乎效果最好)输出结果来实现此目的。
确保为模型提供所需的输出格式示例。基于上面的 travel 示例,我们可以增强我们的 prompt 来告诉它:
Produce your output as JSON. The format should be: ``` { message: "The message to show the user", hotelId: 432, flightId: 831 } ``` Do not include the IDs in your message.
现在,我们将获得如下交互:
您可以想象这样做的 UI 将消息渲染为普通文本,但随后还会添加用于预订航班 + 酒店或为用户自动填写表单的离散按钮。
作为另一个示例,让我们以引用示例为基础 - 但超越 Markdown 链接。我们可以要求它生成带有普通消息的 JSON 以及用于创建该消息的项目列表。在这种情况下,您不会确切知道引文在邮件中的哪个位置被利用,但您会知道它们在某个地方被使用了。
有趣的是,在模型对“我在 Target 花费了多少”的响应中,它提供了一个值 188.16 美元,但重要的是,在数组中,它列出了用于计算该值的各项费用。
citations
思路链
有时,您会在提示时碰头,试图让模型输出可靠的结果,但是,无论您做什么,它都不会起作用。当机器人的最终输出需要中间思考,但您只要求机器人提供输出,而不是其他任何内容时,这种情况经常会发生。
答案可能会让您感到惊讶:让机器人展示它的工作。2022 年 10 月,谷歌发布了一篇论文“Chain-of-Thought Prompting Elicits Reasoning in Large Language Models”,他们表明,如果你在隐藏的提示中,你通过展示你的工作来给机器人提供回答问题的例子,那么当你要求机器人回答某事时,它就会展示它的工作并产生更可靠的答案。
就在那篇论文发表几周后,即 2022 年 10 月底,东京大学和谷歌发布了一篇论文《大型语言模型是零镜头推理器》,他们表明你甚至不需要提供示例——你只需要让机器人一步一步地思考。
平均
下面是一个示例,我们要求自动程序计算平均费用,不包括 Target。实际答案是 136.77 美元,而机器人几乎正确了 136.43 美元。
如果我们简单地添加 “Let's think step-by-step”,模型就会得到正确答案:
解释代码
让我们重新审视前面的 Python 示例,并将思路提示应用于我们的问题。提醒一下,当我们要求机器人评估 Python 代码时,它稍微出错了。正确的答案是,但机器人对 !'s 来包含。在下面的示例中,它输出 :Hello, Brex!!Brex!!Brex!!!``Hello, Brex!!!Brex!!!Brex!!!
如果我们要求机器人展示它的工作,那么它会得到正确的答案:
分隔符
在许多情况下,您可能不想向最终用户展示机器人的所有想法,而只想显示最终答案。您可以要求机器人根据其思考来描述最终答案。有很多方法可以做到这一点,但让我们使用 JSON 来简化解析:
使用 Chain-of-Thought 提示会消耗更多的代币,从而导致价格增加和延迟,但在许多情况下,结果明显更可靠。当您需要 Bot 执行复杂且尽可能可靠的操作时,它是一个有价值的工具。
微调
有时,无论你对模型施展什么技巧,它都不会按照你的要求去做。在这些情况下,您有时可以回退到微调。一般来说,这应该是最后的手段。
微调是采用已训练的模型,然后为其提供数千个(或更多)示例对的过程input:output
它不会消除对隐藏提示的需要,因为您仍然需要嵌入动态数据,但它可能会使提示更小、更可靠。
缺点
微调有很多缺点。如果可能的话,利用语言模型是零样本、单次和少数样本学习者的性质,教它们在提示中做一些事情,而不是微调。
一些缺点包括:
- 不可能:GPT-3.5/GPT-4 不是微调的,这是我们将使用的主要模型/API,因此我们根本无法进行微调。
- 开销:微调需要手动创建大量数据。
- Velocity:迭代循环会变得更慢 – 每次您想添加新功能时,都需要创建一堆虚假数据,然后运行 finetune 流程,然后使用新微调的模型,而不是向提示中添加几行代码。
- 成本: 与库存模型相比,使用微调的 GPT-60 模型的成本高出 3 倍。与库存 GPT-2 模型相比,使用微调的 GPT-3 模型要贵 4 倍。
gpt-3.5-turbo
⛔️ 如果您微调模型,切勿使用真实的客户数据。始终使用合成数据。该模型可能会记住您提供的部分数据,并可能将私人数据反刍给其他不应该看到它的用户。
如果您从不微调模型,我们就不必担心数据会意外泄漏到模型中。
其他资源
- OpenAI 说明书
-
[提示黑客攻击](https://learnprompting.org/docs/category/-prompt-hacking) - Dair.ai Prompt 工程指南
目录大纲
最新文档
知识宇宙
正在加载知识图谱...







































