秦晓曼 发表于 2026-2-1 01:05:04

Agent设计模式学习(基于langchain4j实现)(10) - ReACT

<p>这次我们不再讨论前文的招聘场景,而是学习一种更为广泛使用的Agent模式:<strong>ReACT</strong> (推理+行动)。先来看示意图:</p>
<p></p>
<p>这跟人类解决问题的思考方式很像:<strong>loop(思考-行动)</strong>。当我们遇到一系列问题时,通常先思考,逐个想方案(plan),然后执行(action),解决1个后(解决过程中,可能会借助工具),再来解决下1个,直到所有问题都处理完。</p>
<p> </p>
<p>定义ReAct Agent</p>


1 public interface ReActAssistant {
2   @SystemMessage("""
3             你是一个使用ReAct(Reasoning and Acting)模式的智能助手。
4             请按照以下步骤思考:
5             1. 理解用户的问题
6             2. 思考解决问题需要什么信息
7             3. 如果需要计算或查询,选择合适的工具
8             4. 使用工具获取结果
9             5. 基于结果给出最终答案
10            
11             请用中文思考和回答。
12             当使用工具时,明确说明你要使用的工具。
13             """)
14   @UserMessage("问:{{request}}")
15   @Agent("基于用户提供的问题进行思考和回答")
16   String chat(@V("request") String request);
17
18 }

ReActAssistant
<p>没错,就是这么简单,提示词里写清楚要求就行。</p>
<p> </p>
<p>ReAct 使用示例</p>


1 @SpringBootApplication
2 public class ReActAgentApplication {
3
4   public static void main(String[] args) throws IOException {
5         ConfigurableApplicationContext context = SpringApplication.run(AgentDesignPatternApplication.class, args);
6         ChatModel model = context.getBean("ollamaChatModel", ChatModel.class);
7         SampleTools sampleTools = context.getBean("sampleTools", SampleTools.class);
8
9         ReActAssistant agent = AgenticServices
10               .agentBuilder(ReActAssistant.class)
11               .chatModel(model)
12               .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(15))
13               .tools(sampleTools)
14               .build();
15
16
17         String[] testQueries = {
18               "计算 15 加上 27 等于多少?",
19               "北京现在的天气怎么样?",
20               "计算半径为5的圆的面积",
21               "现在是几点?",
22               "计算长方体的体积,长10,宽5,高3",
23               "帮我算一下 (25 × 4) ÷ 2 等于多少?",
24               "快递单123456,现在到哪了?",
25               "我的订单56789,退款到账了没?"
26         };
27
28         for (String query : testQueries) {
29             System.out.println("问: " + query);
30             try {
31               String response = agent.chat(query);
32               System.out.println("答: " + response);
33               System.out.println("-".repeat(50));
34               // 避免请求过快
35               Thread.sleep(1000);
36             } catch (Exception e) {
37               System.err.println("查询失败: " + e.getMessage());
38             }
39         }
40
41   }
42 }

ReActAgentApplication
<p>这里面的很多问题,需要用到工具,工具示例如下:</p>


1 /**
2* @author junmingyang
3*/
4 @Component("sampleTools")
5 public class SampleTools {
6
7   @Tool("计算两个数的加法运算")
8   public String add(double a, double b) {
9         double result = a + b;
10         System.out.printf("[工具调用] 加法: %.2f + %.2f = %.2f\n", a, b, result);
11         return String.format("%.2f + %.2f = %.2f", a, b, result);
12   }
13
14   @Tool("计算两个数的减法运算")
15   public String subtract(double a, double b) {
16         double result = a - b;
17         System.out.printf("[工具调用] 减法: %.2f - %.2f = %.2f\n", a, b, result);
18         return String.format("%.2f - %.2f = %.2f", a, b, result);
19   }
20
21   @Tool("计算两个数的乘法运算")
22   public String multiply(double a, double b) {
23         double result = a * b;
24         System.out.printf("[工具调用] 乘法: %.2f × %.2f = %.2f\n", a, b, result);
25         return String.format("%.2f × %.2f = %.2f", a, b, result);
26   }
27
28   @Tool("计算两个数的除法运算")
29   public String divide(double a, double b) {
30         if (b == 0) {
31             return "错误:除数不能为零";
32         }
33         double result = a / b;
34         System.out.printf("[工具调用] 除法: %.2f ÷ %.2f = %.2f\n", a, b, result);
35         return String.format("%.2f ÷ %.2f = %.2f", a, b, result);
36   }
37
38   @Tool("获取当前日期和时间")
39   public String getCurrentDateTime() {
40         String datetime = LocalDateTime.now().format(
41               DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
42         );
43         System.out.println("[工具调用] 当前时间: " + datetime);
44         return datetime;
45   }
46
47   @Tool("查询指定城市的天气信息")
48   public String getWeather(String city) {
49         System.out.println("[工具调用] 查询天气: " + city);
50         // 这里可以集成真实的天气API
51         return String.format("%s的天气:晴转多云,温度22-28°C,湿度65%%,东南风2级", city);
52   }
53
54   @Tool("计算圆的面积")
55   public String calculateCircleArea(double radius) {
56         double area = Math.PI * radius * radius;
57         System.out.printf("[工具调用] 圆面积计算: 半径=%.2f, 面积=%.2f\n", radius, area);
58         return String.format("半径为 %.2f 的圆的面积是 %.2f", radius, area);
59   }
60
61   @Tool("查询快递单")
62   public String queryExpressOrder(String expressOrderNo) {
63         System.out.printf("[工具调用] 快递单: %s,已经在运输途中,预订明天送达\n",
64               expressOrderNo);
65         return String.format("[工具调用] 快递单: %s,已经在运输途中,预订明天送达\n",
66               expressOrderNo);
67   }
68
69   @Tool("查询退款进度")
70   public String queryRefundProgress(String orderNo) {
71         System.out.printf("[工具调用] 订单: %s,退款已审批通过,预计1-3个工作日按原路退回\n",
72               orderNo);
73         return String.format("[工具调用] 订单: %s,退款已审批通过,预计1-3个工作日按原路退回\n",
74               orderNo);
75   }
76 }

SampleTools
<p> </p>
<p>运行效果</p>


1 问: 计算 15 加上 27 等于多少?
2 [工具调用] 加法: 15.00 + 27.00 = 42.00
3 答: 计算结果是:15 + 27 = 42。
4 --------------------------------------------------
5 问: 北京现在的天气怎么样?
6 [工具调用] 查询天气: 北京
7 答: 北京当前的天气情况是:
8 - 天气状况:晴转多云
9 - 温度:22-28°C
10 - 湿度:65%
11 - 风力:东南风2级
12
13 总体来说天气比较舒适,适合户外活动。
14 --------------------------------------------------
15 问: 计算半径为5的圆的面积
16 [工具调用] 圆面积计算: 半径=5.00, 面积=78.54
17 答: 半径为5的圆的面积是 **78.54**(平方单位)。
18
19 圆的面积计算公式为:π × 半径² = π × 5² = π × 25 ≈ 78.54
20 --------------------------------------------------
21 问: 现在是几点?
22 [工具调用] 当前时间: 2026-01-31 19:47:39
23 答: 现在的时间是:2026年1月31日 19:47:39
24 --------------------------------------------------
25 问: 计算长方体的体积,长10,宽5,高3
26 [工具调用] 乘法: 10.00 × 5.00 = 50.00
27 [工具调用] 乘法: 50.00 × 3.00 = 150.00
28 答: 长方体的体积是 **150**(立方单位)。
29
30 长方体体积计算公式:长 × 宽 × 高 = 10 × 5 × 3 = 150
31 --------------------------------------------------
32 问: 帮我算一下 (25 × 4) ÷ 2 等于多少?
33 [工具调用] 乘法: 25.00 × 4.00 = 100.00
34 [工具调用] 除法: 100.00 ÷ 2.00 = 50.00
35 答: (25 × 4) ÷ 2 = **50**
36
37 计算过程:
38 - 25 × 4 = 100
39 - 100 ÷ 2 = 50
40 --------------------------------------------------
41 问: 快递单123456,现在到哪了?
42 [工具调用] 快递单: 123456,已经在运输途中,预订明天送达
43 答: 您的快递单123456目前状态:
44 - **物流状态**:已经在运输途中
45 - **预计送达时间**:明天送达
46
47 快递正在正常运输中,请耐心等待。
48 --------------------------------------------------
49 问: 我的订单56789,退款到账了没?
50 [工具调用] 订单: 56789,退款已审批通过,预计1-3个工作日按原路退回
51 答: 您的订单56789退款状态:
52 - **退款状态**:退款已审批通过
53 - **预计到账时间**:1-3个工作日内按原路退回
54
55 退款申请已经通过审核,资金将在1-3个工作日内原路返回到您的支付账户,请注意查收。
56 --------------------------------------------------

View Code
<p>为了让结果看上去更简洁,把跟LLM交互的request与response去掉了。 如果对【LLM生成的计划】以及【如何选择工具】感兴趣,可以观察下request/response日志,以最后1个问题为例,请求参数为:</p>


1 {
2   "model": "minimax-m2:cloud",
3   "messages": [
4   {
5       "role": "system",
6       "content": "你是一个使用ReAct(Reasoning and Acting)模式的智能助手。\n请按照以下步骤思考:\n1. 理解用户的问题\n2. 思考解决问题需要什么信息\n3. 如果需要计算或查询,选择合适的工具\n4. 使用工具获取结果\n5. 基于结果给出最终答案\n\n请用中文思考和回答。\n当使用工具时,明确说明你要使用的工具。\n"
7   },
8   {
9       "role": "assistant",
10       "tool_calls": [
11         {
12         "function": {
13             "name": "multiply",
14             "arguments": {
15               "a": 50,
16               "b": 3
17             }
18         }
19         }
20       ]
21   },
22   {
23       "role": "tool",
24       "content": "50.00 × 3.00 = 150.00"
25   },
26   {
27       "role": "assistant",
28       "content": "长方体的体积是 **150** 立方单位。\n\n计算过程:\n- 长方体体积 = 长 × 宽 × 高\n- 10 × 5 × 3 = 150\n\n所以这个长方体的体积为150立方单位。",
29       "tool_calls": []
30   },
31   {
32       "role": "user",
33       "content": "问:帮我算一下 (25 × 4) ÷ 2 等于多少?"
34   },
35   {
36       "role": "assistant",
37       "content": "我来为您计算 (25 × 4) ÷ 2。",
38       "tool_calls": [
39         {
40         "function": {
41             "name": "multiply",
42             "arguments": {
43               "a": 25,
44               "b": 4
45             }
46         }
47         }
48       ]
49   },
50   {
51       "role": "tool",
52       "content": "25.00 × 4.00 = 100.00"
53   },
54   {
55       "role": "assistant",
56       "tool_calls": [
57         {
58         "function": {
59             "name": "divide",
60             "arguments": {
61               "a": 100,
62               "b": 2
63             }
64         }
65         }
66       ]
67   },
68   {
69       "role": "tool",
70       "content": "100.00 ÷ 2.00 = 50.00"
71   },
72   {
73       "role": "assistant",
74       "content": "(25 × 4) ÷ 2 = **50**\n\n计算过程:\n- 先算 25 × 4 = 100\n- 再算 100 ÷ 2 = 50\n\n所以答案是 50。",
75       "tool_calls": []
76   },
77   {
78       "role": "user",
79       "content": "问:快递单123456,现在到哪了?"
80   },
81   {
82       "role": "assistant",
83       "content": "我来帮您查询快递单123456的状态。",
84       "tool_calls": [
85         {
86         "function": {
87             "name": "queryExpressOrder",
88             "arguments": {
89               "expressOrderNo": "123456"
90             }
91         }
92         }
93       ]
94   },
95   {
96       "role": "tool",
97       "content": "[工具调用] 快递单: 123456,已经在运输途中,预订明天送达\n"
98   },
99   {
100       "role": "assistant",
101       "content": "您的快递单123456目前状态:**已经在运输途中**,预计**明天送达**。\n\n快递正在正常运输中,请耐心等待。",
102       "tool_calls": []
103   },
104   {
105       "role": "user",
106       "content": "问:我的订单56789,退款到账了没?"
107   }
108   ],
109   "options": {
110   "stop": []
111   },
112   "stream": false,
113   "tools": [
114   {
115       "type": "function",
116       "function": {
117         "name": "getWeather",
118         "description": "查询指定城市的天气信息",
119         "parameters": {
120         "type": "object",
121         "properties": {
122             "city": {
123               "type": "string"
124             }
125         },
126         "required": [
127             "city"
128         ]
129         }
130       }
131   },
132   {
133       "type": "function",
134       "function": {
135         "name": "queryExpressOrder",
136         "description": "查询快递单",
137         "parameters": {
138         "type": "object",
139         "properties": {
140             "expressOrderNo": {
141               "type": "string"
142             }
143         },
144         "required": [
145             "expressOrderNo"
146         ]
147         }
148       }
149   },
150   {
151       "type": "function",
152       "function": {
153         "name": "queryRefundProgress",
154         "description": "查询退款进度",
155         "parameters": {
156         "type": "object",
157         "properties": {
158             "orderNo": {
159               "type": "string"
160             }
161         },
162         "required": [
163             "orderNo"
164         ]
165         }
166       }
167   },
168   {
169       "type": "function",
170       "function": {
171         "name": "calculateCircleArea",
172         "description": "计算圆的面积",
173         "parameters": {
174         "type": "object",
175         "properties": {
176             "radius": {
177               "type": "number"
178             }
179         },
180         "required": [
181             "radius"
182         ]
183         }
184       }
185   },
186   {
187       "type": "function",
188       "function": {
189         "name": "getCurrentDateTime",
190         "description": "获取当前日期和时间"
191       }
192   },
193   {
194       "type": "function",
195       "function": {
196         "name": "add",
197         "description": "计算两个数的加法运算",
198         "parameters": {
199         "type": "object",
200         "properties": {
201             "a": {
202               "type": "number"
203             },
204             "b": {
205               "type": "number"
206             }
207         },
208         "required": [
209             "a",
210             "b"
211         ]
212         }
213       }
214   },
215   {
216       "type": "function",
217       "function": {
218         "name": "multiply",
219         "description": "计算两个数的乘法运算",
220         "parameters": {
221         "type": "object",
222         "properties": {
223             "a": {
224               "type": "number"
225             },
226             "b": {
227               "type": "number"
228             }
229         },
230         "required": [
231             "a",
232             "b"
233         ]
234         }
235       }
236   },
237   {
238       "type": "function",
239       "function": {
240         "name": "subtract",
241         "description": "计算两个数的减法运算",
242         "parameters": {
243         "type": "object",
244         "properties": {
245             "a": {
246               "type": "number"
247             },
248             "b": {
249               "type": "number"
250             }
251         },
252         "required": [
253             "a",
254             "b"
255         ]
256         }
257       }
258   },
259   {
260       "type": "function",
261       "function": {
262         "name": "divide",
263         "description": "计算两个数的除法运算",
264         "parameters": {
265         "type": "object",
266         "properties": {
267             "a": {
268               "type": "number"
269             },
270             "b": {
271               "type": "number"
272             }
273         },
274         "required": [
275             "a",
276             "b"
277         ]
278         }
279       }
280   }
281   ]
282 }

最后1个问题-查退款进度-请求LLM
<p>可以看到,走到最后1个问题时(106行),除了所有可用的工具之外(113-281行),前面所有问题及答案(8-103行),也一并发给LLM了,所以LLM看上去才有记忆!</p>
<p><strong>LLM的响应</strong>:</p>


1 {
2   "model": "minimax-m2:cloud",
3   "remote_model": "minimax-m2",
4   "remote_host": "https://ollama.com:443",
5   "created_at": "2026-01-31T11:52:21.93218197Z",
6   "message": {
7   "role": "assistant",
8   "content": "我来帮您查询订单56789的退款进度。",
9   "thinking": "用户询问订单56789的退款进度,我需要使用queryRefundProgress工具来查询这个订单号的退款情况。",
10   "tool_calls": [
11       {
12         "id": "call_dmgzch57",
13         "function": {
14         "index": 0,
15         "name": "queryRefundProgress",
16         "arguments": {
17             "orderNo": "56789"
18         }
19         }
20       }
21   ]
22   },
23   "done": true,
24   "done_reason": "stop",
25   "total_duration": 816309591,
26   "prompt_eval_count": 1023,
27   "eval_count": 63
28 }

查退款进度-LLM响应
<p>从这里看出,LLM选中了工具 queryRefundProgress(第9行)</p>
<p> </p>
<p>时序图</p>
<p></p>
<p> </p>
<p>文中示例代码:</p>
<p>https://github.com/yjmyzz/agentic_turoial_with_langchain4j<br></p>
<p> </p>
<p>参考:</p>
<p>Building Effective AI Agents \ Anthropic</p>
<p>[译] AI Workflow & AI Agent:架构、模式与工程建议(Anthropic,2024)</p>
<p>Agents and Agentic AI | LangChain4j</p><br>来源:程序园用户自行投稿发布,如果侵权,请联系站长删除<br>免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

锑砖 发表于 2026-2-3 07:39:03

懂技术并乐意极积无私分享的人越来越少。珍惜

申倩语 发表于 2026-2-5 07:43:28

感谢发布原创作品,程序园因你更精彩

齐娅晶 发表于 2026-2-5 11:41:36

感谢分享,学习下。

遇玷 发表于 2026-2-6 12:31:52

谢谢楼主提供!

劳暄美 发表于 2026-2-8 09:23:38

懂技术并乐意极积无私分享的人越来越少。珍惜

背竽 发表于 2026-2-8 16:50:32

收藏一下   不知道什么时候能用到

利怡悦 发表于 2026-2-9 10:02:09

感谢分享,下载保存了,貌似很强大

蚬蕞遂 发表于 2026-2-9 10:09:27

不错,里面软件多更新就更好了

眩疝诺 发表于 2026-2-9 13:21:22

谢谢分享,试用一下

磁呃泵 发表于 2026-2-10 22:41:21

这个好,看起来很实用

度阡舅 发表于 2026-2-10 23:40:56

这个有用。

章娅萝 发表于 2026-2-12 05:03:53

鼓励转贴优秀软件安全工具和文档!

贼瘁 发表于 2026-2-12 06:30:07

新版吗?好像是停更了吧。

季卓然 发表于 2026-2-13 13:04:50

鼓励转贴优秀软件安全工具和文档!

夔新梅 发表于 2026-2-13 15:43:58

感谢分享,下载保存了,貌似很强大

全愉婉 发表于 2026-2-13 21:53:58

感谢分享,学习下。

赖秀竹 发表于 7 天前

鼓励转贴优秀软件安全工具和文档!

肇默步 发表于 昨天 22:27

过来提前占个楼
页: [1]
查看完整版本: Agent设计模式学习(基于langchain4j实现)(10) - ReACT