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

AI时代人人都是产品经理:落地流程:AI 核心功能,从需求到上线的全流程管控方法

AI时代人人都是产品经理:落地流程:AI 核心功能,从需求到上线的全流程管控方法

AI的普及正在重构产品经理的工作模式——不再依赖传统的跨部门协作瓶颈,AI可以成为产品经理的"全职助手",覆盖需求分析、原型设计、开发协同、测试验证全流程。本文将拆解AI时代产品核心功能从0到1落地的完整管控方法,让你用AI能力提升300%的落地效率。 一、需求阶段:AI辅助的需求挖掘与标准化 需求是产品的起点,AI可以帮你从海量信息中精准定位用户真实需求,避免"伪需求"浪费资源。 1. 需求挖掘:AI辅助用户洞察 传统需求调研依赖问卷、访谈,效率低且样本有限。AI可以通过以下方式快速完成用户洞察: * 结构化处理非结构化数据:用AI分析用户在社交媒体、客服对话、应用评论中的碎片化反馈,自动提炼高频需求点 * 需求优先级排序:基于KANO模型,AI可以自动将需求划分为基础型、期望型、兴奋型、无差异型四类,输出优先级列表 实战工具与示例: 使用GPT-4+Python脚本批量处理应用商店评论: import openai import pandas as

【软件测试】AI 赋能测试流程

【软件测试】AI 赋能测试流程

AI 赋能测试流程 * 一. AI 基础概念 * 1. AI 是什么? * 2. AI 为什么会被创造出来? * 3. AI 是如何被创造出来的? * 二. AI 赋能测试 * 1. AI 在测试领域的应用 * 2. AI 在测试领域的发展趋势 * 三. AI 驱动的测试流程 * 1. AI 工具介绍 * 2. 需求分析 * 2.1 识别需求中存在的问题 * 2.2 需求快速理解与功能概要生成 * 3. 测试计划 * 4. 测试用例 * 4.1 AI 生成等价类 * 4.2 AI 生成边界值 * 4.

OpenClaw 实战:5 分钟用 AI Agent 自动生成规范测试用例并写入 Excel

OpenClaw 实战:5 分钟用 AI Agent 自动生成规范测试用例并写入 Excel

OpenClaw 实战:5 分钟用 AI Agent 自动生成规范测试用例并写入 Excel 一、核心前提 OpenClaw 是轻量级 Agent 框架,核心聚焦: Skill 注册 → 工具选择 → 任务执行 * 没有 Dify 的可视化界面 * 没有知识库、没有复杂工作流 * 代码极简洁、上手极快 * 适合:测试开发 / 有编程能力的测试工程师 一句话定位: OpenClaw = 极简、轻量、只专注做工具调用的小 Agent 引擎 二、环境准备 1. 安装 OpenClaw 及依赖 # 安装 OpenClaw 核心框架 pip install openclaw # Excel 操作

用Python打造AI三剑客:自动总结+写代码+查资料的完整指南

用Python打造AI三剑客:自动总结+写代码+查资料的完整指南

欢迎文末添加好友交流,共同进步! “ 俺はモンキー・D・ルフィ。海贼王になる男だ!” * 前言 * 目录 * 一、准备工作:环境与API配置 * 1.1 技术栈选择 * 1.2 环境配置 * 1.3 核心工具类封装 * 二、工具一:智能文档总结器 * 2.1 功能设计 * 2.2 核心代码实现 * 2.3 使用效果对比 * 三、工具二:AI代码生成器 * 3.1 功能架构 * 3.2 核心实现 * 交互式代码生成器 * 使用示例 * 4.2 核心代码 * 4.3 搜索效率对比 * 五、