大模型本身的”知识体系“一般来说,局限于受训练时使用的数据。超出这个数据范围的问题,靠模型自身是无法解答的,得依赖各种外挂工具来增强体验。参考下图:
这一节,我们来学习longchain4j 如何让大模型能利用工具外挂增强自身。
假设一个场景:输入1个订单号,让AI回答订单号现在的状态。 AI连是什么订单都不清楚,肯定回答不了。
一、定义工具
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
public class OrderTools {
@Tool("查询订单状态")
public String getOrderStatus(@P("订单ID") String orderId) {
// 模拟查询订单状态的逻辑
return "Order: " + orderId + " is in processing";
}
}
二、使用工具
对于新手而言,请再默念一遍:大模型本身并没有调用外部工具的能力,但是理解上下文后,能表达调用工具的意图。
因此,让AI加上工具外挂的思路是:
/**
* 通过DeepSeek模型查询订单状态。
* 该方法会构造一个包含订单状态查询意图的用户消息,并利用工具调用机制让AI决定是否需要调用订单状态查询工具。
* 如果AI请求调用工具,则执行工具并再次与AI交互以生成最终响应。
*
* @param orderId 订单ID,用于查询对应订单的状态
* @return ResponseEntity<String> 返回订单状态的文本描述或错误信息
*/
@GetMapping(value = "/status/deepseek", produces = MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity<String> getOrderStatusWithDeepseek(@RequestParam String orderId) {
try {
// 注册可用的工具规范,供AI在对话中调用
List<ToolSpecification> toolSpecifications = ToolSpecifications.toolSpecificationsFrom(OrderTools.class);
// 构造用户提问消息
UserMessage userMessage = UserMessage.from("订单" + orderId + "的状态是什么,请用友好的方式回答");
// 构建第一次请求,包含用户消息和工具定义
ChatRequest request = ChatRequest.builder()
.messages(userMessage)
.toolSpecifications(toolSpecifications)
.build();
// 第一次调用LLM,获取AI响应
ChatResponse response = deepSeekChatModel.chat(request);
AiMessage aiMessage = response.aiMessage();
// 检查AI是否希望调用工具,并确认是调用订单状态查询工具
if (aiMessage.hasToolExecutionRequests() && "getOrderStatus".equalsIgnoreCase(aiMessage.toolExecutionRequests().getFirst().name())) {
// 执行订单状态查询工具
String toolResult = orderTools.getOrderStatus(orderId);
// 构造工具执行结果消息
ToolExecutionResultMessage toolExecutionResultMessage = ToolExecutionResultMessage.from(aiMessage.toolExecutionRequests().getFirst(), toolResult);
// 构建第二次请求,将用户消息、AI原始响应和工具执行结果一并发送给AI进行总结
ChatRequest request2 = ChatRequest.builder()
.messages(List.of(userMessage, aiMessage, toolExecutionResultMessage))
.toolSpecifications(toolSpecifications)
.build();
// 第二次调用LLM,生成最终自然语言响应
ChatResponse response2 = deepSeekChatModel.chat(request2);
return ResponseEntity.ok(response2.aiMessage().text());
} else {
log.warn("AI没有请求调用任何工具,响应内容: {}", aiMessage);
return ResponseEntity.ok("AI没有请求调用任何工具,响应内容: " + aiMessage);
}
} catch (Exception e) {
log.error("通过AI调用工具时发生错误", e);
return ResponseEntity.ok("通过AI调用工具失败: " + e.getMessage());
}
}
三、运行效果
四、日志分析
2025-09-29T13:48:57.107+08:00 INFO 17332 --- [longchain4j-study] [nio-8080-exec-4] d.l.http.client.log.LoggingHttpClient : HTTP request:
- method: POST
- url: https://api.deepseek.com/chat/completions
- headers: [Authorization: Beare...00], [User-Agent: langchain4j-openai], [Content-Type: application/json]
- body: {
"model" : "deepseek-chat",
"messages" : [ {
"role" : "user",
"content" : "订单1234567890的状态是什么,请用友好的方式回答"
} ],
"temperature" : 0.7,
"stream" : false,
"max_tokens" : 2048,
"tools" : [ {
"type" : "function",
"function" : {
"name" : "getOrderStatus",
"description" : "查询订单状态",
"parameters" : {
"type" : "object",
"properties" : {
"orderId" : {
"type" : "string",
"description" : "订单ID"
}
},
"required" : [ "orderId" ]
}
}
} ]
}
2025-09-29T13:49:00.228+08:00 INFO 17332 --- [longchain4j-study] [nio-8080-exec-4] d.l.http.client.log.LoggingHttpClient : HTTP response:
- status code: 200
- headers: [access-control-allow-credentials: true], [connection: keep-alive], [content-type: application/json], [date: Mon, 29 Sep 2025 05:48:57 GMT], [server: CW], [set-cookie: [HWWAFSESID=ce3128bfe3b55be8fc; path=/, HWWAFSESTIME=1759124935908; path=/]], [strict-transport-security: max-age=31536000; includeSubDomains; preload], [transfer-encoding: chunked], [vary: origin, access-control-request-method, access-control-request-headers], [x-content-type-options: nosniff], [x-ds-trace-id: 6e877fec76891009fc38758a5b5a2f3c]
- body: {"id":"4041b9d0-ab74-4131-b3ed-57b983ce7d22","object":"chat.completion","created":1759124937,"model":"deepseek-chat","choices":[{"index":0,"message":{"role":"assistant","content":"我来帮您查询订单1234567890的状态。","tool_calls":[{"index":0,"id":"call_00_BysdTtMayce0pCuRfP1GeM8A","type":"function","function":{"name":"getOrderStatus","arguments":"{\"orderId\": \"1234567890\"}"}}]},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":166,"completion_tokens":29,"total_tokens":195,"prompt_tokens_details":{"cached_tokens":128},"prompt_cache_hit_tokens":128,"prompt_cache_miss_tokens":38},"system_fingerprint":"fp_8333852bec_prod0820_fp8_kvcache"}
2025-09-29T13:49:00.278+08:00 INFO 17332 --- [longchain4j-study] [nio-8080-exec-4] d.l.http.client.log.LoggingHttpClient : HTTP request:
- method: POST
- url: https://api.deepseek.com/chat/completions
- headers: [Authorization: Beare...00], [User-Agent: langchain4j-openai], [Content-Type: application/json]
- body: {
"model" : "deepseek-chat",
"messages" : [ {
"role" : "user",
"content" : "订单1234567890的状态是什么,请用友好的方式回答"
}, {
"role" : "assistant",
"content" : "我来帮您查询订单1234567890的状态。",
"tool_calls" : [ {
"id" : "call_00_BysdTtMayce0pCuRfP1GeM8A",
"type" : "function",
"function" : {
"name" : "getOrderStatus",
"arguments" : "{\"orderId\": \"1234567890\"}"
}
} ]
}, {
"role" : "tool",
"tool_call_id" : "call_00_BysdTtMayce0pCuRfP1GeM8A",
"content" : "Order: 1234567890 is in processing"
} ],
"temperature" : 0.7,
"stream" : false,
"max_tokens" : 2048,
"tools" : [ {
"type" : "function",
"function" : {
"name" : "getOrderStatus",
"description" : "查询订单状态",
"parameters" : {
"type" : "object",
"properties" : {
"orderId" : {
"type" : "string",
"description" : "订单ID"
}
},
"required" : [ "orderId" ]
}
}
} ]
}
2025-09-29T13:49:04.053+08:00 INFO 17332 --- [longchain4j-study] [nio-8080-exec-4] d.l.http.client.log.LoggingHttpClient : HTTP response:
- status code: 200
- headers: [access-control-allow-credentials: true], [connection: keep-alive], [content-type: application/json], [date: Mon, 29 Sep 2025 05:49:00 GMT], [server: CW], [set-cookie: [HWWAFSESID=ce3129afe3b55be8fc; path=/, HWWAFSESTIME=1759124935908; path=/]], [strict-transport-security: max-age=31536000; includeSubDomains; preload], [transfer-encoding: chunked], [vary: origin, access-control-request-method, access-control-request-headers], [x-content-type-options: nosniff], [x-ds-trace-id: 77cf15df6dfab84503eb264553ba9d85]
- body: {"id":"8b7e15cd-987c-4ee9-bc40-8d44685baa50","object":"chat.completion","created":1759124940,"model":"deepseek-chat","choices":[{"index":0,"message":{"role":"assistant","content":"根据查询结果,您的订单1234567890目前正在处理中。这意味着您的订单已经成功提交,我们的团队正在为您处理相关事宜。请您耐心等待,一旦订单状态有更新,我们会及时通知您。如果您有任何其他问题,随时可以联系我们的客服团队。"},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":208,"completion_tokens":57,"total_tokens":265,"prompt_tokens_details":{"cached_tokens":192},"prompt_cache_hit_tokens":192,"prompt_cache_miss_tokens":16},"system_fingerprint":"fp_8333852bec_prod0820_fp8_kvcache"}
几点说明:
文中示例代码:https://github.com/yjmyzz/longchain4j-study/tree/day03