מדריך קלוד קוד בעברית

תיעוד 135

הזרמת תגובות בזמן אמת

קבל תגובות בזמן אמת מ-Agent SDK כאשר טקסט וקריאות לכלים מוזרמים פנימה

כברירת מחדל, ה-Agent SDK מניב אובייקטי AssistantMessage מלאים לאחר ש-Claude מסיים ליצור כל תגובה. כדי לקבל עדכונים הדרגתיים כשטקסט וקריאות לכלים נוצרים, הפעל הזרמת הודעות חלקיות.

טיפ: דף זה מכסה הזרמת פלט (קבלת טוקנים בזמן אמת). לגבי מצבי קלט (כיצד אתה שולח הודעות), ראה שליחת הודעות לסוכנים. באפשרותך גם להזרים תגובות באמצעות ה-Agent SDK דרך ה-CLI.

#הפעלת הזרמת פלט

כדי להפעיל הזרמה, הגדר את include_partial_messages (ב-Python) או includePartialMessages (ב-TypeScript) ל-true באפשרויות שלך. הדבר גורם ל-SDK להניב הודעות StreamEvent המכילות אירועי API גולמיים כשהם מגיעים, בנוסף ל-AssistantMessage ול-ResultMessage הרגילים.

לאחר מכן הקוד שלך צריך:

  1. לבדוק את הסוג של כל הודעה כדי להבדיל בין StreamEvent לסוגי הודעות אחרים
  2. עבור StreamEvent, לחלץ את השדה event ולבדוק את ה-type שלו
  3. לחפש אירועי content_block_delta שבהם delta.type הוא text_delta, המכילים את מקטעי הטקסט בפועל

הדוגמה להלן מפעילה הזרמה ומדפיסה מקטעי טקסט כשהם מגיעים. שים לב לבדיקות הסוג המקוננות: תחילה עבור StreamEvent, לאחר מכן עבור content_block_delta, ולאחר מכן עבור text_delta:

Python:

from claude_agent_sdk import query, ClaudeAgentOptions
from claude_agent_sdk.types import StreamEvent
import asyncio


async def stream_response():
    options = ClaudeAgentOptions(
        include_partial_messages=True,
        allowed_tools=["Bash", "Read"],
    )

    async for message in query(prompt="List the files in my project", options=options):
        if isinstance(message, StreamEvent):
            event = message.event
            if event.get("type") == "content_block_delta":
                delta = event.get("delta", {})
                if delta.get("type") == "text_delta":
                    print(delta.get("text", ""), end="", flush=True)


asyncio.run(stream_response())

TypeScript:

import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "List the files in my project",
  options: {
    includePartialMessages: true,
    allowedTools: ["Bash", "Read"]
  }
})) {
  if (message.type === "stream_event") {
    const event = message.event;
    if (event.type === "content_block_delta") {
      if (event.delta.type === "text_delta") {
        process.stdout.write(event.delta.text);
      }
    }
  }
}

#תיעוד StreamEvent

כאשר הודעות חלקיות מופעלות, אתה מקבל אירועי הזרמה גולמיים של Claude API עטופים באובייקט. לסוג זה יש שמות שונים בכל SDK:

  • Python: StreamEvent (ייבוא מתוך claude_agent_sdk.types)
  • TypeScript: SDKPartialAssistantMessage עם type: 'stream_event'

שניהם מכילים אירועי Claude API גולמיים, ולא טקסט מצטבר. עליך לחלץ ולצבור מקטעי טקסט (deltas) בעצמך. הנה המבנה של כל סוג:

Python:

@dataclass
class StreamEvent:
    uuid: str  
# Unique identifier for this event
    session_id: str  
# Session identifier
    event: dict[str, Any]  
# The raw Claude API stream event
    parent_tool_use_id: str | None  
# Always None

TypeScript:

type SDKPartialAssistantMessage = {
  type: "stream_event";
  event: BetaRawMessageStreamEvent; // From Anthropic SDK
  parent_tool_use_id: string | null;
  uuid: UUID;
  session_id: string;
  ttft_ms?: number; // Time to first token in ms, present only on message_start events
};

השדה parent_tool_use_id הוא תמיד None ב-Python ו-null ב-TypeScript. אירועי הזרמה נשלחים עבור הפעלת השיחה הראשית בלבד, ושינויים ברמת הטוקן מסוכני משנה אינם מועברים הלאה. כדי לייחס פלט לסוכן משנה, השתמש בהודעות מלאות, אשר נושאות את parent_tool_use_id. ראה זיהוי הפעלת סוכני משנה.

השדה event מכיל את אירוע ההזרמה הגולמי מתוך Claude API. סוגי אירועים נפוצים כוללים:

סוג אירועתיאור
message_startתחילתה של הודעה חדשה
content_block_startתחילתו של בלוק תוכן חדש (טקסט או שימוש בכלי)
content_block_deltaעדכון הדרגתי לתוכן
content_block_stopסיומו של בלוק תוכן
message_deltaעדכונים ברמת ההודעה (סיבת עצירה, שימוש)
message_stopסיום ההודעה

#זרימת הודעות

כאשר הודעות חלקיות מופעלות, אתה מקבל הודעות בסדר הבא:

StreamEvent (message_start)
StreamEvent (content_block_start) - text block
StreamEvent (content_block_delta) - text chunks...
StreamEvent (content_block_stop)
StreamEvent (content_block_start) - tool_use block
StreamEvent (content_block_delta) - tool input chunks...
StreamEvent (content_block_stop)
StreamEvent (message_delta)
StreamEvent (message_stop)
AssistantMessage - complete message with all content
... tool executes ...
... more streaming events for next turn ...
ResultMessage - final result

ללא הפעלת הודעות חלקיות, אתה מקבל את כל סוגי ההודעות למעט StreamEvent. סוגים נפוצים כוללים את SystemMessage (אתחול הפעלה), AssistantMessage (תגובות מלאות), ResultMessage (תוצאה סופית), והודעת גבול דחיסה המציינת מתי היסטוריית השיחה נדחסה (SDKCompactBoundaryMessage ב-TypeScript, או SystemMessage עם תת-סוג "compact_boundary" ב-Python).

#הזרמת קריאות לכלים

קריאות לכלים מוזרמות גם הן באופן הדרגתי. באפשרותך לעקוב מתי כלים מתחילים לפעול, לקבל את הקלט שלהם בזמן שהוא נוצר, ולראות מתי הם מסתיימים. הדוגמה להלן עוקבת אחר הכלי הנוכחי שמופעל וצוברת את קלט ה-JSON כשהוא מוזרם פנימה. היא משתמשת בשלושה סוגי אירועים:

  • content_block_start: הכלי מתחיל
  • content_block_delta עם input_json_delta: מקטעי קלט מגיעים
  • content_block_stop: קריאת הכלי הושלמה

Python:

from claude_agent_sdk import query, ClaudeAgentOptions
from claude_agent_sdk.types import StreamEvent
import asyncio


async def stream_tool_calls():
    options = ClaudeAgentOptions(
        include_partial_messages=True,
        allowed_tools=["Read", "Bash"],
    )

    
# Track the current tool and accumulate its input JSON
    current_tool = None
    tool_input = ""

    async for message in query(prompt="Read the README.md file", options=options):
        if isinstance(message, StreamEvent):
            event = message.event
            event_type = event.get("type")

            if event_type == "content_block_start":
                
# New tool call is starting
                content_block = event.get("content_block", {})
                if content_block.get("type") == "tool_use":
                    current_tool = content_block.get("name")
                    tool_input = ""
                    print(f"Starting tool: {current_tool}")

            elif event_type == "content_block_delta":
                delta = event.get("delta", {})
                if delta.get("type") == "input_json_delta":
                    
# Accumulate JSON input as it streams in
                    chunk = delta.get("partial_json", "")
                    tool_input += chunk
                    print(f"  Input chunk: {chunk}")

            elif event_type == "content_block_stop":
                
# Tool call complete - show final input
                if current_tool:
                    print(f"Tool {current_tool} called with: {tool_input}")
                    current_tool = None


asyncio.run(stream_tool_calls())

TypeScript:

import { query } from "@anthropic-ai/claude-agent-sdk";

// Track the current tool and accumulate its input JSON
let currentTool: string | null = null;
let toolInput = "";

for await (const message of query({
  prompt: "Read the README.md file",
  options: {
    includePartialMessages: true,
    allowedTools: ["Read", "Bash"]
  }
})) {
  if (message.type === "stream_event") {
    const event = message.event;

    if (event.type === "content_block_start") {
      // New tool call is starting
      if (event.content_block.type === "tool_use") {
        currentTool = event.content_block.name;
        toolInput = "";
        console.log(`Starting tool: ${currentTool}`);
      }
    } else if (event.type === "content_block_delta") {
      if (event.delta.type === "input_json_delta") {
        // Accumulate JSON input as it streams in
        const chunk = event.delta.partial_json;
        toolInput += chunk;
        console.log(`  Input chunk: ${chunk}`);
      }
    } else if (event.type === "content_block_stop") {
      // Tool call complete - show final input
      if (currentTool) {
        console.log(`Tool ${currentTool} called with: ${toolInput}`);
        currentTool = null;
      }
    }
  }
}

#בניית ממשק משתמש להזרמה

דוגמה זו משלבת הזרמת טקסט והזרמת כלים לממשק משתמש מגובש. היא עוקבת אם הסוכן מבצע כלי ברגע נתון (באמצעות דגל in_tool), כדי להציג מחווני סטטוס כגון [Using Read...] בזמן שהכלים פועלים. טקסט מוזרם כרגיל כאשר לא נמצאים בתוך כלי, וסיום הכלי מפעיל הודעת "done". דפוס זה שימושי לממשקי שיחה שצריכים להציג התקדמות במהלך משימות סוכן מרובות שלבים.

Python:

from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
from claude_agent_sdk.types import StreamEvent
import asyncio
import sys


async def streaming_ui():
    options = ClaudeAgentOptions(
        include_partial_messages=True,
        allowed_tools=["Read", "Bash", "Grep"],
    )

    
# Track whether we're currently in a tool call
    in_tool = False

    async for message in query(
        prompt="Find all TODO comments in the codebase", options=options
    ):
        if isinstance(message, StreamEvent):
            event = message.event
            event_type = event.get("type")

            if event_type == "content_block_start":
                content_block = event.get("content_block", {})
                if content_block.get("type") == "tool_use":
                    
# Tool call is starting - show status indicator
                    tool_name = content_block.get("name")
                    print(f"\n[Using {tool_name}...]", end="", flush=True)
                    in_tool = True

            elif event_type == "content_block_delta":
                delta = event.get("delta", {})
                
# Only stream text when not executing a tool
                if delta.get("type") == "text_delta" and not in_tool:
                    sys.stdout.write(delta.get("text", ""))
                    sys.stdout.flush()

            elif event_type == "content_block_stop":
                if in_tool:
                    
# Tool call finished
                    print(" done", flush=True)
                    in_tool = False

        elif isinstance(message, ResultMessage):
            
# Agent finished all work
            print(f"\n\n--- Complete ---")


asyncio.run(streaming_ui())

TypeScript:

import { query } from "@anthropic-ai/claude-agent-sdk";

// Track whether we're currently in a tool call
let inTool = false;

for await (const message of query({
  prompt: "Find all TODO comments in the codebase",
  options: {
    includePartialMessages: true,
    allowedTools: ["Read", "Bash", "Grep"]
  }
})) {
  if (message.type === "stream_event") {
    const event = message.event;

    if (event.type === "content_block_start") {
      if (event.content_block.type === "tool_use") {
        // Tool call is starting - show status indicator
        process.stdout.write(`\n[Using ${event.content_block.name}...]`);
        inTool = true;
      }
    } else if (event.type === "content_block_delta") {
      // Only stream text when not executing a tool
      if (event.delta.type === "text_delta" and !inTool) {
        process.stdout.write(event.delta.text);
      }
    } else if (event.type === "content_block_stop") {
      if (inTool) {
        // Tool call finished
        console.log(" done");
        inTool = false;
      }
    }
  } else if (message.type === "result") {
    // Agent finished all work
    console.log("\n\n--- Complete ---");
  }
}

#מגבלות ידועות

  • פלט מובנה: תוצאת ה-JSON מופיעה רק ב-ResultMessage.structured_output הסופי, ולא כמקטעי שינוי מוזרמים. ראה פלטים מובנים לפרטים.

#השלבים הבאים

כעת, כשבאפשרותך להזרים טקסט וקריאות לכלים בזמן אמת, תוכל לבחון נושאים קשורים אלה: