OpenAI
OpenAI
技术领先与创新前沿
丰富的资源与社区
- 搜索Al相关的项目 star从高到低
- AutoGPT, 智能Agent: https://docs.agpt.co/autogpt/setup/
- GPT-Engineer, 自动生成代码: https://github.com/gpt-engineer-org/gpt-engineer
- 搜索gpt相关的项目 star从高到低
- ChatGPT-Next-Web, ChatBot页 面 : https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web
- ChatGPT 中文调教指南,https://github.com/PlexPt/awesome-chatgpt-prompts-zh
- openai-translator,划词翻译插件: https://github.com/openai-translator/openai-translator
- Chatbox, ChatBot页面: https://github.com/Bin-Huang/chatbox
OpenAI大模型家族
多模态大模型
多模态大模型:能够理解和生成自然语言或代码 +理解图像 +生成图像等
GPT-4:是一个大型多模态模型 (接受文本或图像输入并输出文本),它可以比我们以前的任何模型都更准确地解决难题 这得益于它更广泛的通用知识和更高级的推理能力。 GPT-4可在OpenAl API中供付费客户使用。像gpt-3.5-turbo一样,GPT-4针对聊天进行了优化
对于许多基本任务来说, GPT4和GPT-3.5模型之间的差异并不显著。 然而, 在更复杂的推理情况下, GPT4比我们以前的任何模型都要强大得多
多语言能力 GPT-4不仅在英语中的表现超过了以前的大型语言模型,而且截至2023年,它还超过了大多数最先进的系统 (这些系统往 往有针对特定基准的训练或手工工程)。在MMLU基准测试中,这是一个涵盖57个科目的英语多项选择题套件,GPT-4不 仅在英语中的表现有了显著提升,而且还在其他语言中也展现了强大的性能。
文本大模型
文本大模型:能够理解和生成自然语言或代码
GPT-3.5
推荐使用gpt-3.5-turbo而不是其他GPT-3.5模型,因为它的成本更低,性能更优。
GPT-3.5模型能够理解和生成自然语言或代码。在GPT-3.5系列中,性能最强且最具成本效益的模型是gpt-3.5-turbo,它已针对聊天通过Chat Completions APi进行了优化,但也适用于传统的完成任务。
GPT base
GPT基础模型可以理解和生成自然语言或代码,但没有经过指令跟随的训练。这些模型是原始GPT-3基础模型的替代品,并使用遗留的Completions API。大多数客户应该使用GPT-3.5或GPT-4。
GPT-3 Legacy
GPT-3模型可以理解和生成自然语言。这些模型被更强大的GPT-3.5代模型取代。然而,原始的GPT-3基础模型 (davinci,curie, ada 和 babbage) 是目前唯一可用于微调的模型。
视觉大模型
视觉大模型:能够根据自然语言提示生成和编辑图像的模型。
DALL·E DALL·E是一个AI系统, 它可以根据自然语言描述创建逼真的图像和艺术作品。DALL·E 3目前支持根据提示创建特定大小的新图像。DALL·E 2也支持编辑现有图像,或创建用户提供图像的变体。
语音大模型
语音大模型
- 将文本转换为自然听起来的语音的模型集。
- 将音频转换为文本的模型。
TTS
TTS是一个将文本转换为自然听起来的语音文本的AI模型。 我们提供了两种不同的模型变体,tts-1优化用于速度(实时文本到语音的用例),tts-1-hd优化用于质量
Whisper
Whisper是一个通用的语音识别模型。它训练于一个大型的多样化音频数据集,并且是一个多任务模型,可以执行多语言语音识别以及语音翻译和语言识别。
目前,开源版本的Whisper和 OpenAI APi提供的版本之间没有区别。
只是,OpenAI提供的API,提供了一个优化的推理过程,这使得通过OpenAl的APi运行Whisper比通过其他方式快得多。
Embedding大模型
Embedding大模型:将文本转换为数值形式的模型集。
Embeddings
Embeddings是文本的数值表示,可用于衡量两段文本之间的相关性。目前的第二代Embedding模型 text-embedding-ada-002 旨在以更低的成本替代第一代Embedding模型。 Embedding对于搜索、聚类、推荐、异常检测和分类任务很有用。
审查大模型
审查大模型:检测文本是否可能敏感或不安全的微调模型。
Moderation
Moderation模型旨在检查内容是否符合OpenAl的使用政策。模型提供分类能力,寻找以下类别的内容:仇恨、威胁/仇恨、自残、性行为、性行为/未成年人、暴力和暴力/图形。
Moderation 模型接受任意大小的输入,自动分解成4096个token的块。在输入超过32768个token 的情况下,会使用截断,在罕见的情况下可能会从moderation检查中遗漏少量token。
每个请求到moderation端点的最终结果显示每个类别的最大值。例如,如果4K token的一个块的类别得分为0.9901,另一个得分为0.1901,结果将在API响应中显示0.9901,因为它更高。
模型版本迭代
持续的模型升级。 gpt-3.5-turbo、 gpt-4 和 gpt4-32k 指向最新的模型版本。
您可以通过在发送请求后查看响应对象来验证这一点。响应将包括所使用的具体模型版本 (例如 gpt-3.5-turbo-0613) 。
开发者可以在更新模型后至少继续使用三个月。下面是前一代模型的停用日期以及替换模型。如果您想使用最新的模型版本, 请使用标准模型名称, 如 gpt-4 或 gpt-3.5-turbo。
OpenAI API key和Token
访问OpenAi的服务的方式有两种,第一种是通过ChatGPT页面访问,第二种是通过APi访问。
通过API访问时,我们就要关注如何获取使用API key, 以及了解大模型的计费单元Token。
OpenAI API key
OpenAI API key是一个唯一标识符,充许开发人员通过 API 访问 OpenAI 的模型。API 密钥用于对 API 的请求进行身份验证并跟踪使用情况。共享 API Key违反OpenAl的使用条款。
在哪可以找到OpenAI API key --- User settings
要获取 OpenAI API 密钥,开发人员需要注册一个 OpenAI 帐户。
创建帐户后,开发人员可以从 OpenAI 仪表板请求 API密钥。
OpenAI 提供了多种计划,包括一个免费计划,充许并发人员在有限的访问权限下测试 API。
开发人员可以升级到付费计划以获得对 API 的更多访问权限。
如何使用OpenAI API key
- 要使用 OpenAI API 密钥,开发人员需要将 API 集成到他们的应用程序中。 OpenAI 提供了多种 SDK 和库,可以轻松地将API 集成到不同的编程语言中。开发人员可以使用 SDK 向 API 发送请求并接收响应。响应可用于生成文本、图像和代码。
使用OpenAl API key的最佳实践
- 对 API密钥保密:开发人员应对其 API 密钥保密,不要与任何人共享。API密钥用于验证对 API 的请求,不要在公共存储库中存储 API 密钥。如果您的 API 密钥被公开,您的帐户可能会被滥用,您的帐户可能会被禁用。
- 监控使用情况:并发人员应监控其APi使用情况,以确保他们不会超出其使用限制。OpenAI 提供使用情况报告,并发人员可以使用这些报告来跟踪他们的使用情况。您可以在Usage上查看您的账户的使用情况。
Token
OpenAl 的token可 以理解为文本中的词块。在APl 处理提示之前,输入会被分解成为这些token。这些token并不一定恰好在单词的开始或结束处分割一一token可以包含尾部空格甚至子词。以下是一些理解token长度的有用准则 :
- 1个token = 4个英文字符
- 1个token = 3/4个单词
- 100个token = 75个单词
或者
- 1-2个句子 30个token
- 1个段落 = 100个token
- 1500个单词 2048个token
不同语言中对应的token差异
不同语言中,单词如何被分割成token是不同的。
例如,西班牙语中的Cómo estás(意为你好吗)包含5个token (对于10个字符)。
更高的token-to-char比率可能会使非英语语言的APi实现成本更高。
访问OpenAI API
有OpenAI API key
- 官方API地址
- OpenAI API代理
- chatgptProxyAPI
无OpenAI API key
gpt4free使用
# clone项目
git clone https://github.com/xtekky/gpt4free.git
# 进入项目根目录
cd gpt4free
# 创建虚拟环境
python3 -m venv .venv
# 激活虚拟环境
source .venv/bin/activate
# 换pip源
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/
# 安装依赖
pip i -r requirements.txt
# 在项目跟目录场景test.py文件
vim test.py
test.py
import g4f
g4f.debug.logging = True # Enable debug logging
g4f.debug.check_version = False # Disable automatic version checking
print(g4f.Provider.Bing.params) # Print supported args for Bing
# Using automatic a provider for the given model
print('#### gpt-3.5')
# Streamed completion
response = g4f.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "Hello"}],
stream=True,
)
print(response)
for message in response:
print(message, flush=True, end='')
print()
print('#### gpt-4')
# Normal response
response = g4f.ChatCompletion.create(
model=g4f.models.gpt_4,
messages=[{"role": "user", "content": "Hello"}],
) # Alternative model setting
print(response)
还可以通过openai 的api server方式使用
# 复制server服务到项目根目录
cp g4f\api\run.py run_api.py
# 修改代码
vim run_api.py
run_api.py
import g4f.api
import g4f
if __name__ == "__main__":
print(f'Starting server... [g4f v-{g4f.debug.version}]')
# g4f.api.run_api(debug=True)
g4f.api.run_api(debug=True, port=8899)
测试
import requests
API_BASE = 'http://127.0.0.1:8899'
r = requests.get(f'{API_BASE}/v1/models')
print(r.json())
# 测试对话
import requests
API_BASE = 'http://127.0.0.1:8899'
data = {
'model': 'gpt-3.5-turbo',
'messages': [
{
'role': 'user',
'content': 'say hello'
}
]
}
r = requests.post(f'{API_BASE}/v1/chat/completions', json=data)
print(r.json())
敏感信息
环境变量
### Windows
# 设置
setx OPENAI_API_KEY "your key"
# 查看
echo %OPENAI_API_KEY%
### Linux/Mac 这里用的bash, zsh改为 ~/.zshrc
echo "export OPENAI_API_KEY='your key'" >> ~/.bash_profile
source ~/.bash_profile
echo $OPENAI_API_KEY
使用python-dotenv
python-dotenv 是一个用于从 .env 文件加载环境变量的库。
它将 .env 文件中的变量加载到您的环境中,以便您可以在代码中使用它们。
# clone测试仓库
git clone https://github.com/showmecodett/imooc-langchain-example
# 安装
pip install python-dotenv
新建.erv.template文件放置在你的项目根目录
.env.template 用于同步你的项目里需要使用到的敏感信息(环境变量)
OPENAI_API_KEY=yourkey
DOMAIN=example.org
ADMIN_EMAIL=admin@${DOMAIN}
ROOT_URL=${DOMAIN}/app
Copy .env.template文件并重命名为.env
.env 文件用于保存你的敏感信息,不要提交到代码仓库
cp .env.template .env
修改.gitignore文件
.env
使用
from dotenv import load_dotenv
import os
load_dotenv() # take environment variables from .env.
print(os.environ.get ("OPENAI_API_KEY"))
print(os.environ.get ("DOMAIN"))
print(os.environ.get ("ADMIN_EMAIL" ))
下达指令
OpenAI 的文本生成模型 (通常称为生成预训练变换器GPT或大型语言模型LLM)能够理解自然语言、代码和图像。
这些模型根据输入提供文本输出。这些模型的输入也称为“提示”。
设计提示本质上是如何“编程”一个大型语言模型,通常是通过提供指令或一些示例来成功完成任务。
Completions API(弃用)
Completions翻译成中文是完成。但在这里中文翻译成补全更合适,即补全用户输入的内容。它允许用户输入一段文本(称为prompt),然后由Al模型自动生成接下来的文本内容。
这种补全可以用于多种应用场景,比如写作辅助: 代码生成、自动回复等。
如果在其他地方看到 补全接口 或 完成接口 都是指的这个。
示例:
- 美国的总统是
- 小明摔倒了,他要去
- https://platform.openai.com/docs/api-reference/completions/create
- Completions模型将字符串作为输入,模型将返回一个或多个预测的完成项。大多数开发者应该使用的 Chat Completions API 来使用OpenAl最好和最新的模型。大部分支持传统Completions端点的模型将在2024年1月4日停止服务。
Chat Completions API
Chat Completions服务是一种特定的Completion服务,它专门为对话和聊天类应用设计。
这种服务模式使得Al模型更擅长于处理对话流程,能够更自然地进行问答、对话或模拟聊关场景。
在Chat Completions模式下, Al模型会根据上下文来生成回复,这通常涉及到以下特性:
- 对话历史管理:模型能够记住之前的对话内容,以使生成连贯的回答。
- 适应性回复:模型会根据对话的上下文来调整其回答的风格和内容。
- 更加自然的交流:生成的文本更符合人类的聊关习惯,包括非正式的语言、语等。
Chat Completions模型将消息列表作为输入,并返回模型生成的消息作为输出。
尽管 Chat Completions格式旨在使多轮对话变得简单,但它对于单轮对话也是有效的,也就是Completions的场景。
如果在其他地方看到 聊天补全接口 或 聊天完成接口 都是指的这个。
Completions API VS Chat Completions APl
在Completions格式中,可以通过构建一个包含单个用户消息的请求来使其类似于Chat Completions格式。例如,可以使用以下Completions提示来从英语翻译成法语:
将以下英文文本翻译成法语:“{text}”
等效的聊关提示将是:
[{"role”: “user", "content":'将以下英文文本翻译成法语:"{text}"'}]
这些API之间的区别在于每个API中可用的底层模型不同。 Chat Completions API可以使用最强大的模型 (gpt-4) 和最具成本效益的模型 (gpt-3.5-turbo) 。 而Completions APi 只能使用 gpt-3.5-turbo-instruct, babbage-002和davinci-002,并且在2024年1月4日之后将不再可用
请求方式
POST https://api.openai.com/v1/chat/completions
请求体
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
| messages | 数组 | 是 | 消息列表 |
| model | string | 是 | 模型名称 |
| max_tokens | 整数/null | 是 | 可生成的最大token数 |
| stream | bool/null | 是 | 流式输出,默认false |
| temperature | 整数/null | 是 | 采样多样性,0-1,越大越随机,默认1 |
curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: app lication/ j son" \
-H "Authorization: Bearer $oPENAI _API _ KEY" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "user",
"content": "Say this is a test”"
}
]
}'
响应
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-3.5-turbo-0613",
"system_fingerprint": "fp_44709d6fcb",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "\n\nThis is a test."
},
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 5,
"total_tokens": 17
}
}
python sdk
openai-python在23年11月6日升级到了V1版本,代码进行了重构,不再兼容之前的写法了,目前在网络上,基本都是老版本的写法,需要注意。大家注意下,如果自己的openai-python版本是v0.xx.xx,如v0.27.9,那么就是老版本, 新版本是V1.xx.xx, 如v1.6.1。
# 安装
pip install openai
# 检查openai-python 版本
pip show openai
# 升级
pip install --upgrade openai
使用
# OpenAI api base地t址 : "https://api.openai.com/v1"
# 老版本 (V1以 下的版本) OPENAI_API_BASE
# 新版本 (V1及以 上的版本) OPENAI_BASE_URL
import os
from openai import OpenAI
client = OpenAI(
# This is the default and can be omitted
api_key=os.environ.get("OPENAI_API KEY"),
base_url=os.environ.get("OPENAI_BASE_URL"),
)
chat_completion = client.chat.completions.create(
messages=[
{
"role": "user",
"content": "Say this is a test",
}],
model="gpt-3.5-turbo",
)
print(chat_completion.choices[0].message.content)
封装
import os
from openai import OpenAI
client = OpenAI(
# This is the default and can be omitted
api_key=os.environ.get("OPENAI_API KEY"),
base_url=os.environ.get("OPENAI_BASE_URL"),
)
# 与大模型交互的函数
def chat(prompt, model='gpt-3.5-turbo'):
chat_completion = client.chat.completions.create(
messages=[
{
"role": "user",
"content": "Say this is a test",
}],
model="gpt-3.5-turbo",
)
return chat_completion.choices[0].message.content
print(chat('美国总统是'))
聊天
上面提到的请求是没有记忆的,也就是没有上下文
messages参数
role (角色)
- System (系统):指令/角色扮演。系统消息有助于设置助手的行为。例如,您可以修改助手的个性或提供有关它在整个对话中应如何行为的具体指示。然而请注意,系统消息是可选的,而且没有系统消息时模型的行为可能与使用通用消息(如 "You are a helpful assistant.") 类似。
- user (用户):用户消息是助手需要响应的请求或评论。用户消息可以是任何内容,但是如果您想要模拟与助手的对话,则应该尽可能接近自然语言。
- assistant (助手):助手消息存储以前的助手回应,但也可以由您编写,以提供期望行为的示例。 通常,对话以系统消息开始,然后是用户和助手消息的交替。
助手的回复可以通过下面方式获取
# curl 或 requests
response['choices'][0]['message']['content']
# python-openai
response.choices[0].message.content
有上下文示例
import os
from openai import OpenAI
client = OpenAI(
# This is the default and can be omitted
api_key=os.environ.get("OPENAI_API KEY"),
base_url=os.environ.get("OPENAI_BASE_URL"),
)
def chat(prompt, model='gpt-3.5-turbo'):
chat_completion = client.chat.completions.create(
messages=[
{"role": "system",
"content": "You are a helpful assistant. "
},
{"role": "user",
"content": "您好, 我叫tt"
},
{"role": "assistant",
"content": "您好, tt"
},
{"role": "user",
"content": prompt,
}],
model=model,
)
return chat_completion.choices[0].message.content
print(chat('我是谁'))
了解Embeddings
什么是Embeddings
Embeddings (嵌入)在自然语言处理 (NLP)中起着至关重要的作用,它们的主要目的是将高维、离散的文本数据 (如单词或短语)转换为低维、连续的向量表示。
这些向量不仅编码了词本身的含义,还捕捉到了词语之间的语义和句法关系。
通过embeddings,原本难以直接处理的文本数据可以被机器学习模型理解和操作。
它就是将不可计算、非结构化 的词转化为可计算、结构化 的向量。
为什么需要将词或句子转换成Embeddings
- 保留语义信息:词嵌入能以一种量化的方式捕获词汇间的语义相似性,例如,“国王”与“王后"的嵌入可能会非常接近。
- 简化模型输入:将每个词映射到一个固定维度的向量,使得深度学习模型可以直接处理数值型的数据,而非原始的文本字符串。
- 便于计算和优化:连续向量形式的嵌入比原始的离散标签更适合用于神经网络等模型的数学运算,比如距离度量、加权求和以及线性变换等。
- 下游任务泛化能力:经过训练得到的高质量词嵌入往往能够很好地迁移到各种下游NLP任务中,如情感分析、问答系统、机器翻译等,无需重新从零开始学习词汇的含义。
openai中使用Embeddings
创建嵌入向量
通过调用 OpenAI 的 APl,您可以创建一个代表输入文本的嵌入向量。
请求方法
POST https://api.openai.com/v1/embeddings
请求参数
- input (string 或 array) : 必填项,输入要嵌入的文本,可以编码为字符串或token数组。若要在单次请求中嵌入多个输入,请传递字符串数组或token数组。输入不得超过模型的最大输入token数 (对于 text-embedding-ada-002 模型是8192个token) ,不能是空字符串,并且任何数组维度必须小于等于2048。
- model (string) : 必填项,text-embedding-ada-002 要使用的模型ID。您可以通过 List models API 查看所有可用模型,或在我们的模型概述中查看它们的描述。
- encoding_format (string) : 可选, 默认为 float,返回嵌入向量的格式,可以是 float 或 ba se64 。
- user (string) : 可选,代表您的终端用户的唯一标识符,有助于OpenAI 监控和检测滥用行为。了解更多信息。
curl https://api.openai.com/v1/chat/embeddings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $oPENAI_API_KEY" \
-d '{
"model": "text-embedding-ada-002",
"input": "The food was delicious and the waiter ..."
}'
返回内容 --- 包含嵌入对象的列表
{
"obj ect": "list",
"data": [
{
"object": "embedding",
"embedding": [
0.0023064255,
-0.009327292,
...(共1536个浮点数,对于 ada-002 模型)
-0.0028842222
],
" index": 0
}
],
"model": "text-embedding-ada-002",
"usage": {
"prompt_ tokens": 8,
"total_tokens": 8
}
}
嵌入对象结构
嵌入对象表示由嵌入端点返回的嵌入向量。
- index (integer):该嵌入在嵌入列表中的索引位置。
- embedding (array):嵌入向量,是一个浮点数列表。向量长度取决于所使用的模型,在嵌入指南中有具体说明。
- object (string) : 对象类型,始终为 “embedding” 。
OpenAI Embeddings模型
模型名称:text-embedding-ada-002
分词器:cl100k_base
最大输入令牌数:8191
输出维度:1536
调用示例
import os
from openai import OpenAI
client = OpenAI(
# This is the default and can be omitted
api_key=os.environ.get("OPENAI_API KEY"),
base_url=os.environ.get("OPENAI_BASE_URL"),
)
def embeddings(prompt, model='text-embedding-ada-002'):
embeddings_completion = client.embeddings.create(
input=prompt,
model=model,
)
return embeddings_completion.data[0].embedding
print(embeddings('你好'))
应用
- 搜索 (通过与查询字符串的相关性对结果进行排序)
- 聚类 (根据相似性将文本字符串分组)
- 推荐 (推荐具有相关文本字符串的项目)
- 异常检测 (识别与其他项关联度较低的离群点)
- 多样性测量 (分析相似性分布)
- 分类 (根据最相似标签对文本字符串进行分类)
Stream式输出
SSE
服务器发送事件 (Server-sent events,简称SSE),服务器向客户端推送数据,客户端通过事件监听器接收数据。
严格地说,HTTP 协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息 (streaming)。
也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。
本质上,这种通信就是以流信息的方式,完成一次用时很长的下载。
向OpenAi请求流式输出
要流式传输完成内容,请在调用聊天完成或完成端点时设置 stream=True。
import requests
API_KEY = ''
API_BASE = 'http://127.0.0.1:8899'
headers = {"Authorization": f"Bearer{API_KEY}"}
data = {
'model': 'gpt-3.5-turbo',
'messages': [
{
'role': 'user',
'content': 'say hello'
}
]
}
# 当 requests 的 stream=True 时,不会立即下载,而是在访问 r.content、r.text 属性时才开始下载,适合下载大文件, 一个块一个块
r = requests.post(f'{API_BASE}/v1/chat/completions', headers=headers, json=data, stream=True)
r.text
解析SSE Response
格式
data: 数据块\n\n
data: 数据块\n\n
示例
// 数据块
data: {
"id": "chatcmpl-8cZcTSrwJzlQg9I7P5g62XG2xaBxI",
"object": "chat.comp letion.chunk",
"created": 1704204077,
"model": "gpt-3.5-turbo-1106",
" system_fingerprint": " fp_772e8125bb",
" choices": [
{
"index": 0,
"delta": {
"role": "assistant",
"content": ""
},
"logprobs": null,
"finish_reason": null
}
]
}\n\n
解析格式
for line in r.text.split('\n\n'):
print(line)
解析内容
content从 delta 字段而不是 message 字段提取数据块。
delta可包含的内容
- a role token (e.g., {" role" : "assistant"} )
- a content token (e.g., {" content" : "\n\n"}
- nothing (e.g., {} ), when the stream is over
# 一行一行下载
for line in r.iter_lines():
if not line:
continue
# byte转字符串
data = json.load(line.decode('utf-8').lstrip('data: '))
finish_reason = data['choices'][0]['finish_reason']
if finish_reason == 'stop':
break
print(data['choices'][0]['delta']['content'],end='')
print()
使用sdk
解析服务器发送事件 (Server-sent events, SSE) 并非易事,应该谨慎进行。简单的策略,如通过换行符分割,可能会导致解析错误。
建议使用支持SSE协议的已有客户端库。这些库已经考虑了SSE的所有规则和特殊情况,能够正确地解析事件流。
使用这些库可以避免手动解析时可能遇到的复杂性和错误,使得开发者可以专注于如何使用事件数据,而不是如 何解析它们。
def chat_stream(prompt, model='gpt-3.5-turbo'):
stream = client.chat.completions.create(
messages=[
{"role": "user",
"content": prompt,
}],
model=model,
stream=True
)
return stream
for chunk in chat_stream('写一个关于春天的诗词'):
if chunk.choices[0].delta.content is not None:
print(chunk.choices[0].delta.content, end='')
print()
缺点
- 内容审查问题。请注意,在生产应用程序中使用 stream=True 会使内容的审核变得更加困难,因为部分完成内容可能更难评估。
- 向C端用户提供服务的时候,需要注意内容审查问题。
- 无 usage 字段。流式响应的另一个小缺点是响应不再包括 usage 字段,告诉你消耗了多少令牌。在接收和组合所有响应后,你可以使用 tiktoken 自己计算这一点。
实战解决方案
多轮对话
while True:
user_input = input("User: ")
if user_input == 'quit':
break
for chunk in chat_stream('写一个关于春天的诗词'):
if chunk.choices[0].delta.content is not None:
print(chunk.choices[0].delta.content, end='')
print()
上下文对话
chat_history = [
{"role": "system",
"content": "You are a helpful assistant. "
}
]
def chat_stream2(chat_histories, model='gpt-3.5-turbo'):
stream = client.chat.completions.create(
messages=chat_histories,
model=model,
stream=True
)
return stream
while True:
user_input = input("User: ")
if user_input == 'quit':
break
# 添加到聊天记录
chat_history.append({
"role": "user",
"content": user_input
})
model_resp = ""
print("AI: ", end="")
for chunk in chat_stream2(chat_history):
chunk_content = chunk.choices[0].delta.content
if chunk_content is not None:
print(chunk_content, end='')
model_resp += chunk_content
print()
# 添加到聊天记录
chat_history.append({
"role": "assistant",
"content": model_resp
})
联网
SerpAPI
SerpAPI 是一种 Python 工具,提供 SerpAPI Google 搜索引擎结果 API 和 SerpAPI 必应搜索引擎结果 API 的 包装器。 你可以使用该工具从多种不同的搜索引擎 (包括 Google 和必应)中检索搜索结果。 https://serpapi.com/search-api
解耦搜索引擎
from dataclasses import dataclass, field
from typing import List, Optional
@dataclass
class SearchResultItem:
title: str
link: str
snippet: str # 摘要
@dataclass
class SearchResults:
results: List[SearchResultItem]
def search_prompt(query: str, search_results: SearchResults) -> str:
_prompt = f"""根据搜索引擎的结果,回答用户的问题。
SEARCH _RESULTS: {search_results}
USER _QUERY: {query}
"""
return _prompt
from serpapi import Client
def get_search_results(query: str) -> SearchResults:
params = {
"engine": "google",
"q": query
}
client = Client(api_key=os.environ["SERPAPI_KEY"])
results = client.search(params)
organic_results = results['organic_results']
search_results = SearchResults(
results=[
SearchResultItem(
title=organic_results['title'],
link=organic_results['link'],
snippet=organic_results['snippet']
)
for organic_result in organic_results
]
)
return search_results
def chat_with_search(prompt, model='gpt-3.5-turbo'):
search_results = get_search_results(prompt)
chat(search_prompt(prompt, search_results))
chat_with_search("易建联什么时候退役的")
