AI大模型综合(二)LangGraph4j(完整示例)

目录

一、LangGraph4j简介

1.1 核心特性

1.2 应用场景

1.3 核心概念

状态图StateGraph

节点Node

边Edge

子图 / 子流程 / 嵌套 Graph

状态(State)

检查点

中断 / 人工干预

1.4 使用流程

1.5 官方文档

二、LangGraph4j示例演示


 

 

一、LangGraph4j简介

LangGraph4j 是一个专为 Java设计的开源库,用于构建状态ful、多智能体应用,并与语言模型(LLMs)无缝集成‌,支持复杂任务协作与流程管理。

‌LangGraph4j 基于状态图(StateGraph)模型,通过节点(Node)、边(Edge)和检查点(State)实现智能体协作


1.1 核心特性

流程管理‌:支持循环、条件分支和并行执行,灵活处理复杂业务逻辑。‌‌
‌状态管理‌:通过检查点机制保存执行状态,实现任务中断恢复和上下文追溯,提升系统鲁棒性。‌‌
‌模块化设计‌:节点职责单一,降低代码耦合度,便于扩展与维护。‌‌
‌集成能力‌:与 Spring Boot、LangChain4j 等框架无缝兼容,支持“人在环路”(Human-in-Loop)模式。‌‌无缝集成主流Java生态,与Spring Boot(studio/springboot/)、Quarkus(studio/quarkus/)、Jetty(studio/jetty/)等框架深度整合,提供开箱即用的部署方案,满足从微服务到Serverless的全场景需求

  • 原生支持循环:Agent的“思考-行动”循环、自我纠错、多轮对话等需要循环的场景,在LangGraph4j中可以轻松实现,而无需像传统编程那样写复杂的 while 循环和状态管理代码。
  • 人机协同(Human-in-the-Loop): 图可以在任何节点后暂停,等待人类的输入、审核或确认,然后再继续执行。这对于构建可控、可靠的企业级应用至关重要。

可观测性与调试:

  • 检查点: 在任何点保存图的状态,以便稍后重播或检查。这对于调试和理解复杂交互非常宝贵。
  • 图可视化: 使用 PlantUML 或 Mermaid 生成图的可视化表示,以理解其结构。

1.2 应用场景

舆情监测系统‌:智能体判断用户情绪倾向(正面/负面),通过条件边路由至处理节点,检查点保存中间结果

‌支付流程‌:商品市场智能体调用支付智能体完成交易
人机交互场景: 比如,多个角色的审批流程;

自动化修复场景: 比如,在 自动化 Bug 修复 / 代码生成 中,把生成、运行、调试、修复等阶段建为节点,用 LangGraph 来协同控制流

1.3 核心概念

  • 状态图StateGraph

状态图是一种数据结构,其生命周期存在于整个Langgraph过程中,所有节点的执行过程和结构都可以被记录到状态图中;而且每个节点也都可以随时访问状态图中的数据,来获取其当时的执行过程和结果

StateGraph<S extends AgentState>

        StateGraph
 是用于定义应用程序结构的主要类。您可以在此添加节点和边以创建图。它由 AgentState 进行参数化。

 

AgentState(或其扩展类)表示图的共享状态。它本质上是一个在节点间传递的映射(Map<String, Object>)。每个节点都可以读取此状态并返回对其的更新

        在 StateGraph 中定义好所有节点和边后,你需要调用 compile() 方法将其编译为 CompiledGraph<S extends AgentState>。这个编译后的图是逻辑的不可变、可运行表示。编译过程会验证图结构(例如,检查是否存在孤立节点)。

 

  • 节点Node

节点通常是一个函数(或实现 NodeAction<S> 或 AsyncNodeAction<S> 的类);其主要作用就是用来执行具体的任务。

执行一些计算(例如,调用 LLM、执行工具、人工审查、运行自定义业务逻辑)节点可以是同步的或异步的(CompletableFuture)。

节点往往会对应以下几种行为:

  • 调用 LLM(如 OpenAI、Anthropic、Claude、GPT 模型等)
  • 调用外部工具(API、数据库、搜索、检索系统)(ps:类似@Tool)
  • 访问 / 管理 memory(长期或短期记忆)
  • 逻辑判断 / 条件控制 / 计算 / 转换
  • 人工审查 / 人工输入
  • 边Edge

边就相当于判断逻辑中的分支,边决定了当前节点执行完毕之后,下一个执行的节点。用来表示执行时从一个节点到下一个节点的路径。可以有条件判断、失败重试、错误分支等。

Normal Edges(普通边):从一个节点到另一个节点的无条件过渡;

Conditional Edges(条件边):下一个节点根据当前 AgentState 动态确定

Entry Points(入口点):您还可以使用 addConditionalEntryPoint(...) 为图定义条件入口点

  • 子图 / 子流程 / 嵌套 Graph

复杂场景中,一个节点内部可能又含有子图/子流程,以支持层次化设计

  • 状态(State)

执行 Graph 时,需要一个 状态对象(state) 来在节点间传递上下文数据。这个状态可能是一个键值映射(Map<String, Object>),节点可以读取或写入状态中字段。

  • 检查点

在任何步骤保存图的状态(Checkpoint)。检查点是存储了当前节点的所有信息,包括了状态图,也有检查点版本号,回溯关系之类的信息

检查点 / 恢复执行过程中在关键点或每节点后保存执行状态和状态快照,以支持中断后重启或时间旅行

保存图的状态(Checkpoint)适用的场景:

 

  • 调试:在不同点检查状态,以了解发生了什么。
  • 恢复:将图恢复到之前的状态并继续执行。
  • 长时间运行的流程:持久化长时间运行的智能体交互状态。 你通常会使用 CheckpointSaver 实现(例如,用于内存存储的 MemorySaver,或者你可以实现自己的持久化存储)。
  • 中断 / 人工干预

在某些节点可以插入人工审核、人工干预步骤(human-in-the-loop)

1.4 使用流程

(1)定义状态对象(AgentState):首先,定义一个类或数据结构来表示整个工作流的共享状态(例如,一个包含消息列表、中间结果的 AgentState 对象)。

(2)定义节点(NodeAction):将你的 Agent、工具或其他业务逻辑实现为一个个的函数或方法,这些方法接受当前的状态作为输入,并返回对状态的更新。

(3)构建图(StateGraph):实例化一个 StateGraph<T>, 并传入你定义的状态类。使用 addNode() 将你定义好的节点添加到图中。使用 addEdge() 或 addConditionalEdges()来连接这些节点,定义任务的流转逻辑。

(4)编译图:调用 StateGraph 的 compile()方法,LangGraph4j 会将你定义的图结构编译成一个可执行的Graph对象。

(5)执行:调用编译后图对象的 stream() 或 invoke() 方法,传入初始输入,即可启动整个多智能体系统的协作流程。图会根据你定义的边和条件,自动地在不同节点间流转,直到到达终点。

1.5 官方文档

https://github.com/langgraph4j/langgraph4j/

中文翻译版:https://gitcode.com/gh_mirrors/la/langgraph4j

注:

中文翻译版:https://gitcode.com/GitHub_Trending/la/langchain4j

 

二、LangGraph4j示例演示

示例1: 

执行流程图:

SimpleState:

package com.ai.langgraph4j.example02; import org.bsc.langgraph4j.state.AgentState; import org.bsc.langgraph4j.state.Channel; import org.bsc.langgraph4j.state.Channels; import java.util.ArrayList; import java.util.List; import java.util.Map; //执行 Graph 时,需要一个状态对象(state)来在节点间传递上下文数据。这个状态可能是一个键值映射(Map<String, Object>) public class SimpleState extends AgentState { public static final String MESSAGES_KEY = "messages"; // 定义了 SimpleState,其中包含一个使用 AppenderChannel 来累积字符串的 MESSAGES_KEY public static final Map<String, Channel<?>> SCHEMA = Map.of( MESSAGES_KEY, Channels.appender(ArrayList::new) ); public SimpleState(Map<String, Object> initData) { super(initData); } public List<String> messages() { return this.<List<String>>value("messages") .orElse( List.of() ); } } 

TestTool:

package com.ai.langgraph4j.example02; import dev.langchain4j.agent.tool.P; import dev.langchain4j.agent.tool.Tool; import org.springframework.stereotype.Component; import static java.lang.String.format; @Component public class TestTool { @Tool("tool for test AI agent executor") String execTest(@P("test message") String message) { return format( "test tool ('%s') executed with result 'OK'", message); } @Tool("return current number of system thread allocated by application") int threadCount() { return Thread.getAllStackTraces().size(); } } 

GreeterNodeAgent:

package com.ai.langgraph4j.example02; import org.bsc.langgraph4j.action.NodeAction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Map; @Component public class GreeterNodeAgent implements NodeAction<SimpleState> { @Autowired private TestTool testTool; @Override public Map<String, Object> apply(SimpleState simpleState) throws Exception { System.out.println("GreeterNode 执行了. Current messages: " + simpleState.messages()); testTool.execTest(simpleState.messages().getFirst()); //GreeterNode 会添加一条 “Hello” 消息 return Map.of(SimpleState.MESSAGES_KEY, "Hello from GreeterNode!"); } } 

ResponderNodeAgent:

package com.ai.langgraph4j.example02; import org.bsc.langgraph4j.action.NodeAction; import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; @Component public class ResponderNodeAgent implements NodeAction<SimpleState> { @Override public Map<String, Object> apply(SimpleState simpleState) throws Exception { System.out.println("ResponderNode 执行了. Current messages: " + simpleState.messages()); List<String> currentMessages = simpleState.messages(); if (currentMessages.contains("Hello from GreeterNode!")) { //ResponderNode 会检查问候语并添加一条确认消息 return Map.of(SimpleState.MESSAGES_KEY, "Acknowledged greeting!"); } return Map.of(SimpleState.MESSAGES_KEY, "No greeting found."); } } 
package com.ai.langgraph4j.example02; import org.bsc.langgraph4j.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import static org.bsc.langgraph4j.GraphDefinition.END; import static org.bsc.langgraph4j.GraphDefinition.START; import static org.bsc.langgraph4j.action.AsyncNodeAction.node_async; import org.bsc.langgraph4j.GraphStateException; import org.bsc.langgraph4j.StateGraph; @Configuration public class LG4jConfiguration { @Autowired private GreeterNodeAgent greeterNodeAgent; @Autowired private ResponderNodeAgent responderNodeAgent; @Bean("helloGraph") public StateGraph<SimpleState> buildhelloGraph( GreeterNodeAgent greeterNode, ResponderNodeAgent responderNode ) throws GraphStateException { return new StateGraph<>( SimpleState.SCHEMA, initData -> new SimpleState(initData)) .addNode("greeter", node_async(greeterNode)) .addNode("responder", node_async(responderNode)) // Define edges .addEdge(START, "greeter") // Start with the greeter node .addEdge("greeter", "responder") .addEdge("responder", END) ; } // 创建可运行的 CompiledGraph @Bean("hellocompiledGraphGraph") public CompiledGraph<SimpleState> buildcompiledGraphhelloGraph( ) throws GraphStateException { return new StateGraph<>( SimpleState.SCHEMA, initData -> new SimpleState(initData)) .addNode("greeter", node_async(greeterNodeAgent)) .addNode("responder", node_async(responderNodeAgent)) // Define edges .addEdge(START, "greeter") // Start with the greeter node .addEdge("greeter", "responder") .addEdge("responder", END) .compile() ; } } 

Langgraph4jController:

package com.ai.langgraph4j.example02; import org.bsc.langgraph4j.CompiledGraph; import org.bsc.langgraph4j.GraphStateException; import org.bsc.langgraph4j.StateGraph; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Map; @RestController @RequestMapping(value = "/langgraph4jController") public class Langgraph4jController { @Autowired @Qualifier("helloGraph") private StateGraph<SimpleState> stateGraph; @Autowired @Qualifier("hellocompiledGraphGraph") private CompiledGraph<SimpleState> compiledGraph; //执行 Graph 时,需要状态对象(state) 来在节点间传递上下文数据。这个状态可能是一个键值映射(Map<String, Object>) @RequestMapping("/buildstateGraph") public String buildstateGraph(String message) throws GraphStateException { // 创建+ 运行 var items = stateGraph.compile().stream(Map.of(SimpleState.MESSAGES_KEY, message)); for (var item : items) { System.out.println(item); } return items.stream().toString(); } @RequestMapping("/buildcompiledGraph") public String buildcompiledGraph(String message) throws GraphStateException { // 运行 var items = compiledGraph.stream(Map.of(SimpleState.MESSAGES_KEY, message)); for (var item : items) { System.out.println(item); } var finalState = compiledGraph.invoke(Map.of(SimpleState.MESSAGES_KEY, "开始执行图")); System.out.println("------invoke result = " + finalState); return items.stream().toString(); } } 

执行:

日志内容:

GreeterNode 执行了. Current messages: [图执行开始了]

NodeOutput{node=__START__, state={

messages=[

图执行开始了

]

}}

ResponderNode 执行了. Current messages: [图执行开始了, Hello from GreeterNode!]

NodeOutput{node=greeter, state={

messages=[

图执行开始了

Hello from GreeterNode!

]

}}

NodeOutput{node=responder, state={

messages=[

图执行开始了

Hello from GreeterNode!

Acknowledged greeting!

]

}}

NodeOutput{node=__END__, state={

messages=[

图执行开始了

Hello from GreeterNode!

Acknowledged greeting!

]

}}

注意: 日志内容表示,某个node节点执行后,当时上下文的内容是存储在state结构中的

如果想让controller返回具体内容,可以修改controller返回内容:

// 运行 var items = compiledGraph.stream(Map.of("messages", userMessage)); StringBuilder sb = new StringBuilder(); for (var item : items) { System.out.println(item); sb.append(item.toString()); } return sb.toString();

执行结果:

Read more

基于西门子S7-1200FC PLC与松下机器人Profinet通信实现机器人外部自动控制应用

⒈训练主题 通过西门子S7-1200 PLC与松下机器人Profinet通信实现机器人的外部自动化控制,应用中程序的调配采用二进制方式,同时PLC需要采集机器人安全作业原点(Home点),保证机器人安全作业,通过PLC的编程调试和机器人的配置实现上述功能。 ⒉软硬件配置 ⑴硬件配置 ①机器人控制系统:TM1800G3机器人:YA-1VAR81;机器人连接电缆:TSMWU894LM;电缆单元:TSMWU600;200V/380V变压器:TSMTR010HGG;RT轴焊丝盘架(刚用):TSMYU204;校枪尺:AXU01727T;机器人通信装置(Profinet):TSMYU965,产品实物如下图。 ②西门子PLC:CPU 1214FC DC/DC/RLY,型号:6ES7 214-1HF40-0XB0。 ③按钮:若干。 ④调试电脑1台,注意电脑IP地址在同一个网段(IP:192.168.0.***),子网掩码为:255.255.255.

ComfyUI Manager:AI绘画工作流的智能指挥中心

ComfyUI Manager:AI绘画工作流的智能指挥中心 【免费下载链接】ComfyUI-Manager 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-Manager 在数字艺术创作的海洋中,ComfyUI Manager犹如一艘精密的指挥舰,为AI绘画爱好者们提供全方位的插件与模型管理解决方案。这个强大的工具不仅简化了工作流程,更让创意表达变得更加自由流畅。 快速上手:构建你的数字画室 开始使用ComfyUI Manager的第一步是将其部署到你的工作环境中。通过以下命令,你可以轻松获取这个强大的管理工具: cd custom_nodes && git clone https://gitcode.com/gh_mirrors/co/ComfyUI-Manager comfyui-manager 部署完成后,重启ComfyUI应用程序,你将在界面中发现全新的"Manager"入口,这正是通往高效创作世界的大门。 核心功能深度解析 插件生态系统的智能调度

Nunchaku FLUX.1 CustomV3:让AI绘画变得简单又高效

Nunchaku FLUX.1 CustomV3:让AI绘画变得简单又高效 你是不是也遇到过这些情况: 想用AI画一张海报,结果调了半小时参数,生成的图不是手多一只,就是背景糊成一团; 下载了一个新模型,光是装依赖、配环境就折腾一整天,最后连界面都没打开; 看到别人发的精美插画心痒痒,可翻遍教程还是搞不清“CLIP”“LoRA”“CFG scale”到底在哪儿改、怎么调…… 别急——这次不用折腾。Nunchaku FLUX.1 CustomV3 镜像,就是为“不想研究原理,只想马上出图”的你准备的。 它不是又一个需要手动拼接节点、反复调试权重的复杂工作流,而是一套开箱即用、单卡RTX4090就能跑、改两行文字就能出高质量图的文生图方案。背后融合了 FLUX.1-dev 的强生成能力、FLUX.1-Turbo-Alpha 的响应速度,以及 Ghibsky Illustration LoRA 的细腻画风加持—

AI绘画创业第一步:Stable Diffusion 3.5低成本验证方案

AI绘画创业第一步:Stable Diffusion 3.5低成本验证方案 你是不是也经常刷到别人用AI画出精美插画、定制头像、甚至接单赚钱?看着心动,但又怕买设备、学软件、投钱打水漂?别担心,作为一个从零开始摸索过来的自由职业者,我完全理解你的顾虑。 今天我要分享的,是一套专为自由职业者设计的AI绘画副业启动方案——利用 Stable Diffusion 3.5(SD 3.5) 和云端GPU资源,实现“零硬件投入、低时间成本、快速出图变现”的可行性验证路径。整个过程不需要你懂编程,也不用买显卡,只要会打字、会上网,就能在几个小时内跑通全流程。 为什么选 SD 3.5?因为它不仅是目前开源图像生成模型中的“顶流”,还特别适合商业应用:支持更高分辨率、细节更精细、文字渲染能力更强,而且对提示词(prompt)的理解更加自然。更重要的是,