找回密码
 立即注册
首页 业界区 业界 11. LangChain4j + Tools(Function Calling)的使用详细 ...

11. LangChain4j + Tools(Function Calling)的使用详细说明

博咱 前天 20:58
11. LangChain4j + Tools(Function Calling)的使用详细说明

@
目录

  • 11. LangChain4j + Tools(Function Calling)的使用详细说明

    • 实战LangChain4j + Tools(Function Calling)

      • 方式一: 低级别,使用 ChatModel 和 ToolSpecification API
      • 方式二:高级别,使用 AI Services 和带有 @Tool 注解的 Java 方法


  • 最后:

1.png

官网:https://docs.langchain4j.dev/tutorials/tools
2.png

有一个被称为"工具"或"函数调用"的概念。 它允许 LLM 在必要时调用一个或多个可用的工具,通常由开发者定义。 工具可以是任何东西:网络搜索、调用外部 API 或执行特定代码片段等。 LLM 实际上不能自己调用工具;相反,它们在响应中表达调用特定工具的意图(而不是以纯文本形式响应)(比如:你要查看天气,如果它无法查找的话,它会告诉你可以去某个网站可以查找到天气:比如中国气象网站)。 作为开发者,我们应该使用提供的参数执行这个工具,并将工具执行的结果反馈回来。
简单的一句话:就是说给我们的大模型添加了一些工具,让其可以使用这些工具,实现特定的工具,比如查看天气,查看时间等等功能
3.png

将LLM的智能与外部工具或API无缝连接:

  • 大语言模型(LLMs)不仅仅是文本生成的能手,它们还能触发并调用第3方函数,比如查询微信/调用支付宝/查看顺丰快递单据号等等
  • 重要提示:LLM本身并不执行函数,它只是指示应该调用哪个函数以及如何调用
实战LangChain4j + Tools(Function Calling)

对应 Tools 的使用, LangChain4j 提供了两个抽象级别来使用工具:
● 低级别,使用 ChatModel 和 ToolSpecification API
● 高级别,使用 AI Services 和带有 @Tool 注解的 Java 方法
方式一: 低级别,使用 ChatModel 和 ToolSpecification API

这里我们实现让大模型获取开具发票的功能,开具发票是我们自己编写的一个功能方法。

  • 创建对应项目的 module 模块内容:
  • 导入相关的 pom.xml 的依赖,这里我们采用流式输出的方式,导入 整合 Spring Boot ,langchain4j-open-ai-spring-boot-starter,langchain4j-spring-boot-starter 这里我们不指定版本,而是通过继承的 pom.xml 当中获取。
4.png
  1.       
  2.         <dependency>
  3.             <groupId>dev.langchain4j</groupId>
  4.             langchain4j-open-ai</artifactId>
  5.         </dependency>
  6.         
  7.         <dependency>
  8.             <groupId>dev.langchain4j</groupId>
  9.             langchain4j</artifactId>
  10.         </dependency>
  11.         
  12.         <dependency>
  13.             <groupId>dev.langchain4j</groupId>
  14.             langchain4j-reactor</artifactId>
  15.         </dependency>
复制代码

  • 设置 applcation.yaml / properties 配置文件,其中指明我们的输出响应的编码格式,因为如果不指定的话,存在返回的中文,就是乱码了。
  1. server.port=9010
  2. spring.application.name=langchain4j-10chat-functioncalling
  3. # 设置响应的字符编码,避免流式返回输出乱码
  4. server.servlet.encoding.charset=utf-8
  5. server.servlet.encoding.enabled=true
  6. server.servlet.encoding.force=true
  7. # https://docs.langchain4j.dev/tutorials/spring-boot-integration
  8. #langchain4j.open-ai.chat-model.api-key=${aliQwen-api}
  9. #langchain4j.open-ai.chat-model.model-name=qwen-plus
  10. #langchain4j.open-ai.chat-model.base-url=https://dashscope.aliyuncs.com/compatible-mode/v1
  11. # 大模型调用不可以明文配置,你如何解决该问题
  12. # 1 yml:                ${aliQwen-api},从环境变量读取
  13. # 2 config配置类:      System.getenv("aliQwen-api")从环境变量读取
复制代码

  • 新建一个,新建大模型调用的功能接口FunctionAssistant,就是我们操作大模型要做什么的接口类。这里是实现一个”开发票信息“功能。
5.png
  1. package com.rainbowsea.langchain4jchatfunctioncalling.service;
  2. /**
  3. * @Description: TODO
  4. */
  5. public interface FunctionAssistant
  6. {
  7.     //客户指令:出差住宿发票开票,
  8.     // 开票信息:    公司名称xxx
  9.     // 税号序列:    xx
  10.     // 开票金额:    xxx.00元
  11.     String chat(String message);
  12. }
复制代码

  • 编写大模型三件套(大模型 key,大模型 name,大模型 url) 三件套的大模型配置类。同时编写附加上,我们该实现接口类的,开具发票的功能方法。
对标官网:
6.png

7.png

8.png

9.png

10.png
  1. import com.rainbowsea.langchain4jchatfunctioncalling.service.FunctionAssistant;
  2. import com.rainbowsea.langchain4jchatfunctioncalling.service.InvoiceHandler;
  3. import dev.langchain4j.agent.tool.ToolSpecification;
  4. import dev.langchain4j.memory.chat.MessageWindowChatMemory;
  5. import dev.langchain4j.model.chat.ChatModel;
  6. import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
  7. import dev.langchain4j.model.openai.OpenAiChatModel;
  8. import dev.langchain4j.service.AiServices;
  9. import dev.langchain4j.service.tool.ToolExecutor;
  10. import org.springframework.context.annotation.Bean;
  11. import org.springframework.context.annotation.Configuration;
  12. import java.util.Map;
  13. /**
  14. *
  15. */
  16. @Configuration
  17. public class LLMConfig {
  18.     @Bean
  19.     public ChatModel chatModel() {
  20.         return OpenAiChatModel.builder()
  21.                 .apiKey(System.getenv("aliQwen_api"))
  22.                 .modelName("qwen-plus")
  23.                 .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
  24.                 .build();
  25.     }
  26.     /**
  27.      * @Description: 第一组 Low Level Tool API
  28.      * https://docs.langchain4j.dev/tutorials/tools#low-level-tool-api
  29.      * @Auther: zzyybs@126.com
  30.      */
  31.     @Bean
  32.     public FunctionAssistant functionAssistant(ChatModel chatModel) {
  33.         // 工具说明 ToolSpecification
  34.         ToolSpecification toolSpecification = ToolSpecification.builder()
  35.                 .name("开具发票助手")
  36.                 .description("根据用户提交的开票信息,开具发票")
  37.                 .parameters(JsonObjectSchema.builder()
  38.                         .addStringProperty("companyName", "公司名称")
  39.                         .addStringProperty("dutyNumber", "税号序列")
  40.                         .addStringProperty("amount", "开票金额,保留两位有效数字")
  41.                         .build())
  42.                 .build();
  43.         // 业务逻辑 ToolExecutor
  44.         ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> {
  45.             System.out.println(toolExecutionRequest.id());
  46.             System.out.println(toolExecutionRequest.name());
  47.             String arguments1 = toolExecutionRequest.arguments();
  48.             System.out.println("arguments1****》 " + arguments1);
  49.             return "开具成功";
  50.         };
  51.         return AiServices.builder(FunctionAssistant.class)
  52.                 .chatModel(chatModel)
  53.                 .tools(Map.of(toolSpecification, toolExecutor)) // Tools (Function Calling)
  54.                 .build();
  55.     }
  56. }
复制代码

  • 对外编写访问的 cutroller
  1. package com.rainbowsea.langchain4jchatfunctioncalling.controller;
  2. import cn.hutool.core.date.DateUtil;
  3. import com.rainbowsea.langchain4jchatfunctioncalling.service.FunctionAssistant;
  4. import jakarta.annotation.Resource;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.web.bind.annotation.GetMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8. /**
  9. */
  10. @RestController
  11. @Slf4j
  12. public class ChatFunctionCallingController
  13. {
  14.     @Resource
  15.     private FunctionAssistant functionAssistant;
  16.     //  http://localhost:9010/chatfunction/test1
  17.     @GetMapping(value = "/chatfunction/test1")
  18.     public String test1()
  19.     {
  20.         String chat = functionAssistant.chat("开张发票,公司:xxx科技有限公司 税号:xxx533 金额:668.12");
  21.         System.out.println(chat);
  22.         return "success : "+ DateUtil.now() + "\t"+chat;
  23.     }
  24. }
复制代码
运行测试:
12.png

方式二:高级别,使用 AI Services 和带有 @Tool 注解的 Java 方法

这里我们基于方式一的基础配置,实现
实现让大模型获取到天气服务,这里我们介入第三方天气服务“和风天气开发服务”https://dev.qweather.com/
使用注解

  • @Tool,可以更方便地集成函数调用,只需将Java方法标注为
  • @Tool,LangChain4j就会自动将其转换为ToolSpecification
https://dev.qweather.com/
13.png
14.png

15.png
16.png
17.png
18.png
19.png
20.png


  • 新建天气查询业务类 —— WeatherService ,就是额外附加给大模型的 Tool 工具类方法,用于获取天气的信息。
21.png
  1. package com.rainbowsea.langchain4jchatfunctioncalling.service;
  2. import com.fasterxml.jackson.databind.JsonNode;
  3. import jakarta.annotation.Resource;
  4. import org.apache.hc.client5.http.impl.classic.HttpClients;
  5. import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
  6. import org.springframework.stereotype.Component;
  7. import org.springframework.stereotype.Service;
  8. import org.springframework.web.bind.annotation.RequestParam;
  9. import org.springframework.web.client.RestTemplate;
  10. import com.fasterxml.jackson.databind.ObjectMapper;
  11. /**
  12. * @auther zzyy
  13. * @create 2025-03-12 23:24
  14. */
  15. @Service
  16. public class WeatherService
  17. {
  18.     //和风天气开发服务 https://dev.qweather.com/
  19.     // 替换成你自己的和风天气API密钥
  20.     private static final String API_KEY = System.getenv("weatherAPI");
  21.     // 调用的url地址和指定的城市,本案例以北京为例
  22.     private static final String BASE_URL = "https://devapi.qweather.com/v7/weather/now?location=%s&key=%s";
  23.     public JsonNode getWeatherV2(String city) throws Exception
  24.     {
  25.         //1 传入调用地址url和apikey
  26.         String url = String.format(BASE_URL, city, API_KEY);
  27.         //2 使用默认配置创建HttpClient实例
  28.         var httpClient = HttpClients.createDefault();
  29.         //3 创建请求工厂并将其设置给RestTemplate,开启微服务调用和风天气开发服务
  30.         HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
  31.         //4 RestTemplate微服务调用
  32.         String response = new RestTemplate(factory).getForObject(url, String.class);
  33.         //5 解析JSON响应获得第3方和风天气返回的天气预报信息
  34.         JsonNode jsonNode = new ObjectMapper().readTree(response);
  35.         //6 想知道具体信息和结果请查看https://dev.qweather.com/docs/api/weather/weather-now/#response
  36.         return jsonNode;
  37.     }
  38. }
复制代码

  • 新建类InvoiceHandler,添加上我们方式一开发票的功能,以及我们查询天气的功能:
22.png
  1. package com.rainbowsea.langchain4jchatfunctioncalling.service;
  2. import dev.langchain4j.agent.tool.P;
  3. import dev.langchain4j.agent.tool.Tool;
  4. import lombok.extern.slf4j.Slf4j;
  5. /**
  6. * 知识出处,https://docs.langchain4j.dev/tutorials/tools/#tool
  7. */
  8. @Slf4j
  9. public class InvoiceHandler
  10. {
  11.     @Tool("根据用户提交的开票信息进行开票")
  12.     public String handle(@P("公司名称") String companyName,
  13.                          @P("税号") String dutyNumber,
  14.                          @P("金额保留两位有效数字") String amount) throws Exception
  15.     {
  16.         log.info("companyName =>>>> {} dutyNumber =>>>> {} amount =>>>> {}", companyName, dutyNumber, amount);
  17.         //----------------------------------
  18.         // 这块写自己的业务逻辑,调用redis/rabbitmq/kafka/mybatis/顺丰单据/医疗化验报告/支付接口等第3方
  19.         //----------------------------------
  20.         System.out.println(new WeatherService().getWeatherV2("101010100"));
  21.         return "开票成功";
  22.     }
  23. }
复制代码

  • 修改我们配置大模型的配置类,将我们编写的工具类,附加上给大模型使用,这里使用 .tools 方法
23.png
  1. package com.rainbowsea.langchain4jchatfunctioncalling.config;
  2. import com.rainbowsea.langchain4jchatfunctioncalling.service.FunctionAssistant;
  3. import com.rainbowsea.langchain4jchatfunctioncalling.service.InvoiceHandler;
  4. import dev.langchain4j.agent.tool.ToolSpecification;
  5. import dev.langchain4j.memory.chat.MessageWindowChatMemory;
  6. import dev.langchain4j.model.chat.ChatModel;
  7. import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
  8. import dev.langchain4j.model.openai.OpenAiChatModel;
  9. import dev.langchain4j.service.AiServices;
  10. import dev.langchain4j.service.tool.ToolExecutor;
  11. import org.springframework.context.annotation.Bean;
  12. import org.springframework.context.annotation.Configuration;
  13. import java.util.Map;
  14. /**
  15. *
  16. */
  17. @Configuration
  18. public class LLMConfig {
  19.     @Bean
  20.     public ChatModel chatModel() {
  21.         return OpenAiChatModel.builder()
  22.                 .apiKey(System.getenv("aliQwen_api"))
  23.                 .modelName("qwen-plus")
  24.                 .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
  25.                 .build();
  26.     }
  27.     /**
  28.      * @Description: 第二组 High Level Tool API
  29.      * https://docs.langchain4j.dev/tutorials/tools#high-level-tool-api
  30.      * @Auther: zzyybs@126.com
  31.      */
  32.     @Bean
  33.     public FunctionAssistant functionAssistant(ChatModel chatModel)
  34.     {
  35.         return AiServices.builder(FunctionAssistant.class)
  36.                     .chatModel(chatModel)
  37.                     .tools(new InvoiceHandler())
  38.                 .build();
  39.     }
  40. }
复制代码
最后:

“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”
24.gif


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册