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

news/2024/12/26 3:08:27 标签: 游戏, linux, 运维

当你向 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.niftyadmin.cn/n/5799700.html

相关文章

MQTT协议在树莓派上的安全性和性能测试及其在物联网应用中的应用

论文标题&#xff1a;Testing the Security and Performance of MQTT Protocol on Raspberry Pi for IoT Applications&#xff08;MQTT协议在树莓派上的安全性和性能测试及其在物联网应用中的应用&#xff09; 作者信息&#xff1a; Mohammed El-Hajj&#xff0c;计算机学院…

如何一键将图片的HEIC格式转成jpeg格式

今天有个烦恼 iPhone拍的照片传到电脑上都是HEIC格式 一个个可以手机上转&#xff0c;但是几百个就不方便了 于是搜网上&#xff0c;发现都是破烂儿工具 在github找到这大佬写的工具直接搜HeicConverter 有两个版本 一个是命令行的&#xff1a;拖到需要转换的图片目录&…

打造独特的博客封面:动态封面设置指南

如何设置你的专属封面 1先找到一个好的壁纸 以下是好用的壁纸网站 花瓣网 千图网 包图网 WallHere 壁纸 浏览器搜索可画 可画 或者是下载可画的PC端软件 我这里使用的是可画的PC端软件 我们选择这个 单图海报(横板 - 1200 * 726 像素) 这是我们进入的页面 我们点击…

基于vue框架的的校园互助平台4316j(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,失物招领,闲置交易,即时任务,接受的任务,任务分类,任务取消,闲置订单 开题报告内容 基于Vue框架的校园互助平台开题报告 一、研究背景与意义 随着信息技术的飞速发展&#xff0c;互联网已成为大学生学习生活中不可或缺的一部分。…

【linux进程】进程地址空间进程调度队列

目录 一&#xff0c;进程地址空间1. 观察现象2. 对进程地址空间的理解3. 页表和写时拷贝的再理解 二&#xff0c;进程调度队列1. 活动队列和过期队列2. ctive指针和expired指针4. 原理图如下&#xff1a; 先来一个小小的回顾。 我们在讲C/C语言的时候&#xff0c;老师给大家画过…

《探寻神经网络RNN:从原理到应用的奇幻之旅》

《探寻神经网络RNN&#xff1a;从原理到应用的奇幻之旅》 一、RNN 究竟为何方神圣&#xff1f;二、RNN 的工作原理揭秘&#xff08;一&#xff09;独特的循环结构&#xff08;二&#xff09;信息的 “记忆” 与传递 三、RNN 的数学魔法四、RNN 的超能力与应用领域&#xff08;一…

浏览器怎么设置使用ipv4而不使用ipv6

在浏览器中强制使用IPv4而不是IPv6&#xff0c;可以通过以下几种方式实现&#xff1a; 1. 修改操作系统的设置 大多数浏览器会默认根据操作系统的设置来选择IPv4或IPv6。如果操作系统优先选择IPv6&#xff0c;可以通过禁用IPv6来强制使用IPv4。 在Windows中禁用IPv6 打开控…

中科岩创边坡自动化监测解决方案

行业现状 由于边坡不稳定性因素&#xff0c;可能会造成斜坡上的岩土体沿着某个面不均匀向下向外滑动&#xff0c;形成滑坡&#xff1b;陡峭山坡上岩土体在重力作用下&#xff0c;发生陡然倾落运动&#xff0c;造成崩塌&#xff1b;在沟谷或山坡上产生的夹带大量泥沙、石块等固体…