(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
英文地址,請注明出處:http://en.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. 實際應用場景…