LangGraph 重要注意事项和常见问题

01. 数据状态与归纳函数

在前面的课时中,我们说过在 LangGraph 中 节点 在默认情况下返回的字典数据会将原始数据覆盖,例如下面的代码最终返回结果是 {"messages": [4]} 而不是 [1,2,3,4],如下

class MyState(TypedDict):

    messages: list

def fn1(state: MyState):

    return {"messages": [4]}

# ... (ignore codes of start->fn1->end, blah blah)

r = graph.invoke({"messages": [1, 2, 3]})

如果就是想要 [1, 2, 3, 4] 呢?第一种方法就是拿到 原始状态 的值,更新新数据,然后返回def fn1(state: MyState):

    old = state.get("messages", [])

return {"messages": old + [4]}

除此之外,在 LangGraph 中,还针对 Annotated 进行了封装,在 Python 中 Annotated 只是另外一种形态的 注释,对类型的声明+使用并没有任何影响,例如

不过这样声明有一个好处,在程序中,我们可以通过 .__metadata__ 元数据属性拿到这个值,如下

cn_salary.__metadata__

于是在 LangGraph 中就针对 注释+元数据 进行了封装,使用 Annotated 外挂需要处理数据的 归纳函数,如果外挂了则使用,不外挂也没有任何影响,这就是利用 归纳函数 来更新状态的核心。

代码经过更新后,就可以正常对数据执行相应操作了:

def concat_lists(original: list, new: list) -> list:

    return original + new

class MyState(TypedDict):

    # messages: list

    messages: Annotated[list, concat_lists]

def fn1(state: MyState):

    return {"messages": [4]}

r = graph.invoke({"messages": [1, 2, 3]})

print(r)

# 输出是 {'messages': [1, 2, 3, 4]}

使用 归纳函数 的优点也非常明显,可以让每个 节点 独立执行,不用理会别人在做啥,不需要花额外的功夫去处理 state 里的其他数据,而且在更新 state 结构时,也不需要逐个节点更新,但是添加 归纳函数 后要想执行一些特殊的操作也非常麻烦,要额外花很多功夫,例如在 add_messages() 中的 RemoveMessage 和 更新消息,就进行了额外的判断与处理

02. 多节点并行同时执行

在 LangGraph 中,END 节点非常特殊,并不是 图结构 程序走到 END 节点就终止了,只是 当前路线结束 了, 也就是说 END 是结束当前 路线,并不是结束 图,理解好这个概念才能处理好 多节点并行执行 的情况。

例如如下并行路线

在上述的节点中,如果将图结构转换成带有层级的图,则 左1 和 右1 处于同一层级上,所以这两个节点是并行执行的,但是顺序不一定能保证,虽然在 LangGraph 中会按照连接的顺序来执行,最终输出就是:START->左1->右1->合并。

如果是以下的并行路线

在这个 图结构 中,合并 虽然属于 END 节点,并且在 左1 执行完成之后就会执行 合并,但是 合并节点 并不会终止整个图的执行,而是会和 右2 作为同一层一起执行(并行执行,顺序不确定),所以最终输出:START->左1->右1->合并->右2->右3->合并。

如果想让 合并 节点只执行一次,只要把 左1 和 右3 合并同时连接到 合并 节点上即可,这样这两个节点就处于同一层,更新代码如下

graph.add_edge(["left1", "right3"], "merge")

03. 检查点 CheckPoint

检查点的概念因为它的名字,初次使用理解起来可能会比较吃力,其实只需要把 检查点 看成是一个 存储介质,用来记录这些资料,就好比游戏存档、不同玩家不同场次、可以存起来,然后载入,甚至篡改更新

所以在 LangGraph 图程序中加入 检查点 就等同于加入了一个 外部存储介质,会将每一个节点的 状态 都存储起来(StateSnapshot),变成一个历史的 list,所以对于 图程序 必须配置检查点才可以拿到 snapshot游戏存档:

  • graph.get_state(config):拿到 检查点 的最后一次存档(最后一个节点更新后的状态)。
  • graph.get_state_history(config):拿到检查点的所有存档(每个节点更新后的状态列表)。

在前面的课时中,我们传递的 config 里只有 thread_id,但是在 get_state_history(config) 拿到的所有存档列表中,还存在另外一个字段 thread_ts 代表线程的执行时间,通过该字段就可以唯一定位检查点中的某个存档,例如

StateSnapshot(..., config={'configurable': {'thread_id': '1', 'thread_ts': '1ef2985c-bed5-6dee-8003-6037939ae5aa'}}, ...)

和游戏存档回退一样,如果我们想回退到指定的存档,只需调用 invoke() 玩游戏,并载入指定存档的配置即可

for s in graph.stream(

        input=None,

        config=past_config,  # <--

        stream_mode="values"

):

    print(s)

甚至是我们想篡改 存档 的数据也是可以的,还记得 update_state() 这个函数么,同样可以传入对应的 config,只需要在修改时,传递需要更改的 存档配置 即可,例如

graph.update_state(

    config=past_config,

    values={"crew": [66, 77], "v": "BAD GUY"}

)

不过因为回退机制用得比较少,所以该功能在 LangGraph 的官网藏得也比较深,也没有过多文章做出详细的讲解

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

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

相关文章

避坑指南!解决Navicat运行SQL成功但没有表的问题

在运行转储的SQL文件时&#xff0c;成功运行&#xff0c;试了很多办法都不显示出表。原因&#xff1a;当从一个高版本的 MySQL 数据库导入数据到低版本的 MySQL 数据库时&#xff0c;可能会遇到兼容性问题。因为高版本的 MySQL 可能支持 utf8mb4_0900_ai_ci&#xff0c;而低版本…

在 Elasticsearch 中使用用户行为分析:使用 UBI 和 search-ui 创建一个应用程序

作者&#xff1a;来自 Elastic Eduard Martin 及 Alexander Dvila 通过一个实际示例学习如何在 Elasticsearch 中使用 UBI。我们将创建一个在搜索和点击结果时生成 UBI 事件的应用程序。 想要获得 Elastic 认证吗&#xff1f;看看下一次 Elasticsearch Engineer 培训什么时候开…

SpringBoot3中使用Caffeine缓存组件

SpringBoot3已经把EhCache从框架中删除了&#xff0c;SpringBoot3默认的缓存组件为Caffeine&#xff0c;那么我们在SpringBoot3中如何去使用它了&#xff1f; 1.添加依赖 <dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>ca…

正则表达式与grep文本过滤详解

文章目录前言一、正则表达式概述1.1 定义1.2 主要用途1.3 Linux 中的正则表达式分类1.3.1 基础正则表达式&#xff08;BRE&#xff09;1.3.2 扩展正则表达式&#xff08;ERE&#xff09;二、正则表达式的基本组成2.1 普通字符2.2 元字符2.2.1 基本元字符2.2.2 重复次数相关2.2.…

Dify 集成 Milvus 配置指南

&#x1f9e9; Dify 集成 Milvus 配置指南 &#x1f527; 详细配置步骤 1. 环境准备与克隆仓库 首先确保你的系统已安装 Git、Docker 和 Docker Compose。然后克隆 Dify 的代码仓库&#xff1a; git clone https://github.com/langgenius/dify.git cd dify/docker2. 配置环境变…

为不平,不止于此

口碑可以成就一个人&#xff0c;也可以毁掉一个人&#xff0c; 所以我们选择用实力去创造两种无声的口碑。 要么让期待的你张口而呼&#xff0c; 要么让挑剔的你哑口无言。玛哈特科技创始人 #为不平&#xff0c;不止于此#

0902 C++类的匿名对象

Part 1.梳理思维导图一.匿名对象1.概念没有对象名的类对象2.格式类名();3.作用1.给有名对象初始化2.给对象数组初始化3.作为函数的参数传递给形参4.例子#include <iostream>using namespace std;class Dog {friend void Dogfriend(Dog &b); private:string name;int …

在 PySpark 中解锁窗口函数的力量,实现高级数据转换

本篇文章Mastering PySpark Window Functions: A Practical Guide to Time-Based Analytics适合数据分析和工程师入门了解PySpark的窗口函数。文章的亮点在于详细介绍了窗口函数的基本概念及其在销售数据分析中的实际应用&#xff0c;帮助读者理解如何进行复杂的数据计算而无需…

从理念到实践:三层解耦架构与“无系统”论

在上一篇中&#xff0c;我们揭示了“五层双闭环”治理模型如何像骨骼一样&#xff0c;为数字化转型提供支撑和定型。但再宏伟的蓝图也需要坚实的施工来实现。今天&#xff0c;我们将深入最具体的实施层面&#xff0c;将“业务重塑”和“以人为本”的理念&#xff0c;转化为可落…

详细介绍Linux 内存管理struct page数据结构中的_count和_mapcount有什么区别?

在Linux内核的struct page中&#xff0c;_count&#xff08;或_refcount&#xff09;和_mapcount是两个关键的引用计数成员&#xff0c;它们各自承担不同的职责。以下是深度解析和代码案例&#xff1a;1. _count vs _mapcount 区别详解_count&#xff08;或_refcount&#xff0…

面阵 vs 线阵相机:怎么选不踩坑?选型公式直接套用

面阵vs线阵相机&#xff1a;怎么选不踩坑&#xff1f;选型公式直接套用&#x1f3af;面阵vs线阵相机怎么选不踩坑&#xff1f;&#x1f3af;一、面阵相机&#xff1a;工业检测的“万能选手”&#xff0c;拍全图靠它&#x1f3af;二、线阵相机&#xff1a;大视野/高精度的“专属…

Spring Security 如何使用@PreAuthorize注解

&#x1f9f1; 第一步&#xff1a;环境准备✅ 1. 创建数据库&#xff08;MySQL&#xff09;-- 创建数据库&#xff0c;使用 utf8mb4 字符集支持 emoji 和多语言 CREATE DATABASE security_demo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;-- 使用该数据库 USE security…

JVM中产生OOM(内存溢出)的8种典型情况及解决方案

Java中的OutOfMemoryError&#xff08;OOM&#xff09;是当JVM内存不足时抛出的错误。本文将全面剖析JVM中产生OOM的各种情况&#xff0c;包括堆内存溢出、方法区溢出、栈溢出等&#xff0c;并提供详细的诊断方法和解决方案。 一、OOM基础概念 1.1 OOM错误类型 Java中的OOM是…

【IEEE出版、EI检索、往届会后3个月检索】第四届信号处理、计算机网络与通信国际学术会议(SPCNC 2025)

第四届信号处理、计算机网络与通信国际学术会议&#xff08;SPCNC 2025&#xff09;将于2025年12月5-7日于中国武汉召开&#xff08;线上同步&#xff09;。为本次会议旨在齐聚海内外信号处理、计算机网络与通信等计算机领域的专家学者&#xff0c;为相关领域研究和从业人员提供…

Spring boot注解介绍

1. Spring 核心注解Spring Boot 是基于 Spring 框架的&#xff0c;所以核心注解依然适用。✅ 常见核心注解Component表示一个通用组件&#xff0c;Spring 会自动扫描并注入到容器中。Component public class MyComponent {public void sayHello() {System.out.println("He…

撤销回退 情况⼆:已经 add ,但没有 commit

撤销回退 情况⼆&#xff1a;已经 add &#xff0c;但没有 commit add 后还是保存到了暂存区呢&#xff1f;怎么撤销呢&#xff1f; 1 # 向ReadMe中新增⼀⾏代码 2 hyb139-159-150-152:~/gitcode$ vim ReadMe 3 hyb139-159-150-152:~/gitcode$ cat ReadMe 4 hello bit 5 hell…

【Linux笔记】命令行与vim基础

一、Linux命令行基础 1. 基本语法命令空格参数&#xff08;可写可不写&#xff09;空格文件&#xff0c;文件夹&#xff08;可写可不写&#xff09;ls列出文件夹中的内容/opt 根目录下的opt文件夹ls-a all显示出所有文件以及隐藏文件/optls-a如果不写则输出一个点&#xff0c;当…

Redis 的整数集合:像分类收纳盒一样的整数专属存储

目录 一、先懂定位&#xff1a;为什么需要整数集合&#xff1f;&#xff08;衔接哈希表&#xff09; 二、整数集合的结构&#xff1a;像 “贴了规格标签的收纳盒” 1. encoding&#xff1a;收纳盒的 “规格标签”&#xff08;核心&#xff1a;决定格子大小&#xff09; 2. …

Linux 进程状态 — 僵尸进程

&#x1f381;个人主页&#xff1a;工藤新一 &#x1f50d;系列专栏&#xff1a;C面向对象&#xff08;类和对象篇&#xff09; &#x1f31f;心中的天空之城&#xff0c;终会照亮我前方的路 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 文章目录进…

React 中 key 的作用

React 中 key 的作用是什么&#xff1f; Date: August 31, 2025 Area: 原理key 概念 在 React 中&#xff0c;key 用于识别哪些元素是变化、添加或删除的。 在列表渲染中&#xff0c;key 尤其重要&#xff0c;因为它能提高渲染性能和确保组件状态的一致性。key 的作用 1&#x…