【ChatGPT】OpenAI 如何使用流模式进行回答

ops/2024/12/26 15:33:52/

当你向 OpenAI 请求完成时,默认情况下,整个回复会在一次性响应中全部生成并返回给你。如果你正在生成的回复内容较长,等待完整回复的时间可能会让人觉得有点漫长——好几秒钟呢!为了能更快地获取到部分回复,你可以选择“流式”接收这些正在生成的回复。这样做的话,你就可以在完整的回复还没准备好之前就开始展示或处理部分内容了。

要开启流式回复,只需要在调用 chat completions 或 completions 接口时设置 stream=True。这将返回一个对象,它以 data-only server-sent events 的形式逐步发送回应数据。你应该从 delta 字段而不是 message 字段提取数据块。

缺点

需要注意的是,在生产应用中使用 stream=True 会使管理回复内容变得更加复杂,因为部分回复可能更难以评估。这对 批准的使用情况 可能会产生影响。

示例代码

下面这个笔记本展示了:

  1. 一个典型的聊天回复看起来是什么样子
  2. 流式聊天回复又是什么模样
  3. 流式传输聊天回复能节省多少时间
  4. 如何获取流式聊天回复的令牌使用数据
# !pip install openai
# 导入必要的库
import time  # 用于测量API调用的时间
from openai import OpenAI
import os
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY", "<你的OpenAI API密钥,如果没有设置为环境变量>"))

1. 典型的聊天回复长什么样

通常的 ChatCompletions API 调用会先计算回复,然后一次性返回所有内容。

# 这是一个OpenAI ChatCompletion请求的例子
# https://platform.openai.com/docs/guides/text-generation/chat-completions-api# 记录请求发送前的时间
start_time = time.time()# 发送一个ChatCompletion请求来数到100
response = client.chat.completions.create(model='gpt-4o-mini',messages=[{'role': 'user', 'content': '从1数到100,每个数字之间用逗号隔开,不要换行。例如:1, 2, 3, ...'}],temperature=0,
)
# 计算接收到回复所花费的时间
response_time = time.time() - start_time# 打印延迟时间和收到的文本
print(f"完整回复在请求发出后 {response_time:.2f} 秒内收到")
print(f"完整回复内容:\n{response}")

完整回复在请求发出后 1.88 秒内收到

提取的回复:

ChatCompletionMessage(content='1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100', role='assistant', function_call=None, tool_calls=None)

2. 如何流式传输聊天回复

通过流式API调用,回复是通过一个 事件流 分块增量发送回来的。在Python中,你可以用 for 循环遍历这些事件。

让我们来看看这是什么样子的:

# 这是一个带有 stream=True 的OpenAI ChatCompletion请求例子
# https://platform.openai.com/docs/api-reference/streaming#chat/create-stream# 一个ChatCompletion请求
response = client.chat.completions.create(model='gpt-4o-mini',messages=[{'role': 'user', 'content': "1+1等于多少?用一个词回答。"}],temperature=0,stream=True  # 这次我们设置了 stream=True
)for chunk in response:print(chunk)print(chunk.choices[0].delta.content)print("****************")

如上所示,流式回复有一个 delta 字段,而不是 message 字段。delta 可以包含如下内容:

  • 角色令牌(例如 {"role": "assistant"}
  • 内容令牌(例如 {"content": "\n\n"}
  • 空值(例如 {}),当流结束时

3. 流式传输聊天回复能省下多少时间

现在让 gpt-4o-mini 再次数到100,看看需要多长时间。

# 带有 stream=True 的OpenAI ChatCompletion请求例子
# https://platform.openai.com/docs/api-reference/streaming#chat/create-stream# 记录请求发送前的时间
start_time = time.time()# 发送一个ChatCompletion请求来数到100
response = client.chat.completions.create(model='gpt-4o-mini',messages=[{'role': 'user', 'content': '从1数到100,每个数字之间用逗号隔开,不要换行。例如:1, 2, 3, ...'}],temperature=0,stream=True  # 再次设置 stream=True
)
# 创建变量来收集流式的块
collected_chunks = []
collected_messages = []
# 遍历流式事件
for chunk in response:chunk_time = time.time() - start_time  # 计算块的延迟时间collected_chunks.append(chunk)  # 保存事件回复chunk_message = chunk.choices[0].delta.content  # 提取消息collected_messages.append(chunk_message)  # 保存消息print(f"在请求发出后 {chunk_time:.2f} 秒收到消息: {chunk_message}")  # 打印延迟时间和文本# 打印延迟时间和收到的文本
print(f"完整回复在请求发出后 {chunk_time:.2f} 秒内收到")
# 清除 collected_messages 中的 None
collected_messages = [m for m in collected_messages if m is not None]
full_reply_content = ''.join(collected_messages)
print(f"完整对话内容: {full_reply_content}")
时间对比

在上面的例子中,两个请求都大约用了4到5秒才完全完成。实际的请求时间会根据负载和其他随机因素有所不同。

然而,对于流式请求来说,我们在0.1秒后就收到了第一个令牌,随后的令牌则每隔约0.01-0.02秒就会收到一次。

4. 如何获取流式聊天回复的令牌使用数据

你可以通过设置 stream_options={"include_usage": True} 来获取流式回复的令牌使用统计信息。当你这样做时,作为最后一个块会额外流式传输一个块。你可以通过该块上的 usage 字段访问整个请求的使用数据。当你设置 stream_options={"include_usage": True} 时,有几点需要注意:

  • 除了最后一个块外,所有块的 usage 字段的值都将为 null。
  • 最后一个块的 usage 字段包含整个请求的令牌使用统计数据。
  • 最后一个块的 choices 字段将始终是一个空数组 []

让我们看看它是如何工作的,还是用第2个例子中的方式。

# 带有 stream=True 和 stream_options={"include_usage": True} 的OpenAI ChatCompletion请求例子# 一个ChatCompletion请求
response = client.chat.completions.create(model='gpt-4o-mini',messages=[{'role': 'user', 'content': "1+1等于多少?用一个词回答。"}],temperature=0,stream=True,stream_options={"include_usage": True}, # 获取流式回复的令牌使用情况
)for chunk in response:print(f"choices: {chunk.choices}\nusage: {chunk.usage}")print("****************")

http://www.ppmy.cn/ops/145149.html

相关文章

7种server的服务器处理结构模型

两种高效的事件处理模式 服务器程序通常需要处理三类事件&#xff1a;I/O 事件、信号及定时事件。有两种高效的事件处理模式&#xff1a;Reactor和 Proactor&#xff0c;同步 I/O 模型通常用于实现Reactor 模式&#xff0c;异步 I/O 模型通常用于实现 Proactor 模式。 无论是 …

驱动与用户空间的交互函数

ssize_t read(int fd, void *buf, size_t count, loff_t *offt) fd&#xff1a;要打开的设备文件(文件描述符)&#xff1b; buf&#xff1a;返回给用户空间的数据缓冲区&#xff1b; count&#xff1a;要读取的数据长度&#xff1b; offt&#xff1a;相对于文件首地址的偏移…

鸿蒙UI开发——自定义主题色

1、概述 ArkTs提供了应用内主题切换功能&#xff0c;支持全局主题切换&#xff0c;也支持局部主题切换&#xff0c;效果如下。本文针对主题切换做简单介绍。 2、主题色 ArkTs提供了一套内置主题配色&#xff0c;有Colors对象持有&#xff0c;它包含了默认情况下&#xff0c;关…

数据结构之栈,队列,树

目录 一.栈 1.栈的概念及结构 2.栈的实现 3.实现讲解 1.初始化栈 2.销毁栈 3.压栈 4.出栈 5.返回栈顶元素 6.返回栈内元素个数 7.判断栈内是否为空 二.队列 1.队列的概念及结构 2.队列的实现 3.实现讲解 1.初始化队列 2.销毁队列 3.单个成员入队列 4.单个成员…

08 Django - Django媒体文件静态文件文件上传

九、Django媒体文件&静态文件&文件上传 1.静态文件和媒体文件 媒体文件: 用户上传的文件, 叫做media静态文件: 存放在服务器的 css, js, image等,叫做static 在Django中使用静态文件 {% static img/example.jpg %} > static模板关键字就是在settings.py中指定的…

前端Pako.js 压缩解压库 与 Java 的 zlib 压缩与解压 的互通实现

工具介绍&#xff1a; pako.js 前端压缩解压的库&#xff08;包含 zlib 和gzip 两种实现&#xff0c;这里只介绍 zlib&#xff09; pako 2.0.4 API documentation Java8 原生支持 zlib 和 gzip 业务场景 因为数据太大&#xff0c;网络环境不可控。故前端需要将数据 A 先压缩…

PCL点云库入门——PCL库点云滤波算法之直通滤波(PassThrough)和条件滤波(ConditionalRemoval)

0、滤波算法概述 PCL点云库中的滤波算法是处理点云数据不可或缺的一部分&#xff0c;它们能够有效地去除噪声、提取特征或进行数据降维。例如&#xff0c;使用体素网格滤波&#xff08;VoxelGrid&#xff09;可以减少点云数据量&#xff0c;同时保留重要的形状特征。此外&#…

Leetcode经典题20--长度最小的子数组

题目描述 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0 。 输入输出示例 输入&…