(5)LangGraph4j框架ReActAgent实现

LangGraph4j框架ReActAgent实现

ReAct-Agent概念

ReAct-Agent 是一种大模型应用中的智能体架构。ReAct 是 Re (Reasoning,推理)和 Act(Action,行动)两个单词的简写,用通俗的话来说,它可以让大模型像人一样“思考”和“行动”,实现更强的任务处理能力。这里把它拆解为两个关键部分来说明:

Re(Reasoning,推理)

大模型通过“推理”步骤来理解任务或者问题。就像你面对一个复杂的问题时,先分析现状、列出条件,然后在脑海中一步步推导出答案一样,ReAct 中的“推理”部分会利用模型的语言理解能力,生成逻辑清晰的分析路径。

Act(Action,行动)

仅仅推理还不够,智能体还需要“行动”,也就是执行特定的操作。比如:

  • 通过调用某个工具(例如计算器、数据库查询、外部api接口)来获取信息或解决问题。
  • 根据现有信息做出决定并采取下一步行动。

在 ReAct 框架中,“行动”这一步和“推理”紧密结合。模型不会一次性给出答案,而是以“边想边做”的方式,循环地进行推理和行动,直到完成任务。

实际运作流程

  1. 模型先“想”一想:分析问题,给出可能需要的步骤。
  2. 模型再“做”一做:如果需要,它可以去查外部信息、调用工具,或者生成一个具体操作。
  3. 根据结果再“想” :拿到行动的反馈后,重新推理,调整步骤,直到问题解决。

ReAct 的特点

  • 动态灵活:不像传统模型“一问一答”,ReAct 模型会动态地调整策略。
  • 能调用外部工具:通过执行操作(例如数据库查询或API调用),可以解决大模型本身无法直接处理的问题。
  • 更接近人类思维:这种“想一步,做一步”的方式更像人类解决复杂问题的过程。

通俗来说,ReAct 就是让模型“像人一样,先动脑后动手,再动脑接着手”,在不断循环中完成任务。

LangGraph4j 中的 ReAct-Agent

ReactAgent 接口提供了构建和运行状态图(StateGraph)的功能。它包含两个主要内部类:CallAgent 和 ExecuteTools,分别用于调用 AI 模型生成响应和执行工具请求。

整个流程体现了典型的 ReAct 模式:

  • Reasoning (推理): CallAgent 生成思考并决定是否调用工具。
  • Action (动作): ExecuteTools 执行具体工具操作。
  • 循环直到获得最终答案(final_response)为止。

状态图设计

  • 使用 StateGraph 定义执行流程:

    • 起始节点为 START → reasoning

    • reasoning根据是否需要调用工具 (shouldContinue) 决定下一步:

      • “continue” → action
      • “end” → END
    • action 节点执行完工具后再次回到 reasoning

new StateGraph<>(State.SCHEMA, stateSerializer).addNode("reasoning", node_async(callAgent)).addNode("action", node_async(executeTools))	.addEdge(START, "reasoning").addConditionalEdges("reasoning",edge_async(shouldContinue),Map.of("continue", "action", "end", END)).addEdge("action", "reasoning");

在这里插入图片描述

CallAgent

  • 负责调用 LangChain4J 的聊天模型或流式聊天模型来生成 AI 响应。

  • 根据是否启用流式输出选择不同的执行策略:

    • 非流式模式直接调用 ChatModel.execute() 获取完整响应。
    • 流式模式使用 StreamingChatModel.chat() 并结合 StreamingChatGenerator 来处理逐步生成的结果。
  • 将响应结果映射为结构化格式,支持两种情况:

    • 如果需要执行工具,则返回 messages 字段表示待执行的工具调用。
    • 如果任务完成,则返回 final_response 表示最终答案。
/*** CallAgent 是一个 NodeAction 实现类,用于调用 Agent 模型生成响应。* 可以根据是否开启流式输出选择不同的执行策略。*/
class CallAgent implements NodeAction<State> {private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CallAgent.class);final Agent agent;/*** 使用指定的代理构造 CallAgent。** @param agent 关联到此 CallAgent 的代理*/public CallAgent(Agent agent) {this.agent = agent;}/*** 将来自AI消息的响应结果映射为结构化格式。** @param response 包含AI消息的响应* @return 包含代理结果的Map* @throws IllegalStateException 如果响应的结束原因是不支持的*/private Map<String,Object> mapResult(ChatResponse response )  {var content = response.aiMessage();if (response.finishReason() == FinishReason.TOOL_EXECUTION || content.hasToolExecutionRequests() ) {return Map.of("messages", content);}if( response.finishReason() == FinishReason.STOP || response.finishReason() == null  ) {return Map.of(FINAL_RESPONSE, content.text());}throw new IllegalStateException("不支持的结束原因: " + response.finishReason() );}/*** 应用给定状态的动作并返回结果。** @param state 动作应用到的状态* @return 包含代理结果的Map* @throws IllegalArgumentException 如果状态中没有提供输入*/@Overridepublic Map<String,Object> apply(State state )  {log.trace("[ReactAgent] callAgent...");List<ChatMessage> messages = state.messages();if( messages.isEmpty() ) {log.error("[ReactAgent] callAgent result: {}", "没有提供输入!");throw new IllegalArgumentException("没有提供输入!");}if( agent.isStreaming()) {StreamingChatGenerator<State> generator = StreamingChatGenerator.<State>builder().mapResult(this::mapResult).startingNode("agent").startingState(state).build();agent.execute(messages, generator.handler());log.info("[ReactAgent] callAgent result: {}", generator);return Map.of("_generator", generator);}else {var response = agent.execute(messages);log.info("[ReactAgent] callAgent result: {}", response);return mapResult(response);}}
}

ExecuteTools

  • 处理由 AI 生成的工具调用请求。
  • 使用 LangChain4jToolService 执行这些工具,并将结果整合后返回。
  • 如果没有找到工具请求,则返回提示信息。
/*** ExecuteTools 是一个 NodeAction 实现类,负责执行 AI 生成的工具调用请求。* 通常用于处理用户输入后由 Agent 决定调用哪些外部工具的情况。*/
class ExecuteTools implements NodeAction<State> {private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExecuteTools.class);/*** 将要执行的工具服务。*/final LangChain4jToolService toolService;/*** 使用指定的工具映射构造 ExecuteTools 实例。** @param toolMap 要执行的工具映射,不能为空*/public ExecuteTools(Map<ToolSpecification, ToolExecutor> toolMap) {this.toolService = new LangChain4jToolService(toolMap);}/*** 基于提供的代理状态应用工具执行逻辑。** @param state 当前代理执行器的状态* @return 包含执行中间步骤的地图* @throws IllegalArgumentException 如果没有提供代理结果* @throws IllegalStateException 如果找不到要执行的操作或工具*/@Overridepublic Map<String,Object> apply(State state )  {log.trace("[ReactAgent] executeTools..");var toolExecutionRequests = state.lastMessage().filter(m -> ChatMessageType.AI==m.type()).map(m -> (AiMessage)m).filter(AiMessage::hasToolExecutionRequests).map(AiMessage::toolExecutionRequests);if( toolExecutionRequests.isEmpty() ) {log.info("[ReactAgent] executeTools result: {}" , "没有找到工具执行请求!");return Map.of(FINAL_RESPONSE, "没有找到工具执行请求!");}var result = toolExecutionRequests.get().stream().map(toolService::execute).filter(Optional::isPresent).map(Optional::get).toList();log.info("[ReactAgent] executeTools result: {}" , result);return Map.of("messages", result );}
}

ReactAgent构建

public interface ReactAgent {/*** 状态序列化的支持类型。* 支持标准格式(STD)和 JSON 格式(JSON)。*/enum Serializers {STD(new LangChain4jStateSerializer<>(State::new) ),JSON(new LangChain4jJacksonStateSerializer<>(State::new));private final StateSerializer<State> serializer;/*** 使用指定的序列化器构造新的Serializers枚举实例。** @param serializer 状态序列化器*/Serializers(StateSerializer<State> serializer) {this.serializer = serializer;}/*** 获取状态序列化器。** @return 状态序列化器*/public StateSerializer<State> object() {return serializer;}}/*** Builder 类用于构建 Agent 的状态图(StateGraph)。* 包含构建节点、边及条件判断逻辑。*/class Builder extends Agent.Builder<Builder> {private StateSerializer<State> stateSerializer;/*** 设置状态序列化** @param stateSerializer 状态序列化* @return 更新的实例*/public Builder stateSerializer(StateSerializer<State> stateSerializer) {this.stateSerializer = stateSerializer;return this;}/*** 构建状态图(StateGraph)。** @return 构建的 StateGraph* @throws GraphStateException 如果图形状态中存在错误*/@Overridepublic StateGraph<State> build() throws GraphStateException {if (streamingChatModel != null && chatModel != null) {throw new IllegalArgumentException("chatLanguageModel 和 streamingChatLanguageModel 是互斥的!");}if (streamingChatModel == null && chatModel == null) {throw new IllegalArgumentException("需要 chatLanguageModel 或 streamingChatLanguageModel!");}var agent = new Agent(this);if (stateSerializer == null) {stateSerializer = Serializers.STD.object();}final var callAgent = new CallAgent(agent);final var executeTools = new ExecuteTools(toolMap());final EdgeAction<State> shouldContinue = (state) ->state.finalResponse().map(res -> "end").orElse("continue");return new StateGraph<>(State.SCHEMA, stateSerializer).addNode("agent", node_async(callAgent)).addNode("action", node_async(executeTools)).addEdge(START, "agent").addConditionalEdges("agent",edge_async(shouldContinue),Map.of("continue", "action", "end", END)).addEdge("action", "agent");}}/*** 创建一个新的 GraphBuilder 实例。** @return 新的 Builder 实例*/static Builder builder() {return new Builder();}
}

ReactAgent测试验证

1、创建StateGraph和CompiledGraph

@Bean
public StateGraph<State> reactAgent(@Qualifier("chatModel") ChatModel chatModel) throws GraphStateException {return ReactAgent.builder().name("reactAgent智能体").chatModel(chatModel).toolsFromObject(new TestTools()).toolsFromObject(new TavilySearchTool(searchApiKey)).build();
}
@Bean(value = "reactAgentGraph")
public CompiledGraph<State> reactAgentGraph(@Qualifier("reactAgent") StateGraph<State> reactAgent)throws GraphStateException {return reactAgent.compile();
}

2、创建工具类

public class TestTools {@Tool("返回给定城市的天气预报")public String getWeather(@P("应返回天气预报的城市") String city) {return "The weather in " + city + " is sunny with a high of 25 degrees.";}@Tool("求两个数的和")double add(@P(value = "数字",required = true) int a,@P(value = "数字",required = true) int b) {return a + b;}@Tool("求平方根")double squareRoot(@P(value = "数字",required = true) double x) {return Math.sqrt(x);}
}

3、创建接口

@Slf4j
@RestController
@RequestMapping("/react")
public class ReactController {@Resource(name = "reactAgentGraph")private CompiledGraph<State> reactAgentGraph;@GetMapping("/chat")public String simpleChat(@RequestParam("query") String query) {GraphRepresentation graph = reactAgentGraph.getGraph(GraphRepresentation.Type.PLANTUML, "React智能体");log.info("React-Agent PlantUML Graph:\n{}", graph.content());Optional<State> queryResult = reactAgentGraph.invoke(Map.of("messages", UserMessage.from(query)));return queryResult.get().finalResponse().get();}
}

4、执行结果日志:

在这里插入图片描述

[ReactAgent] callAgent result: ChatResponse { aiMessage = AiMessage { text = null toolExecutionRequests = [ToolExecutionRequest { id = "call_e9837fbced09464b8f9490", name = "getWeather", arguments = "{"arg0": "北京"}" }] }, metadata = QwenChatResponseMetadata{id="0b109d6b-5234-9db1-8305-ef5f666f7bbb", modelName="qwen-plus-latest", tokenUsage=TokenUsage { inputTokenCount = 432, outputTokenCount = 20, totalTokenCount = 452 }, finishReason=TOOL_EXECUTION, searchInfo=SearchInfo[searchResults=[]], reasoningContent=null} }
[ReactAgent] executeTools result: [ToolExecutionResultMessage { id = "call_e9837fbced09464b8f9490" toolName = "getWeather" text = "The weather in 北京 is sunny with a high of 25 degrees." }]
[ReactAgent] callAgent result: ChatResponse { aiMessage = AiMessage { text = "北京的天气晴朗,最高气温为25度。" toolExecutionRequests = [] }, metadata = QwenChatResponseMetadata{id="212e9aef-5f02-98d4-8fae-3201c44d02b4", modelName="qwen-plus-latest", tokenUsage=TokenUsage { inputTokenCount = 482, outputTokenCount = 13, totalTokenCount = 495 }, finishReason=STOP, searchInfo=SearchInfo[searchResults=[]], reasoningContent=null} }

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

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

相关文章

近期学习小结

一、TLS&#xff08;Transport Layer Security&#xff09;握手是建立安全通信通道的关键过程&#xff0c;确保客户端与服务器之间的通信加密和身份验证。以下是TLS 1.2和TLS 1.3的握手流程详解及对比&#xff1a;TLS 1.2 握手流程目标&#xff1a;协商加密套件、交换密钥、验证…

maven本地仓库清缓存py脚本

清_remote.repositories、以及 .lastUpdated 缓存文件&#xff0c;避免换仓库or私服的时候一直往旧地方去download从而引起的failtodownlown问题 import os import sysdef delete_maven_metadata_files(directory):"""递归删除指定目录下的 _remote.repositorie…

职坐标:物联网解决方案实战指南

随着物联网技术的快速发展&#xff0c;其在智能家居、工业制造和农业领域的应用日益广泛&#xff0c;为解决实际挑战提供了高效方案。本文将围绕职坐标一站式IT培训就业服务平台推出的实战指南&#xff0c;系统解析物联网解决方案的核心内容。指南首先概述物联网解决方案的基本…

多云环境下的统一安全架构设计

关键词&#xff1a;多云安全、统一架构、零信任、深度防御、身份管理、威胁检测、SIEM、合规性 &#x1f4da; 文章目录 引言&#xff1a;多云时代的安全挑战多云环境面临的安全挑战统一安全架构设计原则核心安全组件架构多层防护体系设计统一身份管理与访问控制安全监控与威…

批量制作Word:如何根据表格数据的内容批量制作word,根据Excel的数据批量制作word文档的步骤和注意事项

企业批量制作员工劳动合同时&#xff0c;用 Excel 整理员工姓名、职位等信息&#xff0c;模板设对应占位符&#xff0c;系统快速填充生成合同&#xff1b;高校生成成绩单&#xff0c;Excel 存学生成绩数据&#xff0c;模板嵌入科目占位符&#xff0c;批量生成准确成绩单&#x…

STM32f103ZET6之ESP8266模块

一、ESP8265概述 官方网址&#xff1a;ESP8266 Wi-Fi MCU I 乐鑫科技 (espressif.com.cn) ESP8266模块---wifi模块 产品特点&#xff1a;ESP8266 是什么&#xff1f; ESP8266 是由乐鑫科技&#xff08;Espressif Systems&#xff09;开发的一款低成本、高性能的 Wi-Fi 微控制器…

前端设计模式应用精析

引言 设计模式是前端工程化架构的基石&#xff0c;通过抽象核心场景解法提升代码复用性与系统可维护性。本文精析 7 个核心模式&#xff0c;结合原生 JavaScript 与框架实践&#xff0c;揭示模式在现代前端架构中的底层映射与应用。1. 观察者模式&#xff08;Observer&#xff…

【机器学习深度学习】Ollama vs vLLM vs LMDeploy:三大本地部署框架深度对比解析

目录 前言 一、为什么要本地部署大语言模型&#xff1f; 二、三大主流部署方案简介 三、核心对比维度详解 1️⃣ 易用性对比 2️⃣ 性能与并发能力 3️⃣ 模型支持与生态兼容性 4️⃣ 部署环境与平台支持 四、一览对比表 五、详细介绍与比较 ✅ 1. Ollama ✅ 2. vL…

AWS ML Specialist 考试备考指南

以下是针对AWS机器学习专家认证(AWS Certified Machine Learning - Specialty)的备考指南精简版,涵盖核心要点和高效备考策略: ‌一、考试核心要点‌ ‌四大核心领域‌: ‌数据准备(28%)‌:S3数据存储、Glue ETL、Feature Store、数据清洗与特征工程。 ‌模型开发(26%…

yolo8+ASR+NLP+TTS(视觉语音助手)

&#x1f9e9; 模块总览&#xff1a;步骤模块作用①麦克风录音&#xff08;VAD支持&#xff09;获取语音并判断是否有人说话②Whisper语音识别把语音内容识别为文字③DeepSeek 聊天接口发送用户提问并获取 AI 回复④edge-tts 朗读回答把 DeepSeek 回答读出来⑤整合成语音助手主…

Zabbix 分布式监控系统架构设计与优化

一、概念 1.核心概念 Zabbix是一个CS(服务端/客户端)架构的服务Zabbix-Agent获取数据-->发送给-->Zabbix-Server服务端--- >数据会被存放在数据库 <--- Zabbix Web 页面展示数据 2.部署流程 部署ngxphp环境并测试部署数据库 mariadb 10.5及以上 然后进行配置编…

QT——文件选择对话框 QFileDialog

QFileDialog概述QFileDialog是Qt框架中提供的文件对话框类&#xff0c;用于让用户选择文件或目录。它提供了标准的文件选择界面&#xff0c;支持文件打开、保存、多选等常见操作。基本使用方式QFileDialog提供了两种使用方式&#xff1a;静态方法&#xff1a;直接调用类方法快速…

Flask+LayUI开发手记(十一):选项集合的数据库扩展类

条目较少的选项集合&#xff0c;确实可以在程序中直接定义&#xff08;其实最合适的还是存储在一个分类别的数据库表里&#xff09;&#xff0c;但条目较多的选项集合&#xff0c;或者是复杂的树型结构选项集合&#xff0c;一般都是存储在数据库中的&#xff0c;这样维护起来比…

AI学习笔记三十二:YOLOv8-CPP-Inference测试(Linux版本)

若该文为原创文章&#xff0c;转载请注明原文出处。主要介绍如何在Linux系统上安装和部署基于YOLOv8的C推理项目一、服务器准备使用AutoDL平台租用服务器AutoDL有git加速&#xff0c;可以自行启用二、环境配件1、检查Opencv版本pkg-config --modversion opencv4如果版本为4.5&a…

113:路径总和 II

题目&#xff1a;给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。叶子节点 是指没有子节点的节点。解答&#xff1a;用 go主要坑有两个&#xff0c;一个是二维结果切片传递用指针&#xff0c;一个…

Perl 数组

Perl 数组 在Perl编程语言中&#xff0c;数组是处理数据的一种强大工具。数组允许我们将多个值存储在单个变量中&#xff0c;从而简化了代码并提高了效率。本文将详细介绍Perl数组的创建、操作、遍历以及一些高级用法。 数组的创建 在Perl中&#xff0c;创建一个数组非常简单。…

优先队列的实现

目录 引言 堆的基本概念与特性 堆的插入与向上调整 堆的删除与向下调整 优先队列的设计思路 模板参数设计 比较器的作用 核心接口实现 push pop top 附录(完整代码) 引言 优先队列&#xff08;Priority Queue&#xff09;是一种特殊的队列数据结构&#xff0c;其中每…

现代CSS实战:用变量与嵌套重构可维护的前端样式

现代CSS实战&#xff1a;用变量与嵌套重构可维护的前端样式 引言 在传统CSS开发中&#xff0c;我们常常陷入「样式冗余」与「维护噩梦」的循环&#xff1a; 想调整主题色&#xff1f;得全局搜索所有 #3498db 手动替换&#xff0c;稍有不慎就漏改某个角落&#xff1b; 写嵌套…

DHTMLX Suite 9.2 重磅发布:支持历史记录、类Excel交互、剪贴板、拖放增强等多项升级

全球知名的 JavaScript UI 组件库 DHTMLX Suite 迎来 9.2 新版本&#xff01;此次更新虽为次版本号&#xff0c;却实质性提升了 Grid 网格组件的交互能力与用户体验&#xff0c;引入了包括历史记录管理、剪贴板操作、数据选择范围管理、Block 区块选择等多项高级模块&#xff0…

深入理解Java中的Map.Entry接口

文章目录深入理解Java中的Map.Entry接口1. 接口定义2. 核心方法解析2.1 基本方法2.2 Java 8新增的静态方法3. 基本使用示例3.1 遍历Map的条目3.2 修改Map中的值3.3 使用比较器排序4. Java 8/9增强特性4.1 与Stream API结合4.2 Java 9的equals和hashCode默认方法5. 实际应用场景…