Claude Code 学习站

Agent SDK 输入模式:流式 vs 单条消息

对比 Claude Agent SDK 的流式输入模式与单条消息输入模式的能力、限制及 TypeScript/Python 实现示例。

本页目录10
AI 摘要 · 已核查整理于 2026-08-13原文:Streaming Input(Anthropic)Claude Agent SDK流式输入TypeScriptPython
要点速览
  • 流式输入模式(Streaming Input Mode)是官方推荐的默认方式,支持长驻会话、图片上传、消息排队与中断、工具/MCP 全量访问
  • 单条消息输入模式(Single Message Input)更简单,适合一次性查询或 Lambda 等无状态环境,但不支持图片附件、动态排队、实时中断和自然多轮对话
  • TypeScript 中 query() 在遇到 error_max_turns 等错误结果后会 throw,需要用 try/catch 包裹;Python 中 query() 同样会在错误结果后 raise Exception
  • TypeScript 流式生成器抛出异常时,流会以「Claude Code process aborted by user」这类误导性错误结束,需要检查生成器内部代码;Python 生成器异常仅记录 debug 日志且会话会静默卡住
  • 单条消息模式可通过 options.continue(TypeScript)/continue_conversation(Python)实现多轮会话续接

本文是对官方 Agent SDK 某页的中文整理,完整与最新内容以原文为准。原文链接:https://code.claude.com/docs/en/agent-sdk/streaming-vs-single-mode

概览

Claude Agent SDK 支持两种截然不同的输入模式来与 agent 交互:

  • 流式输入模式(Streaming Input Mode):一个持久化的交互式会话
  • 单条消息输入(Single Message Input):利用会话状态与 resume 的一次性查询

流式输入模式(推荐)

流式输入模式是使用 Claude Agent SDK 的首选方式,它能完整访问 agent 的所有能力,并支持丰富的交互式体验。

它允许 agent 作为一个长驻进程运行,接收用户输入、处理中断、上抛权限请求,并进行会话管理。

工作原理

下面的时序图展示了应用、agent、工具/hooks 与文件系统之间的交互关系(消息生成器持续 yield 消息,agent 依次处理并流式返回响应,会话在此期间保持存活,文件系统状态持续保留):

sequenceDiagram
    participant App as Your Application
    participant Agent as Claude Agent
    participant Tools as Tools/Hooks
    participant FS as Environment/<br/>File System

    App->>Agent: Initialize with AsyncGenerator
    activate Agent

    App->>Agent: Yield Message 1
    Agent->>Tools: Execute tools
    Tools->>FS: Read files
    FS-->>Tools: File contents
    Tools->>FS: Write/Edit files
    FS-->>Tools: Success/Error
    Agent-->>App: Stream partial response
    Agent-->>App: Stream more content...
    Agent->>App: Complete Message 1

    App->>Agent: Yield Message 2 + Image
    Agent->>Tools: Process image & execute
    Tools->>FS: Access filesystem
    FS-->>Tools: Operation results
    Agent-->>App: Stream response 2

    App->>Agent: Queue Message 3
    App->>Agent: Interrupt/Cancel
    Agent->>App: Handle interruption

    Note over App,Agent: Session stays alive
    Note over Tools,FS: Persistent file system<br/>state maintained

    deactivate Agent

优势

在流式输入模式下,你运行在一个持久会话中,具备以下能力:

  • 图片上传(Image uploads):可以直接在消息中附加图片,用于视觉分析与理解
  • 消息排队(Queued messages):可以依次发送多条消息进行顺序处理,并支持中断
  • 工具集成(Tool integration):会话期间可完整访问所有工具及自定义 MCP servers
  • 实时反馈(Real-time feedback):可以实时看到响应生成过程,而不仅是最终结果
  • 上下文持久化(Context persistence):在多轮对话中自然地维持会话上下文

实现示例

下面的示例会从当前工作目录读取一张名为 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 版本会在每个响应完成时打印它。Python 版本的 receive_response() 循环在遇到第一个 result 消息时就会结束,因此只会打印出安全分析结果;若要读取两次响应,需按照 Python 参考文档中「继续对话的示例」那样,为每条消息各自使用一对 query()receive_response()

注意

在 TypeScript SDK 中,如果你的消息生成器抛出异常(例如它要读取的文件不存在),流会以一条 Claude Code process aborted by user 的错误结束,而不是原始错误信息,所以看到这条消息时应先检查生成器内部代码。该错误前面可能还会跟着一长串压缩过的 SDK 源码,需要读到输出末尾才能看到真正的错误文本。

在 Python SDK 中,生成器抛出的异常只会被记录为 debug 级别日志,而会话会在不抛出异常的情况下卡住,所以如果流式会话挂起且没有任何输出,应开启 debug 日志并检查你的生成器。

单条消息输入模式

单条消息输入更简单,但限制也更多。

何时使用单条消息输入

在以下场景使用单条消息输入:

  • 你只需要一次性的响应(one-shot response)
  • 你不需要图片附件或会话中途的控制方法
  • 你需要在无状态环境中运行,例如 Lambda 函数

限制

警告

单条消息输入模式支持:

  • 在消息中直接附加图片
  • 动态消息排队
  • 实时中断
  • 自然的多轮对话

如果一次查询以错误结果结束(例如 error_max_turns),单条消息的 query() 调用会在产出最后的 result 消息之后抛出一个包含失败文本的错误,因此如果后续代码还需要继续执行,应将循环包裹在 try 块中。各类 result 子类型请参见「处理结果(Handle the result)」一节(Agent Loop 文档)。

实现示例

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 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)
    # The SDK raises a plain Exception for error results, so match Exception here
    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())

运行该示例时,每次查询都会打印其最终的结果文本:先是身份认证(authentication)流程的说明,然后是授权(authorization)流程的说明。

两种模式的关键差异一览

能力流式输入模式单条消息输入模式
图片附件支持(消息内容可包含 type: "image" 块)不支持
消息排队 / 中途插入新消息支持不支持(动态消息排队)
实时中断支持不支持
多轮自然对话天然支持(单一会话持续存在)需依赖 continue(TypeScript)/ continue_conversation(Python)等会话管理选项拼接
适用场景长驻交互式 agent一次性查询、无状态环境(如 Lambda)
错误结果处理query()error_max_turns 等错误结果后会抛出/raise 异常,需要 try/catch(TypeScript)或 try/except(Python)

注:原文未给出上表中各选项的默认值,故未标注默认值列。