工作流框架-LangGraph

该文章已生成可运行项目,

基本概述

LangGraph 是由 LangChain 团队开发的一个开源框架,旨在帮助开发者构建基于大型语言模型(LLM)的复杂、有状态、多主体的应用。它通过将工作流表示为图结构(graph),提供了更高的灵活性和控制能力,特别适合需要循环逻辑、状态管理以及多主体协作的场景,比如智能代理(agent)和多代理工作流。

LangGraph 是为智能体和工作流设计一套底层编排框架

官方文档:https://langchain-ai.github.io/langgraph/

核心概念

图结构(Graph Structure)

LangGraph 将应用逻辑组织成一个有向图,其中:

-节点(Nodes):代表具体的操作或计算步骤,可以是调用语言模型、执行函数或与外部工具交互等

-边(Edges):定义节点之间的连接和执行顺序,支持普通边(直接连接)和条件边(基于条件动态选择下一步)

状态管理(State Management)

LangGraph 的核心特点是自动维护和管理状态

状态(State)是一个贯穿整个图的共享数据结构,记录了应用运行过程中的上下文信息

每个节点可以根据当前状态执行任务并更新状态,确保系统在多步骤或多主体交互中保持一致性

循环能力(Cyclical Workflows)

与传统的线性工作流(如 LangChain 的 LCEL)不同,LangGraph 支持循环逻辑,这使得它非常适合需要反复推理、决策或与用户交互的代理应用。例如,一个代理可以在循环中不断调用语言模型,直到达成目标。

主要特点

灵活性:开发者可以精细控制工作流的逻辑和状态更新,适应复杂的业务需求

持久性:内置支持状态的保存和恢复,便于错误恢复和长时间运行的任务

多主体协作:允许多个代理协同工作,每个代理负责特定任务,通过图结构协调交互

工具集成:可以轻松集成外部工具(如搜索API)或自定义函数,增强代理能力

人性化交互:支持“人在回路”(human-in-the-loop)功能,让人类在关键步骤参与决策

使用场景

LangGraph 特别适用于以下场景:

对话代理:构建能够记住上下文、动态调整策略的智能聊天机器人 多步骤任务:处理需要分解为多个阶段的复杂问题,如研究、写作或数据分析

多代理系统:协调多个代理分工合作,比如一个负责搜索信息、另一个负责总结内容的系统

与 LangChain 的关系

- LangGraph 是 LangChain 生态的一部分,但它是独立于 LangChain 的一个模块

- LangChain 更擅长处理简单的线性任务链(DAG),而 LangGraph 专注于更复杂的循环和多主体场景

- 你可以单独使用 LangGraph,也可以结合 LangChain 的组件(如提示模板、工具接口)来增强功能

持久化状态

LangGraph 内置了一个持久化层,通过检查点(checkpointer)机制实现。当你使用检查点器编译图时,它会在每个超级步骤(super-step)自动保存图状态的检查点。这些检查点被存储在一个线程(thread)中,可在图执行后随时访问。由于线程允许在执行后访问图的状态,因此实现了人工介入(human-in-the-loop)、记忆(memory)、时间回溯(time travel)和容错(fault-tolerance)等强大功能。

什么是内存(Memory)

记忆是一种认知功能,允许人们存储、检索和使用信息来理解他们的现在和未来。通过记忆功能,代理可以从反馈中学习,并适应用户的偏好。

-短期记忆(Short-term memory)或称为线程范围内的记忆,可以在与用户的单个对话线程中的任何时间被回忆起来。LangGraph将短期记忆管理为代理状态的一部分。状态会被使用检查点机制保存到数据库中,以便对话线程可以在任何时间恢复。当图谱被调用或者一个步骤完成时,短期记忆会更新,并且在每个步骤开始时读取状态。这种记忆类型使得AI能够在与用户的持续对话中保持上下文和连贯性,确保了交互的流畅性和效率。例如,在一系列的询问、回答或命令执行过程中,用户无需重复之前已经提供的信息,因为AI能够记住这些细节并根据需要利用这些信息进行响应或进一步的操作。这对于提升用户体验,尤其是复杂任务处理过程中的体验至关重要。

- 长期记忆(Long-term memory)是在多个对话线程之间共享的。它可以在任何时间、任何线程中被回忆起来。记忆的范围可以限定在任何自定义命名空间内,而不仅仅局限于单个线程ID。LangGraph提供了存储机制,允许您保存和回忆长期记忆。

这种记忆类型使得AI能够在不同对话或用户交互中保留和利用信息。例如,用户的偏好、历史记录或特定的上下文信息可以跨会话保存下来,并在未来的任何交互中被调用。这种方式为用户提供了一种无缝体验,无论他们何时或以何种方式与AI交互,AI都能根据过去的信息做出更个性化、更智能的响应。这对于构建深度用户关系和增强系统适应性至关重要。

图片

持久化

许多AI应用需要记忆功能来在多次交互中共享上下文。在LangGraph中,这种类型的记忆可以通过线程级别的持久化添加到任何StateGraph中。

通过使用线程级别的持久化,LangGraph允许AI在与用户的连续对话或交互过程中保持信息的连贯性和一致性。这意味着,在一个交互中获得的信息可以被保存并在后续的交互中使用,极大地提升了用户体验。例如,用户在一个会话中表达的偏好可以在下一个会话中被记住和引用,使得交互更加个性化和高效。这种方法对于需要处理复杂或多步骤任务的应用特别有用,因为它确保了用户无需重复提供相同的信息,同时也让AI能够更好地理解和响应用户的需求。

LangGraph 中使用 Memory

# !pip install langchain# !pip install langgraph# !pip install langchain-openai
from langgraph.graph import StateGraph, MessagesState, START, ENDfrom langgraph.checkpoint.memory import MemorySaver# 创建 Graph# MessagesState 是一个 State 内置对象,add_messages 是内置的一个方法,将新的消息列表追加在原列表后面graph_builder = StateGraph(MessagesState)
from langchain.chat_models import init_chat_modelllm = init_chat_model("gpt-4o-mini", model_provider="openai")# 定义一个执行节点# 输入是 State,输出是系统回复def chatbot(state: MessagesState):    # 调用大模型,并返回消息(列表)    # 返回值会触发状态更新 add_messages    return {"messages": [llm.invoke(state["messages"])]}graph_builder.add_node("chatbot", chatbot)graph_builder.add_edge(START, "chatbot")graph_builder.add_edge("chatbot", END)# 为了添加持久性,我们需要在编译图表时传递检查点。使用 MemorySaver 就可以记住以前的消息!graph = graph_builder.compile(checkpointer = MemorySaver())
from IPython.display import Image, display# 可视化展示这个工作流try:    display(Image(data=graph.get_graph().draw_mermaid_png()))except Exception as e:    print(e)

图片

config = {"configurable": {"thread_id": "1"}}input_message = {"role": "user", "content": "hi! I'm kevin"}for chunk in graph.stream({"messages": [input_message]}, config, stream_mode="values"):    chunk["messages"][-1].pretty_print()
input_message = {"role": "user", "content": "what's my name?"}for chunk in graph.stream({"messages": [input_message]}, config, stream_mode="values"):    chunk["messages"][-1].pretty_print()

如果我们想开始一个新的对话,可以通过传递不同的会话标识符或配置来实现。这意味着为新的交互创建一个独立的上下文,确保新对话不会受到之前对话状态的影响,从而保持数据和记忆的隔离。但是这样所有记忆都会消失!

input_message = {"role": "user", "content": "what's my name?"}for chunk in graph.stream(    {"messages": [input_message]},    {"configurable": {"thread_id": "2"}},    stream_mode="values",):    chunk["messages"][-1].pretty_print()

LangGraph 中使用 InMemoryStore

InMemoryStore是一个基于内存的存储系统,用于在程序运行时临时保存数据。它通常用于快速访问和存储短期记忆或会话数据。我们可以使用使用 langgraph 和 langchain_openai 库来创建一个基于内存的存储系统(InMemoryStore),并结合 OpenAI 的嵌入模型 (OpenAIEmbeddings) 来处理嵌入向量。

我们不是用了MemorySaver持久化消息吗,为啥还要用InMemoryStore,他们的主要区别在于数据的持久性和应用场景。InMemoryStore主要用于短期、临时的数据储,强调快速访问;而MemorySaver则侧重于将数据从临时存储转移到持久存储,确保数据可以在多次程序执行间保持不变。在我们设计系统时,可以根据具体需求选择合适的存储策略。对于只需要在会话内保持的数据,可以选择InMemoryStore;而对于需要长期保存并能够在不同会话间共享的数据,则应考虑使用MemorySaver或其他形式的持久化存储解决方案。

下面展示一个结合两种方式的例子,实现一个对话模型的调用逻辑,通过从存储系统中检索与用户相关的记忆信息并将其作为上下文传递给模型,同时支持根据用户指令存储新记忆,确保每个用户的记忆数据独立且自包含,从而提升对话的个性化和连贯性。

from langgraph.store.memory import InMemoryStorefrom langchain_community.embeddings import DashScopeEmbeddingsin_memory_store = InMemoryStore(    index={        "embed": DashScopeEmbeddings(model="text-embedding-v1"),        "dims": 1536,    })import uuidfrom typing import Annotatedfrom typing_extensions import TypedDictfrom langchain_core.runnables import RunnableConfigfrom langgraph.graph import StateGraph, MessagesState, STARTfrom langgraph.checkpoint.memory import MemorySaverfrom langgraph.store.base import BaseStorefrom langchain.chat_models import init_chat_modelmodel = init_chat_model("deepseek-chat", model_provider="deepseek")def call_model(state: MessagesState, config: RunnableConfig, *, store: BaseStore):    user_id = config["configurable"]["user_id"]    namespace = ("memories", user_id)    memories = store.search(namespace, query=str(state["messages"][-1].content))    info = "\n".join([d.value["data"] for d in memories])    system_msg = f"You are a helpful assistant talking to the user. User info: {info}"    # Store new memories if the user asks the model to remember    last_message = state["messages"][-1]    if "remember" in last_message.content.lower():        memory = "User name is Kevin"        store.put(namespace, str(uuid.uuid4()), {"data": memory})    response = model.invoke(        [{"role": "system", "content": system_msg}] + state["messages"]    )    return {"messages": response}builder = StateGraph(MessagesState)builder.add_node("call_model", call_model)builder.add_edge(START, "call_model")graph = builder.compile(checkpointer=MemorySaver(), store=in_memory_store)
config = {"configurable": {"thread_id": "1", "user_id": "1"}}input_message = {"role": "user", "content": "Hi! Remember: my name is Kevin"}for chunk in graph.stream({"messages": [input_message]}, config, stream_mode="values"):    chunk["messages"][-1].pretty_print()
# 我们先改变一下config,使用一个新的线程,用户保持不变config = {"configurable": {"thread_id": "2", "user_id": "1"}}input_message = {"role": "user", "content": "what is my name?"}for chunk in graph.stream({"messages": [input_message]}, config, stream_mode="values"):    chunk["messages"][-1].pretty_print()
# 现在,我们可以检查我们的store,并验证我们实际上已经为用户保存了记忆:for memory in in_memory_store.search(("memories", "1")):    print(memory.value)
# 现在,让我们为另一个用户运行这个图,以验证关于第一个用户记忆是独立且自包含的。config = {"configurable": {"thread_id": "3", "user_id": "2"}}input_message = {"role": "user", "content": "what is my name?"}for chunk in graph.stream({"messages": [input_message]}, config, stream_mode="values"):    chunk["messages"][-1].pretty_print()

几个基础概念

- `StateGraph` 将工作流定义成一个状态机- `Node` 工作流中的节点- `Edge` 边,定义节点之间的跳转- `State` 状态,随着工作流的进行可以被更新
实现一个带上下文的 Chatbot
from typing import Annotatedfrom typing_extensions import TypedDictfrom langgraph.graph import StateGraph, START, ENDfrom langgraph.graph.message import add_messages# 定义 Stateclass State(TypedDict):    # 状态变量 messages 类型是 list,更新方式是 add_messages    # add_messages 是内置的一个方法,将新的消息列表追加在原列表后面    messages: Annotated[list, add_messages]# 创建 Graphgraph_builder = StateGraph(State)
from langchain.chat_models import init_chat_modelllm = init_chat_model("gpt-4o", model_provider="openai")# 定义一个执行节点# 输入是 State,输出是系统回复def chatbot(state: State):    # 调用大模型,并返回消息(列表)    # 返回值会触发状态更新 add_messages    return {"messages": [llm.invoke(state["messages"])]}graph_builder.add_node("chatbot", chatbot)graph_builder.add_edge(START, "chatbot")graph_builder.add_edge("chatbot", END)graph = graph_builder.compile()
from IPython.display import Image, display# 可视化展示这个工作流try:    display(Image(data=graph.get_graph().draw_mermaid_png()))except Exception as e:    print(e)
from langchain.schema import AIMessage def stream_graph_updates(user_input: str):    # 向 graph 传入一条消息(触发状态更新 add_messages)    for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}):        for value in event.values():            if "messages" in value and isinstance(value["messages"][-1], AIMessage):                print("Assistant:", value["messages"][-1].content)def run():    # 执行这个工作流    while True:        user_input = input("User: ")        if user_input.strip() == "":            break            stream_graph_updates(user_input)
run()

加入 RAG

# !pip install -U langchain-community pymupdf# !pip install dashscope# !pip install faiss-cpu
from langchain_openai import OpenAIEmbeddingsfrom langchain_text_splitters import RecursiveCharacterTextSplitterfrom langchain_community.vectorstores import FAISSfrom langchain_community.document_loaders import PyMuPDFLoader# 加载文档loader = PyMuPDFLoader("./data/deepseek-v3-1-4.pdf")pages = loader.load_and_split()# 文档切分text_splitter = RecursiveCharacterTextSplitter(    chunk_size=512,    chunk_overlap=200,    length_function=len,    add_start_index=True,)texts = text_splitter.create_documents(    [page.page_content for page in pages[:2]])# 灌库embeddings = OpenAIEmbeddings(model="text-embedding-ada-002")db = FAISS.from_documents(texts, embeddings)# 检索 top-3 结果retriever = db.as_retriever(search_kwargs={"k": 3})
from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate# Prompt模板template = """请根据对话历史和下面提供的信息回答上面用户提出的问题:{input}"""prompt = ChatPromptTemplate.from_messages(    [        HumanMessagePromptTemplate.from_template(template),    ])
def retrieval(state: State):    user_query = ""    if len(state["messages"]) >= 1:        # 获取最后一轮用户输入        user_query = state["messages"][-1]    else:        return {"messages": []}    # 检索    docs = retriever.invoke(str(user_query))    # 填 prompt 模板    messages = prompt.invoke("\n".join([doc.page_content for doc in docs])).messages    return {"messages": messages}
graph_builder = StateGraph(State)graph_builder.add_node("retrieval", retrieval)graph_builder.add_node("chatbot", chatbot)graph_builder.add_edge(START, "retrieval")graph_builder.add_edge("retrieval","chatbot")graph_builder.add_edge("chatbot", END)graph = graph_builder.compile()
run()

加入分支:如果找不到答案则转人工

from langchain.schema import HumanMessage from typing import Literalfrom langgraph.types import interrupt, Commanddef verify(state: State)-> Literal["chatbot","ask_human"]:    message = HumanMessage("请根据对话历史和上面提供的信息判断,已知的信息是否能够回答用户的问题。直接输出你的判断'Y'或'N'")    ret = llm.invoke(state["messages"]+[message])    if 'Y' in ret.content:        return "chatbot"    else:        return "ask_human"def ask_human(state: State):    user_query = state["messages"][-2].content    human_response = interrupt(       {          "question": user_query       }    )    # Update the state with the human's input or route the graph based on the input.    return {        "messages": [AIMessage(human_response)]    }
from langgraph.checkpoint.memory import MemorySavermemory = MemorySaver() # 用于持久化存储 state (这里以内存模拟)graph_builder = StateGraph(State)graph_builder.add_node("retrieval", retrieval)graph_builder.add_node("chatbot", chatbot)graph_builder.add_node("ask_human", ask_human)graph_builder.add_edge(START, "retrieval")graph_builder.add_conditional_edges("retrieval", verify)graph_builder.add_edge("ask_human", END)graph_builder.add_edge("chatbot", END)# 中途会被转人工打断,所以需要 checkpointer 存储状态graph = graph_builder.compile(checkpointer=memory)
from langchain.schema import AIMessage # 当使用 checkpointer 时,需要配置读取 state 的 thread_id# 可以类比 OpenAI Assistants API 理解,或者想象 Redis 中的 key thread_config = {"configurable": {"thread_id": "my_thread_id"}}def stream_graph_updates(user_input: str):    # 向 graph 传入一条消息(触发状态更新 add_messages)    for event in graph.stream(        {"messages": [{"role": "user", "content": user_input}]},        thread_config    ):        for value in event.values():            if isinstance(value, tuple):                return value[0].value["question"]            elif "messages" in value and isinstance(value["messages"][-1], AIMessage):                print("Assistant:", value["messages"][-1].content)                return None    return Nonedef resume_graph_updates(human_input: str):    for event in graph.stream(        Command(resume=human_input), thread_config, stream_mode="updates"    ):        for value in event.values():            if "messages" in value and isinstance(value["messages"][-1], AIMessage):                print("Assistant:", value["messages"][-1].content)def run():    # 执行这个工作流    while True:        user_input = input("User: ")        if user_input.strip() == "":            break        question = stream_graph_updates(user_input)        if question:            human_answer = input("Ask Human: "+question+"\nHuman: ")            resume_graph_updates(human_answer)
run()
from IPython.display import Image, display# 可视化展示这个工作流try:    display(Image(data=graph.get_graph().draw_mermaid_png()))except Exception as e:    print(e)
LangGraph 还支持:- 工具调用- 并行处理- 状态持久化- 对话历史管理- 历史动作回放(用于调试与测试)- 子图管理- 多智能体协作- 等等

更多 LangGraph,参考官方文档:https://langchain-ai.github.io/langgraph/how-tos

LangChain 与 LlamaIndex 的错位竞争

- LangChain 侧重与 LLM 本身交互的封装  - Prompt、LLM、Message、OutputParser 等工具丰富  - 在数据处理和 RAG 方面提供的工具相对粗糙  - 主打 LCEL 流程封装  - 配套 Agent、LangGraph 等智能体与工作流工具  - 另有 LangServe 部署工具和 LangSmith 监控调试工具- LlamaIndex 侧重与数据交互的封装  - 数据加载、切割、索引、检索、排序等相关工具丰富  - Prompt、LLM 等底层封装相对单薄  - 配套实现 RAG 相关工具  - 同样配套智能体与工作流工具  - 提供 LlamaDeploy 部署工具,通过与三方合作提供过程监控调试工具

如何学习大模型 AI ?

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

  • 大模型 AI 能干什么?
  • 大模型是怎样获得「智能」的?
  • 用好 AI 的核心心法
  • 大模型应用业务架构
  • 大模型应用技术架构
  • 代码示例:向 GPT-3.5 灌入新知识
  • 提示工程的意义和核心思想
  • Prompt 典型构成
  • 指令调优方法论
  • 思维链和思维树
  • Prompt 攻击和防范

第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

  • 为什么要做 RAG
  • 搭建一个简单的 ChatPDF
  • 检索的基础概念
  • 什么是向量表示(Embeddings)
  • 向量数据库与向量检索
  • 基于向量检索的 RAG
  • 搭建 RAG 系统的扩展知识
  • 混合检索与 RAG-Fusion 简介
  • 向量模型本地部署

第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

  • 为什么要做 RAG
  • 什么是模型
  • 什么是模型训练
  • 求解器 & 损失函数简介
  • 小实验2:手写一个简单的神经网络并训练它
  • 什么是训练/预训练/微调/轻量化微调
  • Transformer结构简介
  • 轻量化微调
  • 实验数据集的构建

第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

  • 硬件选型
  • 带你了解全球大模型
  • 使用国产大模型服务
  • 搭建 OpenAI 代理
  • 热身:基于阿里云 PAI 部署 Stable Diffusion
  • 在本地计算机运行大模型
  • 大模型的私有化部署
  • 基于 vLLM 部署大模型
  • 案例:如何优雅地在阿里云私有部署开源大模型
  • 部署一套开源 LLM 项目
  • 内容安全
  • 互联网信息服务算法备案

学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。

如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。

这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费

在这里插入图片描述

本文章已经生成可运行项目
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值