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>免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! 懂技术并乐意极积无私分享的人越来越少。珍惜 感谢发布原创作品,程序园因你更精彩 感谢分享,学习下。 谢谢楼主提供! 懂技术并乐意极积无私分享的人越来越少。珍惜 收藏一下 不知道什么时候能用到 感谢分享,下载保存了,貌似很强大 不错,里面软件多更新就更好了 谢谢分享,试用一下 这个好,看起来很实用 这个有用。 鼓励转贴优秀软件安全工具和文档! 新版吗?好像是停更了吧。 鼓励转贴优秀软件安全工具和文档! 感谢分享,下载保存了,貌似很强大 感谢分享,学习下。 鼓励转贴优秀软件安全工具和文档! 过来提前占个楼
页:
[1]