如何流式传输补全

默认情况下,当您向 OpenAI 请求补全时,整个补全会在一次响应中生成并发送回来。

如果您正在生成长补全,等待响应可能需要很多秒。

为了更快地获得响应,您可以“流式传输”补全,即在生成过程中进行传输。这允许您在完整的补全完成之前开始打印或处理补全的开头部分。

要流式传输补全,请在调用聊天补全或补全端点时设置 stream=True。这将返回一个对象,该对象会以仅数据服务器发送事件的形式流式传输响应。请从 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': '数到 100,每个数字之间用逗号隔开,没有换行符。例如:1, 2, 3, ...'}
    ],
    temperature=0,
)
# 计算接收响应所需的时间
response_time = time.time() - start_time

# 打印延迟时间和接收到的文本
print(f"请求后 {response_time:.2f} 秒收到完整响应")
print(f"完整响应:\n{response}")
请求后 1.88 秒收到完整响应
完整响应:
ChatCompletion(id='chatcmpl-9lMgdoiMfxVHPDNVCtvXuTWcQ2GGb', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=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))], created=1721075651, model='gpt-july-test', object='chat.completion', system_fingerprint='fp_e9b8ed65d2', usage=CompletionUsage(completion_tokens=298, prompt_tokens=36, total_tokens=334))

回复可以与 response.choices[0].message 一起提取。

回复的内容可以与 response.choices[0].message.content 一起提取。

reply = response.choices[0].message
print(f"提取的回复: \n{reply}")

reply_content = response.choices[0].message.content
print(f"提取的内容: \n{reply_content}")
提取的回复: 
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)
提取的内容: 
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

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("****************")
ChatCompletionChunk(id='chatcmpl-9lMgfRSWPHcw51s6wxKT1YEO2CKpd', choices=[Choice(delta=ChoiceDelta(content='', function_call=None, role='assistant', tool_calls=None), finish_reason=None, index=0, logprobs=None)], created=1721075653, model='gpt-july-test', object='chat.completion.chunk', system_fingerprint='fp_e9b8ed65d2', usage=None)

****************
ChatCompletionChunk(id='chatcmpl-9lMgfRSWPHcw51s6wxKT1YEO2CKpd', choices=[Choice(delta=ChoiceDelta(content='Two', function_call=None, role=None, tool_calls=None), finish_reason=None, index=0, logprobs=None)], created=1721075653, model='gpt-july-test', object='chat.completion.chunk', system_fingerprint='fp_e9b8ed65d2', usage=None)
Two
****************
ChatCompletionChunk(id='chatcmpl-9lMgfRSWPHcw51s6wxKT1YEO2CKpd', choices=[Choice(delta=ChoiceDelta(content='.', function_call=None, role=None, tool_calls=None), finish_reason=None, index=0, logprobs=None)], created=1721075653, model='gpt-july-test', object='chat.completion.chunk', system_fingerprint='fp_e9b8ed65d2', usage=None)
.
****************
ChatCompletionChunk(id='chatcmpl-9lMgfRSWPHcw51s6wxKT1YEO2CKpd', choices=[Choice(delta=ChoiceDelta(content=None, function_call=None, role=None, tool_calls=None), finish_reason='stop', index=0, logprobs=None)], created=1721075653, model='gpt-july-test', object='chat.completion.chunk', system_fingerprint='fp_e9b8ed65d2', usage=None)
None
****************

如上所示,流式响应具有 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': '数到 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}")
请求后 1.14 秒收到消息: 
请求后 1.14 秒收到消息: 1
请求后 1.14 秒收到消息: ,
请求后 1.14 秒收到消息:  
请求后 1.14 秒收到消息: 2
请求后 1.16 秒收到消息: ,
请求后 1.16 秒收到消息:  
请求后 1.16 秒收到消息: 3
请求后 1.35 秒收到消息: ,
请求后 1.35 秒收到消息:  
请求后 1.35 秒收到消息: 4
请求后 1.36 秒收到消息: ,
请求后 1.36 秒收到消息:  
请求后 1.36 秒收到消息: 5
请求后 1.36 秒收到消息: ,
请求后 1.36 秒收到消息:  
请求后 1.36 秒收到消息: 6
请求后 1.36 秒收到消息: ,
请求后 1.36 秒收到消息:  
请求后 1.36 秒收到消息: 7
请求后 1.36 秒收到消息: ,
请求后 1.36 秒收到消息:  
请求后 1.36 秒收到消息: 8
请求后 1.36 秒收到消息: ,
请求后 1.36 秒收到消息:  
请求后 1.36 秒收到消息: 9
请求后 1.36 秒收到消息: ,
请求后 1.36 秒收到消息:  
请求后 1.36 秒收到消息: 10
请求后 1.36 秒收到消息: ,
请求后 1.36 秒收到消息:  
请求后 1.36 秒收到消息: 11
请求后 1.36 秒收到消息: ,
请求后 1.36 秒收到消息:  
请求后 1.36 秒收到消息: 12
请求后 1.36 秒收到消息: ,
请求后 1.36 秒收到消息:  
请求后 1.45 秒收到消息: 13
请求后 1.45 秒收到消息: ,
请求后 1.45 秒收到消息:  
请求后 1.45 秒收到消息: 14
请求后 1.45 秒收到消息: ,
请求后 1.45 秒收到消息:  
请求后 1.45 秒收到消息: 15
请求后 1.45 秒收到消息: ,
请求后 1.45 秒收到消息:  
请求后 1.46 秒收到消息: 16
请求后 1.46 秒收到消息: ,
请求后 1.46 秒收到消息:  
请求后 1.47 秒收到消息: 17
请求后 1.47 秒收到消息: ,
请求后 1.47 秒收到消息:  
请求后 1.49 秒收到消息: 18
请求后 1.49 秒收到消息: ,
请求后 1.49 秒收到消息:  
请求后 1.52 秒收到消息: 19
请求后 1.52 秒收到消息: ,
请求后 1.52 秒收到消息:  
请求后 1.53 秒收到消息: 20
请求后 1.53 秒收到消息: ,
请求后 1.53 秒收到消息:  
请求后 1.55 秒收到消息: 21
请求后 1.55 秒收到消息: ,
请求后 1.55 秒收到消息:  
请求后 1.56 秒收到消息: 22
请求后 1.56 秒收到消息: ,
请求后 1.56 秒收到消息:  
请求后 1.58 秒收到消息: 23
请求后 1.58 秒收到消息: ,
请求后 1.58 秒收到消息:  
请求后 1.59 秒收到消息: 24
请求后 1.59 秒收到消息: ,
请求后 1.59 秒收到消息:  
请求后 1.62 秒收到消息: 25
请求后 1.62 秒收到消息: ,
请求后 1.62 秒收到消息:  
请求后 1.62 秒收到消息: 26
请求后 1.62 秒收到消息: ,
请求后 1.62 秒收到消息:  
请求后 1.65 秒收到消息: 27
请求后 1.65 秒收到消息: ,
请求后 1.65 秒收到消息:  
请求后 1.67 秒收到消息: 28
请求后 1.67 秒收到消息: ,
请求后 1.67 秒收到消息:  
请求后 1.69 秒收到消息: 29
请求后 1.69 秒收到消息: ,
请求后 1.69 秒收到消息:  
请求后 1.80 秒收到消息: 30
请求后 1.80 秒收到消息: ,
请求后 1.80 秒收到消息:  
请求后 1.80 秒收到消息: 31
请求后 1.80 秒收到消息: ,
请求后 1.80 秒收到消息:  
请求后 1.80 秒收到消息: 32
请求后 1.80 秒收到消息: ,
请求后 1.80 秒收到消息:  
请求后 1.80 秒收到消息: 33
请求后 1.80 秒收到消息: ,
请求后 1.80 秒收到消息:  
请求后 1.80 秒收到消息: 34
请求后 1.80 秒收到消息: ,
请求后 1.80 秒收到消息:  
请求后 1.80 秒收到消息: 35
请求后 1.80 秒收到消息: ,
请求后 1.80 秒收到消息:  
请求后 1.80 秒收到消息: 36
请求后 1.80 秒收到消息: ,
请求后 1.80 秒收到消息:  
请求后 1.82 秒收到消息: 37
请求后 1.82 秒收到消息: ,
请求后 1.82 秒收到消息:  
请求后 1.83 秒收到消息: 38
请求后 1.83 秒收到消息: ,
请求后 1.83 秒收到消息:  
请求后 1.84 秒收到消息: 39
请求后 1.84 秒收到消息: ,
请求后 1.84 秒收到消息:  
请求后 1.87 秒收到消息: 40
请求后 1.87 秒收到消息: ,
请求后 1.87 秒收到消息:  
请求后 1.88 秒收到消息: 41
请求后 1.88 秒收到消息: ,
请求后 1.88 秒收到消息:  
请求后 1.91 秒收到消息: 42
请求后 1.91 秒收到消息: ,
请求后 1.91 秒收到消息:  
请求后 1.93 秒收到消息: 43
请求后 1.93 秒收到消息: ,
请求后 1.93 秒收到消息:  
请求后 1.93 秒收到消息: 44
请求后 1.93 秒收到消息: ,
请求后 1.93 秒收到消息:  
请求后 1.95 秒收到消息: 45
请求后 1.95 秒收到消息: ,
请求后 1.95 秒收到消息:  
请求后 2.00 秒收到消息: 46
请求后 2.00 秒收到消息: ,
请求后 2.00 秒收到消息:  
请求后 2.00 秒收到消息: 47
请求后 2.00 秒收到消息: ,
请求后 2.00 秒收到消息:  
请求后 2.00 秒收到消息: 48
请求后 2.00 秒收到消息: ,
请求后 2.00 秒收到消息:  
请求后 2.00 秒收到消息: 49
请求后 2.00 秒收到消息: ,
请求后 2.00 秒收到消息:  
请求后 2.00 秒收到消息: 50
请求后 2.00 秒收到消息: ,
请求后 2.00 秒收到消息:  
请求后 2.00 秒收到消息: 51
请求后 2.00 秒收到消息: ,
请求后 2.04 秒收到消息:  
请求后 2.04 秒收到消息: 52
请求后 2.04 秒收到消息: ,
请求后 2.04 秒收到消息:  
请求后 2.04 秒收到消息: 53
请求后 2.04 秒收到消息: ,
请求后 2.13 秒收到消息:  
请求后 2.13 秒收到消息: 54
请求后 2.14 秒收到消息: ,
请求后 2.14 秒收到消息:  
请求后 2.14 秒收到消息: 55
请求后 2.14 秒收到消息: ,
请求后 2.14 秒收到消息:  
请求后 2.14 秒收到消息: 56
请求后 2.14 秒收到消息: ,
请求后 2.14 秒收到消息:  
请求后 2.16 秒收到消息: 57
请求后 2.16 秒收到消息: ,
请求后 2.16 秒收到消息:  
请求后 2.17 秒收到消息: 58
请求后 2.17 秒收到消息: ,
请求后 2.17 秒收到消息:  
请求后 2.19 秒收到消息: 59
请求后 2.19 秒收到消息: ,
请求后 2.19 秒收到消息:  
请求后 2.21 秒收到消息: 60
请求后 2.21 秒收到消息: ,
请求后 2.21 秒收到消息:  
请求后 2.34 秒收到消息: 61
请求后 2.34 秒收到消息: ,
请求后 2.34 秒收到消息:  
请求后 2.34 秒收到消息: 62
请求后 2.34 秒收到消息: ,
请求后 2.34 秒收到消息:  
请求后 2.34 秒收到消息: 63
请求后 2.34 秒收到消息: ,
请求后 2.34 秒收到消息:  
请求后 2.34 秒收到消息: 64
请求后 2.34 秒收到消息: ,
请求后 2.34 秒收到消息:  
请求后 2.34 秒收到消息: 65
请求后 2.34 秒收到消息: ,
请求后 2.34 秒收到消息:  
请求后 2.34 秒收到消息: 66
请求后 2.34 秒收到消息: ,
请求后 2.34 秒收到消息:  
请求后 2.34 秒收到消息: 67
请求后 2.34 秒收到消息: ,
请求后 2.34 秒收到消息:  
请求后 2.36 秒收到消息: 68
请求后 2.36 秒收到消息: ,
请求后 2.36 秒收到消息:  
请求后 2.36 秒收到消息: 69
请求后 2.36 秒收到消息: ,
请求后 2.36 秒收到消息:  
请求后 2.38 秒收到消息: 70
请求后 2.38 秒收到消息: ,
请求后 2.38 秒收到消息:  
请求后 2.39 秒收到消息: 71
请求后 2.39 秒收到消息: ,
请求后 2.39 秒收到消息:  
请求后 2.39 秒收到消息: 72
请求后 2.39 秒收到消息: ,
请求后 2.39 秒收到消息:  
请求后 2.39 秒收到消息: 73
请求后 2.39 秒收到消息: ,
请求后 2.39 秒收到消息:  
请求后 2.39 秒收到消息: 74
请求后 2.39 秒收到消息: ,
请求后 2.39 秒收到消息:  
请求后 2.39 秒收到消息: 75
请求后 2.39 秒收到消息: ,
请求后 2.40 秒收到消息:  
请求后 2.40 秒收到消息: 76
请求后 2.40 秒收到消息: ,
请求后 2.42 秒收到消息:  
请求后 2.42 秒收到消息: 77
请求后 2.42 秒收到消息: ,
请求后 2.51 秒收到消息:  
请求后 2.51 秒收到消息: 78
请求后 2.51 秒收到消息: ,
请求后 2.52 秒收到消息:  
请求后 2.52 秒收到消息: 79
请求后 2.52 秒收到消息: ,
请求后 2.52 秒收到消息:  
请求后 2.52 秒收到消息: 80
请求后 2.52 秒收到消息: ,
请求后 2.52 秒收到消息:  
请求后 2.52 秒收到消息: 81
请求后 2.52 秒收到消息: ,
请求后 2.52 秒收到消息:  
请求后 2.52 秒收到消息: 82
请求后 2.52 秒收到消息: ,
请求后 2.60 秒收到消息:  
请求后 2.60 秒收到消息: 83
请求后 2.60 秒收到消息: ,
请求后 2.64 秒收到消息:  
请求后 2.64 秒收到消息: 84
请求后 2.64 秒收到消息: ,
请求后 2.64 秒收到消息:  
请求后 2.64 秒收到消息: 85
请求后 2.64 秒收到消息: ,
请求后 2.64 秒收到消息:  
请求后 2.66 秒收到消息: 86
请求后 2.66 秒收到消息: ,
请求后 2.66 秒收到消息:  
请求后 2.66 秒收到消息: 87
请求后 2.66 秒收到消息: ,
请求后 2.66 秒收到消息:  
请求后 2.68 秒收到消息: 88
请求后 2.68 秒收到消息: ,
请求后 2.68 秒收到消息:  
请求后 2.69 秒收到消息: 89
请求后 2.69 秒收到消息: ,
请求后 2.69 秒收到消息:  
请求后 2.72 秒收到消息: 90
请求后 2.72 秒收到消息: ,
请求后 2.72 秒收到消息:  
请求后 2.82 秒收到消息: 91
请求后 2.82 秒收到消息: ,
请求后 2.82 秒收到消息:  
请求后 2.82 秒收到消息: 92
请求后 2.82 秒收到消息: ,
请求后 2.82 秒收到消息:  
请求后 2.82 秒收到消息: 93
请求后 2.82 秒收到消息: ,
请求后 2.82 秒收到消息:  
请求后 2.82 秒收到消息: 94
请求后 2.82 秒收到消息: ,
请求后 2.82 秒收到消息:  
请求后 2.82 秒收到消息: 95
请求后 2.82 秒收到消息: ,
请求后 2.82 秒收到消息:  
请求后 2.82 秒收到消息: 96
请求后 2.82 秒收到消息: ,
请求后 2.82 秒收到消息:  
请求后 2.82 秒收到消息: 97
请求后 2.82 秒收到消息: ,
请求后 2.82 秒收到消息:  
请求后 2.82 秒收到消息: 98
请求后 2.82 秒收到消息: ,
请求后 2.82 秒收到消息:  
请求后 2.82 秒收到消息: 99
请求后 2.82 秒收到消息: ,
请求后 2.82 秒收到消息:  
请求后 2.82 秒收到消息: 100
请求后 2.82 秒收到消息: None
请求后 2.82 秒收到完整响应
完整对话: 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

时间比较

在上面的示例中,两个请求都花了大约 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("****************")
choices: [Choice(delta=ChoiceDelta(content='', function_call=None, role='assistant', tool_calls=None), finish_reason=None, index=0, logprobs=None)]
usage: None
****************
choices: [Choice(delta=ChoiceDelta(content='Two', function_call=None, role=None, tool_calls=None), finish_reason=None, index=0, logprobs=None)]
usage: None
****************
choices: [Choice(delta=ChoiceDelta(content='.', function_call=None, role=None, tool_calls=None), finish_reason=None, index=0, logprobs=None)]
usage: None
****************
choices: [Choice(delta=ChoiceDelta(content=None, function_call=None, role=None, tool_calls=None), finish_reason='stop', index=0, logprobs=None)]
usage: None
****************
choices: []
usage: CompletionUsage(completion_tokens=2, prompt_tokens=18, total_tokens=20)
****************