LangChain.js中stream() 多模式和streamEvents()事件流式对比

5 阅读5分钟

langchain.js(包括langgraph和deepagents)中流式输出核心解决的是Agent/LLM 实时输出、运行进度、工具调用、自定义业务进度、模型思考链实时打印,分为传统 stream() 多模式新版推荐 streamEvents(v3) 事件流式 两套 API。

一、总览:Streaming 的核心价值

LLM 推理存在网络延迟,一次性返回完整回答会造成用户长时间空白;Streaming 实现逐块实时推送,大幅提升交互体验。 LangChain JS 流式系统支持四类实时数据输出:

  1. Agent 每一步运行状态变更(工具调用、LLM 节点切换)
  2. LLM 逐 Token 文本输出
  3. 模型内部思考/推理 reasoning 片段实时推送
  4. 开发者自定义业务进度日志(如“正在查询数据库 10/100”)

文档重点提示:LangChain v1.3 推荐 Event Streaming(streamEvents + version:v3),替代传统 stream() 多分支判断;它把消息、工具调用、子图、最终状态拆成独立迭代器,无需通过 streamMode 判断数据类型,代码更简洁。

二、三种基础 Stream Mode(stream() 方法使用)

调用 agent.stream(inputs, { streamMode: 模式 }),支持单模式或数组多模式并发。

streamMode输出内容适用场景
updates每一个 Agent 节点执行后的状态增量更新;同一轮多个节点会分多次推送展示 Agent 运行流程:LLM 请求工具 → 工具返回结果 → 最终回答
messagesLLM 生成的逐 Token + 元数据元组 (token, metadata),包含节点名称、子图标识聊天打字动画、实时输出模型回答、提取 reasoning 思考内容
custom开发者在 Tool/Graph 节点内主动推送自定义字符串/对象,依赖 config.writer业务进度、中间查询日志、自定义提示信息

1. updates:流式 Agent 执行进度

Agent 调用工具的完整推送链路(三步):

  1. LLM 节点:携带 tool_call 的 AIMessage
  2. Tool 节点:工具执行结果 ToolMessage
  3. 最终 LLM 节点:整合工具数据后的完整回答

配套关键配置:

  • configurable.thread_id:对话持久化 ID,必须搭配 MemorySaver 记忆存储,实现多轮对话断点续跑
  • 支持 OpenAI / Anthropic / Gemini / Ollama / OpenRouter / Fireworks / Baseten 全模型厂商

示例代码核心逻辑:

const agent = createAgent({
  model: "openai:gpt-5.5",
  tools: [getWeather],
  checkpointer: new MemorySaver(), // 持久化对话必须
});
const config = { configurable: { thread_id: crypto.randomUUID() } };
// streamMode="updates" 监听节点状态变更
const stream = await agent.stream(input, { ...config, streamMode: "updates" });

2. messages:逐 Token 流式 LLM 输出

返回格式 [token, metadata],metadata 携带 langgraph_node(当前执行节点)。 适用场景:纯聊天、不需要看工具进度,只实时打印文字。

for await (const [token, metadata] of await agent.stream(input, { streamMode: "messages" })) {
  console.log("当前节点:", metadata.langgraph_node);
  console.log("输出片段:", token.contentBlocks);
}

3. custom:自定义业务流式日志

在 Tool 函数入参增加 config: LangGraphRunnableConfig,调用 config.writer?.("自定义内容") 向外推送日志。 限制:工具脱离 LangGraph 运行时(单独调用)会报错,必须在 Agent 图流程内执行。

const getWeather = tool(async (input, config: LangGraphRunnableConfig) => {
  config.writer?.(`正在查询城市:${input.city}`); // 自定义流输出
  config.writer?.(`城市数据获取完成`);
  return `天气晴朗`;
}, schema);

// 消费自定义流
for await (const chunk of agent.stream(input, { streamMode: "custom" })) {
  console.log("业务日志:", chunk);
}

4. 多模式并发:同时监听进度、Token、自定义日志

streamMode 传入数组 ["updates", "messages", "custom"],返回统一格式 [mode, chunk],通过第一个字段区分数据类型:

for await (const [streamMode, chunk] of agent.stream(input, {
  streamMode: ["updates", "messages", "custom"]
})) {
  if (streamMode === "messages") { /* 打印token */ }
  if (streamMode === "updates") { /* 节点进度 */ }
  if (streamMode === "custom") { /* 业务日志 */ }
}

三、新版 Event Streaming(streamEvents,官方推荐 v3)

核心优势(对比旧 stream())

  1. 无需 streamMode 分支判断,内置独立迭代器
    • stream.messages:所有 LLM 文本/思考 Token
    • stream.toolCalls:所有工具调用请求与返回结果
    • stream.output:Promise,等待全流程结束获取最终完整状态
  2. LangChain v1.3 标准化类型投影,自动归一化各厂商模型的 reasoning 思考块
  3. 天然支持子图、多工具并行场景,前端交互最友好(文档推荐新项目优先使用)

完整示例(同时打印文字+实时打印工具调用)

const stream = await agent.streamEvents(input, { ...config, version: "v3" });
// 并行两个异步循环:打印文字 + 打印工具调用
await Promise.all([
  // 1. 流式输出文本
  (async () => {
    for await (const message of stream.messages) {
      for await (const token of message.text) {
        process.stdout.write(token);
      }
    }
  })(),
  // 2. 监听工具调用全过程
  (async () => {
    for await (const call of stream.toolCalls) {
      console.log(`\n调用工具:${call.name} 参数:`, call.input);
      console.log(`工具返回结果:`, await call.output);
    }
  })(),
]);
const finalState = await stream.output; // 等待全部执行完成

四、高级场景:流式模型思考链(reasoning tokens)

部分模型(Claude、深度思考类开源模型)会先输出内部推理过程再生成答案,LangChain 统一标准化为 type:"reasoning" 内容块,两种获取方式:

方式1:streamEvents v3(推荐)

// Claude 开启思考预算
const model = new ChatAnthropic({
  model: "claude-sonnet-4-6",
  thinking: { type: "enabled", budget_tokens: 5000 },
});
const agent = createAgent({ model, tools });
const stream = await agent.streamEvents(input, { version: "v3" });
for await (const msg of stream.messages) {
  // 实时打印思考片段
  for await (const thinkToken of msg.reasoning) {
    process.stdout.write(`[思考]${thinkToken}`);
  }
  // 打印最终回答文字
  for await (const textToken of msg.text) {
    process.stdout.write(textToken);
  }
}

方式2:旧 messages 模式过滤 contentBlocks

遍历 token.contentBlocks,判断 block.type === "reasoning" 提取思考内容。

五、禁用流式输出

部分场景需要一次性完整返回,关闭单模型流式:

  1. 标准 OpenAI 等模型:streaming: false
import { ChatOpenAI } from "@langchain/openai";
const model = new ChatOpenAI({ model: "gpt-5.5", streaming: false });
  1. 不支持 streaming 参数的小众模型:使用基类通用配置 disableStreaming: true

适用场景:

  • 多 Agent 系统中,控制部分子 Agent 不实时推送
  • LangSmith 部署,屏蔽敏感模型输出到前端

六、配套关键概念与依赖

1. Checkpointer 记忆持久化

使用 thread_id 保存对话历史必须配置 checkpointer

  • 本地开发:new MemorySaver()(内存存储,重启丢失)
  • LangSmith 云端部署:自动预置持久化存储,无需手动传入

2. createAgent 嵌入子图

若把 Agent 作为父 StateGraph 的节点:

  • 传入 agent.graph 而不是 agent 实例
  • 流式开启 subgraphs: true,保证子图 Token 携带命名空间,区分父子节点输出

七、相关拓展文档(文档末尾 Related)

  1. Frontend streaming:React useStream Hook,前端实时渲染流式对话
  2. Streaming with chat models:不使用 Agent,纯 ChatModel 基础流式
  3. Reasoning with chat models:模型思考链完整配置指南
  4. Standard content blocks:统一内容块规范(text/reasoning/tool_call)
  5. Streaming with human-in-the-loop:流式 + 人工审核中断
  6. LangGraph streaming:底层图流式完整高级参数(values/debug/checkpoints 模式)

八、stream() vs streamEvents(version:"v3") 选型总结

场景推荐 API
新项目、前端交互、需要同时拿 Token + 工具调用streamEvents v3
简单脚本,仅监听 LLM 文字输出stream({streamMode:"messages"})
仅监控 Agent 执行步骤,不展示文字stream({streamMode:"updates"})
需要自定义业务进度日志stream custom 模式 / streamEvents 搭配 writer
兼容旧 LangGraph 代码、复杂多分支逻辑传统 stream 多模式

九、完整执行流程示例(用户提问查天气)

  1. 用户输入:sf 的天气
  2. streamEvents.toolCalls 捕获 get_weather 工具调用,打印参数 city=San Francisco
  3. 工具内部 writer 推送自定义日志(custom 流)
  4. 工具执行完成返回 ToolMessage
  5. streamEvents.messages 同时输出模型思考链 + 最终回答逐字 Token
  6. stream.output 等待全部结束,拿到完整对话状态用于保存/二次处理