LangGraph 入门实战(11)--输出模式

LangGraph 流式输出:values、updates、messages 和 debug

LangGraph 的 graph.stream() 可以边执行节点边返回数据。通过 stream_mode,我们可以选择查看完整状态、节点增量、模型消息流或详细调试信息。

1. 安装与配置

bash 复制代码
pip install -U langgraph langchain-deepseek
export DEEPSEEK_API_KEY="你的 API Key"
python index.py

2. 构建工作流

下面创建一个简单流程:先把"小狗"加入主题,再让 DeepSeek 根据新主题生成笑话。

python 复制代码
import os
from typing import Any, TypedDict, cast

from langchain_core.messages import BaseMessage
from langchain_deepseek import ChatDeepSeek
from langgraph.graph import START, StateGraph
from pydantic import SecretStr


deepseek = ChatDeepSeek(
    model="deepseek-v4-flash",
    temperature=0,
    base_url="https://api.deepseek.com",
    api_key=SecretStr(os.environ["DEEPSEEK_API_KEY"]),
)


class State(TypedDict):
    topic: str
    joke: str


def refine_topic(state: State):
    return {"topic": state["topic"] + "和小狗"}


def generate_joke(state: State):
    response = deepseek.invoke(
        [{"role": "user", "content": f"请生成一个关于{state['topic']}的笑话"}]
    )
    return {"joke": response.content}


graph = (
    StateGraph(State)
    .add_node(refine_topic)
    .add_node(generate_joke)
    .add_edge(START, "refine_topic")
    .add_edge("refine_topic", "generate_joke")
    .compile()
)

initial_state: State = {"topic": "小猫", "joke": ""}

执行顺序如下:

text 复制代码
START -> refine_topic -> generate_joke -> END

3. 四种输出模式

模式 返回内容 适用场景
values 每一步合并后的完整状态 观察状态变化
updates 当前节点更新的字段 监听节点结果
messages 模型消息片段和元数据 实现打字机效果
debug 节点输入、结果、时间和任务 ID 排查工作流问题

values:完整状态

python 复制代码
for event in graph.stream(initial_state, stream_mode="values"):
    print(event)

输出:

text 复制代码
{'topic': '小猫', 'joke': ''}
{'topic': '小猫和小狗', 'joke': ''}
{'topic': '小猫和小狗', 'joke': '小猫和小狗去讲笑话,结果它们都笑了。'}

updates:节点增量

python 复制代码
for event in graph.stream(initial_state, stream_mode="updates"):
    print(event)

输出:

text 复制代码
{'refine_topic': {'topic': '小猫和小狗'}}
{'generate_joke': {'joke': '小猫和小狗去讲笑话,结果它们都笑了。'}}

messages:模型消息流

messages 返回 (message, metadata)。下面用 | 标记每个消息片段的边界:

python 复制代码
for event in graph.stream(initial_state, stream_mode="messages"):
    message, metadata = cast(tuple[BaseMessage, dict[str, Any]], event)
    if message.content:
        print(message.content, end="|", flush=True)
print()

输出:

text 复制代码
小猫|和小狗|去讲笑话|,结果它们都笑了。|

LangGraph 当前的类型声明无法根据 messages 自动推断事件结构,所以这里用 cast 告诉 Pylance 返回值是"消息与元数据"元组。消息片段的实际切分位置由模型决定,metadata["langgraph_node"] 可以用来判断消息来自哪个节点。

debug:调试信息

python 复制代码
for event in graph.stream(initial_state, stream_mode="debug"):
    print(event)

精简输出如下,实际结果还包含时间、任务 ID 和触发来源:

text 复制代码
{'step': 1, 'type': 'task',
 'payload': {'name': 'refine_topic', 'input': {'topic': '小猫', 'joke': ''}}}

{'step': 1, 'type': 'task_result',
 'payload': {'name': 'refine_topic', 'result': {'topic': '小猫和小狗'}}}

小结

日常展示状态用 values,只关心节点变更用 updates,向页面实时输出模型内容用 messages,排查节点执行问题时使用 debug。

示例中的四次 graph.stream() 会完整执行四遍工作流,因此也会调用模型四次。实际项目只需选择需要的模式;如果希望一次获得多种结果,也可以传入 stream_mode=["updates", "messages"]。模型生成内容存在随机性,实际笑话可能与示例不同。

相关推荐
CQU_JIAKE11 小时前
11.7[高体】
java·后端·spring
Csvn12 小时前
认识 Nginx
后端·nginx
红尘散仙12 小时前
谁说终端只能敲键盘?我用 Rust 给小说阅读器加上了鼠标
前端·后端·rust
特立独行的猫A13 小时前
我给女儿写了个打字练习:一边敲键盘,一边把小学英语单词记牢
java·后端·python
cpolar技术支持13 小时前
「我这边连不上你那个服务」—— 用清单驱动的 TCP 连通性只读看板,cpolar 让远端同事自己取证
python·内网穿透·tcp·cpolar·网络诊断
陈随易13 小时前
C++26 草案被否,二十八年来头一回
前端·后端·程序员
云和数据.ChenGuang13 小时前
LangGraph 异步 Node 的设计与写法实践
开发语言·人工智能·python·机器学习·php
金銀銅鐵14 小时前
同一个 Hello World,Kotlin 和 Java 在字节码层面差在哪
jvm·后端·kotlin
天诰14 小时前
SA-K-11 检索会消失吗与四个未解问题
java·服务器·人工智能·python·机器学习·ai编程
benchmark_cc15 小时前
用 QuantDash 读取美股行情:AAPL.US 的运行前检查、排错顺序与数据校验清单
python·数据分析·pandas·量化交易·股票数据·quantdash