メインコンテンツへスキップ
見出し画像

OpenAI Responses API 入門 (6) - ストリーミング

    「Responses API」の「ストリーミング」ついてまとめました。

    ・Streaming API responses

    前回

    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

    次回



     
     

    npaka

     
     
    プログラマー。iPhone / Android / Unity / ROS / AI / AR / VR / RasPi / ロボット / ガジェット。年2冊ペースで技術書を執筆。アニソン / カラオケ / ギター / 猫 twitter : @npaka123

    あなたへのおすすめ