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

תיעוד 174

קלט בזרימה

הבנת שני מצבי הקלט של Claude Agent SDK ומתי להשתמש בכל אחד

#סקירה

Claude Agent SDK תומך בשני מצבי קלט נפרדים לאינטראקציה עם סוכנים:

  • מצב קלט בזרימה: סשן מתמשך ואינטראקטיבי
  • קלט של הודעה יחידה: שאילתות חד פעמיות שמשתמשות במצב הסשן ובחידוש

#מצב קלט בזרימה (מומלץ)

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

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

#יתרונות

במצב קלט בזרימה עובדים בסשן מתמשך עם היכולות האלה:

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

#דוגמה ליישום

הדוגמאות האלה קוראות תמונה בשם diagram.png מתיקיית העבודה. צרו אחת שם קודם, או שנו את שם הקובץ כך שיצביע על התמונה שלכם.

import { query, type SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";
import { readFile } from "fs/promises";

async function* generateMessages(): AsyncGenerator<SDKUserMessage> {
  // First message
  yield {
    type: "user",
    message: {
      role: "user",
      content: "Analyze this codebase for security issues"
    },
    parent_tool_use_id: null
  };

  // Wait for conditions or user input
  await new Promise((resolve) => setTimeout(resolve, 2000));

  // Follow-up with image
  yield {
    type: "user",
    message: {
      role: "user",
      content: [
        {
          type: "text",
          text: "Review this architecture diagram"
        },
        {
          type: "image",
          source: {
            type: "base64",
            media_type: "image/png",
            data: await readFile("diagram.png", "base64")
          }
        }
      ]
    },
    parent_tool_use_id: null
  };
}

// Process streaming responses
for await (const message of query({
  prompt: generateMessages(),
  options: {
    maxTurns: 10,
    allowedTools: ["Read", "Grep"]
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}
from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    AssistantMessage,
    TextBlock,
)
import asyncio
import base64


async def streaming_analysis():
    async def message_generator():
        # First message
        yield {
            "type": "user",
            "message": {
                "role": "user",
                "content": "Analyze this codebase for security issues",
            },
        }

        # Wait for conditions
        await asyncio.sleep(2)

        # Follow-up with image
        with open("diagram.png", "rb") as f:
            image_data = base64.b64encode(f.read()).decode()

        yield {
            "type": "user",
            "message": {
                "role": "user",
                "content": [
                    {"type": "text", "text": "Review this architecture diagram"},
                    {
                        "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": "image/png",
                            "data": image_data,
                        },
                    },
                ],
            },
        }

    # Use ClaudeSDKClient for streaming input
    options = ClaudeAgentOptions(max_turns=10, allowed_tools=["Read", "Grep"])

    async with ClaudeSDKClient(options) as client:
        # Send streaming input
        await client.query(message_generator())

        # Process responses
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(block.text)


asyncio.run(streaming_analysis())

כשמריצים את הדוגמה, גרסת TypeScript מדפיסה כל תשובה כשהיא מסתיימת. הלולאה receive_response() בגרסת Python מסתיימת בהודעת התוצאה הראשונה, ולכן היא מדפיסה את ניתוח האבטחה. כדי לקרוא את שתי התשובות, השתמשו בצמד אחד של query() וreceive_response() לכל הודעה, כפי שמוצג בדוגמה בתיעוד Python להמשך שיחה.

אם הsource של בלוק תמונה חסר או אינו אובייקט, ה SDK לא מדווח על שגיאה. Claude Code שולח ל Claude הערת טקסט במקום התמונה, למשל [Image could not be processed: image block has no source object], והסשן ממשיך.

[!NOTE]

ב SDK של TypeScript, אם מחולל ההודעות זורק חריגה, למשל כשקובץ שהוא קורא חסר, הזרם מסתיים בשגיאה שנוסחה Claude Code process aborted by user במקום השגיאה המקורית, לכן בדקו קודם את הקוד בתוך המחולל כשרואים את ההודעה הזאת. לפני השגיאה עשויה להופיע גם שורה ארוכה ומכווצת של קוד מקור ארוז של ה SDK, לכן קראו עד סוף הפלט כדי לראות את טקסט השגיאה.

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

#קלט של הודעה יחידה

קלט של הודעה יחידה פשוט יותר אבל מוגבל יותר.

#מתי להשתמש בקלט של הודעה יחידה

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

  • צריך תשובה חד פעמית
  • אין צורך בצירופי תמונות או בשיטות שליטה באמצע הסשן
  • צריך לפעול בסביבה חסרת מצב, כמו פונקציית lambda

#מגבלות

[!WARNING]

מצב קלט של הודעה יחידה לא תומך ב:

  • צירוף תמונות ישיר בהודעות
  • תור הודעות דינמי
  • קטיעה בזמן אמת
  • שיחות מרובות תורות באופן טבעי

אם שאילתה מסתיימת בתוצאת שגיאה, כמו error_max_turns, קריאה של query() להודעה יחידה מעלה שגיאה שכוללת את טקסט הכשל אחרי שהיא מניבה את הודעת התוצאה הסופית, לכן עטפו את הלולאה בבלוק try אם הקוד צריך להמשיך. ראו טיפול בתוצאה לתת הסוגים של התוצאה.

#דוגמה ליישום

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

// Simple one-shot query
// query() throws after an error result, such as error_max_turns
try {
  for await (const message of query({
    prompt: "Explain the authentication flow",
    options: {
      maxTurns: 5,
      allowedTools: ["Read", "Grep"]
    }
  })) {
    if (message.type === "result" && message.subtype === "success") {
      console.log(message.result);
    }
  }
} catch (error) {
  console.error(`Query failed: ${error}`);
}

// Continue conversation with session management
try {
  for await (const message of query({
    prompt: "Now explain the authorization process",
    options: {
      continue: true,
      maxTurns: 5
    }
  })) {
    if (message.type === "result" && message.subtype === "success") {
      console.log(message.result);
    }
  }
} catch (error) {
  console.error(`Query failed: ${error}`);
}
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
import asyncio


async def single_message_example():
    # Simple one-shot query using query() function
    # query() raises ResultError after an error result, such as error_max_turns
    try:
        async for message in query(
            prompt="Explain the authentication flow",
            options=ClaudeAgentOptions(max_turns=5, allowed_tools=["Read", "Grep"]),
        ):
            if isinstance(message, ResultMessage) and message.subtype == "success":
                print(message.result)
    except Exception as e:
        print(f"Query failed: {e}")

    # Continue conversation with session management
    try:
        async for message in query(
            prompt="Now explain the authorization process",
            options=ClaudeAgentOptions(continue_conversation=True, max_turns=5),
        ):
            if isinstance(message, ResultMessage) and message.subtype == "success":
                print(message.result)
    except Exception as e:
        print(f"Query failed: {e}")


asyncio.run(single_message_example())

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