Part11 百炼大模型集成到项目中

YangeIT大约 7 分钟中州养老AIIOT版本MysqlApifoxServletHTTPGETPOST

Part11 百炼大模型集成到项目中

1. 智能体集成到项目中

1.0 Spring AI 是什么

Spring AI is an application framework for AI engineering.
Spring AI is an application framework for AI engineering.

官方地址 :https://spring.io/projects/spring-aiopen in new window

Spring AI 可以理解为:

用 Spring Boot 的开发方式去接入大模型,并把提示词、对话、工具调用、RAG、结构化输出等能力封装成更适合 Java 后端开发的 API。

如果不用 Spring AI,我们通常要手写很多内容:

  1. 自己拼接 HTTP 请求去调用模型接口。
  2. 自己维护消息上下文。
  3. 自己定义工具调用协议。
  4. 自己处理模型调用前后的对象转换。

用了 Spring AI 后:

  1. 通过 Starter 引入模型能力。
  2. ChatClient 发起对话。
  3. @Tool 把 Java 方法暴露给模型。
  4. 用 Spring Bean、配置文件、Service、Controller 的方式组织 AI 功能。

这就非常适合我们这种已有 Spring Boot 项目,要把 AI 能力嵌入业务系统的场景。

1.1. 准备SpringAI环境

准备SpringAI环境

今天,我们将使用SpringAI对中州养老项目进行升级,为每一位用户打造一个专属的智能管家。

1. 导入Springai依赖 我们需要在项目中导入alibabaai的依赖和一些配置信息,如下: 导入阴影部分的代码

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.0</version>
        <relativePath/>
    </parent>

    <groupId>cn.yangeit</groupId>
    <artifactId>zzylai</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
<!-- web相关依赖       -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
<!--测试相关依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
<!--  数据库驱动      -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>
        <!-- mybatis plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.5</version>
        </dependency>
<!--  mybatisSpring依赖      -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>3.0.3</version>
        </dependency>
<!--  小辣椒依赖      -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
        </dependency>
<!--    糊涂工具包    -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.13</version>
        </dependency>

        <!-- Token生成与解析-->
        <!-- JWT依赖-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
            <version>2.5.0</version>
        </dependency>

        <!--阿里AI-->
        <dependency>
            <groupId>com.alibaba.cloud.ai</groupId>
            <artifactId>spring-ai-alibaba-starter</artifactId>
            <version>1.0.0-M2.1</version>
        </dependency>

    </dependencies>

    <!--spring-ai 依赖管理-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>1.0.0-M2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
<!--仓库-->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
    </repositories>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>3.5.0</version>
            </plugin>
        </plugins>
    </build>
</project>
































































































 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 












2. 在配置文件中application.yml中,配置百炼大模型的key和模型名字

spring:
  ai:
    dashscope:
      api-key: sk-fa22be36ce6446c0a2b70dbffd97eb11
      chat:
        options:
          model: qwen-max
image
image

3. 在config包中,创建ai配置文件ReservTools.java.在这个文件中,书写供AI调用的Function

@Configuration
public class ReservTools {
    @Autowired
    ReservationMapper reservationMapper;

    @Autowired
    FamilyMemberElderMapper familyMemberElderMapper;

  
  //向量数据库,用于存储文档
   @Bean
    public VectorStore vectorStore(EmbeddingModel embeddingModel){
        return new SimpleVectorStore(embeddingModel);//简单的向量数据库
    }

    //需要在启动程序的时候,将文档存入到向量数据库中
    @Bean
    public CommandLineRunner commandLineRunner(EmbeddingModel embeddingModel, VectorStore vectorStore, @Value("classpath:rag/terms-of-service.txt") Resource resource) {
        System.out.println("正在将文档存入向量数据库中...");
        return args -> {
            vectorStore.write(new TokenTextSplitter().transform(new TextReader(resource).read()));
        };

    }

  //基于内存的会话记忆
    @Bean
    public ChatMemory chatMemory() {
        return new InMemoryChatMemory();
    }
}

4. 在config包中,导入Ai日志类,方便查看AI模型日志信息

public class LoggingAdvisor implements RequestResponseAdvisor {

    @Override
    public AdvisedRequest adviseRequest(AdvisedRequest request, Map<String, Object> context) {
        System.out.println("提示词:"+request);
        return request;
    }
}

5. 在controller的customer包中,创建AI助手控制类:OpenAiController.java


@RestController
@CrossOrigin//  解决跨域问题
public class OpenAiController {

    private final ChatClient chatClient;

    public OpenAiController(ChatClient.Builder chatClientBuilder, ChatMemory chatMemory, VectorStore vectorStore) {
        this.chatClient = chatClientBuilder
                .defaultSystem("""
                        您是中州养老系统的专属客服助手。请以友好、乐于助人且愉快的方式来回复。
                                您正在通过在线聊天系统与客户互动。
                                提供探访预约、取消预约、获取家人列表、取消预约次数等功能的查询。
                                在询问用户之前,请检查消息历史记录以获取此信息。
                                如果探访预约,需要预约人姓名、预约人手机号码,家人姓名,预约时段才能进行增加探访预约。
                                在取消预约之前,请先获取预约信息并且展示给用户,用户确认无误后才进行更改或退定。
                                查询家人列表,如果没有调用到方法,就返回无法查询。
                                请讲中文,如果是列表的信息的话,需要组织下语言。
                                今天的日期是 {current_date}
                                微信用户Id:{userId}
                                我的名字:{name}
                        """)
                .defaultAdvisors(
                        new PromptChatMemoryAdvisor(chatMemory),
                        new LoggingAdvisor(),
                        new QuestionAnswerAdvisor(vectorStore)
                )
                .build();
    }

    @Autowired
    FamilyMemberMapper familyMemberMapper;

    @CrossOrigin//  解决跨域问题
    @GetMapping(value = "/ai/generateStreamAsString", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> generateStreamAsString(
            @RequestParam(value = "message", defaultValue = "讲个笑话") String message) {

        Flux<String> result = this.chatClient
                .prompt()
                .user(message)
                .system(promptSystemSpec -> {
                    promptSystemSpec.param("current_date", LocalDte.now().toString());
                    promptSysteSpec.param("userId", BaseCntext.getCurrentId());
                    promptSystemSpec.param("name", familyMemberMapper.selectById(BaseConext.getCurrentId()).getName());
                })
                .advisors(advisorSpec -> advisorSpec.param(AbstractChatMemoryAdvisor.CHAT_MEMOY_RETRIEVE_SIZE_KEY,10 ))
                .stream()
                .content();

        //在result的后面加上[complete]标记,表示生成完成
        result = result.concatWith(Flux.just("[complete]"));
        return result;
    }
}

6.在resource中创建rag文件夹,并且创建文件terms-of-service.txt作为RAG数据源

本服务条款适用于您对中州养老系统的体验。探访预约和取消预约,即表示您同意这些条款。
1.探访预约
- 通过我们的网站或移动应用程序预订。
- 预约时,需要通过userId查询取消预约的次数,如果取消预约次数超过3次,那么不能进行探访预约,如果没有调用到方法,就返回无法查询。
- 确保个人信息(预约人姓名、预约人手机号码,家人姓名,预约时段等)的准确性
2.取消预定
- 取消预约前,要展示预约信息并且得到用户的确认,才可以执行退定





image
image

7. 导入全新的mp-weixin压缩包,解压到非中文路径后,导入微信开发者工具中,登录后,点击家人,可以进入专属管家页面

image
image

图中的对话,是完成后的效果 ☝️☝️☝️☝️

总结

课堂作业

  1. 跟着上述的操作和视频,完成AI助手的搭建

1.2. 获取取消预约的次数

前言

探访预约指的是用户可以探访已经绑定好的家人,但是需要提前进行预约,预约成功后,才可以进行探访。但是为了防止用户恶意取消预约,所以需要限制取消预约的次数,超过3次,就不能进行探访预约。因此大模型需要调用接口,获取取消预约的次数,然后进行判断,如果超过3次,那么就不能进行探访预约。

1. 首先观察提示词image

2. 在ReservTools中定义Function方法对象,并配置描述,用于获取取消预约的次数

@Autowired
ReservationMapper reservationMapper;

public record UserIdParam(String userId) { }

@Bean
@Description("获取取消预约的次数")
public Function<UserIdParam,String> cancelledCount(){
    return crp -> {
    QueryWrapper<Reservation> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("status", 2);
    queryWrapper.eq("create_by", crp.userId);
    Long count = reservationMapper.selectCount(queryWrapper);
      return crp.userId+"用户,已经取消了"+count+"次";
    };

}

3. 在OpenAiController中配置cancelledCount方法image

4. 重启测试

image
image

1.3. 获得老人列表

前言

如果要进行探访预约,需要知道探访哪个老人,因此大模型需要调用接口,获取老人列表,然后进行展示。

1. 观察提示词

image
image

2. 在ReservTools中定义Function方法对象,并配置描述,用于获取老人列表

image
image

3. 在OpenAiController中配置getElderList方法image

4. 重启测试image

s