提示词入门教程与openAI API基础教程(借鉴梯子教程)

Langchain 学习

一、提示词入门教程

1.Prompt 设计原则

本章的主要内容为编写 Prompt 的原则,在本章中,将给出两个编写 Prompt 的原则与一些相关的策略,你将学习如何基于这两个原则,编写有效的 Prompt,从而有效的指挥 LLM干活。

提示:虽然教程使用的是python语言描述如何调用OpenAI接口,如果你不熟悉Python没关系,学习prompt即可,OpenAI API支持restful api接口,其他大模型的prompt的写法也类似。

1.环境配置

本教程使用 OpenAI 所开放的 ChatGPT API,因此你需要首先拥有一个 ChatGPT 的 API_KEY(也可以直接访问官方网址在线测试),然后需要安装 openai 的第三方库

首先需要安装所需第三方库:
openai:

pip install openai

dotenv:

pip install -U python-dotenv

将自己的 API-KEY 导入系统环境变量

!export OPENAI_API_KEY='api-key'

加载配置的代码

import openai
import os
from dotenv import load_dotenv, find_dotenv
# 导入第三方库

_ = load_dotenv(find_dotenv())
# 读取系统中的环境变量

openai.api_key  = os.getenv('OPENAI_API_KEY')
# 设置 API_KEY

我们将在后续课程中深入探究 OpenAI 提供的 ChatCompletion API 的使用方法,在此处,我们先将它封装成一个函数,你无需知道其内部机理,仅需知道调用该函数输入 Prompt 其将会给出对应的 Completion 即可。

# 一个封装 OpenAI 接口的函数,参数为 Prompt,返回对应结果
def get_completion(prompt, model="gpt-3.5-turbo"):
    '''
    prompt: 对应的提示
    model: 调用的模型,默认为 gpt-3.5-turbo(ChatGPT),有内测资格的用户可以选择 gpt-4
    '''
    messages = [{"role": "user", "content": prompt}]
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=0, # 模型输出的温度系数,控制输出的随机程度
    )
    # 调用 OpenAI 的 ChatCompletion 接口
    return response.choices[0].message["content"]
2.两个基本原则
2.1.原则一:编写清晰、具体的指令

你应该通过提供尽可能清晰和具体的指令来表达您希望模型执行的操作。这将引导模型给出正确的输出,并减少你得到无关或不正确响应的可能。编写清晰的指令不意味着简短的指令,因为在许多情况下,更长的提示实际上更清晰且提供了更多上下文,这实际上可能导致更详细更相关的输出。

2.1.1.策略一

使用分隔符清晰地表示输入的不同部分,分隔符可以是:```,””,<>,,<\tag>等

你可以使用任何明显的标点符号将特定的文本部分与提示的其余部分分开。这可以是任何可以使模型明确知道这是一个单独部分的标记。使用分隔符是一种可以避免提示注入的有用技术。提示注入是指如果用户将某些输入添加到提示中,则可能会向模型提供与您想要执行的操作相冲突的指令,从而使其遵循冲突的指令而不是执行您想要的操作。即,输入里面可能包含其他指令,会覆盖掉你的指令。对此,使用分隔符是一个不错的策略。

以下是一个例子,我们给出一段话并要求 GPT 进行总结,在该示例中我们使用 `` 来作为分隔符

# 需要总结的文本
text = f"""
你应该提供尽可能清晰、具体的指示,以表达你希望模型执行的任务。\
这将引导模型朝向所需的输出,并降低收到无关或不正确响应的可能性。\
不要将写清晰的提示与写简短的提示混淆。\
在许多情况下,更长的提示可以为模型提供更多的清晰度和上下文信息,从而导致更详细和相关的输出。
"""
# 需要提交给AI的prompt,这里嵌入了前面的text变量
prompt = f"""
把用2个反引号括起来的文本总结成一句话。
``{text}``
"""
# 指令内容,使用 `` 来分隔指令和待总结的内容,调用AI获取结果
response = get_completion(prompt)
print(response)

提供清晰具体的指示,避免无关或不正确响应,不要混淆写清晰和写简短,更长的提示可以提供更多清晰度和上下文信息,导致更详细和相关的输出。

2.1.2.策略二

要求一个结构化的输出,可以是 Json、HTML 等格式

第二个策略是要求生成一个结构化的输出,这可以使模型的输出更容易被我们解析,例如,你可以在 Python 中将其读入字典或列表中。。

在以下示例中,我们要求 GPT 生成三本书的标题、作者和类别,并要求 GPT 以 Json 的格式返回给我们,为便于解析,我们指定了 Json 的键。

prompt = f"""
请生成包括书名、作者和类别的三本虚构书籍清单,\
并以 JSON 格式提供,其中包含以下键:book_id、title、author、genre。
"""
response = get_completion(prompt)
print(response)

返回结果

[
  {
    "book_id": 1,
    "title": "The Lost City of Zorath",
    "author": "Aria Blackwood",
    "genre": "Fantasy"
  },
  {
    "book_id": 2,
    "title": "The Last Survivors",
    "author": "Ethan Stone",
    "genre": "Science Fiction"
  },
  {
    "book_id": 3,
    "title": "The Secret Life of Bees",
    "author": "Lila Rose",
    "genre": "Romance"
  }
]
2.1.3.策略三

要求模型检查是否满足条件

如果任务做出的假设不一定满足,我们可以告诉模型先检查这些假设,如果不满足,指示并停止执行。你还可以考虑潜在的边缘情况以及模型应该如何处理它们,以避免意外的错误或结果。

在如下示例中,我们将分别给模型两段文本,分别是制作茶的步骤以及一段没有明确步骤的文本。我们将要求模型判断其是否包含一系列指令,如果包含则按照给定格式重新编写指令,不包含则回答未提供步骤。

# 有步骤的文本
text_1 = f"""
泡一杯茶很容易。首先,需要把水烧开。\
在等待期间,拿一个杯子并把茶包放进去。\
一旦水足够热,就把它倒在茶包上。\
等待一会儿,让茶叶浸泡。几分钟后,取出茶包。\
如果你愿意,可以加一些糖或牛奶调味。\
就这样,你可以享受一杯美味的茶了。
"""
# 发给ai的prompt,嵌入前面text_1变量内容
prompt = f"""
您将获得由三个引号括起来的文本。\
如果它包含一系列的指令,则需要按照以下格式重新编写这些指令:

第一步 - ...
第二步 - …
…
第N步 - …

如果文本中不包含一系列的指令,则直接写“未提供步骤”。"
\"\"\"{text_1}\"\"\"
"""
response = get_completion(prompt)
print("Text 1 的总结:")
print(response)

返回结果

Text 1 的总结:
第一步 - 把水烧开。
第二步 - 拿一个杯子并把茶包放进去。
第三步 - 把烧开的水倒在茶包上。
第四步 - 等待几分钟,让茶叶浸泡。
第五步 - 取出茶包。
第六步 - 如果你愿意,可以加一些糖或牛奶调味。
第七步 - 就这样,你可以享受一杯美味的茶了。

无步骤的文本

text_2 = f"""
今天阳光明媚,鸟儿在歌唱。\
这是一个去公园散步的美好日子。\
鲜花盛开,树枝在微风中轻轻摇曳。\
人们外出享受着这美好的天气,有些人在野餐,有些人在玩游戏或者在草地上放松。\
这是一个完美的日子,可以在户外度过并欣赏大自然的美景。
"""
prompt = f"""
您将获得由三个引号括起来的文本。\
如果它包含一系列的指令,则需要按照以下格式重新编写这些指令:

第一步 - ...
第二步 - …
…
第N步 - …

如果文本中不包含一系列的指令,则直接写“未提供步骤”。"
\"\"\"{text_2}\"\"\"
"""
response = get_completion(prompt)
print("Text 2 的总结:")
print(response)

返回结果

Text 2 的总结:
未提供步骤。
2.1.4.策略四

提供少量示例

即在要求模型执行实际任务之前,提供给它少量成功执行任务的示例。

例如,在以下的示例中,我们告诉模型其任务是以一致的风格回答问题,并先给它一个孩子和一个祖父之间的对话的例子。孩子说,“教我耐心”,祖父用这些隐喻回答。因此,由于我们已经告诉模型要以一致的语气回答,现在我们说“教我韧性”,由于模型已经有了这个少样本示例,它将以类似的语气回答下一个任务。

prompt = f"""
你的任务是以一致的风格回答问题。

<孩子>: 教我耐心。

<祖父母>: 挖出最深峡谷的河流源于一处不起眼的泉眼;最宏伟的交响乐从单一的音符开始;最复杂的挂毯以一根孤独的线开始编织。

<孩子>: 教我韧性。
"""
response = get_completion(prompt)
print(response)

返回

<祖父母>: 韧性就像是一棵树,它需要经历风吹雨打、寒冬酷暑,才能成长得更加坚强。在生活中,我们也需要经历各种挫折和困难,才能锻炼出韧性。记住,不要轻易放弃,坚持下去,你会发现自己变得更加坚强。
2.2.原则二:给模型时间去思考

如果模型匆忙地得出了错误的结论,您应该尝试重新构思查询,请求模型在提供最终答案之前进行一系列相关的推理。换句话说,如果您给模型一个在短时间或用少量文字无法完成的任务,它可能会猜测错误。这种情况对人来说也是一样的。如果您让某人在没有时间计算出答案的情况下完成复杂的数学问题,他们也可能会犯错误。因此,在这些情况下,您可以指示模型花更多时间思考问题,这意味着它在任务上花费了更多的计算资源。

2.2.1.策略一

指定完成任务所需的步骤

接下来我们将通过给定一个复杂任务,给出完成该任务的一系列步骤,来展示这一策略的效果

首先我们描述了杰克和吉尔的故事,并给出一个指令。该指令是执行以下操作。首先,用一句话概括三个双引号限定的文本。第二,将摘要翻译成法语。第三,在法语摘要中列出每个名称。第四,输出包含以下键的 JSON 对象:法语摘要和名称数。然后我们要用换行符分隔答案。

text = f"""
在一个迷人的村庄里,兄妹杰克和吉尔出发去一个山顶井里打水。\
他们一边唱着欢乐的歌,一边往上爬,\
然而不幸降临——杰克绊了一块石头,从山上滚了下来,吉尔紧随其后。\
虽然略有些摔伤,但他们还是回到了温馨的家中。\
尽管出了这样的意外,他们的冒险精神依然没有减弱,继续充满愉悦地探索。
"""
# example 1
prompt_1 = f"""
执行以下操作:
1-用一句话概括下面用三个双引号括起来的文本。
2-将摘要翻译成法语。
3-在法语摘要中列出每个人名。
4-输出一个 JSON 对象,其中包含以下键:French_summary,num_names。

请用换行符分隔您的答案。

Text:
\"\"\"{text}\"\"\"
"""
response = get_completion(prompt_1)
print("prompt 1:")
print(response)

返回结果

prompt 1:
1-兄妹在山顶井里打水时发生意外,但仍然保持冒险精神。
2-Dans un charmant village, les frère et sœur Jack et Jill partent chercher de l'eau dans un puits au sommet de la montagne. Malheureusement, Jack trébuche sur une pierre et tombe de la montagne, suivi de près par Jill. Bien qu'ils soient légèrement blessés, ils retournent chez eux chaleureusement. Malgré cet accident, leur esprit d'aventure ne diminue pas et ils continuent à explorer joyeusement.
3-Jack, Jill
4-{
   "French_summary": "Dans un charmant village, les frère et sœur Jack et Jill partent chercher de l'eau dans un puits au sommet de la montagne. Malheureusement, Jack trébuche sur une pierre et tombe de la montagne, suivi de près par Jill. Bien qu'ils soient légèrement blessés, ils retournent chez eux chaleureusement. Malgré cet accident, leur esprit d'aventure ne diminue pas et ils continuent à explorer joyeusement.",
   "num_names": 2
}

上述输出仍然存在一定问题,例如,键“姓名”会被替换为法语,因此,我们给出一个更好的 Prompt,该 Prompt 指定了输出的格式

prompt_2 = f"""
1-用一句话概括下面用<>括起来的文本。
2-将摘要翻译成英语。
3-在英语摘要中列出每个名称。
4-输出一个 JSON 对象,其中包含以下键:English_summary,num_names。

请使用以下格式:
文本:<要总结的文本>
摘要:<摘要>
翻译:<摘要的翻译>
名称:<英语摘要中的名称列表>
输出 JSON:<带有 English_summary 和 num_names 的 JSON>

Text: <{text}>
"""
response = get_completion(prompt_2)
print("\nprompt 2:")
print(response)

返回结果

prompt 2:
摘要:兄妹杰克和吉尔在迷人的村庄里冒险,不幸摔伤后回到家中,但仍然充满冒险精神。
翻译:In a charming village, siblings Jack and Jill set out to fetch water from a mountaintop well. While climbing and singing, Jack trips on a stone and tumbles down the mountain, with Jill following closely behind. Despite some bruises, they make it back home safely. Their adventurous spirit remains undiminished as they continue to explore with joy.
名称:Jack,Jill
输出 JSON:{"English_summary": "In a charming village, siblings Jack and Jill set out to fetch water from a mountaintop well. While climbing and singing, Jack trips on a stone and tumbles down the mountain, with Jill following closely behind. Despite some bruises, they make it back home safely. Their adventurous spirit remains undiminished as they continue to explore with joy.", "num_names": 2}
2.2.2.策略二

指导模型在下结论之前找出一个自己的解法

有时候,在明确指导模型在做决策之前要思考解决方案时,我们会得到更好的结果。

接下来我们会给出一个问题和一个学生的解答,要求模型判断解答是否正确

prompt = f"""
判断学生的解决方案是否正确。

问题:
我正在建造一个太阳能发电站,需要帮助计算财务。

    土地费用为 100美元/平方英尺
    我可以以 250美元/平方英尺的价格购买太阳能电池板
    我已经谈判好了维护合同,每年需要支付固定的10万美元,并额外支付每平方英尺10美元
    作为平方英尺数的函数,首年运营的总费用是多少。

学生的解决方案:
设x为发电站的大小,单位为平方英尺。
费用:

    土地费用:100x
    太阳能电池板费用:250x
    维护费用:100,000美元+100x
    总费用:100x+250x+100,000美元+100x=450x+100,000美元
"""
response = get_completion(prompt)
print(response)

返回

学生的解决方案是正确的。

但是注意,学生的解决方案实际上是错误的。

我们可以通过指导模型先自行找出一个解法来解决这个问题。

在接下来这个 Prompt 中,我们要求模型先自行解决这个问题,再根据自己的解法与学生的解法进行对比,从而判断学生的解法是否正确。同时,我们给定了输出的格式要求。通过明确步骤,让模型有更多时间思考,有时可以获得更准确的结果。在这个例子中,学生的答案是错误的,但如果我们没有先让模型自己计算,那么可能会被误导以为学生是正确的。

prompt = f"""
请判断学生的解决方案是否正确,请通过如下步骤解决这个问题:

步骤:

    首先,自己解决问题。
    然后将你的解决方案与学生的解决方案进行比较,并评估学生的解决方案是否正确。在自己完成问题之前,请勿决定学生的解决方案是否正确。

使用以下格式:

    问题:问题文本
    学生的解决方案:学生的解决方案文本
    实际解决方案和步骤:实际解决方案和步骤文本
    学生的解决方案和实际解决方案是否相同:是或否
    学生的成绩:正确或不正确

问题:

    我正在建造一个太阳能发电站,需要帮助计算财务。 
    - 土地费用为每平方英尺100美元
    - 我可以以每平方英尺250美元的价格购买太阳能电池板
    - 我已经谈判好了维护合同,每年需要支付固定的10万美元,并额外支付每平方英尺10美元
    作为平方英尺数的函数,首年运营的总费用是多少。

学生的解决方案:

    设x为发电站的大小,单位为平方英尺。
    费用:
    1. 土地费用:100x
    2. 太阳能电池板费用:250x
    3. 维护费用:100,000+100x
    总费用:100x+250x+100,000+100x=450x+100,000

实际解决方案和步骤:
"""
response = get_completion(prompt)
print(response)

返回结果

正确的解决方案和步骤:
    1. 计算土地费用:100美元/平方英尺 * x平方英尺 = 100x美元
    2. 计算太阳能电池板费用:250美元/平方英尺 * x平方英尺 = 250x美元
    3. 计算维护费用:10万美元 + 10美元/平方英尺 * x平方英尺 = 10万美元 + 10x美元
    4. 计算总费用:100x美元 + 250x美元 + 10万美元 + 10x美元 = 360x + 10万美元

学生的解决方案和实际解决方案是否相同:否

学生的成绩:不正确
3.局限性

虚假知识:模型偶尔会生成一些看似真实实则编造的知识

如果模型在训练过程中接触了大量的知识,它并没有完全记住所见的信息,因此它并不很清楚自己知识的边界。这意味着它可能会尝试回答有关晦涩主题的问题,并编造听起来合理但实际上并不正确的答案。我们称这些编造的想法为幻觉。

2.迭代优化Prompt

1.环境配置

同上一章,我们首先需要配置使用 OpenAI API 的环境

import openai
import os
from dotenv import load_dotenv, find_dotenv
# 导入第三方库

_ = load_dotenv(find_dotenv())
# 读取系统中的环境变量

openai.api_key  = os.getenv('OPENAI_API_KEY')
# 设置 API_KEY

一个封装 OpenAI 接口的函数,参数为 Prompt,返回对应结果

def get_completion(prompt, model="gpt-3.5-turbo"):
    '''
    prompt: 对应的提示
    model: 调用的模型,默认为 gpt-3.5-turbo(ChatGPT),有内测资格的用户可以选择 gpt-4
    '''
    messages = [{"role": "user", "content": prompt}]
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=0, # 模型输出的温度系数,控制输出的随机程度
    )
    # 调用 OpenAI 的 ChatCompletion 接口
    return response.choices[0].message["content"]
2.任务-从产品说明书生成一份营销产品描述

这里有一个椅子的产品说明书,描述说它是一个中世纪灵感家族的一部分,讨论了构造、尺寸、椅子选项、材料等等,产地是意大利。假设您想要使用这份说明书帮助营销团队为在线零售网站撰写营销式描述

# 示例:产品说明书
fact_sheet_chair = """
概述

    美丽的中世纪风格办公家具系列的一部分,包括文件柜、办公桌、书柜、会议桌等。
    多种外壳颜色和底座涂层可选。
    可选塑料前后靠背装饰(SWC-100)或10种面料和6种皮革的全面装饰(SWC-110)。
    底座涂层选项为:不锈钢、哑光黑色、光泽白色或铬。
    椅子可带或不带扶手。
    适用于家庭或商业场所。
    符合合同使用资格。

结构

    五个轮子的塑料涂层铝底座。
    气动椅子调节,方便升降。

尺寸

    宽度53厘米|20.87英寸
    深度51厘米|20.08英寸
    高度80厘米|31.50英寸
    座椅高度44厘米|17.32英寸
    座椅深度41厘米|16.14英寸

选项

    软地板或硬地板滚轮选项。
    两种座椅泡沫密度可选:中等(1.8磅/立方英尺)或高(2.8磅/立方英尺)。
    无扶手或8个位置PU扶手。

材料
外壳底座滑动件

    改性尼龙PA6/PA66涂层的铸铝。
    外壳厚度:10毫米。
    座椅
    HD36泡沫

原产国

    意大利
"""
# prompt设计:基于说明书创建营销描述
prompt = f"""
你的任务是帮助营销团队基于技术说明书创建一个产品的营销描述。

根据\"\"\"标记的技术说明书中提供的信息,编写一个产品描述。

技术说明: \"\"\"{fact_sheet_chair}\"\"\"
"""
response = get_completion(prompt)
print(response)

返回:

产品描述:

我们自豪地推出美丽的中世纪风格办公家具系列,其中包括文件柜、办公桌、书柜、会议桌等。我们的产品采用多种外壳颜色和底座涂层,以满足您的个性化需求。您可以选择塑料前后靠背装饰(SWC-100)或10种面料和6种皮革的全面装饰(SWC-110),以使您的办公室更加舒适和时尚。

我们的底座涂层选项包括不锈钢、哑光黑色、光泽白色或铬,以满足您的不同需求。椅子可带或不带扶手,适用于家庭或商业场所。我们的产品符合合同使用资格,为您提供更加可靠的保障。

我们的产品采用五个轮子的塑料涂层铝底座,气动椅子调节,方便升降。尺寸为宽度53厘米|20.87英寸,深度51厘米|20.08英寸,高度80厘米|31.50英寸,座椅高度44厘米|17.32英寸,座椅深度41厘米|16.14英寸,为您提供舒适的使用体验。

我们的产品还提供软地板或硬地板滚轮选项,两种座椅泡沫密度可选:中等(1.8/立方英尺)或高(2.8/立方英尺),以及无扶手或8个位置PU扶手,以满足您的不同需求。

我们的产品采用改性尼龙PA6/PA66涂层的铸铝外壳底座滑动件,外壳厚度为10毫米,座椅采用HD36泡沫,为您提供更加舒适的使用体验。我们的产品原产国为意大利,为您提供更加优质的品质保证。
2.1.问题一:生成文本太长

它似乎很好地写了一个描述,介绍了一个惊人的中世纪灵感办公椅,很好地完成了要求,即从技术说明书开始编写产品描述。就是内容太长了,做营销文案不合适。

因此,通过要求它限制生成文本长度。

# 优化后的 Prompt,要求生成描述不多于 50 词
prompt = f"""
您的任务是帮助营销团队基于技术说明书创建一个产品的零售网站描述。

根据\"\"\"标记的技术说明书中提供的信息,编写一个产品描述。

使用最多50个词。

技术规格:\"\"\"{fact_sheet_chair}\"\"\"
"""
response = get_completion(prompt)
print(response)

返回

中世纪风格办公家具系列,包括文件柜、办公桌、书柜、会议桌等。多种颜色和涂层可选,可带或不带扶手。底座涂层选项为不锈钢、哑光黑色、光泽白色或铬。适用于家庭或商业场所,符合合同使用资格。意大利制造。

LLM返回的内容,有时候会略多于50个字符,问题不大。

2.2.问题二:细节优化

这个网站并不是直接向消费者销售,它实际上旨在向家具零售商销售家具,他们会更关心椅子的技术细节和材料。在这种情况下,可以修改这个提示,让它更精确地描述椅子的技术细节。

# 优化后的 Prompt,说明面向对象,应具有什么性质且侧重于什么方面
prompt = f"""
您的任务是帮助营销团队基于技术说明书创建一个产品的零售网站描述。

根据\"\"\"标记的技术说明书中提供的信息,编写一个产品描述。

该描述面向家具零售商,因此应具有技术性质,并侧重于产品的材料构造。

使用最多50个单词。

技术规格: \"\"\"{fact_sheet_chair}\"\"\"
"""
response = get_completion(prompt)
print(response)

返回

这款中世纪风格办公家具系列包括文件柜、办公桌、书柜和会议桌等,适用于家庭或商业场所。可选多种外壳颜色和底座涂层,底座涂层选项为不锈钢、哑光黑色、光泽白色或铬。椅子可带或不带扶手,可选软地板或硬地板滚轮,两种座椅泡沫密度可选。外壳底座滑动件采用改性尼龙PA6/PA66涂层的铸铝,座椅采用HD36泡沫。原产国为意大利。

我们希望在描述的结尾包括产品ID。因此,可以进一步改进这个提示(prompt),要求在描述的结尾,包括在技术说明中的每个7个字符产品ID。

# 更进一步
prompt = f"""
您的任务是帮助营销团队基于技术说明书创建一个产品的零售网站描述。

根据\"\"\"标记的技术说明书中提供的信息,编写一个产品描述。

该描述面向家具零售商,因此应具有技术性质,并侧重于产品的材料构造。

在描述末尾,包括技术规格中每个7个字符的产品ID。

使用最多50个单词。

技术规格: \"\"\"{fact_sheet_chair}\"\"\"
"""
response = get_completion(prompt)
print(response)

返回

这款中世纪风格的办公家具系列包括文件柜、办公桌、书柜和会议桌等,适用于家庭或商业场所。可选多种外壳颜色和底座涂层,底座涂层选项为不锈钢、哑光黑色、光泽白色或铬。椅子可带或不带扶手,可选塑料前后靠背装饰或10种面料和6种皮革的全面装饰。座椅采用HD36泡沫,可选中等或高密度,座椅高度44厘米,深度41厘米。外壳底座滑动件采用改性尼龙PA6/PA66涂层的铸铝,外壳厚度为10毫米。原产国为意大利。产品IDSWC-100/SWC-110
2.3.问题三:需要一个表格形式的描述

要求它抽取信息并组织成表格,并指定表格的列、表名和格式,还要求它将所有内容格式化为可以在网页使用的 HTML。

# 要求它抽取信息并组织成表格,并指定表格的列、表名和格式
prompt = f"""
您的任务是帮助营销团队基于技术说明书创建一个产品的零售网站描述。

根据\"\"\"标记的技术说明书中提供的信息,编写一个产品描述。

该描述面向家具零售商,因此应具有技术性质,并侧重于产品的材料构造。

在描述末尾,包括技术规格中每个7个字符的产品ID。

在描述之后,包括一个表格,提供产品的尺寸。表格应该有两列。第一列包括尺寸的名称。第二列只包括英寸的测量值。

给表格命名为“产品尺寸”。

将所有内容格式化为可用于网站的HTML格式。将描述放在<div>元素中。

技术规格:\"\"\"{fact_sheet_chair}\"\"\"
"""

response = get_completion(prompt)
print(response)

返回

<div>
<h2>中世纪风格办公家具系列椅子</h2>
<p>这款椅子是中世纪风格办公家具系列的一部分,适用于家庭或商业场所。它有多种外壳颜色和底座涂层可选,包括不锈钢、哑光黑色、光泽白色或铬。您可以选择带或不带扶手的椅子,以及软地板或硬地板滚轮选项。此外,您可以选择两种座椅泡沫密度:中等(1.8磅/立方英尺)或高(2.8磅/立方英尺)。</p>
<p>椅子的外壳底座滑动件是改性尼龙PA6/PA66涂层的铸铝,外壳厚度为10毫米。座椅采用HD36泡沫,底座是五个轮子的塑料涂层铝底座,可以进行气动椅子调节,方便升降。此外,椅子符合合同使用资格,是您理想的选择。</p>
<p>产品ID:SWC-100</p>
</div>

<table>
  <caption>产品尺寸</caption>
  <tr>
    <th>宽度</th>
    <td>20.87英寸</td>
  </tr>
  <tr>
    <th>深度</th>
    <td>20.08英寸</td>
  </tr>
  <tr>
    <th>高度</th>
    <td>31.50英寸</td>
  </tr>
  <tr>
    <th>座椅高度</th>
    <td>17.32英寸</td>
  </tr>
  <tr>
    <th>座椅深度</th>
    <td>16.14英寸</td>
  </tr>
</table>

3.文本概括 Summarizing Prompt设计

1.引言

当今世界上有太多的文本信息,几乎没有人能够拥有足够的时间去阅读所有我们想了解的东西。好消息是,目前LLM在文本概括任务上展现了强大的水准,也已经有不少团队将这项功能插入了自己的软件应用中。

本章节将介绍如何使用编程的方式,调用API接口来实现“文本概括”功能。

首先,我们需要OpenAI包,加载API密钥,定义getCompletion函数。

import openai
import os
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
openai.api_key = OPENAI_API_KEY

def get_completion(prompt, model="gpt-3.5-turbo"): 
    messages = [{"role": "user", "content": prompt}]
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=0, # 值越低则输出文本随机性越低
    )
    return response.choices[0].message["content"]
2.文本概括Prompt实验

这里我们举了个商品评论的例子。对于电商平台来说,网站上往往存在着海量的商品评论,这些评论反映了所有客户的想法。如果我们拥有一个工具去概括这些海量、冗长的评论,便能够快速地浏览更多评论,洞悉客户的偏好,从而指导平台与商家提供更优质的服务。

prod_review_zh = """
这个熊猫公仔是我给女儿的生日礼物,她很喜欢,去哪都带着。
公仔很软,超级可爱,面部表情也很和善。但是相比于价钱来说,
它有点小,我感觉在别的地方用同样的价钱能买到更大的。
快递比预期提前了一天到货,所以在送给女儿之前,我自己玩了会。
"""
2.1.限制输出文本长度

尝试限制文本长度为最多30词,对文本进行总结。

prompt = f"""
你的任务是从电子商务网站上生成一个产品评论的简短摘要。

请对三个双引号之间的评论文本进行概括,最多30个词汇。

评论: \"\"\"{prod_review_zh}\"\"\"
"""

response = get_completion(prompt)
print(response)

返回

可爱软熊猫公仔,女儿喜欢,面部表情和善,但价钱有点小贵,快递提前一天到货。
2.2.调整总结内容的角度和侧重点

有时,针对不同的业务,我们对文本的侧重会有所不同。例如对于商品评论文本,物流会更关心运输时效,商家更加关心价格与商品质量,平台更关心整体服务体验。

我们可以通过增加Prompt提示,来体现对于某个特定角度的侧重。

侧重于运输(物流)

prompt = f"""
你的任务是从电子商务网站上生成一个产品评论的简短摘要。

请对三个双引号之间的评论文本进行概括,最多30个词汇,并且聚焦在产品运输上。

评论: \"\"\"{prod_review_zh}\"\"\"
"""

response = get_completion(prompt)
print(response)

返回

快递提前到货,熊猫公仔软可爱,但有点小,价钱不太划算。

可以看到,输出结果以“快递提前一天到货”开头,体现了对于快递效率的侧重。

侧重于价格与质量

prompt = f"""
你的任务是从电子商务网站上生成一个产品评论的简短摘要。

请对三个双引号之间的评论文本进行概括,最多30个词汇,并且聚焦在产品价格和质量上。

评论: \"\"\"{prod_review_zh}\"\"\"
"""

response = get_completion(prompt)
print(response)

返回

可爱软熊猫公仔,面部表情友好,但价钱有点高,尺寸较小。快递提前一天到货。

可以看到,输出结果以“质量好、价格小贵、尺寸小”开头,体现了对于产品价格与质量的侧重。

2.3.关键信息提取

在2.2节中,虽然我们通过添加关键角度侧重的Prompt,使得文本摘要更侧重于某一特定方面,但是可以发现,结果中也会保留一些其他信息,如价格与质量角度的概括中仍保留了“快递提前到货”的信息。有时这些信息是有帮助的,但如果我们只想要提取某一角度的信息,并过滤掉其他所有信息,则可以要求LLM进行“文本提取(Extract)”而非“文本概括(Summarize)”。

prompt = f"""
你的任务是从电子商务网站上的产品评论中提取相关信息。

请从以下三个双引号之间的评论文本中提取产品运输相关的信息,最多30个词汇。

评论: \"\"\"{prod_review_zh}\"\"\"
"""

response = get_completion(prompt)
print(response)

返回

快递比预期提前了一天到货。

4.利用AI推理能力的Prompt设计

本章将从产品评论和新闻文章中推断情感和主题。

这些任务可以看作是模型接收文本作为输入并执行某种分析的过程。这可能涉及提取标签、提取实体、理解文本情感等等。如果你想要从一段文本中提取正面或负面情感,在传统的机器学习工作流程中,需要收集标签数据集、训练模型、确定如何在云端部署模型并进行推断。这样做可能效果还不错,但是这个过程需要很多工作。而且对于每个任务,如情感分析、提取实体等等,都需要训练和部署单独的模型。

大型语言模型的一个非常好的特点是,对于许多这样的任务,你只需要编写一个prompt即可开始产生结果,而不需要进行大量的工作。这极大地加快了应用程序开发的速度。你还可以只使用一个模型和一个 API 来执行许多不同的任务,而不需要弄清楚如何训练和部署许多不同的模型。

代码配置

首先,我们需要OpenAI包,加载API密钥,定义getCompletion函数。

import openai
import os
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
openai.api_key = OPENAI_API_KEY

def get_completion(prompt, model="gpt-3.5-turbo"): 
    messages = [{"role": "user", "content": prompt}]
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=0, # 值越低则输出文本随机性越低
    )
    return response.choices[0].message["content"]
商品评论文本

这是一盏台灯的评论。

lamp_review_zh = """
我需要一盏漂亮的卧室灯,这款灯具有额外的储物功能,价格也不算太高。\
我很快就收到了它。在运输过程中,我们的灯绳断了,但是公司很乐意寄送了一个新的。\
几天后就收到了。这款灯很容易组装。我发现少了一个零件,于是联系了他们的客服,他们很快就给我寄来了缺失的零件!\
在我看来,Lumina 是一家非常关心顾客和产品的优秀公司!
"""
情感(正向/负向)推理

现在编写一个prompt来分类这个评论的情感。如果我想让系统告诉我这个评论的情感是什么,只需要编写 “以下产品评论的情感是什么” 这个prompt,加上通常的分隔符和评论文本等等。

prompt = f"""
以下用三个双引号分隔的产品评论的情感是什么?

评论文本: \"\"\"{lamp_review_zh}\"\"\"
"""
response = get_completion(prompt)
print(response)

输出

情感是积极的/正面的。

如果你想要给出更简洁的答案,以便更容易进行后处理,可以使用上面的prompt并添加另一个指令,以一个单词 “正面” 或 “负面” 的形式给出答案。这样就只会打印出 “正面” 这个单词,这使得文本更容易接受这个输出并进行处理。

prompt = f"""
以下用三个双引号分隔的产品评论的情感是什么?

用一个单词回答:「正面」或「负面」。

评论文本: \"\"\"{lamp_review_zh}\"\"\"
"""
response = get_completion(prompt)
print(response)

输出

正面
识别情感类型

让我们看看另一个prompt,仍然使用台灯评论。这次我要让它识别出以下评论作者所表达的情感列表,不超过五个。

prompt = f"""
识别以下评论的作者表达的情感。包含不超过五个项目。将答案格式化为以逗号分隔的单词列表。

评论文本: \"\"\"{lamp_review_zh}\"\"\"
"""
response = get_completion(prompt)
print(response)

返回

满意,感激,信任,赞扬,愉快

大型语言模型非常擅长从一段文本中提取特定的东西。在上面的例子中,评论正在表达情感,这可能有助于了解客户如何看待特定的产品。

识别愤怒

对于很多企业来说,了解某个顾客是否非常生气很重要。所以你可能有一个类似这样的分类问题:以下评论的作者是否表达了愤怒情绪?因为如果有人真的很生气,那么可能值得额外关注,让客户支持或客户成功团队联系客户以了解情况,并为客户解决问题。

prompt = f"""
以下评论的作者是否表达了愤怒?评论用三个双引号分隔。给出是或否的答案。

评论文本: \"\"\"{lamp_review_zh}\"\"\"
"""
response = get_completion(prompt)
print(response)

返回

上面这个例子中,客户并没有生气。注意,如果使用常规的监督学习,如果想要建立所有这些分类器,不可能在几分钟内就做到这一点。我们鼓励大家尝试更改一些这样的prompt,也许询问客户是否表达了喜悦,或者询问是否有任何遗漏的部分,并看看是否可以让prompt对这个灯具评论做出不同的推论。

从客户评论中提取产品和公司名称

接下来,让我们从客户评论中提取更丰富的信息。信息提取是自然语言处理(NLP)的一部分,与从文本中提取你想要知道的某些事物相关。因此,在这个prompt中,我要求它识别以下内容:购买物品和制造物品的公司名称。

同样,如果你试图总结在线购物电子商务网站的许多评论,对于这些评论来说,弄清楚是什么物品,谁制造了该物品,弄清楚积极和消极的情感,以跟踪特定物品或特定制造商的积极或消极情感趋势,可能会很有用。

在下面这个示例中,我们要求它将响应格式化为一个 JSON 对象,其中物品和品牌是键。

prompt = f"""
从评论文本中识别以下项目:
- 评论者购买的物品
- 制造该物品的公司

评论文本用三个双引号分隔。将你的响应格式化为以 “物品” 和 “品牌” 为键的 JSON 对象。
如果信息不存在,请使用 “未知” 作为值。
让你的回应尽可能简短。

评论文本: \"\"\"{lamp_review_zh}\"\"\"
"""
response = get_completion(prompt)
print(response)

返回

{
  "物品": "卧室灯",
  "品牌": "Lumina"
}

如上所示,它会说这个物品是一个卧室灯,品牌是 Luminar,你可以轻松地将其加载到 Python 字典中,然后对此输出进行其他处理。

5.文本转换 Transforming(Prompt设计)

1.引言

LLM非常擅长将输入转换成不同的格式,例如多语种文本翻译、拼写及语法纠正、语气调整、格式转换等。

本章节将介绍如何使用编程的方式,调用API接口来实现“文本转换”功能。

首先,我们需要OpenAI包,加载API密钥,定义getCompletion函数。

import openai
import os
import time
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY2")
openai.api_key = OPENAI_API_KEY

def get_completion(prompt, model="gpt-3.5-turbo", temperature=0): 
    messages = [{"role": "user", "content": prompt}]
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=temperature, # 值越低则输出文本随机性越低
    )
    return response.choices[0].message["content"]
2.文本翻译
2.1.中文转西班牙语
prompt = f"""
将以下中文翻译成西班牙语: 
\"\"\"您好,我想订购一个搅拌机。\"\"\"
"""
response = get_completion(prompt)
print(response)

返回:

Hola, me gustaría ordenar una batidora.
2.2.识别语种
prompt = f"""
请告诉我以下文本是什么语种: 
\"\"\"Combien coûte le lampadaire?\"\"\"
"""
response = get_completion(prompt)
print(response)

返回:

这是法语。
2.3.多语种翻译
prompt = f"""
请将以下文本分别翻译成中文、英文、法语和西班牙语: 
\"\"\"I want to order a basketball.\"\"\"
"""
response = get_completion(prompt)
print(response)

返回:

中文:我想订购一个篮球。
英文:I want to order a basketball.
法语:Je veux commander un ballon de basket.
西班牙语:Quiero pedir una pelota de baloncesto.
2.4.翻译+正式语气
prompt = f"""
请将以下文本翻译成中文,分别展示成正式与非正式两种语气: 
\"\"\"Would you like to order a pillow?\"\"\"
"""
response = get_completion(prompt)
print(response)

返回:

正式语气:请问您需要订购枕头吗?
非正式语气:你要不要订一个枕头?
2.5.通用翻译器

随着全球化与跨境商务的发展,交流的用户可能来自各个不同的国家,使用不同的语言,因此我们需要一个通用翻译器,识别各个消息的语种,并翻译成目标用户的母语,从而实现更方便的跨国交流。

user_messages = [
  "La performance du système est plus lente que d'habitude.",  # System performance is slower than normal         
  "Mi monitor tiene píxeles que no se iluminan.",              # My monitor has pixels that are not lighting
  "Il mio mouse non funziona",                                 # My mouse is not working
  "Mój klawisz Ctrl jest zepsuty",                             # My keyboard has a broken control key
  "我的屏幕在闪烁"                                             # My screen is flashing
]

for issue in user_messages:
    time.sleep(20)
    prompt = f"告诉我以下文本是什么语种,直接输出语种,如法语,无需输出标点符号: \"\"\"{issue}\"\"\""
    lang = get_completion(prompt)
    print(f"原始消息 ({lang}): {issue}\n")

    prompt = f"""
    将以下消息分别翻译成英文和中文,并写成
    中文翻译:xxx
    英文翻译:yyy
    的格式:
    \"\"\"{issue}\"\"\"
    """
    response = get_completion(prompt)
    print(response, "\n=========================================")

返回:

原始消息 (法语): La performance du système est plus lente que d'habitude.

中文翻译:系统性能比平时慢。
英文翻译:The system performance is slower than usual. 
=========================================
原始消息 (西班牙语): Mi monitor tiene píxeles que no se iluminan.

中文翻译:我的显示器有一些像素点不亮。
英文翻译:My monitor has pixels that don't light up. 
=========================================
原始消息 (意大利语): Il mio mouse non funziona

中文翻译:我的鼠标不工作了。
英文翻译:My mouse is not working. 
=========================================
原始消息 (波兰语): Mój klawisz Ctrl jest zepsuty

中文翻译:我的Ctrl键坏了
英文翻译:My Ctrl key is broken. 
=========================================
原始消息 (中文): 我的屏幕在闪烁

中文翻译:我的屏幕在闪烁。
英文翻译:My screen is flickering. 
=========================================
3.语气/风格调整

写作的语气往往会根据受众对象而有所调整。例如,对于工作邮件,我们常常需要使用正式语气与书面用词,而对同龄朋友的微信聊天,可能更多地会使用轻松、口语化的语气。

prompt = f"""
将以下文本翻译成商务信函的格式: 
\"\"\"小老弟,我小羊,上回你说咱部门要采购的显示器是多少寸来着?\"\"\"
"""
response = get_completion(prompt)
print(response)

返回:

尊敬的XXX(收件人姓名):

您好!我是XXX(发件人姓名),在此向您咨询一个问题。上次我们交流时,您提到我们部门需要采购显示器,但我忘记了您所需的尺寸是多少英寸。希望您能够回复我,以便我们能够及时采购所需的设备。

谢谢您的帮助!

此致

敬礼

XXX(发件人姓名)
4.格式转换

ChatGPT非常擅长不同格式之间的转换,例如JSON到HTML、XML、Markdown等。在下述例子中,我们有一个包含餐厅员工姓名和电子邮件的列表的JSON,我们希望将其从JSON转换为HTML。

data_json = { "resturant employees" :[ 
    {"name":"Shyam", "email":"shyamjaiswal@gmail.com"},
    {"name":"Bob", "email":"bob32@gmail.com"},
    {"name":"Jai", "email":"jai87@gmail.com"}
]}

prompt = f"""
将以下Python字典从JSON转换为HTML表格,保留表格标题和列名:{data_json}
"""
response = get_completion(prompt)
print(response)

返回:

<table>
  <caption>resturant employees</caption>
  <thead>
    <tr>
      <th>name</th>
      <th>email</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Shyam</td>
      <td>shyamjaiswal@gmail.com</td>
    </tr>
    <tr>
      <td>Bob</td>
      <td>bob32@gmail.com</td>
    </tr>
    <tr>
      <td>Jai</td>
      <td>jai87@gmail.com</td>
    </tr>
  </tbody>
</table>
5.拼写及语法纠正

拼写及语法的检查与纠正是一个十分常见的需求,特别是使用非母语语言,例如发表英文论文时,这是一件十分重要的事情。

以下给了一个例子,有一个句子列表,其中有些句子存在拼写或语法问题,有些则没有,我们循环遍历每个句子,要求模型校对文本,如果正确则输出“未发现错误”,如果错误则输出纠正后的文本。

text = [ 
  "The girl with the black and white puppies have a ball.",  # The girl has a ball.
  "Yolanda has her notebook.", # ok
  "Its going to be a long day. Does the car need it’s oil changed?",  # Homonyms
  "Their goes my freedom. There going to bring they’re suitcases.",  # Homonyms
  "Your going to need you’re notebook.",  # Homonyms
  "That medicine effects my ability to sleep. Have you heard of the butterfly affect?", # Homonyms
  "This phrase is to cherck chatGPT for spelling abilitty"  # spelling
]

for i in range(len(text)):
    time.sleep(20)
    prompt = f"""请校对并更正以下文本,注意纠正文本保持原始语种,无需输出原始文本。
    如果您没有发现任何错误,请说“未发现错误”。

    例如:
    输入:I are happy.
    输出:I am happy.
    \"\"\"{text[i]}\"\"\""""
    response = get_completion(prompt)
    print(i, response)

返回:

0 The girl with the black and white puppies has a ball.
1 未发现错误。
2 It's going to be a long day. Does the car need its oil changed?
3 Their goes my freedom. They're going to bring their suitcases.
4 输出:You're going to need your notebook.
5 That medicine affects my ability to sleep. Have you heard of the butterfly effect?
6 This phrase is to check chatGPT for spelling ability.
6.一个综合样例:文本翻译+拼写纠正+风格调整+格式转换
text = f"""
Got this for my daughter for her birthday cuz she keeps taking \
mine from my room.  Yes, adults also like pandas too.  She takes \
it everywhere with her, and it's super soft and cute.  One of the \
ears is a bit lower than the other, and I don't think that was \
designed to be asymmetrical. It's a bit small for what I paid for it \
though. I think there might be other options that are bigger for \
the same price.  It arrived a day earlier than expected, so I got \
to play with it myself before I gave it to my daughter.
"""

prompt = f"""
针对以下三个反引号之间的英文评论文本,
首先进行拼写及语法纠错,
然后将其转化成中文,
再将其转化成优质淘宝评论的风格,从各种角度出发,分别说明产品的优点与缺点,并进行总结。
润色一下描述,使评论更具有吸引力。
输出结果格式为:
【优点】xxx
【缺点】xxx
【总结】xxx
注意,只需填写xxx部分,并分段输出。
将结果输出成Markdown格式。
\"\"\"{text}\"\"\"
"""
response = get_completion(prompt)
display(Markdown(response))

返回:

【优点】

超级柔软可爱,女儿生日礼物非常受欢迎。
成人也喜欢熊猫,我也很喜欢它。
提前一天到货,让我有时间玩一下。
【缺点】

一只耳朵比另一只低,不对称。
价格有点贵,但尺寸有点小,可能有更大的同价位选择。
【总结】 这只熊猫玩具非常适合作为生日礼物,柔软可爱,深受孩子喜欢。虽然价格有点贵,但尺寸有点小,不对称

6.AI写作Prompt设计

AI扩展(续写)是将短文本,例如一组说明或主题列表,输入到大型语言模型中,让模型生成更长的文本,例如基于某个主题写文章。这样做有一些很好的用途,例如将大型语言模型用作头脑风暴的伙伴。但这种做法也存在一些问题,例如某人可能会使用它来生成大量垃圾邮件。因此,当你使用大型语言模型的这些功能时,请仅以负责任的方式和有益于人们的方式使用它们。

在本章中,你将学会如何基于 OpenAI API 生成适用于每个客户评价的客户服务电子邮件。我们还将使用模型的另一个输入参数称为温度,这种参数允许您在模型响应中变化探索的程度和多样性。

1.环境配置

同以上几章,你需要类似的代码来配置一个可以使用 OpenAI API 的环境
将自己的 API-KEY 导入系统环境变量

!export OPENAI_API_KEY='api-key'

演示代码

import openai
import os
from dotenv import load_dotenv, find_dotenv
# 导入第三方库

_ = load_dotenv(find_dotenv())
# 读取系统中的环境变量

openai.api_key  = os.getenv('OPENAI_API_KEY')
# 设置 API_KEY

# 一个封装 OpenAI 接口的函数,参数为 Prompt,返回对应结果
def get_completion(prompt, model="gpt-3.5-turbo", temperature=0):
    '''
    prompt: 对应的提示
    model: 调用的模型,默认为 gpt-3.5-turbo(ChatGPT),有内测资格的用户可以选择 gpt-4
    temperature: 温度系数
    '''
    messages = [{"role": "user", "content": prompt}]
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=temperature, # 模型输出的温度系数,控制输出的随机程度
    )
    # 调用 OpenAI 的 ChatCompletion 接口
    return response.choices[0].message["content"]
2.定制客户邮件

我们将根据客户评价和情感撰写自定义电子邮件响应。因此,我们将给定客户评价和情感,并生成自定义响应即使用 LLM 根据客户评价和评论情感生成定制电子邮件。

我们首先给出一个示例,包括一个评论及对应的情感

# 我们可以在推理那章学习到如何对一个评论判断其情感倾向
sentiment = "negative"

# 一个产品的评价
review = f"""
他们在11月份的季节性销售期间以约49美元的价格出售17件套装,折扣约为一半。\
但由于某些原因(可能是价格欺诈),到了12月第二周,同样的套装价格全都涨到了70美元到89美元不等。\
11件套装的价格也上涨了大约10美元左右。\
虽然外观看起来还可以,但基座上锁定刀片的部分看起来不如几年前的早期版本那么好。\
不过我打算非常温柔地使用它,例如,\
我会先在搅拌机中将像豆子、冰、米饭等硬物研磨,然后再制成所需的份量,\
切换到打蛋器制作更细的面粉,或者在制作冰沙时先使用交叉切割刀片,然后使用平面刀片制作更细/不粘的效果。\
制作冰沙时,特别提示:\
将水果和蔬菜切碎并冷冻(如果使用菠菜,则轻轻煮软菠菜,然后冷冻直到使用;\
如果制作果酱,则使用小到中号的食品处理器),这样可以避免在制作冰沙时添加太多冰块。\
大约一年后,电机发出奇怪的噪音,我打电话给客服,但保修已经过期了,所以我不得不再买一个。\
总的来说,这些产品的总体质量已经下降,因此它们依靠品牌认可和消费者忠诚度来维持销售。\
货物在两天内到达。
"""

我们已经使用推断课程中学到的提取了情感,这是一个关于搅拌机的客户评价,现在我们将根据情感定制回复。

这里的指令是:假设你是一个客户服务AI助手,你的任务是为客户发送电子邮件回复,根据通过三个反引号分隔的客户电子邮件,生成一封回复以感谢客户的评价。

prompt = f"""
你是一位客户服务的AI助手。
你的任务是给一位重要客户发送邮件回复。
根据客户通过\"\"\"分隔的评价,生成回复以感谢客户的评价。提醒模型使用评价中的具体细节
用简明而专业的语气写信。
作为“AI客户代理”签署电子邮件。
客户评论:
\"\"\"{review}\"\"\"
评论情感:{sentiment}
"""
response = get_completion(prompt)
print(response)

返回:

尊敬的客户,

非常感谢您对我们产品的评价。我们非常抱歉您在购买过程中遇到了价格上涨的问题。我们一直致力于为客户提供最优惠的价格,但由于市场波动,价格可能会有所变化。我们深表歉意,如果您需要任何帮助,请随时联系我们的客户服务团队。

我们非常感谢您对我们产品的详细评价和使用技巧。我们将会把您的反馈传达给我们的产品团队,以便改进我们的产品质量和性能。

再次感谢您对我们的支持和反馈。如果您需要任何帮助或有任何疑问,请随时联系我们的客户服务团队。

祝您一切顺利!

AI客户代理
3.使用温度系数

接下来,我们将使用语言模型的一个称为“温度”的参数,它将允许我们改变模型响应的多样性。您可以将温度视为模型探索或随机性的程度。

例如,在一个特定的短语中,“我的最爱食品”最有可能的下一个词是“比萨”,其次最有可能的是“寿司”和“塔可”。因此,在温度为零时,模型将总是选择最有可能的下一个词,而在较高的温度下,它还将选择其中一个不太可能的词,在更高的温度下,它甚至可能选择塔可,而这种可能性仅为五分之一。您可以想象,随着模型继续生成更多单词的最终响应,“我的最爱食品是比萨”将会与第一个响应“我的最爱食品是塔可”产生差异。因此,随着模型的继续,这两个响应将变得越来越不同。

一般来说,在构建需要可预测响应的应用程序时,我建议使用温度为零。在所有课程中,我们一直设置温度为零,如果您正在尝试构建一个可靠和可预测的系统,我认为您应该选择这个温度。如果您尝试以更具创意的方式使用模型,可能需要更广泛地输出不同的结果,那么您可能需要使用更高的温度。

prompt = f"""
你是一名客户服务的AI助手。
你的任务是给一位重要的客户发送邮件回复。
根据通过\"\"\"分隔的客户电子邮件生成回复,以感谢客户的评价。
如果情感是积极的或中性的,感谢他们的评价。
如果情感是消极的,道歉并建议他们联系客户服务。
请确保使用评论中的具体细节。
以简明和专业的语气写信。
以“AI客户代理”的名义签署电子邮件。
客户评价:\"\"\"{review}\"\"\"
评论情感:{sentiment}
"""
response = get_completion(prompt, temperature=0.7)
print(response)

返回:

尊敬的客户,

非常感谢您对我们产品的评价。我们由衷地为您在购买过程中遇到的问题表示抱歉。我们确实在12月份的第二周调整了价格,但这是由于市场因素所致,并非价格欺诈。我们深刻意识到您对产品质量的担忧,我们将尽一切努力改进产品,以提供更好的体验。

我们非常感激您对我们产品的使用经验和制作技巧的分享。您的建议和反馈对我们非常重要,我们将以此为基础,进一步改进我们的产品。

如果您有任何疑问或需要进一步帮助,请随时联系我们的客户服务部门。我们将尽快回复您并提供帮助。

最后,请再次感谢您对我们产品的评价和选择。我们期待着未来与您的合作。

此致

敬礼

AI客户代理

在温度为零时,每次执行相同的提示时,您应该期望获得相同的完成。而使用温度为0.7,则每次都会获得不同的输出。

所以,您可以看到它与我们之前收到的电子邮件不同。让我们再次执行它,以显示我们将再次获得不同的电子邮件。

因此,我建议您自己尝试温度,以查看输出如何变化。总之,在更高的温度下,模型的输出更加随机。您几乎可以将其视为在更高的温度下,助手更易分心,但也许更有创造力。

7.聊天机器人Prompt设计

使用一个大型语言模型的一个令人兴奋的事情是,我们可以用它来构建一个定制的聊天机器人。在这一节中,我们将探索如何利用聊天格式(接口)与个性化或专门针对特定任务或行为的聊天机器人进行延伸对话。

启动
import os
import openai

OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY2")
openai.api_key = OPENAI_API_KEY

像 ChatGPT 这样的聊天模型实际上是组装成以一系列消息作为输入,并返回一个模型生成的消息作为输出的。虽然聊天格式的设计旨在使这种多轮对话变得容易,但我们通过之前的学习可以知道,它对于没有任何对话的单轮任务也同样有用。

接下来,我们将定义两个辅助函数。第一个是单轮的,我们将prompt放入看起来像是某种用户消息的东西中。另一个则传入一个消息列表。这些消息可以来自不同的角色,我们会描述一下这些角色。

第一条消息是一个系统消息,它提供了一个总体的指示,然后在这个消息之后,我们有用户和助手之间的交替。如果你曾经使用过 ChatGPT 网页界面,那么你的消息是用户消息,而 ChatGPT 的消息是助手消息。系统消息则有助于设置助手的行为和角色,并作为对话的高级指示。你可以想象它在助手的耳边低语,引导它的回应,而用户不会注意到系统消息。

因此,作为用户,如果你曾经使用过 ChatGPT,你可能不知道 ChatGPT 的系统消息是什么,这是有意为之的。系统消息的好处是为开发者提供了一种方法,在不让请求本身成为对话的一部分的情况下,引导助手并指导其回应。

def get_completion(prompt, model="gpt-3.5-turbo"):
    messages = [{"role": "user", "content": prompt}]
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=0, # 控制模型输出的随机程度
    )
    return response.choices[0].message["content"]

def get_completion_from_messages(messages, model="gpt-3.5-turbo", temperature=0):
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=temperature, # 控制模型输出的随机程度
    )
#     print(str(response.choices[0].message))
    return response.choices[0].message["content"]

现在让我们尝试在对话中使用这些消息。我们将使用上面的函数来获取从这些消息中得到的回答,同时,使用更高的 temperature(越高生成的越多样)。

系统消息说,你是一个说话像莎士比亚的助手。这是我们向助手描述它应该如何表现的方式。然后,第一个用户消息是,给我讲个笑话。接下来的消息是,为什么鸡会过马路?然后最后一个用户消息是,我不知道。

messages =  [  
{'role':'system', 'content':'你是一个像莎士比亚一样说话的助手。'},    
{'role':'user', 'content':'给我讲个笑话'},   
{'role':'assistant', 'content':'鸡为什么过马路'},   
{'role':'user', 'content':'我不知道'}  ]

response = get_completion_from_messages(messages, temperature=1)
print(response)

返回:

因为它要去找“母鸡”。哈哈哈!(注:此为英文双关语,"chicken"是鸡的意思,也是胆小的意思;"cross the road"是过马路的意思,也是“破坏规则”的意思。)

让我们做另一个例子。助手的消息是,你是一个友好的聊天机器人,第一个用户消息是,嗨,我叫Isa。我们想要得到第一个用户消息。

messages =  [  
{'role':'system', 'content':'你是个友好的聊天机器人。'},    
{'role':'user', 'content':'Hi, 我是Isa。'}  ]
response = get_completion_from_messages(messages, temperature=1)
print(response)

返回:

嗨,Isa,很高兴见到你!有什么我可以帮助你的吗?

让我们再试一个例子。系统消息是,你是一个友好的聊天机器人,第一个用户消息是,是的,你能提醒我我的名字是什么吗?

messages =  [  
{'role':'system', 'content':'你是个友好的聊天机器人。'},    
{'role':'user', 'content':'好,你能提醒我,我的名字是什么吗?'}  ]
response = get_completion_from_messages(messages, temperature=1)
print(response)

返回:

抱歉,我不知道您的名字,因为我们是虚拟的聊天机器人和现实生活中的人类在不同的世界中。

如上所见,模型实际上并不知道我的名字。

因此,每次与语言模型的交互都是一个独立的交互,这意味着我们必须提供所有相关的消息,以便模型在当前对话中进行引用。如果想让模型引用或 “记住” 对话的早期部分,则必须在模型的输入中提供早期的交流。我们将其称为上下文。让我们试试。

messages =  [  
{'role':'system', 'content':'你是个友好的聊天机器人。'},
{'role':'user', 'content':'Hi, 我是Isa'},
{'role':'assistant', 'content': "Hi Isa! 很高兴认识你。今天有什么可以帮到你的吗?"},
{'role':'user', 'content':'是的,你可以提醒我, 我的名字是什么?'}  ]
response = get_completion_from_messages(messages, temperature=1)
print(response)

返回:

当然可以!您的名字是Isa。

现在我们已经给模型提供了上下文,也就是之前的对话中提到的我的名字,然后我们会问同样的问题,也就是我的名字是什么。因为模型有了需要的全部上下文,所以它能够做出回应,就像我们在输入的消息列表中看到的一样。

订餐机器人

现在,我们构建一个 “订餐机器人”,我们需要它自动收集用户信息,接受比萨饼店的订单。

下面这个函数将收集我们的用户消息,以便我们可以避免手动输入,就像我们在刚刚上面做的那样。这个函数将从我们下面构建的用户界面中收集提示,然后将其附加到一个名为上下文的列表中,并在每次调用模型时使用该上下文。模型的响应也会被添加到上下文中,所以模型消息和用户消息都被添加到上下文中,因此上下文逐渐变长。这样,模型就有了需要的信息来确定下一步要做什么。

def collect_messages(_):
    prompt = inp.value_input
    inp.value = ''
    context.append({'role':'user', 'content':f"{prompt}"})
    response = get_completion_from_messages(context) 
    context.append({'role':'assistant', 'content':f"{response}"})
    panels.append(
        pn.Row('User:', pn.pane.Markdown(prompt, width=600)))
    panels.append(
        pn.Row('Assistant:', pn.pane.Markdown(response, width=600, style={'background-color': '#F6F6F6'})))

    return pn.Column(*panels)

现在,我们将设置并运行这个 UI 来显示订单机器人。初始的上下文包含了包含菜单的系统消息。请注意,上下文会随着时间的推移而不断增长。

!pip install panel
import panel as pn  # GUI
pn.extension()

panels = [] # collect display 

context = [{'role':'system', 'content':"""
你是订餐机器人,为披萨餐厅自动收集订单信息。
你要首先问候顾客。然后等待用户回复收集订单信息。收集完信息需确认顾客是否还需要添加其他内容。
最后需要询问是否自取或外送,如果是外送,你要询问地址。
最后告诉顾客订单总金额,并送上祝福。

请确保明确所有选项、附加项和尺寸,以便从菜单中识别出该项唯一的内容。
你的回应应该以简短、非常随意和友好的风格呈现。

菜单包括:

菜品:
意式辣香肠披萨(大、中、小) 12.95、10.00、7.00
芝士披萨(大、中、小) 10.95、9.25、6.50
茄子披萨(大、中、小) 11.95、9.75、6.75
薯条(大、小) 4.50、3.50
希腊沙拉 7.25

配料:
奶酪 2.00
蘑菇 1.50
香肠 3.00
加拿大熏肉 3.50
AI酱 1.50
辣椒 1.00

饮料:
可乐(大、中、小) 3.00、2.00、1.00
雪碧(大、中、小) 3.00、2.00、1.00
瓶装水 5.00
"""} ]  # accumulate messages


inp = pn.widgets.TextInput(value="Hi", placeholder='Enter text here…')
button_conversation = pn.widgets.Button(name="Chat!")

interactive_conversation = pn.bind(collect_messages, button_conversation)

dashboard = pn.Column(
    inp,
    pn.Row(button_conversation),
    pn.panel(interactive_conversation, loading_indicator=True, height=300),
)
dashboard
messages =  context.copy()
messages.append(
{'role':'system', 'content':'创建上一个食品订单的 json 摘要。\
逐项列出每件商品的价格,字段应该是 1) 披萨,包括大小 2) 配料列表 3) 饮料列表,包括大小 4) 配菜列表包括大小 5) 总价'},    
)

response = get_completion_from_messages(messages, temperature=0)
print(response)

以下是上一个食品订单的 JSON 摘要:

{
  "order": {
    "pizza": {
      "type": "芝士披萨",
      "size": "大",
      "price": 10.95
    },
    "toppings": [
      {
        "name": "蘑菇",
        "price": 1.5
      }
    ],
    "drinks": [
      {
        "name": "雪碧",
        "size": "大",
        "price": 3
      },
      {
        "name": "雪碧",
        "size": "大",
        "price": 3
      }
    ],
    "sides": [],
    "total_price": 18.45
  }
}

现在,我们已经建立了自己的订餐聊天机器人。请随意自定义并修改系统消息,以更改聊天机器人的行为,并使其扮演不同的角色和拥有不同的知识。

二、OpenAI API基础教程

1.OpenAI(ChatGPT开发) API 介绍

OpenAI

OpenAI是一家人工智能研究公司,由伊隆·马斯克、萨姆·阿尔特曼等人创立于2015年,总部位于美国加州旧金山。

OpenAI的主要业务包括人工智能研究、开发和应用,旨在通过人工智能技术实现自动化、智能化和普惠性。公司的研究团队在自然语言处理、计算机视觉、强化学习等领域取得了很多成果,如在语言模型方面推出了GPT系列模型,这些模型在机器翻译、文本生成、自然语言理解等任务中都取得了很好的效果。

ChatGPT

ChatGPT是基于GPT技术的一种对话生成模型,由OpenAI推出,可用于构建智能客服、聊天机器人等应用场景。它是一种可以自动学习并生成自然语言的人工智能模型。

OpenAI API

OpenAI API是一款由OpenAI推出的人工智能API服务,提供了包括自然语言处理、图像处理等在内的多种功能。

OpenAI API支持的应用场景包括:

  1. 自然语言处理: OpenAI API可以实现自然语言处理相关的任务,如情感分析、文本摘要、文本翻译等。
  2. 对话生成: 使用ChatGPT功能,可以构建智能客服、聊天机器人等应用场景。
  3. 图像处理: OpenAI API提供了图像处理相关的功能,如图像分类、目标检测等。
  4. 文本生成: OpenAI API可以生成各种类型的文本,如新闻报道、小说、诗歌等。
  5. 语音处理: OpenAI API可以处理语音相关的任务,如语音识别、语音合成等。

2.OpenAI 关键概念

模型(Models)

OpenAI API提供了多种不同的预训练模型,可以用于解决各种人工智能任务。这些模型包括自然语言处理、图像处理、推荐系统等领域,如GPT、DALL-E等。用户可以根据自己的需求选择合适的模型来进行应用开发。

提示:AI模型就是一种用来完成某项任务的计算机程序,它可以根据输入的数据进行学习和预测,并输出相应的结果。

Prompt(提示)

大家玩过ChatGPT,在聊天框输入的内容,就是Prompt。

在ChatGPT中,Prompt是指用户输入的对话开场白或上下文,用于指导模型生成相应的对话回复。Prompt对于ChatGPT模型的输出结果具有非常重要的影响,可以决定模型生成的对话回复的风格、主题和连贯性等。

提示:Prompt(提示)是我们控制AI的指令,所以普通用户都称他为”咒语“,AI能不能返回我们想要的内容,关键就是你能不能把问题描述清楚。

Tokens

在OpenAI API中,Token指的是文本处理中的最小单元,比如单词、标点符号、数字等。在文本处理中,通常会将文本切分成一个一个的Token,然后再进行后续的处理和分析。

在OpenAI API中,文本处理的计费方式是按照Tokens的数量计算的。

对于不同的模型和任务,每个Token的计费方式和价格会有差异。在使用OpenAI API进行文本处理时,系统会自动计算输入文本中的Token数量,并按照所选模型和任务的价格进行计费。一般来说,使用较复杂的模型和任务,所需的Token数量会更多,计费也会更高。

API KEY

API KEY是OpenAI API的访问密钥,用于标识和验证API的调用者。用户需要先在OpenAI官网注册账号并申请API KEY。

3.OpenAI SDK介绍

官方REST API

OpenAI官方提供Http API接口,任何开发语言都可以直接通过Http请求调用接口。其他各种编程语言的SDK也是对官网Http API的封装。

提示:本教程,仅从Http API接口角度讲解,其他开发语言的SDK参数含义跟HTTP API参数数一样的。

Python SDK

官方Python SDK例子

1.安装库

pip install openai

2.Python例子

import os
import openai

# 官网申请的API KEY
openai.api_key = os.getenv("OPENAI_API_KEY")

# 调用AI模型
response = openai.Completion.create(model="text-davinci-003", prompt="你是谁?", temperature=0, max_tokens=7)
Node.js SDK

官方Node.js例子

1.安装依赖

npm install openai

2.Node.js例子

const { Configuration, OpenAIApi } = require("openai");
// 官网申请的API key
const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

// 调用模型
const response = await openai.createCompletion({
  model: "text-davinci-003",
  prompt: "你是谁?",
  temperature: 0,
  max_tokens: 7,
});
其他社区SDK

如果不想直接调用http api可以到github找社区开发者封装的SDK

4.OpenAI API Key申请&API 安全认证

1.登录OpenAI

访问 https://platform.openai.com/ 下面是登录后的页面

img

说明:账号注册,网上已经很多教程,这里就不再重复。

2.申请API KEY

点击个人信息,选择 View API keys 菜单
img

进入API keys页面,在这里创建API KEY,保存好即可。
img

3.REST API安全认证

OpenAI API 使用 API 密钥进行身份验证。主要通过Http请求头设置前面申请到的API KEY即可。

3.1.http请求头

OPENAI_API_KEY 代表个人申请的api key

Authorization: Bearer OPENAI_API_KEY
3.2.API认证例子

查询OpenAI目前支持的所有模型列表

curl https://api.openai.com/v1/models \
  -H "Authorization: Bearer $OPENAI_API_KEY"

返回:

{
  "data": [
    {
      "id": "model-id-0",
      "object": "model",
      "owned_by": "organization-owner",
      "permission": [...]
    },
    {
      "id": "model-id-1",
      "object": "model",
      "owned_by": "organization-owner",
      "permission": [...]
    },
    {
      "id": "model-id-2",
      "object": "model",
      "owned_by": "openai",
      "permission": [...]
    },
  ],
  "object": "list"
}

说明:id就是模型id,后续的接口调用会用到,需要传入一个我们希望使用的模型id,例如:gpt-3.5-turbo 这个模型id

5.OpenAI 模型介绍

OpenAI模型分类

OpenAI 提供多种不同功能的模型,每种的模型的功能和价格都有所差异,模型分类如下:

模型名称模型描述
GPT-4一组在 GPT-3.5 上改进的模型,可以理解并生成自然语言或代码
GPT-3.5一组在 GPT-3 上改进的模型,可以理解并生成自然语言或代码
DALL·E可以在给定自然语言提示的情况下生成和编辑图像的模型
Whisper一种可以将音频转换为文本的模型
Embeddings一组可以将文本转换为数字形式的模型
Moderation可以检测文本是否敏感或不安全的微调模型
GPT-3一组可以理解和生成自然语言的模型

提示:前面只是大的模型分类,有些模型还有很多小的分类,详情请参考后续章节。

GPT-4

GPT-4 是一个大型多模态模型(目前支持文本输入和文本输出,将来会支持图像输入),由于其更广泛的常识和高级推理,它可以比我们以前的任何模型更准确地解决难题能力。与 gpt-3.5-turbo 一样,GPT-4 针对聊天进行了优化,但也适用于传统的任务。

下面是GPT-4相关模型介绍:

模型介绍最大Tokens
gpt-4比任何 GPT-3.5 模型都更强大,能够执行更复杂的任务,并针对聊天进行了优化。8,192 tokens
gpt-4-0314gpt-4 2023 年 3 月 14 日的快照。与 gpt-4 不同,此模型不会收到更新,并且仅在 2023 年 6 月 14 日结束的三个月内提供支持。8,192 tokens
gpt-4-32k与基本 gpt-4 模式相同的功能,但上下文长度是其 4 倍。将使用我们最新的模型迭代进行更新。32,768 tokens
gpt-4-32k-0314gpt-4-32 2023 年 3 月 14 日的快照。与 gpt-4-32k 不同,此模型不会收到更新,并且仅在 2023 年 6 月 14 日结束的三个月内提供支持。32,768 tokens
GPT-3.5

GPT-3.5 模型可以理解并生成自然语言或代码。目前模型推理速度比GPT4块

模型介绍最大Tokens
gpt-3.5-turbo功能最强大的 GPT-3.5 模型并针对聊天进行了优化,成本仅为 text-davinci-003 的 1/10。4,096 tokens
gpt-3.5-turbo-0301gpt-3.5-turbo 的快照,2023 年 3 月 1 日。与 gpt-3.5-turbo 不同,此模型不会收到更新,并且仅在 2023 年 6 月 1 日结束的三个月内提供支持。4,096 tokens
text-davinci-003比curie, babbage, 和 ada 模型更好的质量、支持更长的文本输出4,097 tokens
text-davinci-002与 text-davinci-003 类似的功能,但使用监督微调而不是强化学习进行训练4,097 tokens
code-davinci-002针对代码生成相关任务进行优化的模型8,001 tokens
Embeddings

Embeddings主要用于生成文本向量,嵌入(Embeddings)是文本的数字表示,可用于衡量两段文本之间的相关性。我们的第二代嵌入模型 text-embedding-ada-002 旨在以一小部分成本取代之前的 16 种第一代嵌入模型。Embeddings可用于搜索、聚类、推荐、异常检测和分类任务。

6.OpenAI Prompt提示语

1.Prompt介绍

Prompt 是 GPT 系列语言模型中的一个特性,它可以通过提供一些指令或者例子来“命令”模型,让它完成各种不同的自然语言处理任务,例如生成内容或代码、文本摘要、对话、创意写作、风格转换等。通过设计合适的 Prompt,我们可以让模型更好地理解我们的任务需求,并生成符合我们要求的结果。简单来说,Prompt 是用来指导模型生成文本的一种方式,可以看做是模型的输入。

说明:在调用OpenAI的API,核心就是通过Prompt描述自己的需求或者问题,然后调用AI接口回答问题。

2.Prompt例子
2.1.生成SQL

Prompt提示语:

# 生成一个查询所有订单信息的 SQL 语句。
# MYSQL数据表名:orders,查询条件:状态为"已发货"。
SQL:

ChatGPT返回:

SELECT * FROM orders WHERE status='已发货';
2.2.生成Go代码

Prompt提示语:

## 生成Go代码,要求如下:
1、函数签名: OpenAiTask(prompt string) string
2、函数功能要求:调用OpenAi completions接口,执行prompt查询

## 下面是生成的Go代码

ChatGPT返回:

package main

import (
    "bytes"
    "encoding/json"
    "io/ioutil"
    "net/http"
    "strings"
)

func OpenAiTask(prompt string) string {
    url := "https://api.openai.com/v1/completions"
    data := `{"prompt": "` + prompt + `", "max_tokens": 1024, "n": 1, "stop": ".", "model": "text-davinci-002", "temperature": 0.7}`
    req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(data)))
    if err != nil {
        return "Error: " + err.Error()
    }
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Authorization", "Bearer YOUR_API_KEY")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return "Error: " + err.Error()
    }
    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "Error: " + err.Error()
    }

    var result map[string]interface{}
    err = json.Unmarshal(body, &result)
    if err != nil {
        return "Error: " + err.Error()
    }

    choices, ok := result["choices"].([]interface{})
    if !ok || len(choices) == 0 {
        return "Error: empty response from API"
    }

    text, ok := choices[0].(map[string]interface{})["text"].(string)
    if !ok {
        return "Error: invalid response format from API"
    }

    return strings.TrimSpace(text)
}
3.Prompt提示语设计
明确任务需求

在编写 Prompt 提示语时,要明确任务的具体需求,包括任务的类型、目标和输入输出等。

使用简明易懂的语言

Prompt 提示语应该使用简明易懂的语言,避免使用过于专业化或复杂的术语和概念,让模型能够更好地理解和处理。

提供足够的信息

Prompt 提示语需要提供足够的高质量信息,以帮助模型更好地理解和学习任务的相关知识和技能。

说明:在跟GPT模型对话过程,需要先给GPT输入一定数量的背景信息,提高GPT模型回答问题的质量。

使用具有代表性的示例

Prompt 提示语应该包含具有代表性的示例,以帮助模型更好地理解任务需求和数据特征,提高模型的准确性和效率。

说明:如果你希望GPT根据你指定的格式,回答问题,例如:以markdown格式返回、以表格方式返回等,需要先给一个返回格式例子,让GPT根据指定格式返回。

制定明确的标签和类别

Prompt 提示语需要制定明确的标签和类别,以便模型能够更好地对数据进行分类和分析。

避免模糊或歧义的语言

Prompt 提示语需要避免使用模糊或歧义的语言,以免让模型产生混淆或错误的理解和判断。

提示:Prompt提示语设计核心就是自己需要先把问题描述清楚,。

7.OpenAI 快速入门

1.入门介绍

OpenAI 的核心API接口之一,就是https://api.openai.com/v1/completions,直接调用各种AI模型,完成下游任务。

提示:日常问答、生成代码、代码检测、问题分类等等都可以调用这个接口完成任务,就是你有什么问题直接调用这个接口,问AI就行。

2.API认证

调用API需要在http请求头设置token

例子:

Authorization: Bearer OPENAI_API_KEY

OPENAI_API_KEY就是你申请的token

提示:请求参考:API Token申请

3.调用AI完成任务

prompt提示语

### PostgreSQL 数据表及其属性:
#
# Employee(id, name, department_id)
# Department(id, name, address)
# Salary_Payments(id, employee_id, amount, date)
#
### 查询最近 3 个月雇用了超过 10 名员工的部门名称列表
SELECT

POST请求参数:

{
    "model": "text-davinci-003",
    "prompt": "### PostgreSQL 数据表及其属性:## Employee(id, name, department_id)# Department(id, name, address)# Salary_Payments(id, employee_id, amount, date)#### 查询最近 3 个月雇用了超过 10 名员工的部门名称列表SELECT",
    "temperature": 0
}

参数说明:

  • model 选什么模型,这里选择text-davinci-003模型
  • prompt 提示语参数
  • temperature - Temperature 是一种用于控制生成文本多样性的超参数,取值 0-2,取值越低,代表多样式越低,选择0,基本上每次返回的结果都一样,如果取值越大,每次返回的结果可能都不一样

下面是以curl命令发出的http请求

curl --location --request POST --X POST 'https://api.openai.com/v1/completions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer $OPENAI_API_KEY' \
--data '{
    "model": "text-davinci-003",
    "prompt": "### PostgreSQL 数据表及其属性:## Employee(id, name, department_id)# Department(id, name, address)# Salary_Payments(id, employee_id, amount, date)#### 查询最近 3 个月雇用了超过 10 名员工的部门名称列表SELECT",
    "temperature": 0
}'
4.关于Temperature超参数

在 OpenAI API 中,Temperature 是一种用于控制生成文本多样性的超参数,比如 GPT 系列模型。它的取值范围通常为 0 到 2,表示生成文本的多样性程度。

具体地说,当 Temperature 的值较低时,生成的文本会趋于更加确定和重复,而当 Temperature 的值较高时,生成的文本会更加随机和多样化。举例来说,如果 Temperature 值为 0.5,则生成文本的多样性会比 Temperature 值为 0.1 或 0.9 的时候更为中等。

8.Function calling(函数调用)

1. Function calling介绍

在GPT模型中,Function calling(函数调用)是指通过API向模型提供描述性的函数,使其能够智能地选择输出一个包含参数的JSON对象,以便调用一个或多个函数。值得注意的是,Chat Completions API并不直接执行函数调用,而是生成可以用于在代码中执行函数的JSON。

通俗的讲Function calling功能就是我们提供一组函数的定义(包括函数的功能描述、参数描述),把函数的定义传递给GPT模型,由模型根据用户的问题决定要调用那个函数,由于模型无法执行我们定义的外部函数,模型只能以请求响应的方式返回希望调用那个函数(包括函数调用参数),我们程序收到模型请求结果后,在本地执行函数调用,然后把函数调用的结果拼接到提示词中再次传给模型,让模型进一步处理,最后在把结果返回给用户。

2. Function calling的应用场景

以下是其在实际应用中的一些例子:

  • 创建调用外部API回答问题的助手,例如定义函数send_email(to: string, body: string)get_current_weather(location: string, unit: 'celsius' | 'fahrenheit')
  • 将自然语言转换为API调用,例如将“Who are my top customers?”转换为get_customers(min_revenue: int, created_before: string, limit: int)然后调用内部API。
  • 从文本中提取结构化数据,例如定义函数extract_data(name: string, birthday: string)sql_query(query: string)

利用函数调用功能,我们可以实现智能体(AI Agent),让AI可以跟我们本地的系统、数据库互动,例如让AI去查询最新的天气、查询股票价格、让AI去点外卖、订机票等等。

3. 支持Function calling的模型

并非所有版本的模型都经过了函数调用数据的训练。目前支持函数调用的模型有:gpt-4gpt-4-turbo-previewgpt-4-0125-previewgpt-4-1106-previewgpt-4-0613gpt-3.5-turbogpt-3.5-turbo-1106gpt-3.5-turbo-0613

此外,模型gpt-4-turbo-previewgpt-4-0125-previewgpt-4-1106-previewgpt-3.5-turbo-1106支持并行函数调用功能,这允许它们一次性执行多个函数调用,并且能够并行解决这些函数调用效果和结果。

提示:Function calling功能带来的潜在风险在于,它可能导致模型产生错误参数(即幻觉参数)。因此,在代表用户对外界产生实际影响之前(例如发送电子邮件、在线发布、进行购买等),建议在产品层面增加用户确认流程,用户确认之后再执行函数。

4. Function calling例子
4.1 python例子

在OpenAI平台上实现Function calling通常遵循下面的基本步骤,以下将通过查询天气的案例,使用Python代码详细讲解整个过程。

步骤1: 准备可被模型调用的函数和函数定义

首先,我们需要定义一个可以被GPT模型调用的函数。这通常意味着我们需要准备一个我们自己的函数,这个函数能够根据传入的参数执行某些操作,比如与第三方API通信。

import json

# 这是一个假设的函数,用于获取当前的天气情况
def get_current_weather(location, unit="fahrenheit"):
    # 在实际应用中,这里会与某个天气API接口进行交互来获取数据
    # 这里为了简化示例返回了固定的数据
    return json.dumps({
        "location": location, 
        "temperature": "18", 
        "unit": unit
    })
步骤2: 根据问题和tools参数调用模型

接下来,我们需要通过Chat Completion API调用GPT模型,并传入用户的查询(如“当前天气如何”),以及tools参数,其中包含了我们刚刚定义的get_current_weather函数的描述。

from openai import OpenAI

client = OpenAI()

# 定义tools参数,其中包含了get_current_weather函数的描述
tools = [{
    "type": "function",
    "function": {
        "name": "get_current_weather",
        "description": "获取给定地点的当前天气",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "城市名称,例如:“旧金山,CA”"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"]
                }
            },
            "required": ["location"]
        }
    }
}]

# 发起调用,传入用户的问题
response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=[{"role": "user", "content": "旧金山当前的天气如何?"}],
    tools=tools
)
步骤3: 本地执行函数

模型返回的结果会包含模型希望调用的函数,函数信息通常包含在tool_calls响应参数中,我们就可以根据tool_calls参数描述的函数调用信息,在本地执行相应的函数调用。

# 解析模型响应中的tool_calls
tool_calls = response.choices[0].message.tool_calls

# 如果模型确定要调用一个函数
if tool_calls:
    # 获取模型生成的参数
    # ps: 这里只是假设模型仅调用一个函数,实际上有可能调用多个函数
    arguments = json.loads(tool_calls[0].function.arguments)
    # 执行我们之前定义的函数
    # ps: 这里为了演示以硬编码的方式调用本地函数,实际业务你可以根据tool_calls参数动态的选择调用本地函数。
    weather_info = get_current_weather(**arguments)
    print(weather_info) # 我们可以在这里看到函数调用查询到的天气信息
步骤4: 通过函数返回结果再次调用模型

现在,我们可以将函数返回的结果作为一个新的消息发送给模型,这样模型就可以对这些结果进行处理并生成一个面向用户的响应。

# 使用刚才函数返回的结果继续与模型对话
follow_up_response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": "旧金山当前的天气如何?"},
        {"role": "function", "name": "get_current_weather", "content": weather_info}
    ],
    tools=tools
)

说明:
上面例子通过function消息的方式,告诉gpt函数返回内容

{"role": "function", "name": "get_current_weather", "content": weather_info}

实际上,你也可以简单的把函数返回的内容作为参考内容放到sytem消息prompt里面,让AI参考这些信息回答问题。

步骤5: 获取模型最终响应结果

最后,我们可以获取模型的最终响应并将其提供给用户。在此步骤中,模型会根据我们给予的天气信息输出一个面向用户友好的回答。

# 处理得到最终的模型响应
final_output = follow_up_response.choices[0].message.content
print(final_output) # 这个输出就是我们要展示给用户的天气信息

通过以上步骤,我们就完成了一个使用GPT模型以及函数调用的完整的查询天气的例子。

4.2. Function call函数定义说明
4.2.1 Tools参数的字段含义

函数调用(Function Call)在使用时,需要在tools参数中定义函数的相关信息。tools参数是一个包含多个函数定义的数组,每个函数定义包含以下字段:

  1. type: 此字段表示工具的类型,在函数调用中该字段应设为"function"

  2. function
    

    : 此字段包含函数的详细信息,是一个对象,其具体字段如下:

    • name: 函数的名称,是一个字符串。

    • description: 对函数作用的描述,可以帮助模型生成符合用户期望的参数。

    • parameters
      

      : 描述函数的参数定义,是一个对象,该对象包含下列子字段:

      • type: 定义参数的类型,在大多数情况下应设为"object"

      • properties
        

        : 函数的每个参数的具体定义,每个参数定义都是一个对象,通常包含下列子字段:

        • type: 参数的数据类型(如"string""integer""boolean"等)。
        • description: 此参数的描述,以帮助模型理解其用途。
        • enum (可选): 当type"string"时,enum字段可以指定一个字符串的数组,表示有效值的集合。
      • required: 一个包含必填参数名称的字符串数组。

4.2.2 Tools定义示例

现在我们将提供几个tools定义的例子,以便于理解每个字段如何使用。

示例 1:获取当前天气信息

{
    "type": "function",
    "function": {
        "name": "get_current_weather",
        "description": "获取指定地点的当前天气信息",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "需要查询天气的城市,如'San Francisco, CA'"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "温度单位,'celsius'表示摄氏度,'fahrenheit'表示华氏度"
                }
            },
            "required": ["location", "unit"]
        }
    }
}

在上述示例中,我们定义了一个名为get_current_weather的函数,用于获取指定地点的当前天气。参数包括location(位置)和unit(单位),其中unit有两个有效值:”celsius”(摄氏度)和”fahrenheit”(华氏度)。

示例 2:查找特定艺术家的专辑

{
    "type": "function",
    "function": {
        "name": "find_artist_albums",
        "description": "查找特定艺术家的所有专辑",
        "parameters": {
            "type": "object",
            "properties": {
                "artist_name": {
                    "type": "string",
                    "description": "艺术家的名称"
                }
            },
            "required": ["artist_name"]
        }
    }
}

在这个示例中,我们创建了一个名为find_artist_albums的函数,它的作用是查找特定艺术家的所有专辑。此函数只需要一个参数:artist_name(艺术家名称)。

4.3. http请求function call例子

OpenAI是通过http协议的方式开放API,下面讲解如何通过http api使用function call功能,其他编程语言的开发者可以参考这个例子。

4.3.1. 步骤1:通过用户问题和函数声明调用模型

首先我们需要把用户的问题和我们支持的函数清单一起发给GPT模型,让模型根据用户的问题自动分析需要调用那个函数来回答用户问题。

下面例子,告诉GPT我们有一个get_current_weather函数可以用来查询指定城市的天气信息。

curl --location 'https://api.aiproxy.io/v1/chat/completions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {OPENAI_KEY}' \
--data '{
    "model": "gpt-3.5-turbo",
    "messages": [
        {
            "role": "user",
            "content": "今天上海天气怎么样?"
        }
    ],
    "tools": [
        {
            "type": "function",
            "function": {
                "name": "get_current_weather",
                "description": "获取指定地点的当前天气信息",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "需要查询天气的城市,如'\''San Francisco, CA'\''"
                        },
                        "unit": {
                            "type": "string",
                            "enum": [
                                "celsius",
                                "fahrenheit"
                            ],
                            "description": "温度单位,'\''celsius'\''表示摄氏度,'\''fahrenheit'\''表示华氏度"
                        }
                    },
                    "required": [
                        "location",
                        "unit"
                    ]
                }
            }
        }
    ]
}'

请求参数说明:

{
    "model": "gpt-3.5-turbo", // 需要调用的gpt模型
    "messages": [ // 这里是gpt的消息列表,包括用户的问题
        {
            "role": "user",
            "content": "今天上海天气怎么样?"
        }
    ],
    "tools": [
      // 这里是你的函数定义,告诉gpt有什么函数可以调用
    ]
}

tools参数定义参考4.2.2章节。

GPT模型正常处理的情况下,你会得到类似下面的API响应结果:

{
    "model": "gpt-3.5-turbo-0613",
    "object": "chat.completion",
    "usage": {
        "prompt_tokens": 122,
        "completion_tokens": 27,
        "total_tokens": 149
    },
    "id": "chatcmpl-8mL4hS4zNMocyR2ajKyAvSTcbNaao",
    "created": 1706531447,
    "choices": [
        {
            "index": 0,
            "delta": null,
            "message": {
                "role": "assistant",
                "tool_calls": [ // tool_calls参数代表GPT希望调用的函数列表
                    {
                        "id": "call_1iF09ttX1R9ESR18Ul2nLe1R",
                        "type": "function",
                        "function": {
                            "name": "get_current_weather",  // 代表GPT希望通过调用get_current_weather函数,回答用户问题。
                            "arguments": "{\n  \"location\": \"Shanghai, China\",\n  \"unit\": \"celsius\"\n}" // 这里是调用get_current_weather函数的输入参数
                        }
                    }
                ]
            },
            "finish_reason": "tool_calls"
        }
    ]
}
4.3.2. 步骤2:本地执行函数调用

因为GPT模型本身是没法执行具体的函数调用,只是告诉我们希望调用那个函数,因此我们本地程序需要根据模型请求返回的tool_calls参数,执行具体函数调用,不同编程语言执行本地函数的方式不一样,python的例子,可以参考前面章节。

4.3.3. 步骤3:通过函数返回结果再次调用模型

因为函数的调用是在本地执行的,所以我们需要把函数执行的结果和用户的问题再次送入GPT模型,让GPT做出最终的回答。

curl --location 'https://api.aiproxy.io/v1/chat/completions' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer sk-Roc5MX1zEuVxiuaMaETV6wZ2jXcCehjUCzwP9AcNErUiwppQ' \
--data '{
    "model": "gpt-3.5-turbo",
    "messages": [
        {
            "role": "user",
            "content": "今天上海天气怎么样?"
        },
        {
            "role": "function",
            "name": "get_current_weather",
            "content": "{\"city\":\"上海\", \"temperature\":\"25摄氏度\"}"
        }
    ],
    "tools": [
        {
            "type": "function",
            "function": {
                "name": "get_current_weather",
                "description": "获取指定地点的当前天气信息",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "location": {
                            "type": "string",
                            "description": "需要查询天气的城市,如'\''San Francisco, CA'\''"
                        },
                        "unit": {
                            "type": "string",
                            "enum": [
                                "celsius",
                                "fahrenheit"
                            ],
                            "description": "温度单位,'\''celsius'\''表示摄氏度,'\''fahrenheit'\''表示华氏度"
                        }
                    },
                    "required": [
                        "location",
                        "unit"
                    ]
                }
            }
        }
    ]
}'

说明,上面请求多了一条function消息告诉GPT模型函数的返回值,GPT会根据函数返回信息直接回答用户问题,不会再调用函数。

function消息,代表函数的返回值,格式如下:

 {
            "role": "function", // 消息类型是function,代表函数返回值
            "name": "get_current_weather", // 告诉gpt当前消息是get_current_weather函数的返回值
            "content": "{\"city\":\"上海\", \"temperature\":\"25摄氏度\"}"  // 函数返回内容,可以是json格式,也可以是其他文本内容。
}

下面是GPT做出的最终回答:

{
    "model": "gpt-3.5-turbo-0613",
    "object": "chat.completion",
    "usage": {
        "prompt_tokens": 144,
        "completion_tokens": 17,
        "total_tokens": 161
    },
    "id": "chatcmpl-8mLmvvKAjSql7rGF8fvQeddKhWYvr",
    "created": 1706534189,
    "choices": [
        {
            "index": 0,
            "delta": null,
            "message": {
                "role": "assistant",
                "content": "今天上海的天气是25摄氏度。"
            },
            "finish_reason": "stop"
        }
    ]
}

9.Embeddings(文本嵌入)

1.嵌入(Embeddings)简介
1.1. 什么是嵌入(Embeddings)

嵌入,或者叫做Embeddings,在机器学习领域,尤其是在处理自然语言处理(NLP)问题时,是一种将文本数据转换为数值向量的技术。在人类语言中,单词和短语的意义是由它们的上下文和使用环境决定的。嵌入的目标是捕获这些语言单位的语义,使计算机可以理解和处理它们。

Embeddings的核心思想是将类似意思的词语映射到数学空间中的临近点,即,将词语表示为高维空间中的点,这样语义上相似的词(例如“国王”和“王后”)在空间中的距离会很近。Embeddings通常由浮点数组成,即使是非常不同的文本片段(如“dog”和“canine”),也可以有相似的嵌入表示。

提示:作为应用开发者,你可以简单的理解意思相近的两个文本句子,他们之间的Embeddings向量相似度是很高的。

1.2. 嵌入的应用场景

Embeddings广泛应用于多种场景,下面是一些主要的用例:

  1. 搜索(Search):通过嵌入特征,可以根据与查询文本的相关性来排列搜索结果。
  2. 聚类(Clustering):嵌入可以帮助识别和归纳语义上相似的文本片段,形成群组。
  3. 推荐系统(Recommendations):基于相关性推荐可以帮助发现并推荐与已知项相似的其他项。
  4. 异常检测(Anomaly Detection):嵌入可以用来识别与主要数据集显著不同的数据点。
  5. 多样性度量(Diversity Measurement):嵌入也可以用于分析不同文本之间的相似性分布。
  6. 分类(Classification):通过将文本与一组已知标签的嵌入进行比较,可以将其分类到最相似的类别中。
2.OpenAI Embeddings介绍
2.1. OpenAI Embeddings模型概览5

OpenAI提供了第三代嵌入模型,包括text-embedding-3-smalltext-embedding-3-large。这些模型是基于OpenAI独特的深度学习技术构建的,旨在提供高度多语言性能,同时它们也在设法降低成本。

这些模型在处理嵌入时,具有各自独特的特点。例如,text-embedding-3-small提供了1536维的嵌入向量,而text-embedding-3-large则提供了3072维的嵌入向量,用于涵盖更加复杂的文本特性。通过调整参数,可以控制嵌入的维数,以满足特定应用场景的需求。

2.2. 模型的选择与使用

选择合适的嵌入模型取决于特定应用的要求。以下是如何在不同应用场景中做出选择:

  1. 在关注性能的场景下:如果需要捕获更细粒度的语义信息,比如在精细化推荐系统或者高精度文本分类中,通常推荐使用text-embedding-3-large,虽然它的成本比小模型要高,但能提供更丰富的文本特征表示。
  2. 在成本敏感型应用中:对于需要处理大量数据,但对精度要求不是特别高的应用,例如初始的数据探索或者快速原型开发,那么text-embedding-3-small是一个更经济的选择,因为它在保持相对较高性能的同时,可以显著减少成本。
  3. 多语言环境:由于这些嵌入模型具有较高的多语言性能表现,它们在处理跨语言或多种语言场景时特别有用,这使其在全球化应用中成为理想的选择。

选择正确的嵌入模型将依赖于具体需求、数据的复杂性以及期望达到的平衡点(性能与成本之间的平衡)。

3. 如何使用Embeddings
3.1 使用curl调用Embeddings API

curl是一个常用的命令行工具,用于发送HTTP请求。下面的例子展示了如何使用curl来获取文本的嵌入表示:

curl https://api.openai.com/v1/embeddings \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $OPENAI_API_KEY" \
    -d '{
        "input": "机器学习是人工智能的一个分支。",
        "model": "text-embedding-3-small"
    }'

在上述命令中,$OPENAI_API_KEY变量包含了用户的OpenAI API密钥,在实际使用时应将其替换为有效的密钥。

执行该命令后,OpenAI的Embeddings API将返回包含文本嵌入表示的响应。下面是一个API调用结果的示例:

{
  "object": "list",
  "data": [
    {
      "object": "embedding",
      "index": 0,
      "embedding": [  // 这里就是特征向量
        -0.006929283495992422,
        -0.005336422007530928,
        ...  // 此处省略其余数字以便展示
        -4.547132266452536e-05,
        -0.024047505110502243
      ],
    }
  ],
  "model": "text-embedding-3-small",
  "usage": {
    "prompt_tokens": 5,
    "total_tokens": 5
  }
}
3.2 使用Python客户端调用Embeddings API

除了使用curl直接在命令行中调用API之外,你也可以使用Python客户端。这需要先安装openai官方库。以下是如何用Python获取文本嵌入表示的代码实例:

import openai

openai.api_key = 'YOUR_OPENAI_API_KEY'  # 替换为你的OpenAI API密钥

response = openai.Embedding.create(
  input="人工智能正在改变世界。",
  model="text-embedding-3-small"
)

embedding_vector = response['data'][0]['embedding']
print(embedding_vector)

执行此Python脚本,你会得到类似于使用curl时的嵌入向量。这个向量是一个浮点数列表,表示了输入文本在嵌入空间中的数值表示。

调用结果如下:

[-0.0032198824, 0.0022555287, ..., 0.0015886585, -0.0021505365]
3.2 操作嵌入向量

OpenAI只是提供了Embeddings文本向量化计算模型,如果你想使用Embeddings实现文本相似搜索之类的功能,你需要学习向量数据库知识,例如:Qdrant、Chroma、Milvus等。

10.Fine-tuning(GPT模型微调)

1. Fine-tuning简介
1.1. 模型微调的定义与优势

模型微调(Fine-tuning)是深度学习中的一个概念,指在预训练模型(Pre-trained Model)的基础上继续训练,以适应特定任务或数据集的过程。预训练模型已经在海量的数据上训练,学习到了丰富的特征表示。通过微调,可以在这个基础上进一步提升模型对于特定任务的性能。

相较于从头开始训练模型,微调的优势主要包括:

  1. 节省时间和资源:预训练模型省去了从零开始训练模型的时间和计算资源,尤其是在大型模型和复杂任务中更为显著。
  2. 数据效率:微调通常只需要相对较少的标注数据即可取得良好的效果,特别是在数据稀缺的领域中。
  3. 转移学习:预训练模型在多样化的数据上学习,微调可以将这些知识转移到特定任务,提高泛化能力。
  4. 性能提升:微调可以让模型更好地贴合特定任务的需求,有助于提高模型质量,减少错误率。

例如,借助OpenAI的API,用户可以通过微调来定制化GPT模型,以获得更高品质的结果,同时节省因长Prompt而产生的代价,降低延迟。

1.2. 实际应用案例

微调在多种实际场景中被证实非常有效。例如:

  • 设定风格和口吻:通过微调,可以让聊天机器人的回答更具有特定的风格或口吻,如正式、幽默或是贴近某一行业的专业语言。
  • 提高可靠性:在敏感的应用中,如医疗咨询或法律建议,微调可以减少误解或不准确回答的发生,从而提升整体的可靠性。
  • 应对复杂提示:有些任务需要处理复杂的用户输入,微调可以帮助模型更好地理解这些复杂的场景并给出正确的响应。
  • 特定任务性能提升:对于某些难以通过单一提示描述的任务,如文本生成中的风格迁移、特定主题的文本生成等,微调可以极大地改善模型的相关性能。

通过这些案例,我们可以看出微调使模型能够更好地适应特定应用场景,提供更准确和个性化的服务。

2. 何时使用Fine-tuning
2.1. 分析任务需求

微调是在确定已有的通用模型无法满足具体需求时采用的策略。当任务有以下特点时,可能需要微调:

  • 样式、语调、格式或其他定性方面有特殊需求
  • 需要提高在产生期望输出方面的可靠性
  • 处理诸多细节案例时需要特定的方式
  • 执行难以在提示中明确说明的技能或任务

判断是否需要微调的步骤一般包括:

  1. 尝试“提示工程”,即调整输入提示的方式来优化结果。
  2. 分析现有模型效果,判断是否必要进行微调。
  3. 如决定进行微调,准备相关的数据集用于进一步训练。
2.2. Fine-tuning与prompt engineering比较

Fine-tuning与prompt engineering(提示工程)是改进模型性能的两种不同策略。提示工程指的是通过精心设计的prompt来指导模型生成预期的回应,而不改动模型本身。它通常是追求性能改进的第一步,因为其反馈周期快,且不要求训练数据。

然而,某些情况下,即使经过了精心设计的prompt,模型仍然难以达到预期效果。在这些情况下,Fine-tuning成为提高模型性能的必然选择。通过提供大量例子让模型学习,微调能够在不同任务上达到比单纯提示工程更好的效果。

3. 支持Fine-tuning的模型

OpenAI提供了一系列支持Fine-tuing的模型,其中包括gpt-3.5-turbo-1106(推荐使用)、gpt-3.5-turbo-0613babbage-002davinci-002,以及实验性接入的gpt-4-0613。这些模型可以通过Fine-tuing进一步训练以适应用户的特定需求。

Fine-tuning不仅适用于新的数据集,用户还可以在已微调过的模型基础上继续进行微调。这在获取了更多数据,并希望在不重复之前训练步骤的情况下进一步优化模型时非常有用。

对于大多数用户而言,gpt-3.5-turbo以其良好的结果和易用性成为首选。考虑到持续改进和用户的具体需求,OpenAI可能会不断更新和扩展支持微调的模型范围。

4. 准备训练数据
4.1. 数据集格式

为了进行Fine-tuning,你需要准备一个符合指定格式要求的数据集。通常,这个数据集包含了一系列的输入和期望的输出,OpenAI的Fine-tuning API支持两种主要的数据格式:对话模型和简单的问答对。

对话模型 数据集格式通常用于gpt-3.5-turbo模型,每个示例都是以一个对话的形式来组织的,其中每条消息都有角色、内容和可选名字。示例数据结构如下:

{
  "messages": [
    {"role": "system", "content": "你是一个有帮助的助理。"},
    {"role": "user", "content": "今天天气怎么样?"},
    {"role": "assistant", "content": "今天天气晴朗,适合外出。"}
  ]
}

每个案例必须被格式化为一个具有JSON Lines(.jsonl)格式的文件,每一行代表一个训练样本, 例子:

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?"}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters."}]}

简单的问答对 数据集格式适用于如babbage-002davinci-002之类的模型,格式更简单,由一对promptcompletion的组合构成。参考示例如下:

{
  "prompt": "今天天气如何?",
  "completion": "今天天气晴朗,适合外出。"
}

同样,每个训练样本暂用一行,例子:

{"prompt": "<prompt text>", "completion": "<ideal generated text>"}
{"prompt": "<prompt text>", "completion": "<ideal generated text>"}
{"prompt": "<prompt text>", "completion": "<ideal generated text>"}

在创建Fine-tuning数据时,仔细考虑提供的每一个指令或提示,确保训练样例间的一致性,并尽量覆盖所有预期使用场景。

4.2. 训练与测试数据分割

创建Fine-tuning数据集后,合理地划分训练集和测试集是至关重要的。通常,数据集会被分成两部分,大部分用于训练模型(通常是70%到90%),剩余的部分用于测试(剩下的10%到30%)。这样的分割有助于验证模型在看不见的数据上的效能,和严格评估模型性能。

数据集的分割可以手动完成,也可以写代码分割,后面章节会介绍如何使用测试集数据评估模型。

5. 创建Fine-tuned模型
5.1. 选择合适的预训练模型

在开始fine-tuning之前,选择正确的预训练模型是确保任务成功的关键。以下是选择合适预训练模型的几点建议:

  1. 任务类型: 根据您的任务的性质,如语言理解、生成或者特定领域的问题解答,选取最适合这些任务的模型。比如,gpt-3.5-turbo 模型适用于多数场景,它平衡了性能和易用性。
  2. 数据量: 如果您拥有的训练数据相对较少,您可能会倾向于选择一个较小的模型,如babbage-002,因为它需要较少的数据来调整参数。
  3. 性能需求: 对于需要更复杂、更精细化任务处理的场景,可以考虑选择性能更强的davinci-002模型。
  4. 成本考量: 不同的模型有不同的计算和存储要求,通常,更大的模型成本更高。根据预算和性能需求进行平衡。
  5. 实验性特性: gpt-4-0613 模型目前还在实验阶段,如果要尝试最新技术并且对实验性接口具有容忍度,可以考虑申请访问。
5.2. Fine-tuning流程

Fine-tuning的流程涵盖了准备数据、上传文件、创建训练任务和监控进度等多个步骤。以下是详细流程:

5.2.1. 准备数据

根据目标任务准备适量的训练和测试数据,并且确保数据格式符合要求,如JSON Lines(.jsonl)格式, 请参考前面的章节内容。

5.2.2. 上传数据

通过OpenAI的Files API上传你的训练数据文件,指定文件的用途为fine-tune,如下所示:

   curl https://api.openai.com/v1/files \
     -H "Authorization: Bearer $OPENAI_API_KEY" \
     -F purpose="fine-tune" \
     -F file="@mydata.jsonl"

上传成功后你可以拿到一个文件ID,用于后续的模型训练任务。

5.2.3. 创建训练任务

使用OpenAI的SDK或CLI工具启动fine-tuning任务,并指定所需的参数和模型。例如:

   from openai import OpenAI
   client = OpenAI()

   client.fine_tuning.jobs.create(
     training_file="file-abc123", 
     model="gpt-3.5-turbo"
   )

training_file参数指定训练数据文件ID,model参数指定我们基于什么模型进行训练。

5.2.4. 监控训练任务

下面介绍通过python如何查询训练结果。

from openai import OpenAI
# 忽略api key参数设置
client = OpenAI()

# 显示10个模型微调任务
client.fine_tuning.jobs.list(limit=10)

# 查询指定任务ID的详细信息,如果模型训练成功,可以通过任务信息中fine_tuned_model 参数获取到微调的模型名称
client.fine_tuning.jobs.retrieve("ftjob-abc123")

# 根据任务ID取消任务
client.fine_tuning.jobs.cancel("ftjob-abc123")

# 根据任务ID查询任务日志
client.fine_tuning.jobs.list_events(fine_tuning_job_id="ftjob-abc123", limit=10)

# 删除指定的微调模型
client.models.delete("ft:gpt-3.5-turbo:acemeco:suffix:abc123")
6. Fine-tuning过程中的参数调整
6.1. 超参数的理解与调整

超参数是在模型训练前设置的,且通常无法从数据中学习的参数。以下是几个重要的超参数:

  • Epoch数(n_epochs): 这决定了您的模型将遍历整个数据集的次数。过多的epoch可能导致过拟合,过少则可能导致模型未充分学习。
  • 学习率(learning_rate_multiplier): 学习率决定了模型在每次迭代中更新其权重的幅度。过高的学习率可能导致模型学习过程不稳定,而过低则可能导致学习过程缓慢。
  • Batch大小(batch_size): 批处理大小决定了每次模型更新时将考虑多少训练实例。较大的批处理有助于稳定训练,但可能会增加内存压力。

超参数的调整通常需要根据模型的性能反复试验,以找到最优的参数组合。

使用超参数启动微调任务的例子:

from openai import OpenAI
client = OpenAI()

client.fine_tuning.jobs.create(
  training_file="file-abc123", 
  model="gpt-3.5-turbo", 
  hyperparameters={
    "n_epochs":2
  }
)

通过hyperparameters参数设置超参数。

6.2 迭代和模型改进方法

在初次fine-tuning之后,可能需要进行迭代,以进一步优化模型性能。以下是一些迭代的策略:

  • 增加数据: 如果模型在某些类型的输入上表现不佳,尝试增加这类输入的例子。
  • 反思数据质量: 检查训练数据是否包含了不正确或有歧义的信息。这些质量问题可能会导致模型表现不佳。
  • 数据均衡: 确保训练数据在类别、样式等方面具有多样性和均衡性。
  • 调整超参数: 如前所述,调整Epoch数、学习率和Batch大小可能会显著影响模型的性能。

通过这些方法,您可以逐步优化您的fine-tuned模型,以获得最佳的性能表现。

7. 评估与使用Fine-tuned模型
7.1 如何评估Fine-tuned模型

当我们完成模型的微调工作后,评估微调模型的性能至关重要。以下是一些标准评估方法:

  1. 比较样本: 使用前面准备的测试样本,分别调用基础模型和Fine-tuned模型,然后对比输出结果,这样可以比较Fine-tuned模型效果如何。
  2. 统计指标: 对微调过程中的损失(loss)和准确度(accuracy)等指标进行追踪。训练过程中损失应该降低,而准确度应该提高。
  3. A/B测试: 设计实验,划分流量,同时运行基础模型和Fine-tuned模型来观察在实际环境中的表现差异。
  4. 用户反馈: 收集使用模型的用户反馈,尤其是在自然语言处理任务中,用户满意度是衡量模型性能的关键指标。
7.2 怎么使用Fine-tuned模型

使用Fine-tuned的模型非常简单,只需要将你的Fine-tuned模型名称作为参数传入API调用中。以下是使用Fine-tuned模型的示例代码:

Python 示例

from openai import OpenAI

client = OpenAI(api_key='你的API密钥')

response = client.chat.completions.create(
  model="模型名称",
  messages=[
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello!"}
  ]
)
print(response.choices[0].message)

这里面,“模型名称”需要替换为你Fine-tuned模型的具体名称,例如 “ft:模型名字:你的组织:你的Fine-tuning名称:id”。

第7章:Fine-tuning的最佳实践

在进行Fine-tuning的过程中,我们可以遵循一些最佳实践来进一步提升模型表现:

  1. 数据质量: 确保训练数据高质量和多样性,避免因数据不准确或单一导致模型表现不佳。
  2. 数据分布: 训练数据应覆盖所有可能的输入情况以确保模型在真实场景中的表现。
  3. 小步迭代: 逐步增加训练数据,观察模型表现的变化,而不是一次性添加大量数据。
  4. 超参数调整: 根据模型的表现调整学习率、批次大小和迭代次数等超参数。
  5. 持续改进: 微调模型不是一次性的过程,定期迭代更新数据集和模型可以持续提高模型的效果。

常见问题与解决方案:

  • Q: Fine-tuned模型没有达到预期效果怎么办?
    • A: 仔细检查并改进训练数据的质量和多样性,根据评估结果调整训练策略。
  • Q: 模型在某些特定情况下表现不佳应该如何处理?
    • A: 增加针对该情况的训练样本,以增强模型在该场景下的处理能力。
  • Q: 如何控制Fine-tuning过程中的成本?
    • A: 提前预估Token数量,评估不同模型的费用。

综合这些建议和工具,你将能够最大化你的模型微调效果,并确保微调过程符合你的预期和需求。

11.DALL·E模型API介绍

1. DALL·E模型介绍

OpenAI的DALL·E模型是一个能够从文本提示中生成图像的人工智能系统。DALL·E合成图像的能力涵盖了从简单的图像复制到创造性地重新想象文本描述的场景。该模型的名字来源于画家萨尔瓦多·达利(Salvador Dalí)和动画角色沃利(WALL·E)的混合,意在表达它在艺术创作与自动化领域的交汇。

DALL·E模型通过深度学习训练来理解文本提示,并将这些提示转化为视觉表示。无论是摄影作品、绘画、数字艺术还是任何其他形式的图像,DALL·E均能够根据描述生成匹配的图像。

2. DALL·E图片生成模型的基本使用

OpenAI为DALL·E提供了API接口,使开发者能够将模型集成到自己的应用或服务中。以下是使用DALL·E 3和DALL·E 2 API接口生成图片的基本流程和参数含义:

curl -X POST https://api.openai.com/v1/images/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "model": "dall-e-2", # 模型版本,可以是"dall-e-3"或"dall-e-2"。
        "prompt": "文本提示", # 用于生成图像的文本。
        "n": 1, # 请求生成的图像数量。
        "size": "1024x1024", # 图像的尺寸。
        "quality": "standard" # 图像的质量,可以是"hd"。
      }'
  • model: 指定所使用的DALL·E模型版本。
  • prompt: 提供给模型的文本提示,模型会根据此文本生成图像。
  • n: 指定要生成的图片数量,DALL·E 3一次只能生成1张图像,而DALL·E 2可以同时生成最多10张图像。
  • size: 生成图像的大小。对于dall-e-2,必须为256x256、512x512或1024x1024中的一个。dall-e-3型号必须为1024x1024、1792x1024或1024x1792之一。
  • quality: 设置生成图像的质量,standard为标准质量,hd为高清质量。
3. 图片编辑与变体生成(仅限DALL·E 2)
3.1. 图片编辑(编辑或扩展图片)

使用DALL·E 2的图片编辑功能,可以上传一个图片和相应的蒙层(mask),蒙层的透明区域表示将要编辑的部分,模型会根据新的文本提示在这些区域中生成内容。这个功能可以创造出不同于原有图片元素的新元素,从而生成编辑过的版本。

继续使用curl命令的API请求示例:

curl -X POST https://api.openai.com/v1/images/edits \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: multipart/form-data" \
  -F "model=dall-e-2" \
  -F "prompt=新的文本描述" \
  -F "image=@/path_to_your_original_image.png" \
  -F "mask=@/path_to_your_mask.png" \
  -F "n=1" \
  -F "size=1024x1024"
  • image: 包含原始图片的文件。
  • mask: 包含蒙层,其中透明区域表示应该被模型处理的区域。
  • prompt: 新的文本提示,描述整个新图像的内容,而不仅仅是被擦除的区域。

要注意,上传的原始图片和蒙层都必须是正方形PNG图片,且大小不超过4MB,并具有相同的尺寸。

例子:

curl https://api.openai.com/v1/images/edits \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -F image="@sunlit_lounge.png" \
  -F mask="@mask.png" \
  -F model="dall-e-2" \
  -F prompt="阳光充足的室内休息区,有一个游泳池,里面有一只火烈鸟" \
  -F n=1 \
  -F size="1024x1024"

原始图片
img

蒙层图片
img

生成后的图片
img

3.2. 图片变体生成

使用DALL·E 2生成图片的变体是从已有的图像出发,生成一些在内容上或风格上的不同版本。这个功能可以用来探索某个图像的不同可能性或创造性演变。

同样地,利用curl发送一个API请求:

curl -X POST https://api.openai.com/v1/images/variations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: multipart/form-data" \
  -F "image=@/path_to_your_image.png" \
  -F "n=2" \
  -F "size=1024x1024"
  • image: 包含要生成变体的原始图片文件。
  • n: 要生成变体的数量,可以通过此参数控制。

和之前一样,输入的图像必须是小于4MB的正方形PNG文件。

12.视觉模型(Vision)gpt-4-vision-preview

1. GPT-4视觉模型介绍

GPT-4视觉模型(GPT-4V)是OpenAI推出的一种多模态人工智能模型,它在GPT-4的基础上集成了视觉理解功能。与传统的文本处理模型不同,GPT-4V能够接收并分析图像内容,并针对图像提供描述、回答问题或进行交互。

应用场景示例:
  • 商品识别与分类:电子商务平台可以使用GPT-4V识别商品图片,提供商品描述,帮助改善搜索和推荐系统。
  • 辅助医疗决策:虽然GPT-4V不适合直接进行专业的医学影像诊断,但它可以协助医护人员进行初步的图像理解和数据整理。
  • 教育与研究:在教学和科研中,GPT-4V可用于分析图表、实验结果,如自动解读科学图像数据。
  • 交通监控分析:通过分析路况监控图像,GPT-4V能够辅助交通管理系统进行实时状况报告和事故识别。
2. 简单例子

下面通过一个简单的CURL请求示例来展示如何使用GPT-4视觉模型分析图像:

API请求参数说明:
  • model: 指定使用的模型版本,这里为 “gpt-4-vision-preview”。
  • messages: 包含角色定义和内容,其中内容中可以包含文本和图像链接。
  • max_tokens: 指定生成文本的最大长度限制。
CURL请求示例:
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4-vision-preview",
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "这张图片中有什么?"
          },
          {
            "type": "image_url",
            "image_url": {
              "url": "您的图片链接"
            }
          }
        ]
      }
    ],
    "max_tokens": 300
  }'

通过上方的请求,我们向GPT-4视觉模型提交了一张图片,并问了一个简单的问题:“这张图片中有什么?”。模型会分析图像内容,并根据图像内容提供回答。

3. 以base64编码的方式上传图片

在某些情况下,您可能需要上传本地的图片文件给GPT-4视觉模型。这时,我们可以通过base64编码的方式将图片数据嵌入到API请求中。

Python代码示例:
import base64
import requests

# OpenAI API Key
api_key = "YOUR_OPENAI_API_KEY"

# 将图片转base64格式
def encode_image(image_path):
  with open(image_path, "rb") as image_file:
    return base64.b64encode(image_file.read()).decode('utf-8')

# 本地图片路径
image_path = "path_to_your_image.jpg"

# 获取图片base64编码格式
base64_image = encode_image(image_path)

headers = {
  "Content-Type": "application/json",
  "Authorization": f"Bearer {api_key}"
}

payload = {
  "model": "gpt-4-vision-preview",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "What’s in this image?"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": f"data:image/jpeg;base64,{base64_image}"
          }
        }
      ]
    }
  ],
  "max_tokens": 300
}

response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)

print(response.json())

在上述代码中,我们首先将本地的图片文件转换为base64编码的字符串,然后将这个字符串作为请求的一部分发送给API。模型返回的内容包含了对图片内容的描述。

4. 处理多图输入

有时候需要一次性分析多张图片。GPT-4视觉模型支持同时接收多个图像输入,并能够让用户询问关于这些图片的问题或比较它们之间的差异。

多图输入示例:
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4-vision-preview",
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "这些图片中有什么不同?"
          },
          {
            "type": "image_url",
            "image_url": {
              "url": "第一张图片的链接",
            }
          },
          {
            "type": "image_url",
            "image_url": {
              "url": "第二张图片的链接",
            }
          }
        ]
      }
    ],
    "max_tokens": 300
  }'

在这个请求中,我们向API提交了两张图片,模型会分别分析每一张,并根据提出的问题,给出关于图片的描述和比较。这种方法非常适用于需要对图片集进行总体分析的场景。

5. 设置图片分析详情级别

在使用 GPT-4 视觉模型进行图片分析时,您可以根据需求设置分析的详情级别。通过调整 detail 参数,可选择 low(低)、high(高)或 auto(自动)中的一个。下面为您详细解释每个选项的含义及如何设置:

  • low:选择低详情级别会禁用“高分辨率”模型。该模型将接收低分辨率的512像素 x 512像素版本的图片,并用65个tokens的预算来代表图片。这适用于不需要高细节的场景,有助于获得更快的响应速度且消耗更少的输入tokens。
  • high:高详情级别允许模型首先看到低分辨率的图片,然后基于输入图片的大小,创建512像素方格的详细裁剪版本。每个详细裁剪以65个tokens的双倍预算(即129 tokens)表示。
  • auto:自动详情级别将根据图片输入的大小决定是使用 lowhigh 详情级别。

通过如下代码示例可以展示如何设置详情级别:

import base64
import requests

# OpenAI API密钥
api_key = "你的OPENAI_API_KEY"

# 图片路径
image_path = "path_to_your_image.jpg"

# 对图片进行base64编码
base64_image = base64.b64encode(open(image_path, "rb").read()).decode('utf-8')

headers = {
  "Content-Type": "application/json",
  "Authorization": f"Bearer {api_key}"
}

payload = {
  "model": "gpt-4-vision-preview",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "这张图片中有什么?"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": f"data:image/jpeg;base64,{base64_image}",
            "detail": "high"  # 设置为高详情级别
          }
        }
      ]
    }
  ],
  "max_tokens": 300
}

response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)

print(response.json())
6. 理解模型的局限和管理图片
6.1. 模型的局限性

GPT-4视觉模型尽管功能强大,但它并非万能,了解其局限性对于使用它来进行图片理解至关重要。以下是一些已知限制的概述:

  • 医学影像:模型不适合解释专业医学影像,如CT扫描,不应被用作医疗建议。
  • 非英文文字:模型处理含有非拉丁字母表文本的图片时可能性能不佳,如日语或韩语文字。
  • 空间定位:模型在需要精确蕴含位置关联的任务上表现欠佳,例如识别棋盘上棋子的位置。
  • 图像细节:模型可能难以理解图像中的图表或颜色和样式(如实线、虚线)变化的文本。
  • 图像旋转:模型可能误解倾斜或颠倒的文本和图像。
6.2 管理会话中的图片

由于Chat Completions API是无状态的,因此需要自己管理传递给模型的消息(包括图片)。如果您希望多次使用相同的图片,每次API请求时都需要重新传递图片数据。

# ...之前示例代码...

# 在需要时重复使用base64_image变量
# 不需要再次进行图片编码,除非你需要更新或更换图片

# 再次请求API作出对新问题的回应
additional_payload = {
  "model": "gpt-4-vision-preview",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "根据这张图片,你有哪些建议?"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": f"data:image/jpeg;base64,{base64_image}"
          }
        }
      ]
    }
  ],
  "max_tokens": 300
}

new_response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=additional_payload)

print(new_response.json())
7. 成本计算

使用detail: low选项的每张图片固定消耗85个tokens。对于detail: high选项的图片,首先把图片按比例缩放以适应2048px x 2048px的尺寸,然后确保图片短边为768px。之后统计图片分为多少个512px的方块,每个方块消耗170个tokens,并在最后总计数中增加85个tokens。

例如,如果一张图片的尺寸是1024px x 1024px并且选择detail: high,它的token花费将是:

  • 首先,1024小于2048,所以没有初始大小调整。
  • 然后,最短的边是1024,所以我们将图像缩小到768 x 768。
  • 需要4个512px的正方形块来表示图像,因此最终的令牌成本为170 * 4 + 85 = 765。

如需详细了解成本计算方法,请参考GPT-4视觉模型的文档。

8. 常见问题

下面列举了一些使用 GPT-4 视觉模型时,用户可能遇到的常见问题及其答案:

Q: 是否可以针对gpt-4的图像功能进行微调?

A: 目前我们不支持对gpt-4的图像功能进行微调。

Q: 我可以使用gpt-4生成图像吗?

A: 不,您可以使用dall-e-3生成图像,使用gpt-4-vision-preview来理解图像。

Q: 支持哪些类型的文件上传?

A: 我们目前支持PNG (.png)、JPEG (.jpeg和.jpg)、WEBP (.webp)和非动态GIF (.gif)。

13.学习语音模型(文本转语音、语音转文本)

1. 语音模型概览
1.1. OpenAI的TTS和STT模型介绍
TTS(文本转语音)模型

OpenAI提供的TTS模型能够将文本资料转换为语音输出。这个过程涵盖了文本的分析、语音合成算法的应用,以及音质调整等步骤。它使计算机可以读出任何书面文本,使内容更加易于理解和接受。对于视障人士、驾驶员或仅仅是希望通过听的方式接收信息的人来说,TTS是一项重要技术。

STT(语音转文本)模型

与TTS相对应,STT模型可以将语音信息转换为书面文本。在处理原始音频输入时,STT系统需先执行语音检测,然后是特征提取,之后利用声学模型和语言模型将音频信号映射到词汇上,最终生成文本输出。STT技术广泛应用于语音识别、会议记录、实时字幕生成等场景。

1.2. 应用场景案例
  • 博客朗读
  • 多语种语音生成
3. 文本转语音API
3.1. 快速开始

在本节中,我们将通过curl命令和Python客户端演示如何将文本快速转换为语音。无论是开发者还是非技术用户,只需简单地发送API请求,即可轻松生成语音文件。

使用curl发送请求

要使用curl命令行工具生成语音,你需要按照如下步骤进行:

  1. 确保你的系统已安装curl,并且你已经拥有有效的OpenAI API密钥。
  2. 使用下面的curl命令,将文本转换为语音:
curl https://api.openai.com/v1/audio/speech \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "tts-1",
    "input": "今天是个搭建人们喜爱产品的绝佳日子!",
    "voice": "alloy"
  }' \
  --output speech.mp3

在上述命令中,$OPENAI_API_KEY是你的API密钥,input字段是你想要转换的文本,model字段指定了使用的声音模型, voice参数是声线选择,这里选择alloy金属合成音。最后的--output选项指定了输出文件的名称与格式。

使用Python客户端

如果你更喜欢使用Python编程语言,可以使用如下代码示例:

from openai import OpenAI

client = OpenAI()

response = client.audio.speech.create(
    model="tts-1",
    voice="alloy",
    input="今天是个搭建人们喜爱产品的绝佳日子!"
)

response.stream_to_file("output.mp3")

在这段代码中,我们首先导入openai库并创建一个OpenAI客户端实例。然后,我们利用audio.speech.create方法发送请求,指定模型、声音和要转换的文本。最后,使用stream_to_file方法将生成的语音流保存到文件中。

3.2. 选择音质和声音

选择适合您项目的音质和声音是确保最佳用户体验的关键步骤。我们的API提供了两种音质模型选项:tts-1tts-1-hd

  • tts-1: 提供更低的延迟,适合实时应用,但音质相对较低。
  • tts-1-hd: 提供更高质量的音频输出,适合非实时的高质量语音生成需求。

此外,OpenAI的TTS API提供了不同的声线选项:

  • Alloy
  • Echo
  • Fable
  • Onyx
  • Nova
  • Shimmer

根据项目需求和目标受众,你可以测试不同的语音样本以选择最匹配的声音。考虑到口语风格、语速和音调等因素,尝试找到能够传达适当情感和专业度的声音。

3.3. 支持的输出格式与语言

OpenAI提供的TTS API默认输出格式为MP3,但还支持其他多种音频格式,包括:

  • Opus: 适合互联网流媒体和通信,低延迟。
  • AAC: 用于数字音频压缩,受YouTube、Android、iOS等偏好。
  • FLAC: 无损音频压缩格式,音频爱好者用于归档。

在多语言支持方面,API主要跟随Whisper模型,提供丰富的语言选项,支持很多国家语言。

3.4. 实时音频流功能

为了满足实时应用的需求,我们的API提供了实时音频流支持。以下是一个用于实现实时音频流的Python示例:

from openai import OpenAI

client = OpenAI()

response = client.audio.speech.create(
    model="tts-1",
    voice="alloy",
    input="Hello world! This is a streaming test.",
)

response.stream_to_file("output.mp3")
4. 语音转文本API
4.1. 快速开始

在这一节中,我们主要介绍OpenAI提供的API进行语音转文本的功能。

首先,您需要有一个有效的OpenAI API密钥,然后准备一个音频文件。

下面使用curl命令来发送一个包含音频文件的POST请求。您需要替换OPENAI_API_KEY为您的API密钥,同时设置正确的文件路径。

curl --request POST \
  --url https://api.openai.com/v1/audio/transcriptions \
  --header 'Authorization: Bearer OPENAI_API_KEY' \
  --header 'Content-Type: multipart/form-data' \
  --form file=@/path/to/your/audio/file.mp3 \
  --form model=whisper-1

执行上述命令后,您将收到一个JSON格式的响应,包含转换后的文本信息。

例如:

{
  "text": "Imagine the wildest idea that you've ever had, and you're curious about how it might scale to something that's a 100, a 1,000 times bigger.
....
}
4.2. 支持的文件格式和大小

此API支持各种常见的音频文件格式,以满足不同场景下的需求。支持的文件格式包括但不限于mp3, mp4, mpeg, mpga, m4a, wav, webm等。这样,用户可以方便地处理多种来源的音频文件。

对于文件大小,当前API的限制是最大不超过25MB。这意味着,如果您的音频文件大于25MB,您需要将其分割为多个小于25MB的文件段,或使用更高效的压缩格式。例如,mp3opus通常提供高效的压缩,从而在不牺牲太多音质的情况下减少文件的大小。

如果碰到大于25MB的文件,可以考虑使用Python中的PyDub库来分割您的音频:

from pydub import AudioSegment

audio_file = AudioSegment.from_file("your_large_audio_file.mp3")

# PyDub handles time in milliseconds
# 设定分割的时间间隔
interval = 10 * 60 * 1000  # 10分钟

chunks = make_chunks(audio_file, interval)

for i, chunk in enumerate(chunks):
    chunk_name = f"audio_chunk{i}.mp3"
    chunk.export(chunk_name, format="mp3")

在上述代码中,make_chunks函数将会把一个大的音频文件分割为多个时间间隔为10分钟的音频片段。这些片段均不超过接口要求的文件大小限制,可以单独上传至OpenAI API进行转录。

请注意,虽然PyDub为我们提供一个易于处理音频文件的途径,但还是推荐您在使用任何第三方软件时格外注意其安全性和稳定性。OpenAI并不对第三方软件提供任何保证。

14.OpenAI Assistants API开发教程

1. 介绍OpenAI的Assistants API
1.1 Assistants API 的定义与作用

Assistants API允许开发者在自己的应用程序中构建人工智能助手。通过定义自定义的指令与选择模型,助手可以利用模型、工具和知识来回应用户的查询。当前,Assistants API支持三种类型的工具:代码解析器(Code Interpreter)、检索(Retrieval)和函数调用(Function calling)。

1.2 Assistants API 的应用场景

Assistants API适用于各种需要交互式AI支持的场景。例如:

  • 客户支持: 自动回答常见问题,减少人工客服的工作量。
  • 在线教学: 解答学生提出的问题,提供定制化的学习支持。
  • 数据分析: 分析用户上传的数据文件,生成报告和可视化图表。
  • 个性化推荐: 根据用户的历史交互,提供个性化的建议和服务。
1.3. Assistants的核心概念

img

Assistants API核心对象包括Assistant、Thread和Message。以下是这些对象的详细介绍及其作用:

Assistant

Assistant对象是构建在OpenAI模型之上,能够调用工具的AI助手。您可以自定义Assistant的指令,定制其个性和功能。例如,您可以创建一个名为”数据分析师”的Assistant,它通过“code_interpreter”工具分析数据并生成图表。

Thread

Thread对象表示用户和Assistant之间的对话会话。您可以为每个用户创建一个Thread,并在用户与Assistant交互时将消息添加到其中。Thread对象有效地存储消息历史,并在需要时截断消息以符合模型的上下文长度限制。

Message

Message对象可以是由用户或Assistant创建的消息。消息可能包含文本、图像和其他文件。消息作为列表存储在Thread上。在API的实际使用中,开发者可以向Thread添加用户消息,并根据需要触发Assistant的响应。

Run

Run对象代表执行一次助手请求,在Thread消息内容的基础上调用助手。助手使用它的配置和线程的消息通过调用模型和工具来执行任务。作为运行的一部分,助手将消息附加到线程中。

2. Assistants API开发流程
2.1 创建你的Assistant

要创建一个Assistant,您需要通过API发送包含指令、模型名和工具配置的请求。这里是一个简单的创建个人数学导师助手的例子:

curl "https://api.openai.com/v1/assistants" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1" \
  -d '{
    "instructions": "你是一个个人数学导师。编写并运行代码来回答数学问题。",
    "name": "Math Tutor",
    "tools": [{"type": "code_interpreter"}],
    "model": "gpt-4"
  }'

API参数说明:

  • instructions - 系统指令,告诉助手需要干什么。
  • name - 助手名字
  • tools - 定义助手可以使用那些工具。每个助手最多可以有128个工具。目前工具的类型可以是code_interpreter、retrieval或function。
  • model - 助手使用那个模型?

创建Assistant成功之后可以得到Assistant ID。

2.2 创建会话Thread

一个Thread代表一个对话,当用户开启对话时,我们推荐为每个用户创建一个会话Thread。您可以通过以下方式创建Thread:

curl https://api.openai.com/v1/threads \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1" \
  -d ''

Thread创建成功后,可以拿到Threadid。

2.3 向Thread添加消息

你可以向特定的Thread中添加消息,这些消息包含文本,并且可以选择性地包含用户允许上传的文件。例如:

curl https://api.openai.com/v1/threads/{thread_id}/messages \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1" \
  -d '{
      "role": "user",
      "content": "我需要解这个方程 `3x + 11 = 14`。你能帮我吗?"
    }'

API参数说明:

  • thread_id - 代表对话线程ID,创建Thread的时候可以拿到对话线程ID。
  • API请求体是一条用户消息,通常代表用户的问题,跟对话模型的消息结构类似。
2.4 运行Assistant以产生响应

要让助手响应用户消息,您需要创建一个Run。这使得助手读取Thread并决定是否调用工具(如果启用了)或简单地使用模型以最佳方式回答查询。

提示:到目前为止,助手并没有响应用户的问题,只有调用Run api,AI助手才会响应用户的问题。

curl https://api.openai.com/v1/threads/{thread_id}/runs \
  -H "Authorization: Bearer YOUR_OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "OpenAI-Beta: assistants=v1" \
  -d '{
    "assistant_id": "assistant_id",
    "instructions": "请以Jane Doe称呼用户。该用户为高级账户。"
  }'

API参数说明:

  • thread_id - 代表对话线程ID,创建Thread的时候可以拿到对话线程ID。
  • assistant_id - 代表助手ID,创建Assistant的时候可以拿到助手ID。
  • instructions - 助手指令,可以覆盖创建Assistant的时候设置的指令。

API请求成功会得到一个Run ID

2.5 检查Assistant运行状态

在Assistant启动一个任务(Run)后,任务的执行是异步的。这意味着我们需要定期检查Run的状态,以确定它是否已经完成。为了检查Run的状态,可以通过CURL发出HTTP请求。下面是对这一过程的具体介绍。

CURL请求示例:
curl https://api.openai.com/v1/threads/thread_abc123/runs/run_abc123 \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1"
API参数详解:
  • https://api.openai.com/v1/threads/thread_abc123/runs/run_abc123:这是API的请求URL,其中thread_abc123是线程(Thread)的唯一标识符,而run_abc123是Run的唯一标识符。
响应体示例:
{
  "id": "run_abc123",
  "object": "thread.run",
  "status": "completed",
  "created_at": 1699073585,
  ...
}
API响应参数详解:
  • id:Run的唯一标识符。
  • object:表明了返回对象的类型,这里是thread.run
  • status:Run的状态,可能的值包括queued(排队中)、in_progress(处理中)、completed(完成)、requires_action(需要进一步操作)、failed(失败)等。
  • created_at:Run创建的时间戳。
2.6 获取Assistant响应结果

当Assistant Run运行完成后,我们可以通过检查线程(Thread)中添加的消息来读取Assistant的响应结果。下面通过CURL请求展示如何发起请求,以及对API的参数进行详细讲解。

提示:跟Assistant助手的对话过程,类似两个人聊天的过程,当Assistant助手处理完用户的问题,会把Assistant助手消息追加到对话线程Thread中,因此我们只要查询对话线程Thread中的最新消息就可以获取助手的响应。

CURL请求示例:
curl https://api.openai.com/v1/threads/thread_abc123/messages \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1"
API参数详解:
  • https://api.openai.com/v1/threads/thread_abc123/messages:API的请求URL,thread_abc123是线程(Thread)的唯一标识符。
  • 与之前检查Run状态时的请求头部相同,包含认证信息和API版本信息。
Assistant响应结果示例:

在此示例中,用户向助手提了一个数学问题,助手在处理结束后在Thread中添加了响应的Message。

用户:我需要解决方程`3x + 11 = 14`。你能帮我吗?
助手:当然可以,Jane Doe。为了解方程`(3x + 11 = 14)`,您需要将`(x)`隔离在方程的一侧。让我为您计算`(x)`的值。
助手:方程`(3x + 11 = 14)`的解是`(x = 1)`

在从助手获取响应结果后,可以将其展示给用户,辅助用户更好地了解和利用助手为他们提供的服务。

3. Tools:OpenAI提供的内置工具
3.1 Code Interpreter工具

Code Interpreter工具允许Assistants API编写并在沙盒执行环境中运行Python代码。这个工具可以处理各种数据和格式的文件,并生成带有数据和图像的图形的文件。Code Interpreter使您的Assistant能够迭代地运行代码来解决复杂的代码和数学问题。当Assistant写的代码运行失败时,它可以通过尝试不同的代码来迭代这个代码,直到代码执行成功。

启用Code Interpreter

要启用Code Interpreter,请在创建Assistant对象时在tools参数中传递code_interpreter

curl https://api.openai.com/v1/assistants \
  -u :$OPENAI_API_KEY \
  -H 'Content-Type: application/json' \
  -H 'OpenAI-Beta: assistants=v1' \
  -d '{
    "instructions": "你是一个个人数学导师。当被问到数学问题时,写代码并运行代码来回答问题。",
    "tools": [
      { "type": "code_interpreter" }
    ],
    "model": "gpt-4-turbo-preview"
  }'

然后,模型会根据用户请求的性质决定在Run时何时调用Code Interpreter。您可以通过Assistant的instructions来促进此行为(例如,“写代码来解决这个问题”)。

使用Code Interpreter处理文件

Code Interpreter可以从文件中解析数据。这在您想为Assistant提供大量数据或允许您的用户上传自己的文件进行分析时很有用。请注意,为Code Interpreter上传的文件不会被索引以用于检索。有关如何为检索索引文件的详细信息,请参阅下面的Retrieval工具部分。

在Assistant级别传递的文件可以被所有与此Assistant关联的Runs访问:

# 上传目的为"assistants"的文件
curl https://api.openai.com/v1/files \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -F purpose="assistants" \
  -F file="@/path/to/mydata.csv"

# 使用文件ID创建Assistant
curl https://api.openai.com/v1/assistants \
  -u :$OPENAI_API_KEY \
  -H 'Content-Type: application/json' \
  -H 'OpenAI-Beta: assistants=v1' \
  -d '{
    "instructions": "你是一个个人数学导师。当被问到数学问题时,写代码并运行代码来回答问题。",
    "tools": [{"type": "code_interpreter"}],
    "model": "gpt-4-turbo-preview",
    "file_ids": ["file_123abc456"]
  }'
读取Code Interpreter生成的图像和文件

Code Interpreter也可以在API中输出文件,例如生成图像图表、CSV和PDF等。有两种类型的文件被生成:图片和数据文件(例如,Assistant生成的带有数据的CSV文件)。

当Code Interpreter产生一个图像时,您可以在Assistant Message响应的file_id字段中查找和下载这个文件:

{
    "id": "msg_abc123",
    "object": "thread.message",
    "created_at": 1698964262,
    "thread_id": "thread_abc123",
    "role": "assistant",
    "content": [
    {
      "type": "image_file",
      "image_file": {
        "file_id": "file-abc123"
      }
    }
  ]
  // ...
}
3.2 Retrieval工具

Retrieval工具通过向Assistant增加从模型之外的知识(比如专有产品信息或用户提供的文档)来增强其能力。一旦文件上传并传递给Assistant,OpenAI将自动对您的文档进行切片、索引并存储嵌入,并实现向量搜索以检索相关内容以回答用户查询。

启用Retrieval

在Assistant的tools参数中传递retrieval来启用Retrieval:

curl https://api.openai.com/v1/assistants \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1" \
  -d '{
    "instructions": "你是一个客户支持聊天机器人。使用你的知识库来最佳地响应客户查询。",
    "tools": [{"type": "retrieval"}],
    "model": "gpt-4-turbo-preview"
  }'
使用Retrieval上传文件

与Code Interpreter类似,文件可以在Assistant级别或个别Message级别上传。

# 上传目的为"assistants"的文件
curl https://api.openai.com/v1/files \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -F purpose="assistants" \
  -F file="@/path/to/knowledge.pdf"

# 将文件添加到Assistant
curl "https://api.openai.com/v1/assistants" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1" \
  -d '{
    "instructions": "你是一个客户支持聊天机器人。使用你的知识库来最佳地响应客户查询。",
    "name": "Math Tutor",
    "tools": [{"type": "retrieval"}],
    "model": "gpt-4-turbo-preview"
    "file_ids": ["file_123abc456"]
  }'
3.3 Function calling工具

与Chat Completions API类似,Assistants API支持调用函数。Function calling允许您向Assistants描述函数,并使其智能返回需要调用的函数以及其参数。在Run调用函数时,Assistants API会暂停执行,并且您可以提供函数调用的结果以继续Run执行。

定义函数

在创建Assistants助手时,你可以定义一组函数供助手调用。这些函数需要在创建助手对象时明确指定。每个函数都应该有一个唯一的名字、描述以及参数规范。

下面的代码展示了如何用curl命令在创建助手时定义两个函数:

curl https://api.openai.com/v1/assistants \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1" \
  -d '{
    "instructions": "你是一个天气预报机器人。使用提供的函数来回答问题。",
    "tools": [{
      "type": "function",
      "function": {
        "name": "getCurrentWeather",
        "description": "获取某个地点的天气情况",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {"type": "string", "description": "城市和省份,例如:旧金山,加州"},
            "unit": {"type": "string", "enum": ["c", "f"]}
          },
          "required": ["location"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "getNickname",
        "description": "获取城市的昵称",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {"type": "string", "description": "城市和省份,例如:旧金山,加州"}
          },
          "required": ["location"]
        }
      }
    }],
    "model": "gpt-4-turbo-preview"
  }'
读取Assistant调用的函数

当用户向助手提交一条消息,并且消息内容触发了一次函数调用时,你需要读取这次函数调用的信息。这一过程中,助手会产生一个requires_action状态的运行(Run),此时你可以通过检索Run对象来获取函数调用的详细信息。

以下是一个检索Run对象的示例,展示了如何获取需要调用的函数信息:

{
  "id": "run_abc123",
  "object": "thread.run",
  "status": "requires_action",
  "required_action": {
    "type": "submit_tool_outputs",
    "submit_tool_outputs": {
      "tool_calls": [
        {
          "id": "call_abc123",
          "type": "function",
          "function": {
            "name": "getCurrentWeather",
            "arguments": "{\"location\":\"旧金山\"}"
          }
        },
        {
          "id": "call_abc456",
          "type": "function",
          "function": {
            "name": "getNickname",
            "arguments": "{\"location\":\"洛杉矶\"}"
          }
        }
      ]
    }
  },
  ...
}

tool_calls参数包含了函数调用信息,你只要在本地程序调用对应的函数即可。

提交函数输出

在本地执行了函数调用并获得结果后,你需要将这些结果提交给Assistants助手,以便助手可以继续处理用户的请求。提交函数输出时,需要确保输出与原始函数调用相关联。

以下是如何提交函数输出结果的示例代码:

curl https://api.openai.com/v1/threads/thread_abc123/runs/run_123/submit_tool_outputs \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "OpenAI-Beta: assistants=v1" \
  -d '{
    "tool_outputs": [
      {
        "tool_call_id": "call_abc123",
        "output": "{\"temperature\": \"22\", \"unit\": \"celsius\"}"
      }, 
      {
        "tool_call_id": "call_abc456",
        "output": "{\"nickname\": \"LA\"}"
      }
    ]
  }'

参数说明:

  • thread_abc123 代表对话threadID
  • run_123 代表Run对象的ID
  • tool_call_id 代表某个函数调用ID,通过前面的tool_calls参数获得。

在成功提交了所有函数输出后,Run对象的状态会再次更新,助手将继续处理,并返回最终的响应给用户。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值