JavaAI03-数据来源

Function-call(Tools)

  • 目前的大模型AI,都是只知道一些通用的、网络上能查到的信息,并且他们的知识库都有一定的延迟。那么现在要让他查询自己私有系统中的数据时,它就需要调用我们的系统API了。
  • 具体流程:
    • AI收到一个问题
    • AI识别到,这个问题需要去我们的程序应用中获取
    • AI提取关键词
    • 调用 changshaNameCount 方法
    • 通过返回结果再结合上下文,再次请求大模型
    • 响应结果

实现一个案例

  • 创建一个maven项目

  • pom.xml

    xml 复制代码
    <dependencyManagement>
        <dependencies>
            <!-- 引入 Spring Boot BOM -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>3.4.3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!-- SpringBoot 核心包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    
        <!-- SpringBoot Web容器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    
        <!-- 阿里云百炼 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
            <version>1.0.0-beta3</version>
        </dependency>
    
        <!-- webflux -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
    
        <!-- langchain4j核心 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
            <version>1.0.0-beta3</version>
        </dependency>
    </dependencies>
  • application.yml(需要所选的大模型支持Function-call)

    yml 复制代码
    langchain4j:
      community:
        dashscope:
          chatModel:
            api-key: "sk-xxxxxxxxxxx"
            model-name: qwen-plus
          streaming-chat-model:
            api-key: "sk-xxxxxxxxxxx"
            model-name: qwen-plus
  • 创建一个ToolsService,即用来提供给AI的方法

    java 复制代码
    import dev.langchain4j.agent.tool.P;
    import dev.langchain4j.agent.tool.Tool;
    import org.springframework.stereotype.Service;
    
    @Service
    public class PigToolsService{
    
        @Tool("猪头肉市有多少人口")
        public  Integer pigPersonNumCount(@P("人数") String personNum){
            System.out.println("模拟查询业务数据库,或者模拟调用api接口......" + personNum);
            return 10;
        }
    
        @Tool("猪头肉市有的人们最爱吃的食物")
        public  String pigPersonLikeEat(@P("城市") String city, @P("行为") String behavior){
            System.out.println("模拟查询业务数据库,或者模拟调用api接口......" + city + "、" + behavior);
            return "爱吃青菜,总之一般不吃吃猪头肉";
        }
    }
    • PigToolsService 配置到了IOC容器中
    • @Tool 用于告诉AI什么对话调用这个方法
    • @P("XX") 用于告诉AI ,调用方法的时候需要提取对话中的什么信息, 这里提取的是 人数
  • Config 配置类,自定义的Assistant

    java 复制代码
    import com.qi.tools.PigToolsService;
    import dev.langchain4j.memory.ChatMemory;
    import dev.langchain4j.memory.chat.MessageWindowChatMemory;
    import dev.langchain4j.model.chat.ChatLanguageModel;
    import dev.langchain4j.model.chat.StreamingChatLanguageModel;
    import dev.langchain4j.service.AiServices;
    import dev.langchain4j.service.TokenStream;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class AiConfig {
    
        public interface Assistant {
            String chat(String message);
            // 流式响应
            TokenStream stream(String message);
        }
        
        @Bean
        public Assistant assistant(ChatLanguageModel qwenChatModel,
                                   StreamingChatLanguageModel qwenStreamingChatModel,
                                   PigToolsService toolsService //从IOC容器中取了 自定义的PigToolsService
        ) {
            ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
    
            Assistant assistant = AiServices.builder(Assistant.class)
                    .chatLanguageModel(qwenChatModel)
                    .streamingChatLanguageModel(qwenStreamingChatModel)
                    .tools(toolsService) //使用了自定义的PigToolsService,ai有需要的话会调用
                    .chatMemory(chatMemory)
                    .build();
    
            return  assistant;
        }
        
    }
  • Controller类

    java 复制代码
    import com.qi.config.AiConfig;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @RequestMapping("/Tools")
    @RestController
    public class ToolsController {
    
        @Autowired
        AiConfig.Assistant assistant;
    
        @RequestMapping(value = "/test1")
        public String test1(@RequestParam("message") String message) {
            return assistant.chat(message);
        }
    
    }
  • 调用接口测试,可以看到AI会基于我们程序提供的方法结果上,进行自己的创作

  • 此时控制台的打印

预设角色

  • 大模型本身是没有目的的,对话想聊什么就聊什么。
  • 那么想要把他集成进我们业务中,就需要给他预设一个角色。
  • 很简单,就是告诉他自己是个什么角色。

案例:票务助手

  • 原本我们有一个票务系统,现在要接入大模型,让他充当一个简单客服,帮助用户退票。

  • 需求:用户说预定或者退票时,大模型会应道用户说出车次和姓名,然后帮用户预定/退票。(仅单单演示案例,不考虑业务的安全方面)

  • 前提是我们本身必须为大模型准备两个业务方法,用来预定和退票。

  • 在langchain4j中实现逻辑:

    • @SystemMessage 系统消息, 一般做一些预设角色的提示词,设置大模型的基本职责
    • 可以通过{{current_date}} 传入参数, 因为预设词中的文本可能需要实时变化
    • @V("current_date"), 通过@V传入{{}}中的参数
    • 一旦参数不止一个, 就需要通过@UserMessage设置用户信息
  • 定义一个Assistant

    java 复制代码
    import dev.langchain4j.model.chat.ChatLanguageModel;
    import dev.langchain4j.model.chat.StreamingChatLanguageModel;
    import dev.langchain4j.service.*;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class RoleConfig {
    
        public interface RoleAssistant {
    
            @SystemMessage("""
                    您是"猪头肉"航空公司的客户聊天支持代理。请以友好、乐于助人且愉快的方式来回复。
                            您正在通过在线聊天系统与客户互动。 
                            在提供有关预订或取消预订的信息之前,您必须始终从用户处获取以下信息:车次、客户姓名。
                            请讲中文。
    					   今天的日期是 {{current_date}}.
                    """)
            TokenStream stream(@UserMessage String message, @V("current_date") String currentDate);
        }
    
    
        @Bean
        public RoleConfig.RoleAssistant roleAssistant(ChatLanguageModel qwenChatModel,
                                            StreamingChatLanguageModel qwenStreamingChatModel) {
    
    
            RoleConfig.RoleAssistant assistant = AiServices.builder(RoleConfig.RoleAssistant.class)
                    .chatLanguageModel(qwenChatModel)
                    .streamingChatLanguageModel(qwenStreamingChatModel)
                    .build();
    
            return assistant;
        }
    
    }
    • """ 是java15引入的文本块,用来写多行字符串,不用手动加\n,直接换行写内容,更清晰。
  • controller接口

    java 复制代码
    import com.qi.config.RoleConfig;
    import dev.langchain4j.service.TokenStream;
    import jakarta.servlet.http.HttpServletResponse;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import reactor.core.publisher.Flux;
    
    import java.time.LocalDate;
    
    @RequestMapping("/role")
    @RestController
    public class RoleController {
    
        @Autowired
        RoleConfig.RoleAssistant roleAssistant;
    
        @RequestMapping(value = "/test1",produces ="text/stream;charset=UTF-8")
        public Flux<String> memoryStreamChat(@RequestParam("message") String message, HttpServletResponse response) {
            TokenStream stream = roleAssistant.stream(message, LocalDate.now().toString());
    
            return Flux.create(sink -> {
                stream.onPartialResponse(s -> sink.next(s))
                        .onCompleteResponse(c -> sink.complete())
                        .onError(sink::error)
                        .start();
    
            });
        }
    
    }
  • 调用接口,此时可以看到他已经代入了预设的角色,此时目的性已经很强了

  • 加入Tools,定义预定和退票方法

    java 复制代码
    import dev.langchain4j.agent.tool.P;
    import dev.langchain4j.agent.tool.Tool;
    import org.springframework.stereotype.Service;
    
    @Service
    public class TrainToolsService {
    
        @Tool("退票")
        public  String refundTicket(@P("车次") String train, @P("姓名") String personName){
            System.out.println("模拟调用数据库退票" + train + "、" + personName);
            return "退票成功";
        }
    
        @Tool("预定")
        public  String reserveTicket(@P("车次") String train, @P("姓名") String personName){
            System.out.println("模拟调用数据库预定票" + train + "、" + personName);
            return "预定成功";
        }
    
    }
  • 修改RoleConfig,加入定义的预定和退票方法(tools)

    java 复制代码
    @Bean
        public RoleAssistant roleAssistant(ChatLanguageModel qwenChatModel,
                                            StreamingChatLanguageModel qwenStreamingChatModel,
                                           TrainToolsService trainToolsService) {
    
            RoleAssistant assistant = AiServices.builder(RoleAssistant.class)
                    .chatLanguageModel(qwenChatModel)
                    .streamingChatLanguageModel(qwenStreamingChatModel)
                    .tools(trainToolsService)
                    .build();
    
            return assistant;
        }
  • 浏览器调用


  • 另外:假设大模型不支持系统消息(一般都支持),可以用@UserMessage代替@SystemMessage

    • 但是要注意,不能同时存在两个@UserMessage
    java 复制代码
    interface Friend {
    
        @UserMessage("你是一个航空智能助手,你需要帮助用户进行服务: {{it}}")
        String chat(String userMessage);
    }
相关推荐
garmin Chen11 小时前
从 Transformer 到 Agent:大模型技术全景解析
java·人工智能·python·深度学习·transformer
愚公移码11 小时前
蓝凌EKP18产品:流程引擎技术篇之流程核心概念模型
java·人工智能·流程引擎·蓝凌
Full Stack Developme11 小时前
Apache Tika 教程
java·开发语言·python·apache
鹅城剑仙11 小时前
Java线程池完全指南
java
李白的天不白11 小时前
SmartAdmin(基于 Spring Boot 框架)中配置跨域请求 VUE3 设置请求头
java·前端
橙子进阶之路11 小时前
Java线程(CompletableFuture)
java·开发语言
鹅城剑仙12 小时前
Java CompletableFuture 异步编程完全指南
java
2601_9618752412 小时前
法考备考计划表|学习计划|资料已整理
java·开发语言·学习·eclipse·tomcat·c#·hibernate
重生之我是Java开发战士12 小时前
【Java SE】多线程(三):单例模式,阻塞队列,线程池与定时器
java·javascript·单例模式
AI人工智能+电脑小能手12 小时前
【大白话说Java面试题 第115题】【并发篇】第15题:说一下悲观锁和乐观锁的区别?
java·开发语言·面试