Skip to content

Commit 76180ed

Browse files
committed
增加文档:[多智能体协同:轻松搞定智能体工具调用](https://esdoc.bbossgroups.com/#/jobflow-deepseek-fuctioncall)
1 parent 584a696 commit 76180ed

File tree

4 files changed

+255
-0
lines changed

4 files changed

+255
-0
lines changed

docs/_sidebar.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- [自定义函数流程任务节点使用介绍](jobflow-customnode.md)
66
- [工作流节点间共享和传递参数使用文档](jobflow-nodeparam.md)
77
- [Deepseek对话工作流使用介绍](jobflow-deepseek.md)
8+
- [多智能体协同:轻松搞定智能体工具调用](jobflow-deepseek-fuctioncall.md)
89
- [MongoDB数据源定义和使用](MongoDBDatasource.md)
910
- **Getting started**
1011
- [Elasticsearch Quick start](quickstart.md)
40.9 KB
Loading
106 KB
Loading
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
# 多智能体协同:轻松搞定智能体工具调用
2+
3+
在上篇文档中介绍了[通过bboss jobflow实现基于Deepseek的多智能体流程排功能](https://esdoc.bbossgroups.com/#/jobflow-deepseek),本文在上文中案例基础上继续扩展流程功能,实现智能体工具调用功能:将用户问题和工具清单发送给 Deepseek,并由 Deepseek 匹配对应工具并提取参数,通过工具调用节点调用工具,最后通过生成查询结果和建议节点调用Deepseek分析工具调用结果数据,生成并输出最终问题答案。
4+
5+
![](images\workflow\jobworkflow-toolcall.png)
6+
7+
完整案例源码地址:
8+
9+
[https://gitee.com/bboss/bboss-datatran-demo/blob/main/src/main/java/org/frameworkset/datatran/imp/jobflow/JobFlow2ndDeepseekTest.java](https://gitee.com/bboss/bboss-datatran-demo/blob/main/src/main/java/org/frameworkset/datatran/imp/jobflow/JobFlow2ndDeepseekTest.java)
10+
11+
以下介绍具体技术实现:
12+
13+
---
14+
15+
## ✅1. 功能目标
16+
17+
将用户的问题(如“查询杭州天气”)与定义好的工具清单(如 `get_weather`)一起提交给 Deepseek 的 `/chat/completions` 接口,让 Deepseek 自动识别需要调用哪个工具,并提取出对应的参数(如 `location: "杭州"`)。
18+
19+
---
20+
21+
## 🧩2. 核心步骤解析
22+
23+
### 2.1. 构建请求内容
24+
25+
你需要构建一个包含以下信息的 `DeepseekMessages` 对象:
26+
- **messages**:历史对话记录(包括用户提问)
27+
- **tools**:可调用的工具描述列表
28+
- **model**:使用的模型名称(如 `"deepseek-chat"`
29+
- **stream**:是否启用流式响应
30+
- **max_tokens**:最大输出 token 数量
31+
32+
```java
33+
DeepseekMessages deepseekMessages = new DeepseekMessages();
34+
deepseekMessages.setMessages(deepseekMessageList); // 历史对话记录
35+
deepseekMessages.setModel(model); // 模型名
36+
deepseekMessages.setStream(stream); // 是否流式输出
37+
deepseekMessages.setMax_tokens(this.max_tokens); // 最大 token 数量
38+
deepseekMessages.setTools(tools); // 工具清单
39+
```
40+
41+
42+
### 2.2. 定义工具清单(JSON 格式)
43+
44+
你使用 JSON 字符串定义了一个工具 `get_weather`,它接受一个 `location` 参数:
45+
46+
```json
47+
[
48+
{
49+
"type": "function",
50+
"function": {
51+
"name": "get_weather",
52+
"description": "Get weather of an location, the user should supply a location first",
53+
"parameters": {
54+
"type": "object",
55+
"properties": {
56+
"location": {
57+
"type": "string",
58+
"description": "The city and state, e.g. San Francisco, CA"
59+
}
60+
},
61+
"required": ["location"]
62+
}
63+
}
64+
}
65+
]
66+
```
67+
68+
69+
> 💡 注意:确保 JSON 格式正确,否则 Deepseek 可能无法解析工具描述。
70+
71+
### 2.3. 发送请求到 Deepseek API
72+
73+
使用 `HttpRequestProxy.sendJsonBody()` 向 Deepseek 的 `/chat/completions` 接口发送请求:
74+
75+
```java
76+
Map response = HttpRequestProxy.sendJsonBody(this.getDeepseekService(), deepseekMessages, "/chat/completions", Map.class);
77+
```
78+
79+
80+
返回结果中会包含匹配的工具信息及参数,例如:
81+
82+
```json
83+
{
84+
"choices": [
85+
{
86+
"message": {
87+
"role": "assistant",
88+
"content": "",
89+
"tool_calls": [
90+
{
91+
"id": "call_abc123",
92+
"type": "function",
93+
"function": {
94+
"name": "get_weather",
95+
"arguments": "{\"location\": \"杭州\"}"
96+
}
97+
}
98+
]
99+
}
100+
}
101+
]
102+
}
103+
```
104+
105+
106+
### 2.4. 提取工具调用信息
107+
108+
从响应中提取工具调用详情:
109+
110+
```java
111+
List<Map> toolcalls = (List<Map>) message.get("tool_calls");
112+
Map tool = toolcalls.get(0);
113+
114+
String toolId = (String) tool.get("id");
115+
String functionName = (String) ((Map) tool.get("function")).get("name");
116+
String functionArguments = (String) ((Map) tool.get("function")).get("arguments");
117+
118+
Map arguments = SimpleStringUtil.json2Object(functionArguments, Map.class);
119+
String location = (String) arguments.get("location"); // 提取出城市名:"杭州"
120+
```
121+
122+
123+
### 2.5. 调用工具并反馈结果
124+
125+
模拟调用工具函数并构造响应消息:
126+
127+
```java
128+
logger.info("模拟调用函数:{}(\"{}\"),返回值为:24℃", functionName, location);
129+
130+
// 构造 tool 角色的消息
131+
DeepseekMessage deepseekMessage = new DeepseekMessage();
132+
deepseekMessage.setRole("tool");
133+
deepseekMessage.setContent("24℃");
134+
deepseekMessage.setTool_call_id(toolId);
135+
deepseekMessageList.add(deepseekMessage);
136+
```
137+
138+
139+
### 2.6. 再次调用 Deepseek 获取最终回答
140+
141+
将工具结果作为上下文再次传入 Deepseek,生成自然语言的回答:
142+
143+
```java
144+
deepseekMessages = new DeepseekMessages();
145+
deepseekMessages.setMessages(deepseekMessageList);
146+
deepseekMessages.setModel(model);
147+
deepseekMessages.setStream(stream);
148+
deepseekMessages.setMax_tokens(this.max_tokens);
149+
150+
response = HttpRequestProxy.sendJsonBody(this.getDeepseekService(), deepseekMessages, "/chat/completions", Map.class);
151+
//提取最终回答并记录消息记录到历史记录清单
152+
choices = (List) response.get("choices");
153+
message = (Map) ((Map) choices.get(0)).get("message");
154+
deepseekMessage = new DeepseekMessage();
155+
deepseekMessage.setRole("assistant");
156+
deepseekMessage.setContent((String) message.get("content"));
157+
//将第二个问题答案添加到工作流上下文中,保存Deepseek通话记录
158+
deepseekMessageList.add(deepseekMessage);
159+
//输出查询杭州天气结果以及饮食、衣着及出行建议
160+
logger.info(deepseekMessage.getContent());
161+
```
162+
163+
164+
---
165+
166+
167+
168+
## ✅ 3. 示例完整调用逻辑
169+
170+
```java
171+
/**
172+
* 5.构建第三个任务节点:单任务节点 调用工具查询杭州天气
173+
*/
174+
jobFlowNodeBuilder = new DeepseekJobFlowNodeBuilder("3", "Deepseek-chat-天气查询", new DeepseekJobFlowNodeFunction() {
175+
@Override
176+
public Object call(JobFlowNodeExecuteContext jobFlowNodeExecuteContext) throws Exception {
177+
//从工作流上下文中,获取Deepseek历史通话记录
178+
List<DeepseekMessage> deepseekMessageList = (List<DeepseekMessage>) jobFlowNodeExecuteContext.getJobFlowContextData("messages");
179+
if(deepseekMessageList == null){
180+
deepseekMessageList = new ArrayList<>();
181+
jobFlowNodeExecuteContext.addJobFlowContextData("messages",deepseekMessageList);
182+
}
183+
//用户查询杭州天气
184+
DeepseekMessage deepseekMessage = new DeepseekMessage();
185+
186+
deepseekMessage.setRole("user");
187+
// 用户问题
188+
deepseekMessage.setContent("查询杭州天气,并根据天气给出穿衣、饮食以及出行建议");
189+
190+
// 构建请求对象
191+
DeepseekMessages deepseekMessages = new DeepseekMessages();
192+
deepseekMessages.setMessages(deepseekMessageList);
193+
deepseekMessages.setModel("deepseek-chat");
194+
deepseekMessages.setTools(tools);
195+
196+
// 发起请求
197+
Map response = HttpRequestProxy.sendJsonBody("deepseek", deepseekMessages, "/chat/completions", Map.class);
198+
199+
// 解析响应中的工具调用
200+
List<Map> toolcalls = (List<Map>) ((Map) ((Map) response.get("choices")).get(0)).get("message").get("tool_calls");
201+
Map tool = toolcalls.get(0);
202+
String location = (String) SimpleStringUtil.json2Object((String) ((Map) tool.get("function")).get("arguments"), Map.class).get("location");
203+
204+
// 模拟调用工具
205+
logger.info("调用 get_weather({})", location);
206+
207+
// 构造 tool 返回消息
208+
DeepseekMessage toolResponse = new DeepseekMessage();
209+
toolResponse.setRole("tool");
210+
//设置工具返回的杭州天气温度
211+
toolResponse.setContent("24℃");
212+
toolResponse.setTool_call_id((String) tool.get("id"));
213+
deepseekMessageList.add(toolResponse);
214+
215+
// 再次调用 Deepseek 生成最终回答
216+
deepseekMessages.setMessages(deepseekMessageList);
217+
response = HttpRequestProxy.sendJsonBody("deepseek", deepseekMessages, "/chat/completions", Map.class);
218+
choices = (List) response.get("choices");
219+
message = (Map) ((Map) choices.get(0)).get("message");
220+
deepseekMessage = new DeepseekMessage();
221+
deepseekMessage.setRole("assistant");
222+
deepseekMessage.setContent((String) message.get("content"));
223+
//将第二个问题答案添加到工作流上下文中,保存Deepseek通话记录
224+
deepseekMessageList.add(deepseekMessage);
225+
//输出查询杭州天气结果以及饮食、衣着及出行建议
226+
logger.info(deepseekMessage.getContent());
227+
228+
return response;
229+
}
230+
231+
}).setDeepseekService("deepseek").setModel("deepseek-chat").setMax_tokens(4096);
232+
233+
/**
234+
* 4 将第工具调用节点添加到工作流构建器
235+
*/
236+
jobFlowBuilder.addJobFlowNode(jobFlowNodeBuilder);
237+
```
238+
239+
240+
---
241+
## 📌 4. 总结
242+
243+
本文通过实际案例代码,详细地介绍了AI智能体工具调用功能:将用户问题和工具清单发送给 Deepseek,并由 Deepseek 匹配对应工具并提取参数,通过工具调用节点调用工具,最后通过生成查询结果和建议节点调用Deepseek分析工具调用结果数据,生成并输出最终问题答案。
244+
245+
| 步骤 | 目的 |
246+
|------|------|
247+
| 构建 `DeepseekMessages` | 准备请求数据 |
248+
| 设置 `tools` 属性 | 提供可用工具描述 |
249+
| 发送请求到 `/chat/completions` | 让 Deepseek 解析用户意图并选择工具 |
250+
| 解析 `tool_calls` | 提取匹配的工具及参数 |
251+
| 模拟调用工具 | 执行实际业务逻辑获取结果 |
252+
| 再次调用 Deepseek | 结合原始问题与工具结果生成自然语言回复 |
253+
254+
---

0 commit comments

Comments
 (0)