首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >longchain4j 学习系列(3)-工具调用(Tool Calling)

longchain4j 学习系列(3)-工具调用(Tool Calling)

作者头像
菩提树下的杨过
发布2025-10-01 08:12:44
发布2025-10-01 08:12:44
10600
代码可运行
举报
运行总次数:0
代码可运行

大模型本身的”知识体系“一般来说,局限于受训练时使用的数据。超出这个数据范围的问题,靠模型自身是无法解答的,得依赖各种外挂工具来增强体验。参考下图:

image
image

这一节,我们来学习longchain4j 如何让大模型能利用工具外挂增强自身。

假设一个场景:输入1个订单号,让AI回答订单号现在的状态。 AI连是什么订单都不清楚,肯定回答不了。

一、定义工具

代码语言:javascript
代码运行次数:0
运行
复制
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加上工具外挂的思路是:

  • 帮我回答个问题,如果你搞不定,我这里有一堆工具(及工具使用说明书),你可以告诉我,想用哪个工具
  • 根据你选择的工具,我帮你调用它,然后把工具的结果告诉你
  • 有了工具加持后的结果,再结合我最初提的问题,给我最终答案
代码语言:javascript
代码运行次数:0
运行
复制
 /**
 * 通过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());
    }
}

三、运行效果

image
image

四、日志分析

代码语言:javascript
代码运行次数:0
运行
复制
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"}

 几点说明:

  • 14-27行日志可以看出,第1次请求deepseek时,把可用的工具(及说明书),都告诉了大模型
  • 36行是deepseek的回复,其中 {"role":"assistant","content":"我来帮您查询订单1234567890的状态。","tool_calls":[{"index":0,"id":"call_00_BysdTtMayce0pCuRfP1GeM8A","type":"function","function":{"name":"getOrderStatus","arguments":"{\"orderId\": \"1234567890\"}"}}]} ,模型表明了想调用getOrderStatus的意图,并识别出了调用的参数。
  • 59-61行,第2次请求模型时,把工具调用的结果,一并发给模型。
  • 88行,模型综合分析后,将 "in processing",正确转换成了更友好的”处理中“

文中示例代码:https://github.com/yjmyzz/longchain4j-study/tree/day03

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-09-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档