LangGraph-1-快速入门

LangGraph 的核心概念

        LangGraph 是 LangChain 生态系统中的关键组件,专门用于构建有状态、多参与者的应用程序。它基于图论概念,允许开发者创建复杂的代理工作流,特别适合构建需要循环、分支和协作的智能系统。

1. 图结构的Agent编排

在 LangGraph 中,应用被建模为一个有向图(Directed Graph):

  • 节点(Node):代表一个操作步骤,如调用 LLM、执行工具函数等。

  • 边(Edge):定义节点之间的执行顺序和条件逻辑,支持循环和分支。

这种结构使得复杂的工作流(如多轮对话、任务分解与执行)可以被清晰地表达和管理。

2. 状态管理与持久化

LangGraph 内置了状态管理机制,允许在图的每一步之后自动保存状态。这支持:

  • 错误恢复:在出现异常时从最近的检查点恢复执行。

  • 人工干预:在关键节点暂停,等待人工审核或输入。

  • “时间旅行”:回溯到某个状态,修改后重新执行。

状态的持久化使得应用具有更高的可靠性和可调试性。

3. 人机协作(Human-in-the-Loop)

LangGraph 支持在执行过程中引入人工决策,特别适用于需要专家判断的场景,如医疗诊断、金融分析等。系统可以在某些节点暂停,等待人工输入后再继续执行。

4. 流式输出与实时反馈

通过支持逐个令牌的流式传输,LangGraph 提供了更好的用户体验。用户可以实时看到代理的思考过程和中间结果,增强了交互性和透明度。

核心组件

组件描述
State工作流中传递的共享数据结构(TypedDict)
Nodes执行特定任务的函数(LLM调用、工具执行等)
Edges定义节点间转移关系的条件
Condition决定工作流走向的分支条件
Checkpoint保存工作流状态,支持暂停/恢复
Channels节点间通信的数据管道

简单的一个聊天智能体:

from typing import TypedDict, Annotated
from langgraph.constants import START, END
from langgraph.graph import add_messages, StateGraph
from model.deepseek import deepseek_llm

# 聊天状态
#add_messages 是一个特殊的 ** reducer 函数 **,用于在状态图(StateGraph)中管理消息历史。
#它告诉 LangChain:当有新的消息加入时,应该以何种方式更新状态中的消息列表。
#默认行为是将新消息追加到已有消息列表中。
class ChatSate(TypedDict):
    messages: Annotated[list, add_messages]
    
#定义一个流程图
graph = StateGraph(ChatSate)

#定义一个节点
def chatbot(state: ChatSate) -> ChatSate:
    return {"messages": deepseek_llm.invoke(state["messages"])}

#添加节点
graph.add_node("chatbot", chatbot)
#添加边
graph.add_edge(START, "chatbot")
graph.add_edge("chatbot", END)
graph = graph.compile()
#生成流程图
#image = graph.get_graph().draw_mermaid_png()
#with open("graph1.png", "wb") as f:
#    f.write(image)

def loop_graph_invoke(user_input: str):
    for chunk in graph.stream({'messages': [('user', user_input)]}):
        for value in chunk.values():
            print('AI:', value['messages'].content)

if __name__ == '__main__':
    while True:
        user_input = input('User:')
        if user_input.lower() in ['q', 'exit', 'bye', 'quit']:
            print('AI:', 'Bye')
            break
        else:
            loop_graph_invoke(user_input)

 生成图:

                                ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        

测试:

START 节点

START 节点是一个特殊节点,它代表将用户输入发送到图形的节点。引用此节点的主要目的是确定哪些节点应该首先被调用。​​​​​​​

from langgraph.graph import STARTgraph.add_edge(START, "my_node")graph.add_edge("my_node", "other_node")

END 节点

END 节点是一个特殊节点,它代表一个终端节点。当您想要指定哪些边在完成操作后没有动作时,会引用此节点。一个流程通常只有一个开始节点和结束节点。​​​​​​​

from langgraph.graph import ENDgraph.add_edge("other_node", END)

边(Edges)

边定义了逻辑如何路由以及图形如何决定停止。这是您的代理如何工作以及不同节点如何相互通信的重要部分。有一些关键类型的边。

  • 普通边:直接从一个节点到下一个节点。

  • 条件边:调用一个函数来确定下一个要转到的节点。

  • 入口点:用户输入到达时首先调用的节点。

  • 条件入口点:调用一个函数来确定用户输入到达时首先调用的节点。

        一个节点可以有多个输出边。如果一个节点有多个输出边,则所有这些目标节点将在下一个超级步骤中并行执行。

普通边

如果您总是想从节点 A 到节点 B,您可以直接使用add_edge方法。

graph.add_edge("node_a", "node_b")

条件边

如果您想选择性地路由到一个或多个边(或选择性地终止),您可以使用add_conditional_edges方法。此方法接受节点的名称和一个“路由函数”,该函数将在该节点执行后被调用。

graph.add_conditional_edges("node_a", routing_function)

类似于节点, routing_function 接受图形的当前 state 并返回一个值。

默认情况下,返回值 routing_function 用作要将状态发送到下一个节点的节点名称(或节点列表)。

所有这些节点将在下一个超级步骤中并行运行。

您可以选择提供一个字典,该字典将 routing_function 的输出映射到下一个节点的名称。

graph.add_conditional_edges("node_a", routing_function, {True: "node_b", False:"node_c"})

入口点

入口点是图形启动时运行的第一个节点。您可以从虚拟的 START 节点使用 add_edge 方法到要执行的第一 个节点,以指定进入图形的位置。​​​​​​​

from langgraph.graph import STARTgraph.add_edge(START, "my_node")

条件入口点

条件入口点允许您根据自定义逻辑从不同的节点开始。您可以从虚拟的 START 节点使用add_conditional_edges 来实现这一点。​​​​​​​

from langgraph.graph import STARTgraph.add_conditional_edges(START, routing_function)

您可以选择提供一个字典,该字典将 routing_function 的输出映射到下一个节点的名称。

graph.add_conditional_edges(START, routing_my,{True: "my_node", False: "other_node"}) 

 对刚才的聊天智能体进一步改进,加入一个网络搜索工具,

import os
from typing import Annotated, TypedDict
from langchain_tavily import TavilySearch
from langgraph.checkpoint.memory import MemorySaver
from langgraph.constants import START, END
from langgraph.graph import add_messages, StateGraph
from langgraph.prebuilt import ToolNode, tools_condition
from model.deepseek import deepseek_llm

class ChatSate(TypedDict):
    # messages:状态中保存数据的key
    messages: Annotated[list, add_messages]


graph = StateGraph(ChatSate)

# 定义一个互联网搜索工具
os.environ["TAVILY_API_KEY"] = ""
search_tool = TavilySearch(max_result=5)
runnable = deepseek_llm.bind_tools([search_tool])

# 定义第一个节点
def chatbot(state: ChatSate) -> ChatSate:
    return {"messages": runnable.invoke(state["messages"])}


# 定义第二个节点工具节点
too_node = ToolNode([search_tool])

# 添加边
graph.add_node("agent", chatbot)
graph.add_node("tools", too_node)
# 加入条件边
graph.add_conditional_edges(
    "agent",
    #条件变量,根据智能体的回答决定是否调用工具
    tools_condition
)
graph.add_edge("tools", "agent")  # 流程从tools 到 chatbot
graph.add_edge(START, "agent")  # 流程从start 到 chatbot
graph.add_edge("agent", END)  # 流程从chatbot 到 END
graph.set_entry_point("agent")  # 设置入口节点
#保存对话记录到内存中
memory_checkpointer = MemorySaver()
graph = graph.compile(checkpointer=memory_checkpointer)

# png = graph.get_graph().draw_mermaid_png()
# with open("graph2.png", "wb") as f:
#    f.write(png)

def loop_graph_invoke(user_input: str):
#加入会话配置
    result = graph.invoke({'messages': [('user', user_input)]}, config={"configurable": {"thread_id": "1234"}})
    if type(result['messages']) is list:
        print('AI:', result['messages'][-1].content)
    else:
        print('AI:', result['messages'].content)


while True:
    user_input = input('User:')
    if user_input.lower() in ['q', 'exit', 'bye', 'quit']:
        print('AI:', 'Bye')
        break
    else:
        loop_graph_invoke(user_input)

生成的流程图

                                          

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值