langchain系列(九)- LangGraph 子图详解

news2025/3/11 20:06:19

目录

一、导读

 二、原理说明

1、简介

2、子图图示

3、使用说明

三、基础代码实现

1、实现功能

2、Graph 图示

3、代码实现

4、输出

5、分析

四、人机交互

1、实现中断

2、历史状态(父图)

3、历史状态(子图)

4、历史回溯

5、整体代码

五、子图状态更改

1、修改状态

2、恢复执行

3、整体代码

4、更新节点

5、更新子图


一、导读

环境:OpenEuler、Windows 11、WSL 2、Python 3.12.3 langchain 0.3 langgraph 0.2

背景:前期忙碌的开发阶段结束,需要沉淀自己的应用知识,过一遍LangGraph

时间:20250307

说明:技术梳理,LangGraph 的多代理(多智能体)可以基于子图实现,此处对子图进行说明,案例基于官方文档进行部分的修改

官方文档地址:LangGraph 子图实现

 二、原理说明

1、简介

子图允许构建具有多个组件的复杂系统,这些组件本身是图。使用子图的常见用例是构建多代理系统。子图其本质就是一个节点,只不过该节点是一个图而已。由此可知:也有孙子图、曾孙子图等

在添加子图时,主要问题是父图和子图如何进行通信,即它们如何在图执行期间相互传递状态。这里有两种情况:

父图和子图共享state。在这种情况下,您可以添加一个编译后的子图节点

父图和子图具有不同的state。在这种情况下,您必须添加一个调用子图的节点函数:当父图和子图具有不同的状态模式时,这在调用子图之前或之后需要转换状态时很有用

2、子图图示

主节点具有选择性,分别是subgraph1、subgraph2

3、使用说明

一种常见的情况是父图和子图通过共享state进行通信。例如,在多代理系统中,代理通常通过共享的state进行通信。

如果你的子图与父图共享state,你可以按照以下步骤将其添加到父图中:

定义子图工作流(如下例中的subgraph_builder)并进行编译

在定义父图工作流时,将编译后的子图传递给.add_node方法

三、基础代码实现

1、实现功能

开始节点进行意图分类,如果天气相关则走天气相关的子图;否则走智能助手节点。

2、Graph 图示

3、代码实现

from langgraph.graph import StateGraph, END, START, MessagesState
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from typing import Literal
from langgraph.checkpoint.memory import MemorySaver

@tool
def get_weather(city: str):
    """获取天气信息"""
    return f"{city},晴空万里,阳光明媚!"

# 添加记忆存储
memory = MemorySaver()

# 配置信息,用于记录对话记录
config = {"configurable": {"thread_id": "1"}}


# 指定大模型的API Key 等相关信息
llm = ChatOpenAI(
    base_url="https://lxxxxx.enovo.com/v1/", 
    api_key="sxxxxxxxwW",
    model_name="qwen2.5-instruct"
    )


# 绑定工具
model = raw_model.bind_tools([get_weather])

# 子图的state
class SubGraphState(MessagesState):
    city: str

# 识别地点(城市)
def model_node(state: SubGraphState):
    system_message = """用户的问题是某个地方的天气问题,请辨别具体城市名称,并输出城市名称。"""
    messages = [{"role": "system", "content": system_message}] + state["messages"]
    result = raw_model.invoke(messages)
    return {"city": result.content}

# 天气工具节点
def weather_node(state: SubGraphState):
    result = get_weather.invoke({"city": state["city"]})
    return {"messages": [{"role": "assistant", "content": result}]}

# 子图的添加节点、边以及编译图
subgraph = StateGraph(SubGraphState)
subgraph.add_node(model_node)
subgraph.add_node(weather_node)
subgraph.add_edge(START, "model_node")
subgraph.add_edge("model_node", "weather_node")
subgraph.add_edge("weather_node", END)
subgraph = subgraph.compile()

# 意图分类state
class RouterState(MessagesState):
    route: Literal["天气", "其他"]

# 意图分类节点
def router_node(state: RouterState):
    system_message = """用户输入与天气相关则输出"天气",与天气无关返回"其他”"""
    messages = [{"role": "system", "content": system_message}] + state["messages"]
    route = raw_model.invoke(messages)
    return {"route": route.content}

# 智能助手节点
def normal_llm_node(state: RouterState):
    response = raw_model.invoke(state["messages"])
    return {"messages": [response]}

# 选择边函数
def route_after_prediction(state: RouterState):
    if state["route"] == "天气":
        return "weather_graph"
    else:
        return "normal_llm_node"

# 父图的添加边、节点以及编译父图
graph = StateGraph(RouterState)
graph.add_node(router_node)
graph.add_node(normal_llm_node)
# 将子图作为一个节点添加到父图中
graph.add_node("weather_graph", subgraph)
graph.add_edge(START, "router_node")
graph.add_conditional_edges("router_node", route_after_prediction)
graph.add_edge("normal_llm_node", END)
graph.add_edge("weather_graph", END)
graph = graph.compile(checkpointer=memory)


# 以流式调用图
def stream_graph_updates(user_input: str):
    for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}, config=config, stream_mode="updates"):
        if event.get("router_node"):
            continue
        else:
            for value in event.values():
                print("Assistant:", value["messages"][-1].content)

# 设置聊天退出方法
while True:
    try:
        user_input = input("User: ")
        if user_input.lower() in ["quit", "exit", "q"]:
            print("Goodbye!")
            break

        stream_graph_updates(user_input)
    except Exception as e:
        print(e)
        user_input = "What do you know about LangGraph?"
        print("User: " + user_input)
        stream_graph_updates(user_input)
        break

4、输出

User: 北京天气怎么样
Assistant: 北京,晴空万里,阳光明媚!
User: hi
Assistant: Hello! How can I assist you today?
User: 天津的天气怎么样
Assistant: 天津,晴空万里,阳光明媚!

5、分析

据上述输出可知,询问天气则会返回相关信息;其他对话内容会按照普通助手功能回复。

四、人机交互

1、实现中断

子图实现中断仅需在编译的时候添加 interrupt_before=["节点名称"],修改如下:

subgraph = subgraph.compile(interrupt_before=["weather_node"])

这样修改就会导致在weather_node发生中断,且输出值为 {'__interrupt__': ()},所以判断该dict是否存在__interrupt__即可。

调用图的地方进行判断,如下:

def stream_graph_updates(user_input: str):
    for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}, config=config, stream_mode="updates"):
        if "__interrupt__" in event:
            print("中断")
        elif event.get("router_node"):
            continue
        else:
            for value in event.values():
                print("Assistant:", value["messages"][-1].content)

循环输出内容如下:

User: 北京天气怎么样
中断
User: 

2、历史状态(父图)

由于此时运行状态已经到了while True:,所以此时也不存在graph等变量信息。

所以,想要实现人机交互,需要在输出中断的地方即:print("中断"),下方执行逻辑并恢复状态

添加如下代码,来查看所有的历史节点

for h in graph.get_state_history(config=config):
    print(h.next)
else:
    print("遍历结束")

其输出信息如下:

 User: 北京天气怎么样
中断
('weather_graph',)
('router_node',)
('__start__',)
遍历结束
User: 

3、历史状态(子图)

显然,存在问题,由上述的Graph图示可知,该问题到达了model_node节点,但是遍历却没有。该问题是由于子图的问题。如何查询所有的遍历呢?weather_graph是子图,可以先获取子图的state,然后再遍历子图的历史记录,方法如下

# 以流式调用图
def stream_graph_updates(user_input: str):
    for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}, config=config, stream_mode="updates"):
        if "__interrupt__" in event:
            print("中断")
            for h in graph.get_state_history(config): 
                print(h.next)
                if h.next == ("weather_graph",):
                    weather_graph_state = h.tasks[0].state
            for h in graph.get_state_history(weather_graph_state):
                print(h.next)
                if h.next == ("model_node",):
                    model_node_state = h

            print(model_node_state.next)
        elif event.get("router_node"):
            continue
        else:
            for value in event.values():
                print("Assistant:", value["messages"][-1].content)

此处代码为了遍历所有,并未将判断后就停止遍历

输出内容

User: 北京天气怎么样
中断
('weather_graph',)
('router_node',)
('__start__',)
('weather_node',)
('model_node',)
('__start__',)
('model_node',)
User: 

最开始打印的是父图的节点信息,获得子图的state后,定义为weather_graph_state,之后遍历weather_graph_state的历史记录,找到指定的model_node,抵达目标历史记录定位。

4、历史回溯

实现时空穿梭,此时如果在 print(model_node_state.next)下添加stream_graph_updates(user_input),如果user_input发生变化,则按照逻辑去执行,反之实现死循环,部分代码如下:

# 以流式调用图
def stream_graph_updates(user_input: str):
    for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}, config=config, stream_mode="updates"):
        if "__interrupt__" in event:
            print("中断")
            for h in graph.get_state_history(config): 
                print(h.next)
                if h.next == ("weather_graph",):
                    weather_graph_state = h.tasks[0].state
            for h in graph.get_state_history(weather_graph_state):
                print(h.next)
                if h.next == ("model_node",):
                    model_node_state = h

            print(model_node_state.next)

            stream_graph_updates(user_input)
        elif event.get("router_node"):
            continue
        else:
            for value in event.values():
                print("Assistant:", value["messages"][-1].content)

输出内容如下

User: 北京天气怎么样
中断
('weather_graph',)
('router_node',)
('__start__',)
('weather_node',)
('model_node',)
('__start__',)
('model_node',)
中断
('weather_graph',)
('router_node',)
('__start__',)
('weather_graph',)
('router_node',)
('__start__',)
('weather_node',)
('model_node',)
('__start__',)
('model_node',)
中断
('weather_graph',)
('router_node',)
('__start__',)
('weather_graph',)

。。。

此处添加自己的逻辑,可以实现如果出现错误,实现自动回溯功能

5、整体代码

from langgraph.graph import StateGraph, END, START, MessagesState
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from typing import Literal
from langgraph.checkpoint.memory import MemorySaver

@tool
def get_weather(city: str):
    """获取天气信息"""
    return f"{city},晴空万里,阳光明媚!"

# 添加记忆存储
memory = MemorySaver()

# 配置信息,用于记录对话记录
config = {"configurable": {"thread_id": "1"}}


# 指定大模型的API Key 等相关信息
llm = ChatOpenAI(
    base_url="https://lxxxxx.enovo.com/v1/", 
    api_key="sxxxxxxxwW",
    model_name="qwen2.5-instruct"
 
    )

# 绑定工具
model = raw_model.bind_tools([get_weather])

# 子图的state
class SubGraphState(MessagesState):
    city: str

# 识别地点(城市)
def model_node(state: SubGraphState):
    system_message = """用户的问题是某个地方的天气问题,请辨别具体城市名称,并输出城市名称。"""
    messages = [{"role": "system", "content": system_message}] + state["messages"]
    result = raw_model.invoke(messages)
    return {"city": result.content}

# 天气工具节点
def weather_node(state: SubGraphState):
    result = get_weather.invoke({"city": state["city"]})
    return {"messages": [{"role": "assistant", "content": result}]}

# 子图的添加节点、边以及编译图
subgraph = StateGraph(SubGraphState)
subgraph.add_node(model_node)
subgraph.add_node(weather_node)
subgraph.add_edge(START, "model_node")
subgraph.add_edge("model_node", "weather_node")
subgraph.add_edge("weather_node", END)
# subgraph = subgraph.compile()
subgraph = subgraph.compile(interrupt_before=["weather_node"])

# 意图分类state
class RouterState(MessagesState):
    route: Literal["天气", "其他"]

# 意图分类节点
def router_node(state: RouterState):
    system_message = """用户输入与天气相关则输出"天气",与天气无关返回"其他”"""
    messages = [{"role": "system", "content": system_message}] + state["messages"]
    route = raw_model.invoke(messages)
    return {"route": route.content}

# 智能助手节点
def normal_llm_node(state: RouterState):
    response = raw_model.invoke(state["messages"])
    return {"messages": [response]}

# 选择边函数
def route_after_prediction(state: RouterState):
    if state["route"] == "天气":
        return "weather_graph"
    else:
        return "normal_llm_node"

# 父图的添加边、节点以及编译父图
graph = StateGraph(RouterState)
graph.add_node(router_node)
graph.add_node(normal_llm_node)
# 将子图作为一个节点添加到父图中
graph.add_node("weather_graph", subgraph)
graph.add_edge(START, "router_node")
graph.add_conditional_edges("router_node", route_after_prediction)
graph.add_edge("normal_llm_node", END)
graph.add_edge("weather_graph", END)
graph = graph.compile(checkpointer=memory)


# 以流式调用图
def stream_graph_updates(user_input: str):
    for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}, config=config, stream_mode="updates"):
        if "__interrupt__" in event:
            print("中断")
            for h in graph.get_state_history(config): 
                print(h.next)
                if h.next == ("weather_graph",):
                    weather_graph_state = h.tasks[0].state
            for h in graph.get_state_history(weather_graph_state):
                print(h.next)
                if h.next == ("model_node",):
                    model_node_state = h

            print(model_node_state.next)

            stream_graph_updates(user_input)
        elif event.get("router_node"):
            continue
        else:
            for value in event.values():
                print("Assistant:", value["messages"][-1].content)

# 设置聊天退出方法
while True:
    try:
        user_input = input("User: ")
        if user_input.lower() in ["quit", "exit", "q"]:
            print("Goodbye!")
            break

        stream_graph_updates(user_input)
    except Exception as e:
        print(e)
        user_input = "What do you know about LangGraph?"
        print("User: " + user_input)
        stream_graph_updates(user_input)
        break

五、子图状态更改

我会询问北京天气怎么,通过中断,将其state中的cityvalue修改为天津,实现该demo的功能。

此处我会将部分代码修改,因为上述代码本身为了能够清晰明了的展示其功能

1、修改状态

城市获取的节点是model_node,通过人机交互回溯到该节点,并更新该历史状态中的city信息。

获取当前状态

state = graph.get_state(config)

city对应的value修改为 天津

graph.update_state(state.tasks[0].state, {"city": "天津"})

部分代码如下

# 以流式调用图
def stream_graph_updates(user_input: str):
    for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}, config=config, stream_mode="updates"):
        if "__interrupt__" in event:
            print("中断")
            for h in graph.get_state_history(config): 
                if h.next == ("weather_graph",):
                    weather_graph_state = h.tasks[0].state
                    break
            for h in graph.get_state_history(weather_graph_state):
                if h.next == ("model_node",):
                    state = graph.get_state(config)
                    graph.update_state(state.tasks[0].state, {"city": "天津"})
                    break
        elif event.get("router_node"):
            continue
        else:
            for value in event.values():
                print("Assistant:", value["messages"][-1].content)

该段代码实现了将第一个taskcity值,修改为天津

2、恢复执行

因为此节点不需要输入信息,故而此处输入信息为None,代码如下

# 恢复执行graph
def update_city():
    for event in graph.stream(None, config=config, stream_mode="updates"):
        print(event.get("weather_graph").get("messages")[-1].content)

此函数在graph.update_state(state.tasks[0].state, {"city": "天津"})添加update_city()

graph.update_state(state.tasks[0].state, {"city": "天津"})
update_city()

3、整体代码

from langgraph.graph import StateGraph, END, START, MessagesState
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from typing import Literal
from langgraph.checkpoint.memory import MemorySaver

@tool
def get_weather(city: str):
    """获取天气信息"""
    return f"{city},晴空万里,阳光明媚!"

# 添加记忆存储
memory = MemorySaver()

# 配置信息,用于记录对话记录
config = {"configurable": {"thread_id": "1"}}


# 指定大模型的API Key 等相关信息
llm = ChatOpenAI(
    base_url="https://lxxxxx.enovo.com/v1/", 
    api_key="sxxxxxxxwW",
    model_name="qwen2.5-instruct"
    )

# 绑定工具
model = raw_model.bind_tools([get_weather])

# 子图的state
class SubGraphState(MessagesState):
    city: str

# 识别地点(城市)
def model_node(state: SubGraphState):
    system_message = """用户的问题是某个地方的天气问题,请辨别具体城市名称,并输出城市名称。"""
    messages = [{"role": "system", "content": system_message}] + state["messages"]
    result = raw_model.invoke(messages)
    return {"city": result.content}

# 天气工具节点
def weather_node(state: SubGraphState):
    result = get_weather.invoke({"city": state["city"]})
    return {"messages": [{"role": "assistant", "content": result}]}

# 子图的添加节点、边以及编译图
subgraph = StateGraph(SubGraphState)
subgraph.add_node(model_node)
subgraph.add_node(weather_node)
subgraph.add_edge(START, "model_node")
subgraph.add_edge("model_node", "weather_node")
subgraph.add_edge("weather_node", END)
# subgraph = subgraph.compile()
subgraph = subgraph.compile(interrupt_before=["weather_node"])

# 意图分类state
class RouterState(MessagesState):
    route: Literal["天气", "其他"]

# 意图分类节点
def router_node(state: RouterState):
    system_message = """用户输入与天气相关则输出"天气",与天气无关返回"其他”"""
    messages = [{"role": "system", "content": system_message}] + state["messages"]
    route = raw_model.invoke(messages)
    return {"route": route.content}

# 智能助手节点
def normal_llm_node(state: RouterState):
    response = raw_model.invoke(state["messages"])
    return {"messages": [response]}

# 选择边函数
def route_after_prediction(state: RouterState):
    if state["route"] == "天气":
        return "weather_graph"
    else:
        return "normal_llm_node"

# 父图的添加边、节点以及编译父图
graph = StateGraph(RouterState)
graph.add_node(router_node)
graph.add_node(normal_llm_node)
# 将子图作为一个节点添加到父图中
graph.add_node("weather_graph", subgraph)
graph.add_edge(START, "router_node")
graph.add_conditional_edges("router_node", route_after_prediction)
graph.add_edge("normal_llm_node", END)
graph.add_edge("weather_graph", END)
graph = graph.compile(checkpointer=memory)

# 恢复执行graph
def update_city():
    for event in graph.stream(None, config=config, stream_mode="updates"):
        print(event.get("weather_graph").get("messages")[-1].content)

# 以流式调用图
def stream_graph_updates(user_input: str):
    for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}, config=config, stream_mode="updates"):
        if "__interrupt__" in event:
            print("中断")
            for h in graph.get_state_history(config): 
                if h.next == ("weather_graph",):
                    weather_graph_state = h.tasks[0].state
                    break
            for h in graph.get_state_history(weather_graph_state):
                if h.next == ("model_node",):
                    state = graph.get_state(config)
                    # state.values["city"] = "天津"
                    graph.update_state(state.tasks[0].state, {"city": "天津"})
                    update_city()
                    break
        elif event.get("router_node"):
            continue
        else:
            for value in event.values():
                print("Assistant:", value["messages"][-1].content)

# 设置聊天退出方法
while True:
    try:
        user_input = input("User: ")
        if user_input.lower() in ["quit", "exit", "q"]:
            print("Goodbye!")
            break

        stream_graph_updates(user_input)
    except Exception as e:
        print(e)
        user_input = "What do you know about LangGraph?"
        print("User: " + user_input)
        stream_graph_updates(user_input)
        break

输出内容

User: 北京天气怎么样
中断
天津,晴空万里,阳光明媚!
User: 

4、更新节点

指定节点,指定输出内容

只需将

graph.update_state(state.tasks[0].state, {"city": "天津"})

替换为

graph.update_state(
    state.tasks[0].state,
    {"messages": [{"role": "assistant", "content": "天津,晴空万里,阳光明媚!"}]},
    as_node="weather_node",
)

输出内容

User: 北京天气怎么样
中断
天津,晴空万里,阳光明媚!
User: 

5、更新子图

指定子图(子图本质就是一个节点),指定输出内容

由于是针对整个子图操作,所以不再需要update_city方法,部分代码如下

for h in graph.get_state_history(weather_graph_state):
    if h.next == ("model_node",):
        graph.update_state(
            config,
            {"messages": [{"role": "assistant", "content": "天津,晴空万里,阳光明媚!"}]},
            as_node="weather_graph",
        )
        messages = graph.get_state(config).values["messages"]
        print(messages[-1].content)
        break

输出内容

User: 北京天气怎么样
中断
天津,晴空万里,阳光明媚!
User: 

由于此处代码变化有些多,此处提供完整代码

from langgraph.graph import StateGraph, END, START, MessagesState
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from typing import Literal
from langgraph.checkpoint.memory import MemorySaver

@tool
def get_weather(city: str):
    """获取天气信息"""
    return f"{city},晴空万里,阳光明媚!"

# 添加记忆存储
memory = MemorySaver()

# 配置信息,用于记录对话记录
config = {"configurable": {"thread_id": "1"}}


# 指定大模型的API Key 等相关信息
llm = ChatOpenAI(
    base_url="https://lxxxxx.enovo.com/v1/", 
    api_key="sxxxxxxxwW",
    model_name="qwen2.5-instruct"
    )

# 绑定工具
model = raw_model.bind_tools([get_weather])

# 子图的state
class SubGraphState(MessagesState):
    city: str

# 识别地点(城市)
def model_node(state: SubGraphState):
    system_message = """用户的问题是某个地方的天气问题,请辨别具体城市名称,并输出城市名称。"""
    messages = [{"role": "system", "content": system_message}] + state["messages"]
    result = raw_model.invoke(messages)
    return {"city": result.content}

# 天气工具节点
def weather_node(state: SubGraphState):
    result = get_weather.invoke({"city": state["city"]})
    return {"messages": [{"role": "assistant", "content": result}]}

# 子图的添加节点、边以及编译图
subgraph = StateGraph(SubGraphState)
subgraph.add_node(model_node)
subgraph.add_node(weather_node)
subgraph.add_edge(START, "model_node")
subgraph.add_edge("model_node", "weather_node")
subgraph.add_edge("weather_node", END)
# subgraph = subgraph.compile()
subgraph = subgraph.compile(interrupt_before=["weather_node"])

# 意图分类state
class RouterState(MessagesState):
    route: Literal["天气", "其他"]

# 意图分类节点
def router_node(state: RouterState):
    system_message = """用户输入与天气相关则输出"天气",与天气无关返回"其他”"""
    messages = [{"role": "system", "content": system_message}] + state["messages"]
    route = raw_model.invoke(messages)
    return {"route": route.content}

# 智能助手节点
def normal_llm_node(state: RouterState):
    response = raw_model.invoke(state["messages"])
    return {"messages": [response]}

# 选择边函数
def route_after_prediction(state: RouterState):
    if state["route"] == "天气":
        return "weather_graph"
    else:
        return "normal_llm_node"

# 父图的添加边、节点以及编译父图
graph = StateGraph(RouterState)
graph.add_node(router_node)
graph.add_node(normal_llm_node)
# 将子图作为一个节点添加到父图中
graph.add_node("weather_graph", subgraph)
graph.add_edge(START, "router_node")
graph.add_conditional_edges("router_node", route_after_prediction)
graph.add_edge("normal_llm_node", END)
graph.add_edge("weather_graph", END)
graph = graph.compile(checkpointer=memory)

# 恢复执行graph
def update_city():
    for event in graph.stream(None, config=config, stream_mode="updates"):
        print(event)
        print(event.get("weather_graph").get("messages")[-1].content)

# 以流式调用图
def stream_graph_updates(user_input: str):
    for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}, config=config, stream_mode="updates"):
        if "__interrupt__" in event:
            print("中断")
            for h in graph.get_state_history(config): 
                if h.next == ("weather_graph",):
                    weather_graph_state = h.tasks[0].state
                    break
            for h in graph.get_state_history(weather_graph_state):
                if h.next == ("model_node",):
                    graph.update_state(
                        config,
                        {"messages": [{"role": "assistant", "content": "天津,晴空万里,阳光明媚!"}]},
                        as_node="weather_graph",
                    )
                    messages = graph.get_state(config).values["messages"]
                    print(messages[-1].content)
                    break
        elif event.get("router_node"):
            continue
        else:
            for value in event.values():
                print("Assistant:", value["messages"][-1].content)

# 设置聊天退出方法
while True:
    try:
        user_input = input("User: ")
        if user_input.lower() in ["quit", "exit", "q"]:
            print("Goodbye!")
            break

        stream_graph_updates(user_input)
    except Exception as e:
        print(e)
        user_input = "What do you know about LangGraph?"
        print("User: " + user_input)
        stream_graph_updates(user_input)
        break

六、综述

1、子图是父图的节点,可是孙图绝不是父图的节点

2、愚公移山 :子子孙孙,无穷尽也

3、子图的使用基本是在多智能体中使用

4、通信尽量使用state,避免函数调用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2313378.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

搜索引擎是如何理解你的查询并提供精准结果的?

目录 一、搜索引擎简单介绍 二、搜索引擎整体架构和工作过程 (一)整体分析 (二)爬虫系统 三个基本点 爬虫系统的工作流程 关键考虑因素和挑战 (三)索引系统 网页处理阶段 预处理阶段 反作弊分析…

IDEA软件安装环境配置中文插件

一、Java环境配置 1. JDK安装8 访问Oracle官网下载JDK8(推荐JDK8,11)Java Downloads | Oracle 双击安装程序,保持默认设置连续点击"下一步"完成安装 验证JDK安装,winR键 然后输入cmd,输入java…

循环神经网络(RNN):时序建模的核心引擎与演进之路

在人工智能处理序列数据的战场上,循环神经网络(RNN)如同一个能够理解时间的智者。从 2015 年谷歌神经机器翻译系统颠覆传统方法,到 2023 年 ChatGPT 实现对话连续性,这些突破都植根于 RNN 对时序建模的深刻理解。本文将…

电脑总显示串口正在被占用处理方法

1.现象 在嵌入式开发过程中,有很多情况下要使用串口调试,其中485/422/232转usb串口是非常常见的做法。 根据协议,接口芯片不同,需要安装对应的驱动程序,比如ch340,cp2102,CDM212364等驱动。可…

R语言和RStudio安装

整体还是比较简单的,主要是记录个流程。 官方镜像站列表R语言官网 1 安装R(2025/3/6) R语言官网:The R Project for Statistical Computing 打开之后就Hello world一下吧 配置环境变量 2 安装RStudio 下载地址:htt…

【C#学习笔记02】基本元素与数据类型

引言 深入了解C语言的基本元素、计算机存储器结构、常量与变量的概念以及数据类型。这些内容是C语言编程的基础,掌握它们对于编写高效、可靠的嵌入式程序至关重要。 1.C语言的基本元素 ​编程语言的发展离不开自然语言,所以编程语言的语法和词汇也是由…

<建模软件安装教程1>Blender4.2系列

Blender4.2安装教程 0注意:Windows环境下安装 第一步,百度网盘提取安装包。百度网盘链接:通过网盘分享的文件:blender.zip 链接: https://pan.baidu.com/s/1OG0jMMtN0qWDSQ6z_rE-9w 提取码: 0309 --来自百度网盘超级会员v3的分…

Docker极简部署开源播放器Splayer结合内网穿透远程流畅在线听歌

前言 嘿,各位音乐发烧友们!如果你厌倦了广告的打扰,渴望在忙碌的生活中找到一片宁静的音乐天地,那么今天这篇教程绝对适合你——如何在Ubuntu上用Docker快速搭建一款高颜值、无广告的某抑云音乐播放器Splayer。 Splayer不仅界面…

显示器长时间黑屏

现象 电脑启动后,进入登录界面前会随机黑屏,有时候十几秒,有时候几分钟 进入桌面后,长时间不操作电脑黑屏,移动鼠标,点击键盘后尝试点亮屏幕,也会消耗较长时间 尝试 重装系统,或者重新安装显卡,都能够恢复,但过段时间以后又出现黑屏情况 集成显卡,独立显卡都出现过 操作系统…

内网安全-横向移动PTH 哈希PTT 票据PTK 密匙Kerberos密码喷射

一.域横向pth,mimkatz,NTLM windwos server 2012 R2之前可能是NTLM和LM,之后为NTLM 1.mimkatz ptk 使用mimkatz进行横向移动 mimikatz sekurlsa::pth /user:administrator(目标本地用户名) /domain:192.168.3.32&a…

自然语言处理文本分析:从词袋模型到认知智能的进化之旅

清晨,当智能音箱准确识别出"播放周杰伦最新专辑"的模糊语音指令时;午间,企业舆情系统自动标记出十万条评论中的负面情绪;深夜,科研人员用GPT-4解析百万篇论文发现新材料线索——这些场景背后,是自…

STM32如何精准控制步进电机?

在工业自动化、机器人控制等场合,步进电机以其高精度、开环控制的特性得到了广泛应用。而在嵌入式系统中,使用STM32进行步进电机的精确控制,已成为开发者的首选方案之一。 本文将从嵌入式开发者的角度,深入探讨如何基于STM32 MCU…

[免费]微信小程序(图书馆)自习室座位预约管理系统(SpringBoot后端+Vue管理端)(高级版)【论文+源码+SQL脚本】

大家好,我是java1234_小锋老师,看到一个不错的微信小程序(图书馆)自习室座位预约管理系统(SpringBoot后端Vue管理端)(高级版),分享下哈。 项目视频演示 【免费】微信小程序(图书馆)自习室座位预约管理系统(SpringBoot后端Vue管理端)(高级版…

STM32 Bootloader理解

STM32 Bootloader个人理解 stm32单片机启动时会先运行一个引导程序Bootloader,该程序可以判断单片机的启动方式,例如stm32f103单片机会利用 boot0 、boot1 两个引脚判断启动模式。判断完启动模式后,设置 SP地址 以及 PC 指针指向对应的地址。…

Linux SSHD 启动失败:OpenSSL 版本不匹配问题分析与解决

文章目录 Linux SSHD 启动失败:OpenSSL 版本不匹配问题分析与解决问题分析解决方案方法 1:重启 SSH 服务方法 2:检查 sshd 依赖的 OpenSSL 版本方法 3:检查 OpenSSL 共享库方法 4:重新安装 OpenSSH 总结 Linux SSHD 启…

SpringBoot实战(三十五)微服务集成OAuth2.0(UAA)

目录 一、知识回顾1.1 什么是 OAuth2 协议?1.2 OAuth2 的4个角色1.3 OAuth2 的3种令牌1.4 OAuth2 的5种认证方式1.5 OAuth2 内置接口地址 二、UAA介绍2.1 概述2.2 UAA的主要功能2.3 UAA 的应用场景 三、微服务集成3.1 集成示例介绍3.2 集成测试 一、知识回顾 在进行…

DeepSeek进阶应用(一):结合Mermaid绘图(流程图、时序图、类图、状态图、甘特图、饼图)

🌟前言: 在软件开发、项目管理和系统设计等领域,图表是表达复杂信息的有效工具。随着AI助手如DeepSeek的普及,我们现在可以更轻松地创建各种专业图表。 名人说:博观而约取,厚积而薄发。——苏轼《稼说送张琥》 创作者&…

DeepSeek未来发展趋势:开创智能时代的新风口

DeepSeek未来发展趋势:开创智能时代的新风口 随着人工智能(AI)、深度学习(DL)和大数据的飞速发展,众多创新型技术已经逐渐走向成熟,而DeepSeek作为这一领域的新兴力量,正逐步吸引越…

从0开始的操作系统手搓教程24——完成我们的键盘驱动子系统

目录 所以,我们现来说说转义字符 我们需要如何处理扫描码 当键入的是双字符键时 当键入的是字母键时 下一篇 我们下面来看看我们的键盘驱动子系统是一个怎么个事情。 驱动程序,你可以认为是对硬件的一层封装。我们按照手册规格的规定姿势&#xff0…

git大文件传输报错

简述 git传输大于25M的文件时会报错,需要使用 Git LFS进行文件传输。 Git LFS(Large File Storage)是 GitHub 推荐的方式,可以管理大文件而不会影响 Git 性能。 操作流程 # 安装 Git LFS git lfs install# 将 PDF 文件添加到 G…