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);
    }
相关推荐
钦拆大仁2 小时前
JDK17新特性
java
小程故事多_802 小时前
Spring AI 赋能 Java,Spring Boot 快速落地 LLM 的企业级解决方案
java·人工智能·spring·架构·aigc
Caarlossss2 小时前
mybatis
java·数据库·tomcat·maven·mybatis·mybatis-spring
喵手2 小时前
项目实战案例:从设计到部署!
java·部署·项目实战·设计
源码获取_wx:Fegn08952 小时前
基于springboot + vue小区人脸识别门禁系统
java·开发语言·vue.js·spring boot·后端·spring
youngee112 小时前
hot100-61电话号码的字母组合
java·数据结构·leetcode
寂寞旅行3 小时前
java敏感词过滤(sensitive-word)
java·开发语言·word
90后小陈老师3 小时前
Java项目接入AI大模型的四种方式
java·开发语言·人工智能
hunjinYang3 小时前
使用嵌入式 Tomcat 创建Java Web应用程序
java·tomcat