[AI] 生成式人工智能的应用 [3] - 通过 API 生成文本

本章涵盖

  • 生成式人工智能模型及其基于特定应用的分类
  • 列出可用模型、了解其功能并选择合适模型的过程
  • OpenAl 提供的 Completion API 和 Chat Completion API、它们的关键属性以及如何使用这些 API 来创建聊天机器人和写作助手等应用程序
  • 完成和聊天完成 API 的高级选项可帮助我们引导模型,从而控制生成 - 例如,使用 Logit Bias 影响令牌概率,并使用存在和频率惩罚来控制模型输出的重复性。
  • 在对话中管理令牌对于改善用户体验和成本效益的重要性

我们观察到LLM提供了一套强大的机器学习工具,专门用于增强自然语言理解和生成。 OpenAI 有两个值得注意的 API:Completion API 和 Chat Completion API。 两者都是生成类似于人类输出的文本的动态且有效的工具。 这些 API 为开发人员提供了制作各种应用程序(从聊天机器人到写作助手)的独特机会。 从很多方面来说,OpenAI 都是第一个采用这种完成和聊天完成 API 模式的公司; 现在几乎涵盖了所有的实现——尤其是当公司想要构建基于人工智能的生成工具和产品时。

OpenAI 的 Completion API 是一种高级工具,可生成上下文适当且连贯的文本来完成用户提示。相反,Chat Completion API 旨在模拟与机器学习模型的交互,保留多个交换中的对话上下文,从而使其成为可能 非常适合交互式应用程序。

本章为扩大企业规模奠定了基础; 在构建智能应用程序时,使用这些 API 可以加速其用例并缩短价值实现时间。我们主要使用 OpenAI 和 Azure OpenAI 作为说明性示例,通常可以互换使用。 代码模型保持一致,API 也基本相似。 许多企业可能会因为 Azure OpenAI 提供的控制而倾向于它,而其他企业可能会青睐 OpenAI。 请务必注意,我们假设 Azure OpenAI 实例已作为 Azure 订阅的一部分进行部署。

本章概述了 Completion 和 Chat CompletionAPI 的基础知识 - 它们有何不同以及何时使用哪一个。 我们将了解如何在应用程序中实现这些 API,以及如何控制模型的生成和随机性。 我们还了解了如何管理令牌,这成为部署到生产时的关键操作考虑因素。 这些是构建关键任务应用程序所需的基本方面。 但首先,让我们首先了解不同的模型类别以及每个模型类别给我们带来的优势。

3.1 模型类别

生成式人工智能模型根据其具体应用可以分为不同的类别,每一类都包含不同类型的模型。我们从了解生成式人工智能中不同模型的分类开始我们的讨论。 这种理解有助于我们确定可用模型的范围,并针对给定情况选择最合适的模型。

不同类型和模型的可用性可能会根据所使用的 API 的不同而有所不同。例如,Azure OpenAI 和 OpenAI 提供不同版本的 LLM。 有些版本可能会被淘汰,有些版本可能会受到限制,而另一些版本可能是某个组织独有的。

不同的模型具有独特的特性和功能,直接影响其成本和计算要求。因此,为每个用例选择正确的模型至关重要。 在传统计算机科学中,这个想法是“越大越好”通常应用于内存、存储、CPU 或带宽。但是,对于LLM,“越大越好”原则仅有时适用。OpenAI 提供了一系列模型,分类如表 3.1 所示。 OpenAI 和 Azure OpenAl 之间的这些是相同的,因为底层模型是相同的。

表 3.1 OpenAI 模型类别

模型类别描述
GPT-4一组多模态模型是最新、最强大的版本。GPT-4 在更大的数据集和更多参数上进行训练,使其能力更强。 它可以执行以前型号无法完成的任务
GPT-3.5一组在GPT-3上改进的模型,可以理解并生成自然语言或代码。不确定时,这些应该是大多数企业的默认模型
DALL.E可以根据提示生成图像的模型。
Embeddings将文本转换为数字形式的模型集。
GPT-3(过时)可以生成和理解自然语言的模型集。 这些是现在被视为遗产的原始模型集。在大多数情况下,人们希望从源自 GPT-3 的 3.5 或 4.0 较新模型之一开始。

这些人工智能模型的每个类别都包含一些变体,这些变体通过某些特征(例如令牌大小)进一步区分。 正如前一章所讨论的,令牌大小决定了模型的上下文窗口,它定义了它可以处理的输入和输出的数量。 例如,原始 GPT-3 模型的最大代币大小为 2K。GPT-3.5-Turbo(GPT-3.5 类别中的模型子集)有两个版本 - 一个代币大小为 4K,另一个版本代币大小为 16K 。 这些是原始 GPT-3 模型的代币大小的两倍和四倍。 下面的表 3.2 概述了更流行的模型及其功能。

模型能力
Ada文本的简单分类、解析和格式化。 该模型是 GPT-3 遗产的一部分。
Babbage语义搜索排名,中等复杂分类。 该模型是 GPT-3 遗产的一部分。
Curie回答问题,高度复杂分类。 该模型是 GPT-3 遗产的一部分。
Davinci总结,生成创意内容。该模型是 GPT-3 遗产的一部分
Cushman-CodexGPT-3 系列的后代,经过自然语言和数十亿行代码的训练。 它是Python能力最强的,并且精通其他十几种编程语言
Davinci-Codex更强大的 Cushman-codex 模型
GPT3.5-Turbo针对聊天用例进行优化的功能最强大的 GPT-3.5 模型比 GPT 3 Davinci 便宜 90%,而且更有效。
GPT-4比任何 GPT-3.5 模型都更强大,能够执行更复杂的任务,并针对聊天模型进行了优化。
text-embedding-
ada-002这种新的嵌入模型取代了用于文本搜索、相似性和代码搜索的五个独立模型,在大多数任务上都优于它们; 此外,它的价格低99.8%。

请注意,上面列出的旧模型仍然可用并且按预期工作。 然而,较新的模型更好,有更多的关注度,并且有更长的支持,大多数应该从 GPT 3.5 Turbo 作为默认模型开始,并根据具体情况使用 GPT-4。 有时,即使是较小的、较旧的型号,例如 GPT-3 Curie,也很好。 这在模型的功能、成本和整体性能之间提供了适当的平衡。

在生成式人工智能的早期阶段,所有模型都只对某些人可用。 这些将因公司、地区以及(如果是 Azure)您的订阅类型等因素而异。 我们需要列出可供我们使用的模型及其功能。 然而,在讨论列表模型之前,让我们先看看让事情正常运行所需的依赖关系。

3.1.1 Dependencies(依赖)

在本节中,我们将在高层调用运行时依赖项和所需的配置。 为了让事情顺利进行,我们至少需要以下物品:

  • 开发 IDE - 我们使用 Visual Studio Code 作为示例,但它可以是您喜欢的任何内容。
  • Python - 本书使用 v3.11.3,但你可以使用任何版本,只要是 v3.7 即可。 或稍后。 如果需要安装Python,可以从https://www.python.org/获取安装说明。
  • OpenAI Python 库 - 我们在大部分代码和演示中使用 Python 库。OpenAI python 库可以在 conda 中简单安装,使用:conda install -c conda-forge openai。如果您使用 pip,则为 pip install --upgrade openai。如果您更喜欢使用特定语言而不是 Python 包,还有适用于特定语言的 SDK。
  • Azure 订阅或 OpenAI API 访问 - 我们交替使用 OpenAI 的端点和 Azure OpenAI(AOAI) 端点; 在大多数情况下,任一选项都有效。 鉴于本书重点关注企业,我们倾向于使用 Azure OpenAI 服务。
  • 要将库与 Azure 端点一起使用,我们需要 api_key。
  • 我们还需要设置 api_type、api_base 和 api_version 属性。api_type 必须设置为“azure”,api_base 指向我们部署的端点,并且通过 api_version 指定相应的 API 版本。
  • Azure OpenAI 使用 ‘engine’ 作为参数来指定模型的名称。在 Azure 订阅中部署模型时,需要将此名称设置为您选择的名称。 例如,后面的图 3.1 向我们展示了一个订阅中的部署的屏幕截图。另一方面,OpenAl 使用参数 ‘model’ 来指定模型的名称。 这些型号名称在发布时是标准的。 您可以在 https://azure.microsoft.com/en-us/products/ai-services/openai-service/ 和 https://platform.openai.com/docs/ 找到有关 AzureOpenAI 和 OpenAI 的更多详细信息。

注意:

本书随附的 GitHub 代码存储库(https://bit.ly/GenAIBook)包含代码的详细信息,包括依赖项和说明。

对端点和密钥进行硬编码并不是可取的做法。 有多种方法可以完成此任务,其中之一包括使用环境变量。 我们在接下来的步骤中演示了这种方法。其他替代方法可以从秘密存储或环境文件中获取它们。 为了简单起见,我们将在本指南中坚持使用环境变量。 但是,我们鼓励您遵守企业的最佳实践和建议。 设置环境变量的过程可以通过下面显示的命令来实现。

在Windows:

setx AOAI_KEY “your-openai-key"
setx AOAI_ENDPOINT “your-openai-endpoint"

注意:您可能需要重新启动终端才能读取新变量。

在Linux/Mac:

export AOAI_ENDPOINT=your-openai-endpoint
export AOAI_KEY=your-openai- key

Bash:

echo export AOAI_KEY=“YOUR KEY”>> /etc/environment && source /et
echo export AOAI_ENDPOINT=“YOURENDPOINT”>> /etc/environment &&

注意:

在本书中,我们将利用开源包管理器“conda”来管理特定的运行时版本和依赖项。 从技术上讲,使用像“conda”这样的包管理器不是强制性的,但它对于隔离和解决问题非常有益,并且强烈推荐。 在这种情况下,我们不会深入研究安装“conda”的细节; 有关如何安装“conda”的详细分步说明,请参阅其官方文档:https://docsconda.io/。

首先,让我们创建一个新的 conda 环境并安装所需的 OpenAl Python 库,如下所示。

$ conda create -n openai python=3.11.3
(base) $ conda activate openai
(openai) $ conda install -c conda-forge openai

现在我们已经安装了依赖项,让我们看看如何开始、连接到 Azure OpenAI 端点并获取可用模型的详细信息。

3.1.2 列出模型

正如我们之前概述的,每个组织可能有不同的使用模型。我们首先了解一个人可以访问哪些模型; 我们使用API,这也帮助我们设置基本环境并使其运行。 我们展示如何使用 Azure OpenAI python SDK 执行此操作,并概述使用 OpenAI API 时的差异。

正如我们在下面的清单 3.1 中看到的,我们连接到 Azure OpenAI 端点,获取所有可用模型的列表,迭代这些模型,并将每个模型的详细信息打印到控制台。

清单 3.1 列出可用的 Azure OpenAI 模型

import os
import openai
openai.api_type ="azure"
openai.api_base = os.getenv("AOAI ENDPOINT")
openai.api_version ="2023-05-15"
openai.api_key = os.getenv("AOAI_KEY")

# Call the models API to retrieve a list of available models
models = openai.Model.list()
# Print names of all the available models, and their capabilities
for model in models['data']:
	print("ID:", model['id'])
	print("Current status;", model['lifecycle_status'])
	print("Model capabilities:",model['capabilities'])
	print("----")

当我们运行它时,我们会看到可用模型的列表。 我们在清单 3.2 中展示了可用模型的示例; 确切的列表对您来说可能有所不同。

清单 3.2 列出 Azure OpenAI 模型的输出

在这里插入图片描述
每个模型都有其独特的功能,表明了它所针对的特定用例 - 特别是聊天补全、补全(常规文本补全)、嵌入和微调。 例如,在需要对话参与的情况下,例如需要大量对话交换的基于聊天的交互,“聊天完成”模型将是理想的选择。 相反,如果您的目标是文本生成,则补全模型将是最合适的。 我们可以使用Azure AI Studio查看OpenAI基础模型,如下图3.1所示。

图 3.1 列出的基本型号

在这里插入图片描述
这是 Azure AI Studio 的一部分,您可以在登录 Azure 订阅并访问 Azure OpenAI 部署时访问它。 您还可以直接通过门户网站 https://oai.azure.com/portal 访问它。 现在我们知道要使用哪个模型,让我们生成一些文本。 我们将使用完成 API 和支持完成的模型。

3.2 Completion API(补全API)

Completion API 是一个生成文本的复杂工具,可用于完成用户提供的提示。 Completion API 构成了 OpenAI API 的支柱,提供了一个简单但强大且灵活的 API。 它旨在生成连贯且上下文适合给定提示的文本。

许多非聊天类型构造的生成示例都使用补全 API。 我们必须使用补全 API 来生成非聊天式对话的文本。 Completion API 的一些好处:

  • 上下文理解:完成 API 可以理解提示的上下文并生成相关文本。
  • 多功能性:它可用于各种应用程序,从创建内容到回答问题,使其成为多种应用程序的宝贵工具。
  • 多语言理解:Completion API 可以理解并生成多种语言的内容,使其成为全球资源。
  • 易于实施:Completion API 非常简单,适合各种技能水平的开发人员使用。

API的结构非常简单,如下所示。 输入(提示)和输出(完成)都是文本格式。 API 响应是一个 JSON 对象,可以使用“text”键提取生成的文本。 这种响应称为文本完成。 完成工作努力遵守提示中提供的说明和上下文,是潜在的输出之一。

response = client.completions.create(
	model="text-davinci-003",
	prompt="write a few bullets on why pets are so awesome",
	max_tokens=60
)
print(response.choices[0].text.strip())

我们从一条指令开始,这是指定我们要生成的内容的提示。 在我们的示例中,指令要求模型生成一些项目符号,概述为什么宠物很棒。 Completion API 有许多参数,但最重要的参数在下面的表 3.3 中详细介绍。我们在本章前面和本书中讨论了许多其他参数 - 提示、标记和温度。 然而,“停止序列”是一个新概念。 我们可以利用这些序列使模型在某个点停止生成标记,例如在句子或列表的末尾。

表 3.3 补全 API

参数类型默认值描述
promptString or Array<|endoftext|>字符串或字符串数组是用于生成这些补全的提示。
max_tokensInterger16完成时生成的最大标记数,包括提示。 最大标记不得超过模型的上下文长度。
temperatureNumber(float)1它可以在 0 到 2 之间。值越高意味着模型承担的风险越大并且更具创造性。
stopString or Arraynull这最多可以是四个序列,其中 AI 停止生成更多令牌。 返回的文本将不包含停止序列。
nInterger1(Optional)定义为每个提示生成的完成次数。 这会生成许多完成并可以快速消耗令牌限制; 我们应该对最大代币有一个合理的设置,并停止管理成本。
streamBooleanFalse(Optional)控制是否在生成令牌时流回部分进度的标志。 如果设置,流将通过 data:[DONE] 消息终止。
best_ofInterger1(Optional)在服务器端生成最佳编译并返回“最佳”完成。此参数不能与 gpt-35-turbo 一起使用
top_pNumber(Float)1(Optional)使用称为核采样的技术控制随机性,这是温度设置的替代方案,其值介于 0 和 1 之间。
logit_biasMapNull(Optional)定义指定标记出现在补全中的可能性。 它使用代币到偏差值的映射(-100 为禁止,100 为独占选择)。
userStringNull(Optional)该参数代表最终用户的唯一 ID,可以帮助调试、监控和检测滥用。
logprobsIntegerNull(Optional)可选的日志概率数组,表示替代标记及其被考虑完成的可能性。该参数不能与 gpt-35-turbo 一起使用
suffixStringNull(Optional)这可以是最多 40 个字符的字符串,作为后缀添加到生成的文本中
echoBoolean0(Optional)确定提示是否包含在完成中。 它对于需要捕获提示的用例很有用。 并用于调试目的。这不能与 gpt-35-turbo 一起使用
presence_penaltyNumber(Float)0(Optional)引导模型的趋势并帮助概述模型行为,以将新主题或想法引入生成的文本中。 其范围从 0.0 到 1.0。
frequency_penaltyNumber(Float)0(Optional)这是另一个有助于引导模型并改进生成结果的参数。它控制生成文本中常见或不常见单词的级别。 它可以设置为 0.0 到 1.0 之间的值
function_call用于控制模型在想要使用函数调用时如何响应函数。这只适用于 0613 或更高版本的 OpenAI 模型。
functions模型可能使用的函数列表。

请注意,上表并不是所有参数的详尽列表,而是最常用的参数,有助于理解一些流程和概念。 有些参数,例如函数,是更高级的用途,将在后面的提示词工程章节中介绍。

我们坚持宠物的主题,并使用该模型来帮助我们为宠物沙龙业务建议名称。 我们要求提供三个名称,说明还概述了一些要使用的重要特征。 这些方面的说明帮助我们引导模型走向某些所需的属性。 请参阅 API 文档以获取完整的参数列表。 让我们调用完成 API 并浏览一下它,如下面的清单 3.3 所示。

清单3.3 调用完成API

import os
import openai
openai.api_type ="azure"
openai.api_base = os.getenv("AOAI_ENDPOINT")
openai.api version ="2022-12-01"
openai.api_key = os.getenv("AOAI_KEY")
prompt_startphrase = "Suggest three names for a new pet salon bus"
response = openai.Completion.create(
	engine="text-davinci-003",
	prompt=prompt_startphrase,
	temperature=0.8,
	max_tokens=100,
	stop=None
)

responsetext = response["choices"][0]["text"] 
print("prompt:" + prompt_startphrase + "nResponse:" + responsete)

此运行的输出如下所示。 恭喜 - 我们使用 API 进行了第一次文本生成。 由于人工智能(尤其是生成式人工智能)的不确定性,运行此程序时看到的输出将与下图所示有所不同。

$ python . petsalon.py

提示词:为新的宠物沙龙业务建议三个名称。 生成的名称创意应唤起积极的情绪并具有以下主要特征:专业、友好、个性化的服务。

回复:
1.Pawsitively Professional Pet Salon
2. Fur & Feathers Friendly Pet Parlor
3. 3.Happy Tails Personalized Pet Pampering

注意:
LLMs和大多数其他生成式人工智能模型都是不确定的,这意味着相同的输入可能会产生不同的输出。 将温度设置更改为零可以使输出更具确定性,但可能会保留少量的可变性。

模型选择:

为手头的任务选择正确的模型至关重要,并且需要在模型功能的背景下完成。 例如,如果我们更改之前清单中的一行代码,并将模型从 GPT-3 (text-davinci-003) 更改为 GPT 3.5 Turbo (gpt-turbo-35),则输出会完全不同,如清单中所示 3.4 下面。

清单 3.4 使用不同模型的更新完成 API

import os
import openai
openai.api_type ="azure"
openai.api_base = os.getenv("AOAI ENDPOINT")
openai.api_version ="2022-12-01"
openai.api_key = os.getenv("AOAI_KEY")
prompt_startphrase = "Suggest three names for a new pet salon bus"
response = openai.Completion.create(
	engine="gpt-turbo-35",
	prompt=prompt_startphrase,
	temperature=0.8,
	max_tokens=100,
	stop=None)
responsetext = response["choices"][o]["text"]

print("Prompt:" + prompt_startphrase + "\nResponse:" + responsete)

正如我们在清单 3.5 中看到的,当我们运行这个更新的代码时,输出有很大不同,但其中大部分没有意义。 这也停止生成并以字母“F”结束,如下所示,因为我们达到了 100 的代币限制并停止生成。

清单 3.5 显示模型更改的输出

$ python .\petsalon.py

Prompt: Suggest three names for a new pet salon business. The gene
Response: Consider using rhymes, puns,or adjectives with positiv
we have created a customer avatar, so you can understand better t
List of Pet Salon Business Name Ideas
PawSpa
PetPamper
F

我们看到输出发生巨大变化的关键原因是模型的能力。 第一个模型(GPT-3 Davinci)是一个完成模型,需要我们指定的指令。 另一方面,第二个模型(GPT3.5 - Turbo)是具有不同期望的聊天完成模型(即适合聊天式对话)。 上市时需要重点关注模型的功能。

现在我们已经看到了一个简单的完成 API 调用,让我们对其进行扩展并了解不同的属性及其含义。

3.2.1 扩展完成

让我们看看 API 的完整响应是什么样的,并逐步了解该结构。 下面的清单 3.6 显示了 API 的完整响应。 选择字段是最有趣的字段之一,因为它有完整的文本。 choice 属性是一个数组,其中每个项目都有一个索引、生成完成的原因 (finish_reason) 和生成的文本(通过 text 属性)。

清单 3.6 来自补全 API 的 API 响应
在这里插入图片描述
下面的表 3.4 显示了其余属性。 使用属性概述了使用的令牌 (total_tokens),包括提示和响应令牌。由于我们按令牌付费,因此构建以下方面的提示非常重要:第一,仅返回所需的内容,最大限度地减少令牌使用;第二, 首先限制生成的代币数量。

表 3.4 完成响应属性

属性描述
choices可以包含一个或多个完成数据的数组。
created创建响应时的 UNIX 日期时间戳。
id响应的唯一标识符,当我们需要跟踪响应时很有用。
模型代表用于生成的模型
object概述响应的数据类型 - 例如,在本例中,它是"text_completion”,概述完成 API。
usage计算该请求使用的令牌数量。

名为 logprobs 的属性指定为响应中的每个标记生成的对数概率的数量。 对数概率对于生成更加多样化和有趣的响应非常有用。 它返回响应中每个标记的前 n 个标记的对数概率。 对数概率以数组数组的形式返回,其中每个子数组对应于响应中的一个标记,并包含该标记的前 n 个标记的对数概率。

3.2.2 Azure 内容安全过滤器

有时,API会返回空响应,如下面的清单3.7所示。当发生这种情况时,我们应该检查finish_reason字段的值。如果其值设置为“content_filter”,则与模型一起工作的内容过滤系统已被触发。 finish_reason 字段指示 API 返回其输出的原因,每个响应都将包含此字段。我们将在本章后面更详细地介绍这一点。

过滤系统使用特定类别来识别潜在有害内容并对其采取操作,作为输入提示和生成完成的一部分。使用这些 API 的应用程序必须处理这种情况,并在适当的退避期后重试。 我们将在本书后面更详细地介绍内容安全过滤器。

清单 3.7 显示空响应的输出
在这里插入图片描述
在这里插入图片描述

3.2.3 Multiple Completions(多次完成)

由于某些原因,我们可能需要多个完成 - 有时,我们需要为同一提示生成多个消息选择。 有时,API 会因容量原因而受到限制,我们可能希望从同一个 API 调用中获得更多信息,而不是受到速率限制。 完成 API 可以返回多个响应; 这是通过将“n”参数设置为大于默认值 1 来完成的。例如,我们可以将此参数添加到完成调用中,如下面的代码片段所示:

response = openai.Completion.create(
	engine="text-davinci-@03",
	prompt=prompt_startphrase,
	temperature=.8,
	max_tokens=100,
	n=2,
	stop=None)

当我们运行这个更新后的代码时,我们得到如下清单 3.8 所示的响应。 属性选择是一个数组,我们有两个项目,索引从零开始。 每个都有生成的文本供我们使用。根据用例,这在选择多个完成时很有帮助。

清单 3.8 显示多个响应的输出
在这里插入图片描述
另一个类似但在某些方面更强大的参数是 best_of 参数。与“n”参数一样,这会生成多个完成,允许选项从中选择最好的。 最好的是每个标记具有最低对数概率的完成。 使用此选项时我们无法流式传输结果。 我们可以将其与"n" 参数,其中 best_of 需求大于 "n”结合起来

让我们看一个例子,如清单 3.9 所示,如果我们将“n”设置为 5,正如我们所期望的,我们会得到 5 个完成; 为简洁起见,我们不会在此处显示所有五个完成,但请注意此调用如何使用 184 个令牌。

清单 3.9 显示多个响应的输出

在这里插入图片描述
如果我们使用 best_of 参数运行类似的调用,请不要指定“n”参数,如下面的代码片段所示。

response = openai.Completion.create(
	engine="text-davinci-003",
	prompt=prompt_startphrase,
	temperature=0.8,
	max_tokens=100,
	best_of=5,
	stop=None)

当我们运行这个时,我们只得到一个完成,如清单3.10所示,但请注意,我们使用了与之前类似的数字令牌(171 vs 184)。这是因为该服务在服务器端生成了五个完成并返回 最好的。 API 使用每个令牌的对数概率来选择最佳选项。 对数概率越高,模型对其预测的信心就越大。

清单 3.10 具有 best_of 5 次完成的输出生成

在这里插入图片描述
影响许多响应的一个参数是温度设置。 让我们看看这如何改变输出。

3.2.4 控制随机性

正如前一章所讨论的,“温度”设置会影响生成输出的随机性。 较低的温度会产生更多的重复性和确定性响应,而较高的温度会产生更多的创新响应。 从根本上来说,没有一个正确的设置——这一切都取决于用例。

对于企业来说,当对多样化和创建文本感兴趣时,就会产生更具创造性的输出——例如用于营销、故事、诗歌、歌词、笑话等内容生成的用例。通常需要更具创造性的事情。 另一方面,企业需要更可靠、更精确的用例答案,例如用于发票生成、提案、代码生成等的文档自动化。这些设置适用于每个 API 调用,因此可以在同一工作流程中组合不同的温度级别。

如前面的示例所示,我们建议将温度设置为 0.8 以进行创意响应。 相反,为了获得更可预测的响应,建议设置为 0.2。 使用示例,让我们检查这些设置如何改变输出并观察多个调用之间的变化。

当温度设置为 0.8 时,我们连续三个调用收到以下响应。 输出按预期变化,提供了与本章中所见类似的建议。 值得注意的是,我们不需要进行三个单独的 API 调用。 如下所示,我们可以在单个 API 调用中将 n’ 参数设置为 3 以生成多个响应。 我们的 API 调用如下所示:

response = openai.Completion.create(
	engine="text-davinci-003",
	prompt=prompt_startphrase,
	temperature=0.8,
	max_tokens=100n=3,stop=None)

下面的清单 3.11 显示了三个响应的创意生成

清单 3.11 温度为 0.8 时的完成输出

在这里插入图片描述
让我们更改设置以使其更具确定性并再次运行请注意,API 调用中的唯一更改是温度=0.2。 正如我们在下面的清单 3.12 中看到的,输出是可预测的和确定性的,其中文本三个响应之间产生的结果非常相似。

清单 3.12 温度为 0.2 时的完成输出

在这里插入图片描述
温度值升至 2,但不建议升至那么高,因为模型会开始出现更多幻觉并创建无意义的文本。 如果我们想要更多的创造力,我们通常希望它是 0.8,最多 1.2。 让我们看看清单 3.13 中的一个例子,我们将温度更改为 1.8。 在这个例子中,我们甚至没有获得第三代,因为我们达到了代币限制并停止了生成。

清单 3.13 温度为 1.8 时的完井输出

在这里插入图片描述
使用 top_p 控制随机性

用于管理随机性的温度参数的替代方案是 top_p 参数。这与温度参数对生成具有相同的影响,但它使用称为“核采样”的不同技术来实现此目的。 本质上,核心采样仅允许概率等于或小于 top_p 值的令牌被视为生成的一部分。

核心采样通过从一小组最有可能的单词中挑选单词来创建文本 - 具有最高的累积概率。 top_p 值根据其中单词的总机会决定该组的大小。组大小可以根据下一个单词的机会而变化。 与其他方法相比,核采样可以帮助避免重复并生成更多样、更清晰的文本。

例如,假设我们将 top_p 值设置为 0.9; 那么只有占概率分布 90% 的 token 才会在一代中被采样。 这使我们能够避免最后 10%,通常非常随机和多样化,并最终成为无意义的幻觉。

top_p 的值越低,模型越一致,但创意越少,因为它选择生成的标记越少。 相反,较高的价值使这一代人更具创造力和多样性,因为它有更多的代币可供操作。 较大的值也使其更容易出现更多错误和随机性。top_p 的确切值取决于用例; 在大多数情况下,top_p 的理想值应该在 0.7 到 0.95 之间。 我们应该更改温度属性或此属性,但不能同时更改两者 - 下面的表 3.5 概述了两者之间的关系。

表 3.5 温度与 Top_P 的关系

TemperatureTop_p效果
专注准确的输出
输出更加多样化,但可能包含错误
输出的多样性较低,但包含错误的可能性较小
非常有创意和多样化的输出,但可能包含许多错误

让我们看看针对特定场景的一些高级 API 选项。

3.3 高级补全 API 选项

现在我们已经了解了 Completion API 的基本构造并了解了其工作原理,接下来我们需要了解与 Completion API 相关的更高级的内容。 其中许多可能看起来并不复杂,但它们给系统架构增加了更多的职责,总体上使实现变得复杂。

3.3.1 流式补全

Completions API 允许流式响应,一旦准备好即可立即访问信息,而不是等待完整响应。对于企业来说,在实时内容生成和较低延迟至关重要的某些情况下,流式传输可能很重要。 此功能可以通过及时处理传入的响应来增强用户体验。

要从 API 的角度启用流式传输,请将“stream”参数修改为“true”。 默认情况下,此可选参数设置为“false”

流媒体使用服务器发送事件 (SSE),它需要客户端实现。 SSE 是一种标准协议,允许服务器在建立初始连接后继续向客户端传输数据。 它是从服务器到客户端的长期单向连接。 SSE 具有低延迟、减少带宽消耗和简单的配置设置等优点。

下面的清单 3.14 演示了如何调整我们的示例以利用流。虽然 API 修改很简单,但我们已经调整了描述并为我们的示例请求了多代(使用“n”属性)。 这使我们能够人为地生成更多文本,从而更容易观察流式生成。

清单 3.14 流式补全

在这里插入图片描述
在管理流式调用时,我们必须特别注意finish_reason属性。 当消息被传输时,每条消息都显示为标准完成,其中的文本代表新生成的令牌。 在这些情况下,finish_reason 保持为空。 然而,最终的消息有所不同 - 它的结束原因可能是“停止”或“长度”,具体取决于触发它的原因,如清单 3.15 所示。

清单 3.15 流媒体 finish_reason

在这里插入图片描述

3.3.2 影响Token概率——Logit Bias

“logit_bias”参数是我们影响输出补全的一种方式。在 API 中,此参数允许我们操纵模型在其响应中生成的某些标记(可以是单词或短语)的概率。 它被称为 Logit Bias,因为它直接影响模型在生成过程中为每个潜在令牌计算的对数几率或 logits。 在将它们转换为概率之前,将偏差值添加到这些对数赔率中,从而改变模型可能从中选择的标记的最终分布。

此功能的重要性在于其引导模型输出的能力。假设我们正在创建一个聊天机器人并希望它避免某些单词或短语,我们可以使用 Logit Bias 来降低模型选择这些标记的可能性。 另一方面,如果我们希望模型支持某些单词或短语,我们可以使用 Logit Bias 来增加它们的可能性。 该参数的范围是从 -100 到 100,并且对单词的标记进行操作。 将令牌设置为 -100 会有效地禁止其生成,并将其设置为 100 会使其具有排他性。

为了使用 Logit Bias,我们提供了一个字典,其中键是标记,值是需要应用于这些标记的偏差。 为了获取令牌,我们使用“tiktoken”库。 一旦你有了合适的标记,你就可以分配一个正偏差以使其更有可能出现,或者分配一个负偏差以使其不太可能出现,如下图 3.2 所示。 这些块显示了不同代币处于不同禁止或排他生成概率的概率程度。 对令牌值进行较小的更改会增加或减少这些令牌在生成的输出中的概率。

图3.2 Logit偏差参数
在这里插入图片描述
让我们用一个例子来看看如何实现这一点。 说出我们宠物沙龙的名字; 我们不想在名称中使用以下单词:“Purr”或“Purrs”或“Meow”。 我们要做的第一件事是为这些单词创建标记。 我们还想添加前面有空格且大写为空格的单词,而大写字母都是不同的标记。 因此,“Meow”和“Meow”(带有一个空格)和“meow”(同样带有一个空格)对我们来说可能是相同的,但是当涉及到标记时,它们都是不同的。 下面的输出向我们展示了相应单词的标记。

‘Purr Purrs Meow Purr purr purrs meow:[30026, 81, 9330, 3808, 42114, 9330, 81, 1308, 81, 1308, 3808, 502, 322]’

现在我们有了令牌,我们可以将它们添加到完成调用中,如清单 3.16 所示。 请注意,我们为每个标记分配了 -100 的偏差。 这会引导模型远离这些词

清单 3.16 Logit Bias 实现

import os
import openai
 
openai.api_type = "azure"
openai.api_base = os.getenv("AOAI_ENDPOINT")
openai.api_version = "2022-12-01"
openai.api_key = os.getenv("AOAI_KEY")
  
prompt_startphrase = "Suggest three names for a new pet salon business. The generated name ideas should evoke positive emotions and the following key features: Professional, friendly, Personalized Service."
 
response = openai.Completion.create(  
  engine="text-davinci-003",  
  prompt=prompt_startphrase,  
  temperature=0.8,  
  max_tokens=100,  
  logit_bias={
      30026:-100,
      81:-100,
      9330:-100,
      808:-100,
      42114:-100,
      1308:-100,
      3808:-100,
      502:-100,
      322:-100
  }  
)  
 
print(response)

运行此命令时,我们没有要避免的任何单词,如下面的清单 3.17 中的输出片段所示。

清单 3.17 Logit 偏差生成的输出

{
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "logprobs": null,
      "text": "\n\n1. Paw Prints Pet Pampering\n2. Furry Friends Fussing\n3. Posh Pet Pooches"
    }
  ],
...
}

我们也可以做相反的事情,对代币进行正向偏置。 假设我们想要过度强调并引导模型走向“Furry”这个词。 我们可以使用之前看到的tiktoken库,看到“Furry”的代币是[37,16682]。 我们可以用这个更新之前的 API 调用,在本例中是正偏差 5,如清单 3.18 所示。

清单 3.18 Logit Bias - 积极实施

response = openai.Completion.create(  
  engine="text-davinci-003",  
  prompt=prompt_startphrase,  
  temperature=0.8,  
  max_tokens=100,  
  logit_bias={
      30026:-100,
      81:-100,
      9330:-100,
      808:-100,
      42114:-100,
      1308:-100, 
      3808:-100,
      502:-100,
      322:-100,
      37:5,
      16682:5
  }  
)

当我们运行它时,我们得到如下清单 3.19 所示的输出。 正如我们所看到的,我们这一生成更加强调“Furry”。 完成也需要更长的时间,因为模型在生成某些令牌时会与偏差竞争。

清单 3.19 输出 Logit Bias - 正向实现

{
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "logprobs": null,
      "text": "\n\n1.FurryFrendz Pet Salon\n2.FurryFurFection Pet Pampering\n3.FurryFurFam Pet Spa"
    }
  ],}

Logit Bias 特征应谨慎使用; 它是指导模型输出的强大工具。 然而,过度或不恰当的使用可能会导致以您不希望的方式产生无意义、过度重复或有偏见的输出。

3.3.3 Presence and Frequency Penalties(存在和频率惩罚)

我们在 API 中有两个附加参数,称为“存在”和“频率惩罚”,它们通过控制生成的重复来帮助引导语言模型的输出。 这两个参数影响单词(技术上是标记序列)在补全中重新出现的可能性。 较高的存在惩罚会鼓励模型专注于提示并避免使用提示中已经出现的标记。 相反,较高频率的惩罚会阻止模型重复。 让我们更详细地看看两者。

存在惩罚参数

存在惩罚参数影响相同标记在输出中出现的频率。 这可以通过使用存在惩罚作为从每次生成令牌的概率中减去的值来实现。 这意味着代币使用的次数越多,再次使用的可能性就越小。 这有助于使模型在生成过程中使用更多样的代币并探索新的主题。 该参数的值可以是从零到二。

默认值为零,这意味着模型不关心标记是否重复。 高存在惩罚 (1.0) 使模型不太可能再次使用相同的标记,而较高的值使模型在输出中引入新主题。 较低的存在惩罚(零)使模型坚持文本中的现有主题。 每次生成令牌时,都会从该令牌的对数概率中减去参数值。

我们可以通过防止相同的文本多次重复来提高生成质量,帮助控制流程,并使输出更具吸引力。 现在,让我们看看频率惩罚参数。

频率惩罚参数

频率惩罚参数控制模型在输出中避免重复的程度。 频率惩罚 (1.0) 越高,模型就越尝试使用不同的单词和短语,从而产生更加多样化的生成。 频率惩罚 (0.0) 越低,模型重复相同单词和短语的次数就越多,输出的可预测性就越高。 这与存在惩罚不同,存在惩罚鼓励模型使用新单词和短语。 每次令牌出现在输出中时,频率惩罚都会增加令牌的对数概率。

这两个参数的最佳值取决于您想要通过输出实现的目标。 通常,选择 0.1 到 1.0 之间的值是最好的,这会明显影响输出。 如果您想要更强的效果,可以将值增加到 2.0,但这可能会降低输出质量。

请注意,调整这些参数需要进行一些试验和错误才能获得所需的结果,因为模型的输出还受到许多其他因素的影响,包括您提供的提示和其他微调参数。 我们可以在下面的图 3.3 中看到存在性和频率惩罚参数的相关性。

图 3.3 惩罚存在参数

在这里插入图片描述

3.3.4 Log Probabilities(日志概率)

正如我们所看到的,当 LLM 生成令牌时,它会为下一个考虑的令牌分配一个概率,并使用各种技术从这些选项中选择完成中使用的令牌。完成 API 的 logprobs 属性公开了每个步骤中这些概率的自然对数 。

这是一个整数(最大值为 5),指示显示完成中包含的每个标记所考虑的替代标记。 如果该值设置为 3,则 API 将为生成中的每个选定令牌返回三个最有可能的令牌的列表。 请注意,API 始终返回采样令牌的 logprobs,因此在响应中,我们最终可能会在数组中得到 logprobs + 1 元素。

从根本上来说,我们用它来帮助调试和改进提示。 如果模型没有生成我们喜欢的文本,我们可以使用它来查看模型考虑的其他单词(技术上的标记)。 这允许我们调整一些其他设置来引导模型。 相反,我们可以使用同样的东西来控制模型生成中的随机性,使输出更具确定性。最后,有时我们还可以用它来了解模型的置信度。 如果几个不同单词的概率相同,则表明模型不确定接下来会出现什么单词。

假设我们想给一只白狗起一个名字; 我们可以调用完成 API,如下所示。 在这个例子中,我们得到了建议的名称Cotton,这个名称还不错。

response = openai.Completion.create(
  engine="text-davinci-002",
  prompt="Suggest a one-word name for a white miniature poodle.",
  temperature=0.8,
  max_tokens=100,
  stop=None)

如果我们想查看该名称考虑了哪些其他标记,我们可以添加下面的 logprobs 属性。

response = openai.Completion.create(
  engine="text-davinci-002",
  prompt="Suggest a one-word name for a white miniature poodle.",
  temperature=0.8,
  max_tokens=100,
  logprobs=3,
  stop=None)

正如下面清单 3.20 中的完成输出所示,我们可以看到模型考虑的其他标记:Casper、Coco 和 Snow。

清单 3.20 输出Log概率

{
  "id": "cmpl-7giPQGlKc6c7BaWmHgOLyZqabIruw",
  "object": "text_completion",
  "created": 1690414840,
  "model": "text-davinci-002",
  "choices": [
    {
      "text": "\n\nCotton",
      "index": 0,
      "finish_reason": "stop",
      "logprobs": {
        "tokens": [
          "\n",
          "\n",
          "C",
          "otton"
        ],
        "token_logprobs": [
          -0.0008873215,
          -4.361666e-06,
          -1.026479,
          -0.56846446
        ],
        "top_logprobs": [
          {
            "\n": -0.0008873215,
            "\n\n": -7.660001,
            " Angel": -10.180796
          },
          {
            "\n": -4.361666e-06,
            "\n\n": -12.970553,
            "<|endoftext|>": -15.136529
          },
          {
            "C": -1.026479,
            "P": -2.255978,
            "Snow": -2.1068947
          },
          {
            "asper": -2.001854,
            "oco": -1.957575,
            "otton": -0.56846446
          }
        ],
        "text_offset": [
          54,
          55,
          56,
          57
        ]
      }
    }
  ],
  "usage": {
    "completion_tokens": 4,
    "prompt_tokens": 12,
    "total_tokens": 16
  }
}

值得提醒我们的是,只有在需要时,我们才应该明智地使用这个属性。 它不仅增加了生成的令牌数量,从而增加了 API 调用的成本,而且还需要时间并增加了 API 调用的时间,从而增加了总体延迟。

现在我们了解了用于文本生成的完成 API,让我们看看如何使用聊天完成 API。

3.4 聊天 补全 API

聊天补全 API 旨在促进交互式和动态对话。它是补全 API 的演变,为用户提供更具对话性和吸引力的体验。 借助此 API,开发人员可以创建与用户对话的应用程序,使其成为创建聊天机器人、写作助手等的理想选择。

与完成 API 相比,聊天完成 API 提供的主要优点是:

  • 增强的交互性:聊天完成 API 允许与用户进行更加动态和交互式的对话,使用户体验更加有吸引力和自然。
  • 上下文理解:API 维护对话的上下文,确保响应相关且连贯。
  • 多轮对话:与更适合单轮任务的Completion API不同,它允许开发人员模拟与多个交互的对话。
  • 成本效益:Completion API 使用 gpt-3.5-turbo 或 gpt-4 模型,其性能与 text-davinci-003 类似,但每个代币价格仅为 10%,使其成为开发者更经济的选择。

从较高层面来看,使用聊天补全 API 与 补全 API 类似。 API 将一系列消息作为输入,构成与模型交互的基础。 消息的顺序很重要,因为它概述了逐轮交互。

每条消息都有两个属性:角色和内容。 角色参数有三个选项 - ‘系统’、‘用户’或’助理’,内容包含来自角色的消息文本。 下面的表 3.6 概述了每个角色及其目的的详细信息。

表 3.6 聊天补全 API 角色描述

角色参数描述
系统“系统”角色通常用于设置助手的行为,并为模型提供高级指令,指导助手在整个对话过程中的行为。在这里我们可以描述助手的个性,告诉它应该回答什么、不应该回答什么,以及如何回答。 格式化响应。 虽然这没有令牌限制,但它包含在每个 API 调用中,并且是总体令牌限制的一部分。
用户这代表用户在对话中的输入; 这些消息包含助理响应的用户指令或查询。
助理这代表助理在对话中之前的消息。 将此视为帮助模型并在轮流进行时提供对话上下文的持续记忆

下面的清单 3.21 向我们展示了聊天完成 API。 正如我们之前所说,数组中消息的顺序很重要,因为它代表了对话的流程。 通常,对话以设置助手行为的“系统”消息开始,然后随着对话轮流进行,“用户”和助手消息交替出现。 助理的回复是根据对话历史记录生成的。

清单 3.21 聊天补全 API

import os
import openai
 
openai.api_type = "azure"
openai.api_base = os.getenv("AOAI_ENDPOINT")
openai.api_version = "2023-05-15"
openai.api_key = os.getenv("AOAI_KEY")
 
response = openai.ChatCompletion.create(
  engine="turbo",
  messages = [
      {"role":"system","content":"You are an AI assistant that helps people find information."},
      {"role":"user","content":"Hello world"},
      {"role":"assistant","content":"Hello! How can I assist you today?"},
      {"role":"user","content":"I want to know more about pets and why dogs are good for humans?"}],
  temperature=0.8,
  max_tokens=800,
  user="amit",
  top_p=0.95,
  frequency_penalty=0,
  presence_penalty=0,
  stop=None)

我们需要更新引擎参数以使用聊天兼容模型之一。 正如我们在本章前面看到的,所有模型都不支持聊天风格,我们需要选择具有 chat_completion 功能的模型(GPT 3.5 Turbo 和 GPT-4)。 所有其他参数与我们在本章前面介绍的 Completion API 相同,我们不会再次讨论这些细节。

注意:
新的 GPT-35-Turbo 和 GPT-4 模型不提供以下参数:logprobs、best_of 和 echo。 尝试设置任何这些参数都会引发异常。

上述示例的输出如下面的清单 3.22 所示。 用户以“Hello World”开始,系统做出响应,询问如何帮助我们处理助理消息。 关于询问狗的详细信息的下一个问题是下一个对话回合。 下一步以及对此执行的响应如下所示。

清单 3.22 聊天完成 API 输出

{
  "id": "chatcmpl-7c9HOaRHmaut94oZacjdUqxOL96H3",
  "object": "chat.completion",
  "created": 1689326490,
  "model": "gpt-35-turbo",
  "choices": [
    {
      "index": 0,
      "finish_reason": "stop",
      "message": {
        "role": "assistant",
        "content": "Dogs are often considered man's best friend for good reason. They provide companionship, protection, and loyalty to their owners. Here are some reasons why dogs are good for humans:\n\n1. They reduce stress: Dogs have been shown to reduce stress and anxiety in their owners. Petting a dog can release endorphins, which are feel-good hormones that can help to reduce stress.\n\n2. They provide companionship: Dogs are ..."
      }
    }
  ],
  "usage": {
    "completion_tokens": 238,
    "prompt_tokens": 60,
    "total_tokens": 298
  }
}

3.4.1 系统角色

系统角色(有些也称为系统消息)包含在消息数组的开头。 该消息提供了模型的初始说明,我们可以提供系统角色中的各种信息,包括:

  • 助手的简单描述
  • 助理的性格特征
  • 您希望助理遵循的规则和说明
  • 模型所需的其他信息(例如常见问题解答中的相关问题)

我们自定义系统角色并包含用例的基本说明。从 API 角度来看,尽管系统角色是可选的,但强烈建议包含它以获得最佳结果。 例如,如果我们扩展前面的宠物和宠物沙龙聊天示例,我们可以指示模型仅以押韵方式回复,如清单 3.23 中的代码片段所示。

清单 3.23 聊天完成系统消息示例

response = openai.ChatCompletion.create(
  engine="turbo",
  messages = [
    {"role": "system", "content": "You are a helpful AI assistant that provides truthful information. You answer all questions in rhyme."},
    {"role": "user", "content": "Hi"},
    {"role": "assistant", "content": "Hello there, how can I assist?\nAsk me a question, don't resist!"},
    {"role": "user", "content": "who are the founders of Microsoft?"},
    {"role": "assistant", "content": "Bill Gates and Paul Allen, it's true,\nAre the founders of Microsoft, through and through."},
    {"role": "user", "content": "what is a good name for a pet salon?"},
    {"role": "assistant","content": "For a pet salon that's simply divine,\nHere's a name that's sure to shine:\n\"Paws and Pamper\" is what I propose,\nA name that's catchy and easy to compose."}],
  temperature=0.7,
  max_tokens=800,
  top_p=0.95,
  frequency_penalty=0,
  presence_penalty=0,
  stop=None)

在上面的例子中,我们可以按照预期进行对话,话题可以轮流变化,但所有答案都是押韵的。

当我们想要为模型提供额外的数据作为对话的上下文时,这称为数据基础。 如果数据量很少,这可以是系统角色的一部分,如下面的代码片段(清单3.24)所示。 另一方面,如果有大量数据,我们应该使用embeddings(嵌入)并使用语义搜索(例如 Azure 认知搜索)检索最相关的信息。

清单 3.24 接地系统消息示例

{"role": "system", "content": Assistant is an intelligent chatbot designed to help users answer technical questions about Azure OpenAI service. Only answer questions using the context below. Don’t make up the answer. If you are unsure of an answer, say 'I don't know'.
 
Context:
- Azure OpenAI Service provides REST API access to OpenAI's powerful language models including the GPT-3, Codex and Embeddings model series.
- Azure OpenAI Service gives customers advanced language AI with OpenAI GPT-3, Codex, and DALL-E models with the security and enterprise promise of Azure.
..."
},
{"role": "user", "content": "What is Azure OpenAI Service?"}

3.4.2 Finish Reason(完成原因)

每个聊天补全 API 响应都有一个编码在“finish_reason”字段中的完成原因。 跟踪这一点很重要,因为它可以帮助我们理解 API 为什么返回它所做的响应。 这对于调试和改进应用程序很有用。 例如,如果您由于长度结束原因收到不完整的响应,您可能需要调整“max_tokens”参数以生成更完整的响应。 下面列出了 finish_reason 的可能值。

  • “stop”:API 完成生成并返回完整消息或由使用 stop 参数提供的停止序列之一终止的消息。
  • ‘length’:由于 max_tokens 参数或令牌限制,生成的模型停止输出。
  • ‘function_call’:模型决定调用一个函数。
  • “content_filter”:部分完成内容因有害内容而被过滤。

3.4.3 非聊天场景的聊天补全接口

对于非聊天场景,我们可以使用 OpenAI 的聊天完成功能。 API 非常相似,被设计为一个灵活的工具,可以适应各种用例,而不仅仅是对话。 在大多数情况下,推荐路径使用聊天补全 API,就像它是补全 API 一样。 主要原因是较新的模型(Chat 3.5-Turbo 和 GPT-4)比早期模型更高效、更便宜且功能更强大。 我们看到的补全用例,例如分析文本、生成文本和回答知识库中的问题,仍然可以使用聊天补全 API。

实现聊天补全 API 非聊天场景通常涉及使用一系列消息和系统消息构建对话以设置助手的行为。 例如,如下清单3.25所示,系统消息设置助理的角色,用户消息提供任务。

清单 3.25 聊天补全作为补全 API 示例

openai.ChatCompletion.create(  
  model="turbo",  
  messages=[  
        {"role": "system", "content": "You are a helpful assistant."},  
        {"role": "user", "content": "Translate the following English text to Spanish: 'Hello, how are you?'"}  
    ]  
)

我们还可以使用一系列用户消息来提供更多上下文或完成更复杂的任务,如下面的清单 3.26 所示。在这个示例中,第一条用户消息设置任务,第二条用户消息提供更具体的细节。 助手生成一个响应,尝试完成用户消息中的任务。

清单 3.26 聊天补全作为补全 API 示例

openai.ChatCompletion.create(  
  model=" turbo",  
  messages=[  
        {"role": "system", "content": "You are a helpful assistant."},  
        {"role": "user", "content": "I need to write a Python function."},  
        {"role": "user", "content": "This function should take two numbers as input and return their sum."}  
    ]  
)

3.4.4 管理对话

我们的示例继续运行,但随着对话的继续,对话将达到模型的令牌限制。 随着对话的每一轮(即提出的问题和收到的答案),消息列表都会增长。 提醒一下,gpt-35-turbo 的代币限制是 4K 代币,gpt-4 和 gpt4-32k 的代币限制分别是 8K 和 32K; 其中包括发送的消息列表的总数和模型响应。 如果总数超过相关模型限制,我们会收到异常。

没有现成的选项可以为我们跟踪此代币计数并确保其落在代币限制内。 作为企业应用程序设计的一部分,我们需要跟踪令牌计数,并仅向模型发送落在限制范围内的提示。

许多企业正在使用聊天 API 实施企业版 ChatGPT。下面是一些可帮助企业管理这些对话的最佳实践。 请记住,获得所需输出的最佳方法包括迭代测试和完善指令。

  • 使用系统消息设置行为:您应该在对话开始时使用系统消息来指导模型的行为,并让企业进行调整以反映其品牌或 IP。
  • 提供明确的指令:如果模型没有生成您想要的输出,请使您的指令更加明确。 你需要像告诉一个小孩不该做什么一样来思考它。
  • 分解复杂的任务:如果您有一项复杂的任务,请将其分解为几个更简单的任务,并将它们作为单独的用户消息发送。 你通常不需要解释它,而是展示它。 这称为思想链(CoT); 我们将在第 6 章中更详细地介绍它。
  • 实验:随意尝试参数以获得所需的输出。 较高的温度值(例如 0.8)使生成更加随机,而较低的值(例如 0.2)使其更具确定性。 您还可以使用最大令牌值来限制响应长度。
  • 管理令牌:了解对话中的令牌总数,因为输入和输出令牌计入总数。 如果对话中的标记太多而无法满足模型的最大限制,则必须截断、省略或缩短文本。
  • 处理敏感内容:如果您正在处理潜在的不安全内容,您应该查看 Azure OpenAI 的 Responsible AI 指南(可从以下位置获取:https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/content-filter)。 另一方面,如果您使用 OpenAI 的 API,那么 OpenAI 的审核指南会很有帮助(可在 https://platform.openai.com/docs/guides/moderation 获取),为 Chat API 的输出添加审核层。

追踪代币

正如我们之前概述的,在使用会话 API 时跟踪令牌是关键 - 如果我们超过总令牌大小,不仅体验会受到影响,而且 API 中的令牌总数也会对延迟产生直接影响 以及对通话时间的影响。 最后,我们使用的代币越多,我们支付的费用就越多。 以下是您可以管理令牌的一些方法:

  • 计算令牌:使用我们之前看到的 tiktoken 库,允许我们计算字符串中有多少个令牌,而无需进行 API 调用。
  • 限制响应长度:使用 max_tokens 属性来限制进行 API 调用时模型响应的长度。
  • 截断长对话:如果对话包含太多标记而无法满足模型的最大限制,我们必须截断、省略或缩短您的文本。
  • 限制轮数:截断或缩短文本的一个好方法是限制对话的轮次。 当对话变长时,这也有助于更好地引导模型,并且它往往会开始产生幻觉。
  • 检查API响应中的“usage”字段:进行API调用后,我们可以检查API响应中的使用字段以查看使用的令牌总数。 这是持续进行的,包括输入和输出令牌,这是跟踪令牌并通过某些用户体验向用户显示它们的好方法。
  • 降低 Temperature:降 Temperature 度参数可以使模型输出更加集中和简洁,这有助于减少响应中使用的令牌数量。

假设我们想为我们的宠物沙龙构建一个聊天应用程序,并允许客户向我们询问有关宠物、美容及其需求的问题。 我们可以构建一个控制台聊天应用程序,如下面的清单 3.27 所示。 这也向我们展示了一种跟踪和管理代币的可能方法。 在这个例子中,我们有一个函数 num_tokens_from_messages,顾名思义,它用于计算对话中的令牌数量。

随着对话逐渐增长,我们计算使用的令牌数量,一旦达到模型限制,旧消息就会从对话中删除。 请注意,我们从索引一开始。 这确保我们始终将系统消息保留在索引零处,并且仅删除用户/助理消息。

清单 3.27 ConsoleChatApp - 令牌管理

import os
import openai
import tiktoken
 
openai.api_type = "azure"
openai.api_base = os.getenv("AOAI_ENDPOINT")
openai.api_version = "2023-05-15"
openai.api_key = os.getenv("AOAI_KEY")
 
system_message = {"role": "system", "content": "You are a helpful assistant."}
max_response_tokens = 250
token_limit = 4096
conversation = []
conversation.append(system_message)
 
def num_tokens_from_messages(messages):
    encoding= tiktoken.get_encoding("cl100k_base")
    num_tokens = 0
    for message in messages:
        num_tokens += 4
        for key, value in message.items():
            num_tokens += len(encoding.encode(value))
            if key == "name":
                num_tokens += -1 
    num_tokens += 2 
 
print("I am a helpful assistant. I can talk about pets and salons.")
 
while True:
    user_input = input("")     
    conversation.append({"role": "user", "content": user_input})
    conv_history_tokens = num_tokens_from_messages(conversation)
 
    while conv_history_tokens + max_response_tokens >= token_limit:
        del conversation[1]
        conv_history_tokens = num_tokens_from_messages(conversation)
 
    response = openai.ChatCompletion.create(
        engine="turbo", 
        messages=conversation,
        temperature=0.8,
        max_tokens=max_response_tokens,
    )
 
    conversation.append({"role": "assistant", "content": response['choices'][0]['message']['content']})
    print("\n" + response['choices'][0]['message']['content'])
    print("(Tokens used: " + str(response['usage']['total_tokens'])  + ")")

聊天补全 API 与补全 API

聊天补全和补全 API 都旨在生成类似人类的文本,并在不同的上下文中使用。补全 API 专为单轮任务而设计,可完成用户提供的提示。 它最适合仅需要单个响应的任务。

另一方面,聊天补全 API 专为多轮对话而设计,可在多次交换中维护对话的上下文。 这使得它更适合交互式应用程序,例如聊天机器人。 聊天补全 API 是一种新的专用 API,用于与 GPT-35-Turbo 和 GPT-4 模型进行交互,并且是首选方法。 Chat 补全 API 更适合聊天机器人,使用不同的“角色”(系统、用户和助理),我们可以获取先前消息的记忆并组织少量示例。

3.4.5 管理代币的最佳实践

对于 LLMs 来说,代币是新货币。 由于大多数企业不再局限于业务关键型用例,因此管理代币将成为优先事项 - 无论是计算、成本还是整体体验。 从企业应用的角度来看,管理代币的一些注意事项如下:

  • Conscience prompts(良心提示词) - 在可能的情况下,使用良心提示词并限制最大代币数量将减少代币的使用,使其更具成本效益。
  • 停止序列 - 使用停止序列来停止生成以避免生成不必要的令牌。
  • 计算代币 - 我们可以使用前面概述的 tiktoken 库来计算代币,并避免调用 API 来执行相同的操作。
  • 较小的模型 - 在计算中,一般来说,更大、更新的硬件和软件被认为更快、更便宜、更好 - 对于LLMs来说不一定是这种情况。在可能的情况下,首先考虑使用较小的模型,例如 GPT-3.5 Turbo,以及它们可能使用的地方 不太合适,然后考虑去下一个。 较小的模型计算强度较低,因此更经济。
  • 使用缓存 - 对于非常静态或重复频繁的提示,实施缓存策略将有助于节省令牌并避免重复进行 API 调用。 对于更复杂的场景,请考虑使用矢量搜索和存储来缓存嵌入,例如 Azure 认知搜索、Pinecone 等。我们将在本书后面获得有关嵌入和搜索的更多详细信息。

3.4.6 其他 LLM 供应商

还有其他供应商现在也提供 LLM 供企业使用。这些可以通过 API 获得,或者在某些情况下作为企业可以自行托管的模型权重提供。 下面的表 3.7 概述了出版时一些比较著名的。 请注意,从商业许可的角度来看,某些限制存在限制。

表 3.7 其他 LLM 供应商

模型描述
LLama 2Meta 发布了 LLama2,这是一个开源 LLM,具有三种规模:70 亿、130 亿和 700 亿个参数,并且免费用于研究和商业目的。 公司可以通过 Azure AI 的模型目录、Hugging Face 或 AWS 等云选项来访问此信息。 希望使用自己的计算和 GPU 托管它的企业可以通过 https://ai.meta.com/llama/ 向 Meta 请求访问。
PaLMPaLM 是 Google 的一个包含 130 亿个参数的模型,是其面向开发者产品的生成式 AI 的一部分。 该模型可以执行文本摘要、对话生成和自然语言推理任务。 在发布时,API 密钥有一个等待名单; 详细信息请参见 https://developers.generativeai.google/ 。
BLOOMBloom 是一个拥有 2230 亿个参数的开源多语言模型,通过与 250 多个机构的 1000 多名研究人员合作,可以理解和生成 100 多种语言的文本。 它可以通过 Hugging Face 进行部署。 更多详情请访问 https://huggingface.co/bigscience/bloom 。
ClaudeClaude是Anthropic开发的120亿参数。 它可以通过其开发者控制台中的 Playground 界面和 API 进行访问,仅用于开发和评估目的。 截至发稿时,如需生产使用,企业需联系Claude进行商业讨论。 更多详细信息可以在 https://docs.anthropic.com/claude/reference/getting-started-with-the-api 找到。

有趣的是,所有这些供应商都遵循 OpenAI 建立的概念和 API 的类似方法。 例如,正如他们的文档所概述的,Google 的补全 API 等效项中的 PaLM 模型如下面的清单 3.28 所示。

清单 3.28 PaLM 生成文本 API 签名

google.generativeai.generate_text(*,
    model: Optional[model_types.ModelNameOptions] = 'models/text-bison-001',
    prompt: str,
    temperature: Optional[float] = None,
    max_output_tokens: Optional[int] = None,
    top_p: Optional[float] = None,
    top_k: Optional[float] = None,
    stop_sequences: Union[str, Iterable[str]] = None,
) -> text_types.Completion

虽然存在这些选项,并且其中一些来自信誉良好的领先技术公司,但对于大多数企业来说,Azure OpenAI 和 OpenAI 是该领域最成熟的,需要最多的企业控制和支持。 在下一章中,我们将切换到图像,看看如何从文本转移到图像并以这种方式生成。

3.5 总结

  • Gen AI 模型根据类型分为不同类别。 每个模型都有附加的功能和特性。为当前的用例选择正确的模型非常重要。 与计算机科学不同,在我们的例子中,最大的模型并不意味着它更好。
  • Completion API 是一个复杂的文本生成工具,可用于完成用户提供的提示,并构成文本生成范例的支柱。
  • Completion API 相对易于使用,只有几个关键参数,例如提示、要生成的令牌数量、有助于引导模型的温度参数以及要生成的完成数量。
  • 该 API 公开了许多用于引导模型以及控制随机性和生成文本的高级选项,例如 Logit Bias、存在惩罚和频率惩罚。 所有这些协同工作,有助于产生更好的产出。
  • 使用 Azure OpenAl 时,内容安全筛选器可以帮助筛选特定类别,以识别潜在有害内容并对其采取操作,作为输入提示和生成的补全的一部分。
  • 聊天完成 API 建立在完成 API 的基础上,从一组指令和 API 到在逐轮交互中与用户对话。 聊天完成由多个系统、用户和辅助角色组成。 对话以设置助手行为的“系统”消息开始,然后随着对话轮流进行,用户消息和“助手”消息交替出现。
  • 系统角色包含在消息数组的开头,它为模型提供了初始指令,包括个性特征、助手要遵循的指令和规则,以及我们想要提供作为模型上下文的附加信息; 此附加信息称为数据接地。
  • 每个完成和聊天完成 API 响应都有一个完成原因,这有助于我们理解 API 为什么返回它所做的响应。这对于调试和改进应用程序非常有用。
  • LLM 都有一个有限的上下文窗口,并且非常昂贵。管理代币对于我们以合理的成本运行事物并适应 API 津贴的上下文变得很重要。 这也有助于我们管理对话中的令牌,以改善用户体验和成本效益
  • 除了 Azure OpenAI 和 OpenAl 之外,还有其他 LLM 提供商,例如 Meta 的 LLama 2、Google 的 PaLM、BigScience 的 Bloom 和 Anthropic 的 Claude 及其产品,它们非常相似,并且遵循补全和聊天补全范例,包括类似的 API。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值