การโต้ตอบในการสตรีม

เมื่อสร้างการโต้ตอบ คุณสามารถตั้งค่า stream: true เพื่อสตรีมการตอบกลับทีละส่วนโดยใช้ เหตุการณ์ที่เซิร์ฟเวอร์ส่ง (SSE)

Python

from google import genai

client = genai.Client()

stream = client.interactions.create(
    model="gemini-3.5-flash",
    input="Count from 1 to 25.",
    stream=True,
)
for event in stream:
    if event.event_type == "step.delta":
        if event.delta.type == "text":
            print(event.delta.text, end="", flush=True)

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});

const stream = await client.interactions.create({
    model: "gemini-3.5-flash",
    input: "Count from 1 to 25.",
    stream: true,
});
for await (const event of stream) {
    if (event.event_type === "step.delta") {
        if (event.delta.type === "text") {
            process.stdout.write(event.delta.text);
        }
    }
}

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  --no-buffer \
  -d '{
    "model": "gemini-3.5-flash",
    "input": "Count from 1 to 25.",
    "stream": true
  }'
event: interaction.created
data: {"interaction":{"id":"v1_...","status":"in_progress","object":"interaction","model":"gemini-3.5-flash"},"event_type":"interaction.created"}

event: interaction.status_update
data: {"interaction_id":"v1_...","status":"in_progress","event_type":"interaction.status_update"}

event: step.start
data: {"index":0,"step":{"type":"thought"},"event_type":"step.start"}

event: step.delta
data: {"index":0,"delta":{"signature":"...","type":"thought_signature"},"event_type":"step.delta"}

event: step.stop
data: {"index":0,"event_type":"step.stop"}

event: step.start
data: {"index":1,"step":{"type":"model_output"},"event_type":"step.start"}

event: step.delta
data: {"index":1,"delta":{"text":"1, 2, 3, 4, 5, 6, ","type":"text"},"event_type":"step.delta"}

event: step.delta
data: {"index":1,"delta":{"text":"7, 8, 9, 10, 11, 12, 13,","type":"text"},"event_type":"step.delta"}

...

event: step.stop
data: {"index":1,"event_type":"step.stop"}

event: interaction.completed
data: {"interaction":{"id":"v1_...","status":"completed","usage":{"total_tokens":346,"total_input_tokens":11,"input_tokens_by_modality":[{"modality":"text","tokens":11}],"total_cached_tokens":0,"total_output_tokens":90,"total_tool_use_tokens":0,"total_thought_tokens":245},"created":"2026-05-12T18:44:51Z","updated":"2026-05-12T18:44:51Z","service_tier":"standard","object":"interaction","model":"gemini-3.5-flash"},"event_type":"interaction.completed"}

event: done
data: [DONE]

ประเภทกิจกรรม

เหตุการณ์ที่เซิร์ฟเวอร์ส่งแต่ละรายการจะมี event_type ที่ตั้งชื่อไว้และข้อมูล JSON ที่เกี่ยวข้อง Interactions API ใช้โมเดลการสตรีมแบบสมมาตร ซึ่งเนื้อหาทั้งหมด ไม่ว่าจะเป็นข้อความ การเรียกใช้เครื่องมือ หรือการคิด จะไหลผ่านเหตุการณ์ที่อิงตามขั้นตอน ที่สอดคล้องกัน

สตรีมแต่ละรายการจะเป็นไปตามโฟลว์เหตุการณ์นี้

  1. interaction.created: การโต้ตอบถูกสร้างขึ้น ซึ่งรวมถึงข้อมูลเมตา (รหัส โมเดล สถานะ)
  2. ชุดขั้นตอน ซึ่งแต่ละขั้นตอนประกอบด้วย:
    • เหตุการณ์ step.start ซึ่งระบุประเภทขั้นตอน (เช่น model_output, thought, function_call)
    • เหตุการณ์ step.delta อย่างน้อย 1 รายการที่มีข้อมูลทีละส่วนสำหรับขั้นตอนนั้น
    • เหตุการณ์ step.stop ซึ่งทำเครื่องหมายขั้นตอนว่าเสร็จสมบูรณ์
  3. เหตุการณ์ interaction.completed ที่มีสถิติ usage สุดท้าย

เมื่อตั้งค่า stream: false API จะแสดงผลออบเจ็กต์ interaction รายการเดียวที่มีอาร์เรย์ steps องค์ประกอบแต่ละรายการใน steps คือเวอร์ชันที่ประกอบขึ้นอย่างสมบูรณ์ของวงจร step.startstep.delta(s) → step.stop

interaction.created

ส่งเมื่อมีการสร้างการโต้ตอบเป็นครั้งแรก มีรหัสการโต้ตอบ โมเดล และสถานะเริ่มต้น

event: interaction.created
data: {"interaction": {"id": "...", "model": "gemini-3.5-flash", "status": "in_progress", "object": "interaction"}, "event_type": "interaction.created"}

interaction.status_update

ส่งสัญญาณการเปลี่ยนสถานะระดับการโต้ตอบ อาจปรากฏระหว่างขั้นตอน

event: interaction.status_update
data: {"interaction_id": "...", "status": "in_progress", "event_type": "interaction.status_update"}

step.start

ทำเครื่องหมายจุดเริ่มต้นของขั้นตอนใหม่ มี type และ index ของขั้นตอน ประเภทขั้นตอนจะกำหนดประเภทเดลต้าที่คาดหวังและลักษณะที่ขั้นตอนปรากฏในการตอบกลับที่ไม่ใช่การสตรีม

ประเภทของขั้นตอน ประเภทเดลต้าที่คาดหวัง คำอธิบาย
model_output text, image, audio เนื้อหาการตอบกลับสุดท้ายของโมเดล
thought thought_signature, thought_summary การให้เหตุผลแบบ Chain-of-thought summary จะปรากฏขึ้นเมื่อเปิดใช้ thinking_summaries เท่านั้น
function_call arguments_delta คำขอให้ไคลเอ็นต์เรียกใช้ฟังก์ชัน ตั้งค่าสถานะการโต้ตอบเป็น requires_action
เครื่องมือฝั่งเซิร์ฟเวอร์ แตกต่างกันไปตามเครื่องมือ เครื่องมือที่ API เรียกใช้ (เช่น google_search_call, google_search_result, code_execution_call, code_execution_result)

ดูรายการทั้งหมดได้ที่ข้อมูลอ้างอิง Interactions API

event: step.start
data: {"index": 0, "step": {"type": "model_output"}, "event_type": "step.start"}

สำหรับการเรียกใช้ฟังก์ชัน ขั้นตอนจะรวมถึงชื่อฟังก์ชัน รหัส และอาร์กิวเมนต์ว่างเปล่า {}

event: step.start
data: {"index": 0, "step": {"type": "function_call", "id":"un6k8t18", "name": "get_weather", "arguments":{}}, "event_type": "step.start"}

step.delta

ข้อมูลทีละส่วนสำหรับขั้นตอนปัจจุบัน ออบเจ็กต์ delta มีฟิลด์ type ที่กำหนดรูปร่าง

ตัวอย่างเช่น

text: โทเค็นข้อความทีละส่วนจากขั้นตอน model_output

event: step.delta
data: {"index": 0, "delta": {"type": "text", "text": "Hello, my name is Phil"}, "event_type": "step.delta"}

event: step.delta
data: {"index": 0, "delta": {"type": "text", "text": ", and I live in Germany." }, "event_type": "step.delta"}

image: ข้อมูลรูปภาพที่เข้ารหัส Base64 จากขั้นตอน model_output

event: step.delta
data: {"index": 0, "delta": {"type": "image", "mime_type": "image/jpeg", "data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAoHBwgHBgoICAgLCg..."}, "event_type": "step.delta"}

thought_summary: เนื้อหาข้อมูลสรุปการคิดจากขั้นตอน thought

event: step.delta
data: {"index": 0, "delta": {"type": "thought_summary", "content": {"type": "text", "text": "I need to find the GCD..."}}, "event_type": "step.delta"}

arguments_delta: สตริง JSON (บางส่วน) สำหรับอาร์กิวเมนต์การเรียกใช้ฟังก์ชัน ต้องสะสมในเดลต้า

event: step.delta
data: {"index": 0, "delta": {"type": "arguments_delta", "arguments": "{\"location\": \"San Francisco, CA\"}"}, "event_type": "step.delta"}

นี่คือประเภทเดลต้าที่พบบ่อยที่สุด ดูรายการประเภทเดลต้าทั้งหมดได้ที่ข้อมูลอ้างอิง Interactions API

step.stop

ทำเครื่องหมายจุดสิ้นสุดของขั้นตอน มี index ของขั้นตอน

event: step.stop
data: {"index": 0, "event_type": "step.stop"}

interaction.completed

ส่งเมื่อการโต้ตอบเสร็จสิ้น มีออบเจ็กต์การโต้ตอบสุดท้ายพร้อมสถิติ usage ในโหมดที่ไม่ใช่การสตรีม นี่คือออบเจ็กต์การตอบกลับระดับบนสุด ไม่รวม steps ในการตอบกลับ

event: interaction.completed
data: {"interaction": {"id": "v1_abc123", "status": "completed", "usage": {"total_input_tokens": 7, "total_output_tokens": 12, "total_tokens": 19}}, "event_type": "interaction.completed"}

error

ส่งเมื่อเกิดข้อผิดพลาดระหว่างการโต้ตอบ มีออบเจ็กต์ข้อผิดพลาดพร้อมข้อความและรหัส

event: error
data: {"error":{"message":"Deadline expired before operation could complete.","code":"gateway_timeout"},"event_type":"error"}

การสตรีมด้วยเครื่องมือ

Interactions API รองรับการสตรีมด้วยเครื่องมือทั้งฝั่งไคลเอ็นต์ (การเรียกใช้ฟังก์ชัน) และฝั่งเซิร์ฟเวอร์ (Google Search, การดำเนินการโค้ด ฯลฯ) ในคำขอเดียว ระหว่างการสตรีม การเรียกใช้เครื่องมือจะปรากฏเป็นขั้นตอนที่พิมพ์ในสตรีมเหตุการณ์ สำหรับการเรียกใช้ฟังก์ชัน เหตุการณ์ step.start จะแสดงชื่อฟังก์ชัน และเหตุการณ์ step.delta จะสตรีมอาร์กิวเมนต์เป็นสตริง JSON (arguments_delta) คุณต้องสะสมเดลต้าเหล่านี้เพื่อรับอาร์กิวเมนต์ทั้งหมด API จะเรียกใช้เครื่องมือฝั่งเซิร์ฟเวอร์ เช่น Google Search โดยอัตโนมัติ ซึ่งจะสร้างขั้นตอน google_search_call และ google_search_result

การสตรีมด้วยการเรียกใช้ฟังก์ชัน

หากต้องการทำการเรียกใช้ฟังก์ชันด้วยการสตรีม ไคลเอ็นต์ต้องจัดการการสนทนาหลายรอบดังนี้

  1. รอบที่ 1 (คำขอฟังก์ชัน): เรียกใช้ interactions.create ด้วย stream: true และ tools ที่คุณกำหนด API จะสตรีมขั้นตอน function_call คุณต้องสะสมสตริง JSON ของอาร์กิวเมนต์ทีละส่วน (arguments_delta) จากเหตุการณ์ step.delta จนกว่าการโต้ตอบจะเสร็จสมบูรณ์ด้วยสถานะ requires_action
  2. รอบที่ 2 (การส่งผลลัพธ์): เรียกใช้ interactions.create อีกครั้ง โดยส่ง previous_interaction_id (ซึ่งตรงกับรหัสของการโต้ตอบแรก) และส่งบล็อก function_result ภายในอาร์เรย์ input ซึ่งจะดำเนินการสตรีมต่อ ทำให้โมเดลสร้างการตอบกลับสุดท้ายได้

Python

from google import genai

client = genai.Client()

weather_tool = {
    "type": "function",
    "name": "get_weather",
    "description": "Get the current weather in a given location",
    "parameters": {
        "type": "object",
        "properties": {
            "location": {
                "type": "string",
                "description": "The city and state, e.g. San Francisco, CA"
            }
        },
        "required": ["location"]
    }
}

# Turn 1: Request function call
stream = client.interactions.create(
    model="gemini-3.5-flash",
    tools=[weather_tool],
    input="What is the weather in Paris right now?",
    stream=True,
)

first_interaction_id = None
func_call_id = None
func_call_name = None
func_args_accumulated = ""

for event in stream:
    if event.event_type == "interaction.created":
        first_interaction_id = event.interaction.id
    elif event.event_type == "step.start":
        step = event.step
        if step.type == "function_call":
            func_call_id = step.id
            func_call_name = step.name
    elif event.event_type == "step.delta":
        if event.delta.type == "arguments_delta":
            func_args_accumulated += event.delta.arguments

# Turn 2: Execute tool and send the result back to resume stream
if func_call_id:
    # Execute weather_tool using accumulated arguments
    dummy_result = {
        "content": [{"type": "text", "text": '{"weather": "Sunny and 22°C"}'}]
    }

    stream2 = client.interactions.create(
        model="gemini-3.5-flash",
        previous_interaction_id=first_interaction_id,
        input=[{
            "type": "function_result",
            "name": func_call_name,
            "call_id": func_call_id,
            "result": dummy_result
        }],
        stream=True,
    )

    for event in stream2:
        if event.event_type == "step.delta":
            if event.delta.type == "text":
                print(event.delta.text, end="", flush=True)

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});

const weatherTool = {
    type: "function",
    name: "get_weather",
    description: "Get the current weather in a given location",
    parameters: {
        type: "object",
        properties: {
            location: {
                type: "string",
                description: "The city and state, e.g. San Francisco, CA"
            }
        },
        required: ["location"]
    }
};

// Turn 1: Request function call
const stream = await client.interactions.create({
    model: "gemini-3.5-flash",
    tools: [weatherTool],
    input: "What is the weather in Paris right now?",
    stream: true,
});

let firstInteractionId = null;
let funcCallId = null;
let funcCallName = null;
let funcArgsAccumulated = "";

for await (const event of stream) {
    if (event.event_type === "interaction.created") {
        firstInteractionId = event.interaction.id;
    } else if (event.event_type === "step.start") {
        const step = event.step;
        if (step.type === "function_call") {
            funcCallId = step.id;
            funcCallName = step.name;
        }
    } else if (event.event_type === "step.delta") {
        if (event.delta.type === "arguments_delta") {
            funcArgsAccumulated += event.delta.arguments;
        }
    }
}

// Turn 2: Execute tool and send the result back to resume stream
if (funcCallId && firstInteractionId && funcCallName) {
    const dummyResult = {
        content: [{ type: "text", text: '{"weather": "Sunny and 22°C"}' }]
    };

    const stream2 = await client.interactions.create({
        model: "gemini-3.5-flash",
        previous_interaction_id: firstInteractionId,
        input: [{
            type: "function_result",
            name: funcCallName,
            call_id: funcCallId,
            result: dummyResult
        }],
        stream: true,
    });

    for await (const event of stream2) {
        if (event.event_type === "step.delta") {
            if (event.delta.type === "text") {
                process.stdout.write(event.delta.text);
            }
        }
    }
}

REST

รอบที่ 1: ขอเรียกใช้ฟังก์ชัน

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  --no-buffer \
  -d '{
    "model": "gemini-3.5-flash",
    "input": "What is the weather in Paris right now?",
    "stream": true,
    "tools": [
      {
        "type": "function",
        "name": "get_weather",
        "description": "Get the current weather in a given location",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "The city and state, e.g. San Francisco, CA"
            }
          },
          "required": ["location"]
        }
      }
    ]
  }'

รอบที่ 2: ส่งผลลัพธ์ของฟังก์ชันโดยใช้ previous_interaction_id และ call_id จากรอบที่ 1

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  --no-buffer \
  -d '{
    "model": "gemini-3.5-flash",
    "previous_interaction_id": "v1_ChdGUVFJYXBXVUdLVEF4TjhQ...",
    "stream": true,
    "input": [
      {
        "type": "function_result",
        "name": "get_weather",
        "call_id": "CALL_ID",
        "result": {
          "content": [
            {
              "type": "text",
              "text": "{\"weather\": \"Sunny and 22°C\"}"
            }
          ]
        }
      }
    ]
  }'

การสตรีมด้วยเครื่องมือหลายรายการ

ตัวอย่างต่อไปนี้ใช้ทั้งเครื่องมือ function และ google_search ในคำขอเดียว

Python

from google import genai

client = genai.Client()

tools = [
    {"type": "google_search"},
    {
        "type": "function",
        "name": "get_weather",
        "description": "Get the current weather in a given location",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The city and state, e.g. San Francisco, CA"
                }
            },
            "required": ["location"]
        }
    }
]

stream = client.interactions.create(
    model="gemini-3.5-flash",
    tools=tools,
    input="Search what is the largest mountain in Europe and what the weather is there right now?",
    stream=True,
)
for event in stream:
    if event.event_type == "step.start":
        step = event.step
        print(f"\n--- Step {event.index}: {step.type} ---")
        # Show details for tool steps
        if step.type == "google_search_call":
            print(f"  Search ID: {step.id}")
        elif step.type == "google_search_result":
            print(f"  Result for: {step.call_id}")
        elif step.type == "function_call":
            print(f"  Function: {step.name}({step.arguments})")
    elif event.event_type == "step.delta":
        if event.delta.type == "text":
            print(event.delta.text, end="", flush=True)
        elif event.delta.type == "google_search_call":
            print(f"  Queries: {event.delta.arguments}")
        elif event.delta.type == "arguments_delta":
            print(f"  Args chunk: {event.delta.arguments}", end="", flush=True)
    elif event.event_type == "interaction.completed":
        print(f"\n\nStatus: {event.interaction.status}")
        if event.interaction.status == "requires_action":
            print("Action required: provide function call results to continue.")

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});

const tools = [
    { type: "google_search" },
    {
        type: "function",
        name: "get_weather",
        description: "Get the current weather in a given location",
        parameters: {
            type: "object",
            properties: {
                location: {
                    type: "string",
                    description: "The city and state, e.g. San Francisco, CA"
                }
            },
            required: ["location"]
        }
    }
];

const stream = await client.interactions.create({
    model: "gemini-3.5-flash",
    tools: tools,
    input: "Search what is the largest mountain in Europe and what the weather is there right now?",
    stream: true,
});
for await (const event of stream) {
    if (event.event_type === "step.start") {
        const step = event.step;
        console.log(`\n--- Step ${event.index}: ${step.type} ---`);
        // Show details for tool steps
        if (step.type === "google_search_call") {
            console.log(`  Search ID: ${step.id}`);
        } else if (step.type === "google_search_result") {
            console.log(`  Result for: ${step.call_id}`);
        } else if (step.type === "function_call") {
            console.log(`  Function: ${step.name}(${JSON.stringify(step.arguments)})`);
        }
    } else if (event.event_type === "step.delta") {
        if (event.delta.type === "text") {
            process.stdout.write(event.delta.text);
        } else if (event.delta.type === "google_search_call") {
            console.log(`  Queries: ${JSON.stringify(event.delta.arguments?.queries)}`);
        } else if (event.delta.type === "arguments_delta") {
            process.stdout.write(`  Args chunk: ${event.delta.arguments}`);
        }
    } else if (event.event_type === "interaction.completed") {
        console.log(`\n\nStatus: ${event.interaction.status}`);
        if (event.interaction.status === "requires_action") {
            console.log("Action required: provide function call results to continue.");
        }
    }
}

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  --no-buffer \
  -d '{
    "model": "gemini-3.5-flash",
    "input": "Search what is the largest mountain in Europe and what the weather is there right now?",
    "stream": true,
    "tools": [
      { "type": "google_search" },
      {
        "type": "function",
        "name": "get_weather",
        "description": "Get the current weather in a given location",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "The city and state, e.g. San Francisco, CA"
            }
          },
          "required": ["location"]
        }
      }
    ]
  }'
event: interaction.created
data: {"interaction":{"id":"v1_...","status":"in_progress","object":"interaction","model":"gemini-3.5-flash"},"event_type":"interaction.created"}

event: interaction.status_update
data: {"interaction_id":"v1_...","status":"in_progress","event_type":"interaction.status_update"}

event: step.start
data: {"index":0,"step":{"id":"mkutnkgn","signature":"","type":"google_search_call"},"event_type":"step.start"}

event: step.delta