LangChain 代理构建在 LangGraph 之上,因此支持同一套流式传输栈,并为代理场景提供面向消息、工具调用、状态和自定义更新的 projections。 对于大多数应用和前端用例,请通过 stream_events(..., version="v3") 使用 Event Streaming。Event Streaming 会返回带类型化 projections 的运行对象,因此可以独立消费每个 projection,而不需要解析 stream-mode 元组。
import { createAgent, tool } from "langchain";
import * as z from "zod";

const getWeather = tool(
  async ({ city }) => `It's always sunny in ${city}!`,
  {
    name: "get_weather",
    description: "Get weather for a city.",
    schema: z.object({ city: z.string() }),
  }
);

const agent = createAgent({
  model: "gpt-5-nano",
  tools: [getWeather],
});

const stream = await agent.streamEvents(
  { messages: [{ role: "user", content: "What is the weather in SF?" }] },
  { version: "v3" }
);

for await (const message of stream.messages) {
  for await (const delta of message.text) {
    process.stdout.write(delta);
  }
}

const finalState = await stream.output;

可以流式传输什么

Projection用途
for event in stream带完整 envelope 的原始协议事件,并可访问每个 channel。
stream.messages模型消息流,每次 LLM 调用一个。
message.text消息的文本 deltas 和最终文本。
message.reasoning暴露 reasoning content 的模型的 reasoning deltas。
message.toolCalls工具调用参数 chunks 和最终工具调用。
message.output模型调用完成后的最终消息对象。
message.usageprovider 返回 token usage metadata 时的用量元数据。
stream.values代理状态快照。
stream.output最终代理状态。
stream.subgraphs嵌套图运行(sub-agents 和普通 subgraphs)。
stream.extensions自定义 transformer projections。
stream.toolCalls工具执行生命周期、输入、输出 deltas、最终输出和错误。
stream.messages 会产生消息流。每个消息流暴露 .text.reasoning.toolCalls.output.usage。异步 projections 可以迭代以获取实时 deltas,也可以 await 以获取最终值。

代理消息

当你想获取每次 LLM 调用的模型输出时,使用 stream.messages
const stream = await agent.streamEvents(input, { version: "v3" });

for await (const message of stream.messages) {
  process.stdout.write(`[${message.node}] `);
  for await (const delta of message.text) {
    process.stdout.write(delta);
  }

  const fullMessage = await message.output;
  console.log(fullMessage.content);

  const usage = await message.usage;
  if (usage) {
    console.log(usage);
  }
}
message.output 会给出最终 AI 消息,包括 provider 特定的 content blocks。在 TypeScript 中,当你只需要 token 计数或其他 usage metadata 时使用 message.usage;在 Python 中,从 message.output.usage_metadata 读取用量。

Reasoning content

Reasoning content 使用与文本内容相同的形状,但只有所选模型发出 reasoning blocks 时才可用。
const stream = await agent.streamEvents(input, { version: "v3" });

for await (const message of stream.messages) {
  for await (const delta of message.reasoning) {
    process.stdout.write(`[thinking] ${delta}`);
  }

  for await (const delta of message.text) {
    process.stdout.write(delta);
  }
}
模型配置详情请参阅 reasoning guide 和你的 provider 集成页。

工具调用

有两个有用的工具调用 projections:
  • message.tool_calls 会在模型生成工具调用时流式传输工具调用参数 chunks。
  • stream.tool_calls 会在工具调用开始后流式传输工具执行生命周期。
const stream = await agent.streamEvents(input, { version: "v3" });

await Promise.all([
  (async () => {
    for await (const message of stream.messages) {
      for await (const chunk of message.toolCalls) {
        console.log("tool call chunk", chunk);
      }
    }
  })(),
  (async () => {
    for await (const call of stream.toolCalls) {
      console.log(call.name, call.input);
      console.log(await call.output, await call.error);
    }
  })(),
]);

流式传输 sub-agents

当一个 create_agent 调用另一个具名 create_agent(通常通过包装工具)时,内部代理的事件会流入嵌套 namespace。传给 create_agentname= 会在流中标识该内部代理,因此你可以按代理筛选和标记。 具名 sub-agents 会作为 handles 出现在 stream.subgraphs 上,与普通 subgraphs 一起出现。每个 handle 会暴露内部代理的 .messages.values.toolCalls.output;可通过 subagent.name(你传入的 name=)筛选并操作特定代理。
import { createAgent, tool } from "langchain";
import { z } from "zod";

const getWeather = tool(
  async ({ city }) => `It's always sunny in ${city}!`,
  { name: "get_weather", schema: z.object({ city: z.string() }) }
);

const weatherAgent = createAgent({
  model: "openai:gpt-5.4",
  tools: [getWeather],
  name: "weather_agent",
});

const callWeather = tool(
  async ({ query }) => {
    const result = await weatherAgent.invoke({
      messages: [{ role: "user", content: query }],
    });
    return result.messages.at(-1)?.text ?? "";
  },
  { name: "call_weather", schema: z.object({ query: z.string() }) }
);

const supervisor = createAgent({
  model: "openai:gpt-5.4",
  tools: [callWeather],
  name: "supervisor",
});

const stream = await supervisor.streamEvents(
  { messages: [{ role: "user", content: "What's the weather in Boston?" }] },
  { version: "v3" }
);

for await (const subagent of stream.subgraphs) {
  if (subagent.name !== "weather_agent") continue;
  process.stdout.write(`${subagent.name}: `);
  for await (const message of subagent.messages) {
    for await (const token of message.text) {
      process.stdout.write(token);
    }
  }
  process.stdout.write("\n");
}
从工具调用的普通 StateGraph subgraphs 也会出现在 stream.subgraphs 上,请在 .compile(name=...) 上设置 name=,以便在 subagent.graph_name 中获得标签。 具名 sub-agents 与普通 subgraphs 共享 stream.subgraphs projection;你在循环中编写的筛选逻辑会将它们区分开。

状态和最终输出

使用 stream.values 获取状态快照,使用 stream.output 获取最终代理状态。
const stream = await agent.streamEvents(input, { version: "v3" });

for await (const snapshot of stream.values) {
  console.log(snapshot);
}

const finalState = await stream.output;

多个 projections

在 JavaScript 中需要多个 projections 时,使用并发消费者:
const stream = await agent.streamEvents(input, { version: "v3" });

await Promise.all([
  (async () => {
    for await (const message of stream.messages) {
      console.log(await message.text);
    }
  })(),
  (async () => {
    for await (const call of stream.toolCalls) {
      console.log(call.name, call.input);
    }
  })(),
]);
要访问未作为类型化 projections 暴露的 channels,或检查完整 event envelope,请迭代原始协议事件:
for await (const event of stream) {
  console.log(event.method, event.params.namespace, event.params.data);
}

自定义更新

当应用需要内置之外的 projection 时,使用自定义 stream transformers,例如检索进度、artifacts 或领域特定事件。
const stream = await agent.streamEvents(input, {
  version: "v3",
  transformers: [toolActivityTransformer],
});

for await (const activity of stream.extensions.toolActivity) {
  console.log(activity);
}

在 middleware 上注册 transformers

Middleware 注册的 transformers 需要 langchain@1.4.3 或更高版本。
Middleware 可以在 hooks 和 tools 旁声明 stream transformer factories。不同语言中的 factory 形状不同: streamTransformers 作为 factories 元组传给 createMiddleware。每个 factory 的形状为 () => StreamTransformer<any>(零参数),并且每个 scope 调用一次。每次调用返回一个新的 transformer 可以让每个 subgraph 保持隔离。
import { createAgent, createMiddleware } from "langchain";

const toolActivityMiddleware = createMiddleware({
  name: "ToolActivityMiddleware",
  streamTransformers: [toolActivityTransformer],
});

const agent = createAgent({
  model: "gpt-5-nano",
  tools: [getWeather],
  middleware: [toolActivityMiddleware],
});
编译时,createAgent 会将 middleware 注册的 factories 与传给自身 streamTransformers 选项的任何内容合并。编译后图上的最终顺序为:
  1. 内置 ToolCallTransformer
  2. Middleware 注册的 factories,按 middleware 顺序排列。
  3. 调用方从 createAgent 提供的 streamTransformers
这样会让内置工具调用 projection 排在消费者 transformers 之前,并让调用方提供的条目拥有最终优先权。 Transformer contract 请参阅 Build your own projection

相关