OpenAI Responses API 入門 (6) - ストリーミング
「Responses API」の「ストリーミング」ついてまとめました。
前回
1. ストリーミング
「OpenAI API」にリクエストを行うと、デフォルトでは、出力全体を生成してから、単一の応答で返します。長い出力を生成する場合、応答を待つのに時間がかかることがあります。ストリーミングを使用すると、応答を生成しながら、出力を返すことができます。
2. OpenAI API の準備
「Google Colab」での「OpenAI API」の準備手順は次のとおりです。
(1) パッケージのインストール。
「Responses API」と「Agent SDK」のパッケージをインストールします。
# パッケージのインストール
!pip install -U openai openai-agents(2) 環境変数の準備。
左端の鍵アイコンで「OPENAI_API_KEY」を設定してから、以下のセルを実行してください。
import os
from google.colab import userdata
# 環境変数の準備 (左端の鍵アイコンでOPENAI_API_KEYを設定)
os.environ["OPENAI_API_KEY"] = userdata.get("OPENAI_API_KEY")(3) クライアントの準備。
from openai import OpenAI
# クライアントの準備
client = OpenAI()3. ストリーミングの実行
(1) メッセージリストの準備。
# メッセージリストの準備
messages = [
{
"role": "user",
"content": "早口言葉を言ってください。",
}
](2) 推論の実行。
ストリーミングを行うには、stream=True を指定します。
# 推論の実行
stream = client.responses.create(
model="gpt-4o",
input=messages,
stream=True,
)
for event in stream:
print(event)ResponseCreatedEvent(response=Response(id='resp_67d5f51fec6881918b309bc3509757480b9e6b9341010ff3', created_at=1742075167.0, error=None, incomplete_details=None, instructions=None, metadata={}, model='gpt-4o-2024-08-06', object='response', output=[], parallel_tool_calls=True, temperature=1.0, tool_choice='auto', tools=[], top_p=1.0, max_output_tokens=None, previous_response_id=None, reasoning=Reasoning(effort=None, generate_summary=None), status='in_progress', text=ResponseTextConfig(format=ResponseFormatText(type='text')), truncation='disabled', usage=None, user=None, store=True), type='response.created')
ResponseInProgressEvent(response=Response(id='resp_67d5f51fec6881918b309bc3509757480b9e6b9341010ff3', created_at=1742075167.0, error=None, incomplete_details=None, instructions=None, metadata={}, model='gpt-4o-2024-08-06', object='response', output=[], parallel_tool_calls=True, temperature=1.0, tool_choice='auto', tools=[], top_p=1.0, max_output_tokens=None, previous_response_id=None, reasoning=Reasoning(effort=None, generate_summary=None), status='in_progress', text=ResponseTextConfig(format=ResponseFormatText(type='text')), truncation='disabled', usage=None, user=None, store=True), type='response.in_progress')
ResponseOutputItemAddedEvent(item=ResponseOutputMessage(id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', content=[], role='assistant', status='in_progress', type='message'), output_index=0, type='response.output_item.added')
ResponseContentPartAddedEvent(content_index=0, item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, part=ResponseOutputText(annotations=[], text='', type='output_text'), type='response.content_part.added')
ResponseTextDeltaEvent(content_index=0, delta='もちろん', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='!', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='こちら', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='は', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='どう', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='です', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='か', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='?\n\n', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='「', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='生', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='麦', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='生', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='米', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='生', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='卵', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='。」\n\n', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='速', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='く', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='言', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='って', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='み', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='て', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='ください', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDeltaEvent(content_index=0, delta='!', item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, type='response.output_text.delta')
ResponseTextDoneEvent(content_index=0, item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, text='もちろん!こちらはどうですか?\n\n「生麦生米生卵。」\n\n速く言ってみてください!', type='response.output_text.done')
ResponseContentPartDoneEvent(content_index=0, item_id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', output_index=0, part=ResponseOutputText(annotations=[], text='もちろん!こちらはどうですか?\n\n「生麦生米生卵。」\n\n速く言ってみてください!', type='output_text'), type='response.content_part.done')
ResponseOutputItemDoneEvent(item=ResponseOutputMessage(id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', content=[ResponseOutputText(annotations=[], text='もちろん!こちらはどうですか?\n\n「生麦生米生卵。」\n\n速く言ってみてください!', type='output_text')], role='assistant', status='completed', type='message'), output_index=0, type='response.output_item.done')
ResponseCompletedEvent(response=Response(id='resp_67d5f51fec6881918b309bc3509757480b9e6b9341010ff3', created_at=1742075167.0, error=None, incomplete_details=None, instructions=None, metadata={}, model='gpt-4o-2024-08-06', object='response', output=[ResponseOutputMessage(id='msg_67d5f52045608191bb7707be7b5a0e140b9e6b9341010ff3', content=[ResponseOutputText(annotations=[], text='もちろん!こちらはどうですか?\n\n「生麦生米生卵。」\n\n速く言ってみてください!', type='output_text')], role='assistant', status='completed', type='message')], parallel_tool_calls=True, temperature=1.0, tool_choice='auto', tools=[], top_p=1.0, max_output_tokens=None, previous_response_id=None, reasoning=Reasoning(effort=None, generate_summary=None), status='completed', text=ResponseTextConfig(format=ResponseFormatText(type='text')), truncation='disabled', usage=ResponseUsage(input_tokens=34, output_tokens=26, output_tokens_details=OutputTokensDetails(reasoning_tokens=0), total_tokens=60, input_tokens_details={'cached_tokens': 0}), user=None, store=True), type='response.completed')(3) 差分テキストのみ出力。
# 推論の実行
stream = client.responses.create(
model="gpt-4o",
input=messages,
stream=True,
)
for event in stream:
if event.type == 'response.output_text.delta':
print(event.delta, end='')もちろん!これはどうですか?
「生麦生米生卵」
または、
「隣の客はよく柿食う客だ」
Colab上では数文字ずつストリーミング出力されます。
4. イベント
「Responses API」は、ストリーミング応答で「イベント」を返します。「イベント」は type でイベント種別を識別することもできます。
主なイベント種別は次のとおりです。
・response.created : モデル応答が開始した時に発行。
・response.output_text.delta : 追加のテキスト差分が発生した時に発行。
・response.completed : モデル応答が完了した時に発行。
・error : エラーが発生した時に発行。
イベント種別完全なリストについては、「ストリーミングのAPIリファレンス」を参照してください。
type StreamingEvent =
| ResponseCreatedEvent
| ResponseInProgressEvent
| ResponseFailedEvent
| ResponseCompletedEvent
| ResponseOutputItemAdded
| ResponseOutputItemDone
| ResponseContentPartAdded
| ResponseContentPartDone
| ResponseOutputTextDelta
| ResponseOutputTextAnnotationAdded
| ResponseTextDone
| ResponseRefusalDelta
| ResponseRefusalDone
| ResponseFunctionCallArgumentsDelta
| ResponseFunctionCallArgumentsDone
| ResponseFileSearchCallInProgress
| ResponseFileSearchCallSearching
| ResponseFileSearchCallCompleted
| ResponseCodeInterpreterInProgress
| ResponseCodeInterpreterCallCodeDelta
| ResponseCodeInterpreterCallCodeDone
| ResponseCodeInterpreterCallIntepreting
| ResponseCodeInterpreterCallCompleted
| Error