实战:Spring AI + DeepSeek-R1 + RAG + Tool Calling:智能对话应用开发全家桶(附有全部代码和测试)

一. 概述

在 AI 大模型技术飞速发展的当下,如何将这些强大的模型能力落地到实际应用中,成为了开发者们关注的焦点。特别是在企业内部知识库、教育问答系统等场景中,能够实现连续对话的 AI 应用具有巨大的应用价值。今天,我们就来聊聊如何结合 Spring AI、Spring AI Alibaba、DeepSeek-R1 模型、RAG 技术以及 Tool Calling,快速搭建一个支持连续对话的 AI 应用。

技术介绍

Spring AI:快速构建 AI 应用的框架

Spring AI 是一个开源框架,专注于帮助开发者快速构建对话系统。它提供了丰富的工具和库,从模型训练到应用部署,都能轻松搞定。简单来说,它就像一个“搭积木”的工具箱,让你可以快速拼出一个 AI 应用。

Spring AI Alibaba 则是 Spring AI 的扩展模块,专门为阿里巴巴的技术生态量身定制。它能让你轻松连接阿里云的服务,比如 DeepSeek-R1 模型,大大简化了在阿里云环境中开发 AI 应用的流程。换句话说,它就像一个“桥梁”,把 Spring AI 和阿里云的能力无缝连接起来。

阿里云百炼平台:强大的 AI 能力支持

阿里云百炼平台是这次项目的核心支持。它提供了 DeepSeek-R1 模型,一个高性能的 AI 模型,可以处理复杂的对话任务。此外,百炼平台还提供了文本嵌入模型 text-embedding-v2,用于将文本转化为向量形式,方便进行相似度计算和检索。这种能力在对话系统中特别重要,因为它能帮助我们更精准地找到用户问题的答案。如何申请可以查看 如何 Spring AI 集成百炼平台

RAG 技术:让对话更精准、更连贯

RAG(检索增强生成)是一种结合检索和生成模型的技术,它能让对话系统从大量文本数据中找到最相关的信息,并将其融入到对话生成中。简单来说,它就像一个“智能助手”,帮助你的 AI 模型更准确地回答问题,同时让对话更连贯、更有信息量。

Tool Calling:AI 模型的高级能力

Tool Calling 是一种让大语言模型调用外部工具的技术。它允许模型通过生成结构化输出来调用工具,即使不实际执行工具调用,也可以使用它来从非结构化文本中提取信息。Tool Calling 的主要优势包括:

  • 增强功能:让模型能够执行特定任务,如数学运算、数据查询等。
  • 提高效率和准确性:通过调用专门设计的工具,模型可以更快、更准确地完成任务。
  • 灵活性和扩展性:可以根据需要调用不同的工具,使得系统具有高度的灵活性和可扩展性。

随着社区中越来越多的大语言模型支持 Tool Calling 能力,它正在逐步取代传统的 Func Calling,成为主流技术。学习和掌握 Tool Calling 技术对于开发者来说至关重要,它将帮助我们更好地利用大语言模型的强大功能,解决实际问题。

二. 环境准备

在开始之前,请确保你的环境满足以下要求:

三. 功能介绍

  1. 集成 Spring AI 提供基础框架支持:Spring AI 作为对话系统开发的基础框架,提供了丰富的工具和库,帮助开发者快速搭建、训练和部署基于 AI 模型的应用程序,为整个项目提供了坚实的技术支撑。
  2. 集成 Spring AI Alibaba,无缝对接阿里百炼平台:通过 Spring AI Alibaba,我们能够轻松调用阿里百炼平台提供的多种 AI 模型,包括高性能的大模型 DeepSeek-R1 和文本嵌入模型 text-embedding-v2。这些模型为对话系统提供了强大的生成能力和精准的向量表示能力。
  3. 基于 Redis 实现记忆对话功能,并支持多种持久化方案:项目通过 Redis 实现了对话记忆功能,确保对话的连贯性和上下文一致性。同时,我们还提供了基于 Redis 的持久化方案,开发者可以根据需求灵活改造为 MySQL 持久化,或者采用 Redis + MySQL 的混合持久化方案,满足不同场景的需求。
  4. 通过向量模型与 ElasticSearch 实现本地知识库功能(RAG 技术):本项目采用阿里百炼平台提供的 text-embedding-v2 向量模型和 ElasticSearch 数据库,实现了本地知识库功能。通过 RAG 技术,系统能够从知识库中检索相关信息并融入对话生成过程。为了验证 RAG 的功能,我们通过工具生成了一份虚拟的医院介绍(“不爱学习康复医院”),以及 3 个科室介绍(“学不会科”、“学不好科”、“爱学习科”)和 20 位医生的介绍。
  5. Tool Calling:通过串联场景实现复杂任务的自动化:项目通过模拟以下三个场景,展示了 Tool Calling 技术如何串联整个技术栈的能力:
    • 场景 1:通过 RAG 找到医生后,进行挂号
    • 场景 2:挂号当日请假
    • 场景 3:挂号当日在医院附近找饭店

通过以上功能,本项目实现了从基础框架支持到复杂任务自动化的完整技术链条,包括 Spring AI + Spring AI Alibaba 调用阿里百炼平台、DeepSeek-R1 大模型、连续对话(Redis 实现)、RAG(向量模型 + ElasticSearch 实现)以及 Tool Calling(串联复杂场景)。这些技术的结合为开发者提供了一个强大的 AI 应用开发范例。

四. Spring AI 集成:完整代码实现

1. maven的核心依赖

<!-- 全局属性管理 -->
<properties>
    <java.version>23</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!-- 自定义依赖版本 -->
    <spring-boot.version>3.4.4</spring-boot.version>
    <spring-ai.version>1.0.0-M6</spring-ai.version>
    <spring-alibaba.version>1.0.0-M6.1</spring-alibaba.version>
    <maven.compiler.version>3.11.0</maven.compiler.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
        <version>${spring-boot.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>${spring-boot.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-elasticsearch-store-spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter</artifactId>
        <version>${spring-alibaba.version}</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.32</version>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.17.0</version>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>${spring-ai.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- 构建配置 -->
<build>
    <plugins>
        <!-- 编译器插件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven.compiler.version}</version>
            <configuration>
                <release>${java.version}</release>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                        <version>1.18.32</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>

        <!-- Spring Boot打包插件 -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludes>
                    <exclude>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                    </exclude>
                </excludes>
            </configuration>
        </plugin>
    </plugins>
</build>

<!-- 仓库配置 -->
<repositories>
    <repository>
        <id>alimaven</id>
        <name>aliyun maven</name>
        <url>https://maven.aliyun.com/repository/public</url>
    </repository>
    <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>

说明:上述配置文件中,我们引入了Spring Boot、Spring AI、Alibaba Cloud AI等核心依赖,确保项目能够顺利构建和运行。同时,通过配置Maven插件和仓库,优化项目的构建流程和依赖管理。

2. 核心配置(application.yml

这里一定要注意的是文本推理模型 model: deepseek-r1, 嵌入模型model: text-embedding-v2用来生成文本的向量数据

server:
  port: 8080
spring:
  application:
    name: Ollama-AI
  data:
    redis:
      host: 127.0.0.1
      port: 6579
      password: 123123
      database: 1
  elasticsearch:
    uris: http://127.0.0.1:9200
  ai:
    dashscope:
      #      注意这个理是使用阿里云百炼平台的API-KEY
      api-key: sk-*****************
      model: deepseek-r1
      embedding:
        options:
          #      嵌入的向量模型
          model: text-embedding-v2
    vectorstore:
      elasticsearch:
        initialize-schema: true
        index-name: spring-ai-rag
        # 这里一定要注意,维度是默认1536,需要和向量模型的维度一致
        dimensions: 1536
        similarity: cosine
        batching-strategy: TOKEN_COUNT

说明:在配置文件中,我们设置了服务器端口、Redis连接信息、Elasticsearch地址以及AI模型的相关参数。通过这些配置,项目能够正确连接到各个服务,并使用指定的模型进行对话处理和数据存储。

3. 实现连续对话

控制器层(DeepseekChatController.java
@Slf4j
@RestController
@RequestMapping("/ai/v1")
public class DeepseekChatController {

    @Autowired
    private ChatClient chatClient;
    @Autowired
    private VectorStore vectorStore;
    @Autowired
    private ChatMemory chatMemory;


    @GetMapping("/data/load")
    public String loadData() throws IOException {
        // 1. 读取文件
        DocumentReader reader = new TextReader("static/demoHospital.txt");
        List<Document> documents = reader.get();

        // 2.切分文件:根据空白行进行分割
        List<Document> splitDocuments = new TokenTextSplitter().apply(documents);
        log.info("文件切分为 [{}]", splitDocuments.size());

        // 3.写入数据
        vectorStore.add(splitDocuments);

        return "success";
    }

    @GetMapping("/select")
    public String search(@RequestParam("query") String query) {
        log.info("query is  [{}]", query);
        List<Document> results = vectorStore.similaritySearch(
//                SearchRequest.builder().query(query).similarityThreshold(0.1).topK(10).build()
                SearchRequest.builder().query(query).similarityThreshold(0.1).topK(10).build()

        );
        log.info("results is [{}]", results);
        return results.toString();
    }

    @GetMapping(value = "/rag/chat", produces = "text/plain; charset=UTF-8")
    public String ragChat(@RequestParam String userId, @RequestParam String message) {
        log.info("userId -> [{}], message --> [{}]", userId, message);
        String text = chatClient.prompt()
                .user(message)
                .advisors(new MessageChatMemoryAdvisor(chatMemory,userId,100))
                .tools(new OaService(), new RestaurantService(),new HospitalService())
                .call().content();
        return text;
    }
}

说明:该控制器类提供了三个接口,分别用于数据加载、数据检索和连续对话。通过这些接口,用户可以与AI系统进行交互,实现数据的存储、查询和对话功能。其中,/rag/chat接口利用ChatClient和ChatMemory实现了连续对话的核心逻辑。这里提供了3个接口:

数据加载接口(/data/load)

  • 功能:将预准备的文本数据加载到系统中。
  • 流程:读取文本文件,将内容切分成小段,通过嵌入模型转化为向量,存储到向量存储中。
  • 作用:为后续的对话和检索提供数据基础。

数据检索接口(/select)

  • 功能:根据用户输入的查询内容,检索最相关的数据。
  • 流程:将用户查询转化为向量,在向量存储中搜索相似内容,返回相关结果。
  • 作用:快速找到与用户问题最相关的答案。

连续对话接口(/rag/chat)

  • 功能:实现多轮连续对话。

  • 流程:接收用户消息,结合之前的对话历史(通过ChatMemory获取),调用AI模型生成回复。

    • 调用 Spring AI 的 ChatClient
      • chatClient.prompt():创建一个聊天请求的入口。
      • .user(message):将用户的消息传递给 AI 模型。
      • .advisors(new MessageChatMemoryAdvisor(chatMemory, userId, 100))
        • 使用 MessageChatMemoryAdvisor 管理对话记忆。
        • chatMemory 是存储对话上下文的内存对象。userId 是当前用户 ID,用于区分不同用户的对话。100 表示记忆的对话轮次上限,确保对话的连贯性。
    • 工具调用
      • .tools(new OaService(), new RestaurantService(), new HospitalService())
        • 注册三个工具服务:
          • OaService:用于请假相关的操作。
          • RestaurantService:用于搜索医院附近的饭店。
          • HospitalService:用于挂号相关的操作。
        • 这些工具将在对话中根据需要被调用。
    • 执行调用
      • .call().content():执行 AI 模型的调用,并返回生成的文本内容。
    • 返回结果
      • return text;:将生成的文本内容返回给客户端。
  • 作用:让AI能够根据上下文生成连贯的回复。

通过这三个接口,DeepseekChatController实现了从数据加载到检索再到连续对话的完整流程,让AI能够高效地与用户互动。

Redis持久化(ChatRedisMemory.java
@Slf4j
@Component
public class ChatRedisMemory implements ChatMemory {

    private static final String KEY_PREFIX = "chat:history:";
    private final RedisTemplate<String, Object> redisTemplate;

    public ChatRedisMemory(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public void add(String conversationId, List<Message> messages) {
        String key = KEY_PREFIX + conversationId;
        List<ChatEntity> listIn = new ArrayList<>();
        for(Message msg: messages){
            String[] strs = msg.getText().split("</think>");
            String text = strs.length==2?strs[1]:strs[0];

            ChatEntity ent = new ChatEntity();
            ent.setChatId(conversationId);
            ent.setType(msg.getMessageType().getValue());
            ent.setText(text);
            listIn.add(ent);
        }
        redisTemplate.opsForList().rightPushAll(key,listIn.toArray());
        redisTemplate.expire(key, 30, TimeUnit.MINUTES);
    }

    @Override
    public List<Message> get(String conversationId, int lastN) {
        String key = KEY_PREFIX + conversationId;
        Long size = redisTemplate.opsForList().size(key);
        if (size == null || size == 0){
            return Collections.emptyList();
        }

        int start = Math.max(0, (int) (size - lastN));
        List<Object> listTmp = redisTemplate.opsForList().range(key, start, -1);
        List<Message> listOut = new ArrayList<>();
        ObjectMapper objectMapper = new ObjectMapper();
        for(Object obj: listTmp){
            ChatEntity chat =  objectMapper.convertValue(obj, ChatEntity.class);
//            log.info("MessageType.USER [{}], chat.getType [{}]",MessageType.USER, chat.getType());
            if(MessageType.USER.getValue().equals(chat.getType())){
                listOut.add(new UserMessage(chat.getText()));
            }else if(MessageType.ASSISTANT.getValue().equals(chat.getType())){
                listOut.add(new AssistantMessage(chat.getText()));
            }else if(MessageType.SYSTEM.getValue().equals(chat.getType())){
                listOut.add(new SystemMessage(chat.getText()));
            }
        }
        return listOut;
    }

    @Override
    public void clear(String conversationId) {
        redisTemplate.delete(KEY_PREFIX + conversationId);
    }
}

说明:此组件实现了 ChatMemory 接口,利用Redis进行对话历史记录的持久化存储。通过RedisTemplate操作Redis列表,实现了对话记录的添加、获取和清除功能,确保对话上下文能够在多次请求之间保持连贯,从而支持连续对话。

配置类与序列化(RedisConfig.java)
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        //生成整个 RedisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

说明:该配置类用于创建 RedisTemplate Bean,通过设置不同的序列化方式,确保在与Redis进行数据交互时,键和值能够正确地进行序列化和反序列化操作,从而保证数据的完整性和可读性。

实体类(ChatEntity.java)
@NoArgsConstructor
@AllArgsConstructor
@Data
public class ChatEntity implements Serializable {
    String chatId;
    String type;
    String text;
}

说明:这是一个简单的Java实体类,用于表示对话中的每一条消息记录。包含对话ID、消息类型和消息文本三个属性,通过Lombok的注解自动生成构造方法、getter和setter方法,简化了代码编写。

4. 聊天对话的初始化bean

@Configuration
@RequiredArgsConstructor
public class ChatInit {

    private final VectorStore vectorStore;
    @Autowired
    private ChatModel chatModel;

    @Bean
    public ChatClient chatClient(ChatMemory chatMemory) {
        return ChatClient.builder(chatModel)
                // 设置系统的默认行为和风格
                .defaultSystem("你是一个专业的助手,遇到不确定或不明确的信息时,会主动询问用户以获取更多信息。在回答问题时,你倾向于使用条理清晰的格式,例如分点列举的方式,以便用户更容易理解和参考。")
                // 注册向量检索顾问,用于从向量存储中检索相关信息
                .defaultAdvisors(
                    new QuestionAnswerAdvisor(
                        vectorStore, 
                        SearchRequest.builder()
                            .similarityThreshold(0.1) // 设置相似度阈值
                            .topK(10) // 设置返回最多 10 条相关结果
                            .build()
                    )
                )
                .build();
    }

    @Bean
    public ChatMemory chatMemory(RedisTemplate<String, Object> redisTemplate) {
        return new ChatRedisMemory(redisTemplate);
    }
}

说明:

  • 对话初始化:通过 ChatClient 配置对话规则和风格,确保对话的连贯性和一致性;
  • 向量检索:结合 QuestionAnswerAdvisorVectorStore,从向量存储中检索相关信息,提升对话的准确性;
  • 对话记忆:基于 Redis 实现对话记忆,确保对话的上下文一致性。

5. Tool calling 相关服务

医院挂号服务(HospitalService.java

@Slf4j
@Description("医院挂号的功能")
public class HospitalService {

    @Tool(description = "挂号接口,帮患者在线挂号的接口")
    String registeInHos (@ToolParam(description = "医生名称", required = true) String docName,
                            @ToolParam(description = "时间", required = true) String time ,
                           @ToolParam(description = "病情描述", required = false) String desc) {
        String rtn1 = "好的,已经为您挂了【"+docName+"】医生的号,就诊时间【"+time+"】,人数为【"+desc+"】";
        String rtn2 = "抱歉,暂时无法为您挂到医生【"+docName+"】的号,请稍后再试";
        return System.currentTimeMillis() % 4 == 0 ? rtn2 : rtn1;
    }

}

办公OA服务(OaService.java

@Slf4j
@Description("OA相关服务,主要用于假期查询和请假")
public class OaService {

    private static int LEFT_DAYS = 5;
    @Tool(description = "员工剩余假期查询:查询员工还有几天的假期可以请")
    public String getCurrentDateTime() {
        return "目前,你还有 【"+LEFT_DAYS+"】 天的假期可以使用";
    }

    @Tool(description = "员工请假,需要传用户id(userId),和需要请假的天数 (days)")
    String askForLeave(@ToolParam(description = "员工工号") String userId ,@ToolParam(description = "需要请假的天数") String days) {
        if(!StringUtils.isNumeric(days)){
            throw new IllegalArgumentException("days参数必须是数字");
        }
        int dayInt = Integer.parseInt(days);
        String rtn1 = "好的,员工【\"+userId+\"】,已经请假【\"+days+\"】天,请好好享受假期";
        String rtn2 = "你的假期不足,无法请假";
        return dayInt>=LEFT_DAYS?rtn2:rtn1;
    }
}

饭店查询和预定服务(RestaurantService.java

@Slf4j
@Description("饭店查询和预定服务")
public class RestaurantService {

    private static int LEFT_DAYS = 5;
    private static Set<String> RESTAURANT_NAME = Set.of( "红龙餐厅", "金莲小馆", "樱花寿司吧", "丝绸之路餐馆", "意大利小酒馆");

    @Tool(description = "查询不爱学习康复医院附近的饭店,餐厅,吃的,甜品,小吃")
    public String queryRestaurantName(@ToolParam(description = "当前位置", required = true) String location) {
        // 从 RESTAURANT_NAME 中随机选择
        String rtn = RESTAURANT_NAME.stream().skip((int) (Math.random() * RESTAURANT_NAME.size())).limit(3).reduce((a, b) -> a + "," + b).get();
        return "当前位置" + location + ",推荐 restaurantName:" + rtn;
    }

    @Tool(description = "预定餐厅,需要提供饭店名称,时间和人数")
    String bookRestaurant (@ToolParam(description = "饭店名称", required = true) String restName,
                            @ToolParam(description = "订餐时间", required = true) String time ,
                           @ToolParam(description = "就餐人数", required = true) String userNumber) {
        String rtn1 = "好的,已经为您预定了【"+restName+"】,就餐时间为【"+time+"】,人数为【"+userNumber+"】";
        String rtn2 = "抱歉,暂时无法为您预定【"+restName+"】,请稍后再试";
        return System.currentTimeMillis() % 4 == 0 ? rtn2 : rtn1;
    }
}

6. 启动类(ToolCallingApplication.java)

@SpringBootApplication
public class ToolCallingApplication {

	public static void main(String[] args) {
		SpringApplication.run(ToolCallingApplication.class, args);
	}

}

说明: 这是Spring Boot应用的启动类,通过 @SpringBootApplication 注解启用Spring Boot的功能,提高应用的性能和效率。

7. 数据准备

我让kimi帮我生成了一个医院的介绍,包含

  • 医院不爱学习康复医院的介绍,
  • 3个科室的介绍,分别是 学不会科,学不好科,爱学习科
  • 每个科室也有对应的医生信息

文本名称 demoHospital.txt

1. 医院介绍
不爱学习康复医院坐落在风景如画的青云市,是一所独具特色的康复专科医院。医院秉持着“让学习不再成为负担,助力患者重拾学习热情”的理念,专注于帮助各类学习障碍患者恢复学习能力,提升学习信心。自2015年建院以来,医院凭借其专业的医疗团队、先进的康复设备和个性化的治疗方案,赢得了患者和家属的广泛赞誉。
医院占地面积约50亩,建筑面积达8000平方米,拥有300张床位。医院设有学不会科、学不好科和爱学习科等特色科室,配备了智能康复机器人、虚拟现实康复系统等先进设备,为患者提供全面、科学的康复治疗。目前,医院有职工300余人,其中高级职称专家50余名,硕士研究生导师20名。他们不仅在临床工作中积累了丰富的经验,还积极参与科研和教学工作,为康复医学的发展做出了重要贡献。
2. 科室介绍
(1)学不会科:
学不会科是医院的核心科室之一,主要针对那些在学习上有严重障碍的患者,如患有注意力缺陷多动障碍(ADHD)、阅读障碍、数学障碍等。科室配备了一支由心理学家、康复治疗师和教育专家组成的多学科团队,为患者提供全面的评估和个性化的康复治疗方案。他们采用认知行为疗法、感觉统合训练、注意力训练等多种方法,帮助患者逐步克服学习障碍,提升学习能力。此外,学不会科还定期开展家长培训课程,帮助家长更好地理解和支持孩子的康复过程,共同助力患者回归正常学习轨道。
(2)学不好科:
学不好科专注于帮助那些学习能力不足但有潜力提升的患者。这些患者可能没有明显的学习障碍,但在学习过程中遇到诸多困难,如学习方法不当、学习动力不足、情绪管理不佳等。科室采用个性化评估和治疗方案,结合认知行为疗法、情绪管理训练和学习技巧辅导等多种方法,帮助患者改善学习效果。学不好科还设有专门的儿童和青少年康复小组,通过游戏化学习和团队合作,激发患者的学习兴趣和动力。此外,科室与学校紧密合作,为患者提供学习支持和跟踪服务,确保患者在康复过程中能够得到持续的指导和帮助。
(3)爱学习科:
爱学习科是医院的新兴科室,专注于帮助患者建立积极的学习心态和良好的学习习惯。科室采用心理辅导、行为矫正和家庭治疗等多种方法,帮助患者克服学习焦虑和拖延症,培养自主学习能力。爱学习科还设有专门的学习能力提升训练营,通过短期集中训练,帮助患者快速提升学习效率和成绩。此外,科室提供线上学习支持服务,方便患者在家中继续接受康复训练。爱学习科致力于帮助每一位患者重拾学习热情,享受学习的乐趣。

3. 医生介绍
(1)张学明宇
性别:男
出生年月:1985年3月
医生职称:主任医师
所在科室:学不会科
毕业院校:本科毕业于“华山医学学院”,硕士毕业于“峨眉医学研究院”,博士毕业于“少林医学大学”。
介绍:张学明宇教授是学不会科的学科带头人,从事康复医学工作20年。他擅长运用心理学和康复治疗技术,帮助患者克服学习障碍。张教授主持多项省级科研项目,发表学术论文30余篇。他多次受邀参加国内外学术会议,分享临床经验。张教授还积极参与社区康复活动,为患者和家属提供免费咨询和指导。

(2)李梦瑶琪
性别:女
出生年月:1990年7月
医生职称:副主任医师
所在科室:学不好科
毕业院校:本科毕业于“武当医学学院”,硕士毕业于“青城医学研究所”,博士毕业于“昆仑医学大学”。
介绍:李梦瑶琪医生是学不好科的骨干力量,专注于提升患者的认知能力和学习技巧。她熟练掌握多种心理评估工具和康复治疗方法,能够为患者制定个性化的治疗方案。李医生积极参与科室的科研工作,多次获得医院科研奖励。她还多次参与社区义诊活动,普及学习障碍防治知识,为提高公众健康意识做出了积极贡献。

(3)王智勇杰
性别:男
出生年月:1988年2月
医生职称:主治医师
所在科室:爱学习科
毕业院校:本科毕业于“恒山医学院”,硕士毕业于“衡山医学研究所”,博士毕业于“泰山医学大学”。
介绍:王智勇杰医生毕业于多所知名院校,专业基础扎实。他在爱学习科领域积累了丰富的临床经验,尤其擅长帮助患者克服学习焦虑和拖延症。王医生熟练掌握认知行为疗法和情绪管理训练,为患者提供全面的心理支持。他积极参与科室的临床教学工作,为年轻医生传授专业知识和技能。王医生还致力于学习障碍的科普宣传,通过线上线下多种渠道,为患者和公众提供健康咨询和指导。

(4)赵思远航
性别:女
出生年月:1992年11月
医生职称:主治医师
所在科室:学不会科
毕业院校:本科毕业于“华山医学学院”,硕士毕业于“峨眉医学研究院”,博士毕业于“少林医学大学”。
介绍:赵思远航医生是学不会科的优秀青年医生,专注于帮助患者克服学习障碍。她熟练掌握多种心理评估工具和康复治疗方法,能够为患者制定个性化的治疗方案。赵医生积极参与科室的科研工作,发表多篇学术论文。她还多次参与社区义诊活动,普及学习障碍防治知识,为提高公众健康意识做出了积极贡献。

(5)刘宇航宇
性别:男
出生年月:1987年6月
医生职称:副主任医师
所在科室:学不好科
毕业院校:本科毕业于“武当医学学院”,硕士毕业于“青城医学研究所”,博士毕业于“昆仑医学大学”。
介绍:刘宇航宇医生从事康复医学工作15年,积累了丰富的临床经验。他擅长运用认知行为疗法和学习技巧辅导,帮助患者改善学习效果。刘医生积极参与科室的科研工作,主持和参与多项科研项目,发表多篇高质量学术论文。他多次受邀参加国内外学术会议,分享临床经验和研究成果。

(6)陈逸风宇
性别:男
出生年月:1989年9月
医生职称:主治医师
所在科室:爱学习科
毕业院校:本科毕业于“恒山医学院”,硕士毕业于“衡山医学研究所”,博士毕业于“泰山医学大学”。
介绍:陈逸风宇医生是爱学习科的优秀青年医生,专注于帮助患者建立积极的学习心态。他熟练掌握多种心理辅导技术和行为矫正方法,能够为患者提供全面的心理支持。陈医生积极参与科室的科研工作,发表多篇学术论文。他多次参加国际学术交流活动,学习先进的医疗技术和理念,不断提升自己的专业水平。

(7)周雨婷婷
性别:女
出生年月:1991年3月
医生职称:主治医师
所在科室:学不会科
毕业院校:本科毕业于“华山医学学院”,硕士毕业于“峨眉医学研究院”,博士毕业于“少林医学大学”。
介绍:周雨婷婷医生是学不会科的骨干力量,专注于帮助患者克服学习障碍。她熟练掌握多种心理评估工具和康复治疗方法,能够为患者制定个性化的治疗方案。周医生积极参与科室的科研工作,发表多篇学术论文。她多次参与社区义诊活动,普及学习障碍防治知识,为提高公众健康意识做出了积极贡献。

(8)孙悦瑶瑶
性别:女
出生年月:1993年1月
医生职称:住院医师
所在科室:学不好科
毕业院校:本科毕业于“武当医学学院”,硕士毕业于“青城医学研究所”,博士毕业于“昆仑医学大学”。
介绍:孙悦瑶瑶医生是学不好科的新生力量,专业基础扎实。她专注于帮助患者提升学习能力,熟练掌握多种心理评估工具和康复治疗方法。孙医生积极参与科室的科研工作,发表多篇学术论文。她多次参与社区义诊活动,普及学习障碍防治知识,为提高公众健康意识做出了积极贡献。

(9)徐浩然宇
性别:男
出生年月:1986年5月
医生职称:主任医师
所在科室:爱学习科
毕业院校:本科毕业于“恒山医学院”,硕士毕业于“衡山医学研究所”,博士毕业于“泰山医学大学”。
介绍:徐浩然宇教授是爱学习科的资深专家,从事康复医学工作20年。他擅长运用心理辅导和行为矫正技术,帮助患者克服学习焦虑和拖延症。徐教授主持多项省级科研项目,发表学术论文40余篇。他多次受邀参加国内外学术会议,分享临床经验。徐教授还积极参与社区康复活动,为患者和家属提供免费咨询和指导。

(10)林晓梦宇
性别:女
出生年月:1990年7月
医生职称:副主任医师
所在科室:学不会科
毕业院校:本科毕业于“华山医学学院”,硕士毕业于“峨眉医学研究院”,博士毕业于“少林医学大学”。
介绍:林晓梦宇医生是学不会科的骨干力量,专注于帮助患者克服学习障碍。她熟练掌握多种心理评估工具和康复治疗方法,能够为患者制定个性化的治疗方案。林医生积极参与科室的科研工作,发表多篇学术论文。她多次参与社区义诊活动,普及学习障碍防治知识,为提高公众健康意识做出了积极贡献。

(11)张云飞宇
性别:男
出生年月:1988年2月
医生职称:主治医师
所在科室:学不好科
毕业院校:本科毕业于“恒山医学院”,硕士毕业于“衡山医学研究所”,博士毕业于“泰山医学大学”。
介绍:张云飞宇医生毕业于多所知名院校,专业基础扎实。他在学不好科领域积累了丰富的临床经验,尤其擅长帮助患者提升学习能力。张医生熟练掌握多种心理评估工具和康复治疗方法,能够为患者制定个性化的治疗方案。他积极参与科室的科研工作,发表多篇学术论文。张医生还致力于学习障碍的科普宣传,通过线上线下多种渠道,为患者和公众提供健康咨询和指导。

(12)李梦琪琪
性别:女
出生年月:1992年11月
医生职称:主治医师
所在科室:爱学习科
毕业院校:本科毕业于“华山医学学院”,硕士毕业于“峨眉医学研究院”,博士毕业于“少林医学大学”。
介绍:李梦琪琪医生是爱学习科的优秀青年医生,专注于帮助患者建立积极的学习心态。她熟练掌握多种心理辅导技术和行为矫正方法,能够为患者提供全面的心理支持。李医生积极参与科室的科研工作,发表多篇学术论文。她多次参加国际学术交流活动,学习先进的医疗技术和理念,不断提升自己的专业水平。

(13)王浩宇宇
性别:男
出生年月:1987年6月
医生职称:副主任医师
所在科室:学不会科
毕业院校:本科毕业于“武当医学学院”,硕士毕业于“青城医学研究所”,博士毕业于“昆仑医学大学”。
介绍:王浩宇宇医生从事康复医学工作15年,积累了丰富的临床经验。他擅长运用心理评估和康复治疗技术,帮助患者克服学习障碍。王医生积极参与科室的科研工作,主持和参与多项科研项目,发表多篇高质量学术论文。他多次受邀参加国内外学术会议,分享临床经验和研究成果。

(14)陈逸扬宇
性别:男
出生年月:1989年9月
医生职称:主治医师
所在科室:学不好科
毕业院校:本科毕业于“恒山医学院”,硕士毕业于“衡山医学研究所”,博士毕业于“泰山医学大学”。
介绍:陈逸扬宇医生是学不好科的优秀青年医生,专注于帮助患者提升学习能力。他熟练掌握多种心理评估工具和康复治疗方法,能够为患者制定个性化的治疗方案。陈医生积极参与科室的科研工作,发表多篇学术论文。他多次参加国际学术交流活动,学习先进的医疗技术和理念,不断提升自己的专业水平。陈医生还致力于学习障碍的科普宣传,通过线上线下多种渠道,为患者和公众提供健康咨询和指导。

(15)周雨晨宇
性别:女
出生年月:1991年3月
医生职称:主治医师
所在科室:爱学习科
毕业院校:本科毕业于“华山医学学院”,硕士毕业于“峨眉医学研究院”,博士毕业于“少林医学大学”。
介绍:周雨晨宇医生是爱学习科的骨干力量,专注于帮助患者克服学习焦虑和拖延症。她熟练掌握多种心理辅导技术和行为矫正方法,能够为患者提供全面的心理支持。周医生积极参与科室的科研工作,发表多篇学术论文。她多次参与社区义诊活动,普及学习障碍防治知识,为提高公众健康意识做出了积极贡献。周医生还致力于学习障碍的科普宣传,通过线上线下多种渠道,为患者和公众提供健康咨询和指导。

(16)孙悦宁宇
性别:女
出生年月:1993年1月
医生职称:住院医师
所在科室:学不会科
毕业院校:本科毕业于“武当医学学院”,硕士毕业于“青城医学研究所”,博士毕业于“昆仑医学大学”。
介绍:孙悦宁宇医生是学不会科的新生力量,专业基础扎实。她专注于帮助患者克服学习障碍,熟练掌握多种心理评估工具和康复治疗方法。孙医生积极参与科室的科研工作,发表多篇学术论文。她多次参与社区义诊活动,普及学习障碍防治知识,为提高公众健康意识做出了积极贡献。孙医生还致力于学习障碍的科普宣传,通过线上线下多种渠道,为患者和公众提供健康咨询和指导。

(17)徐浩宇航
性别:男
出生年月:1986年5月
医生职称:主任医师
所在科室:学不好科
毕业院校:本科毕业于“恒山医学院”,硕士毕业于“衡山医学研究所”,博士毕业于“泰山医学大学”。
介绍:徐浩宇航教授是学不好科的资深专家,从事康复医学工作20年。他擅长运用心理辅导和行为矫正技术,帮助患者提升学习能力。徐教授主持多项省级科研项目,发表学术论文40余篇。他多次受邀参加国内外学术会议,分享临床经验。徐教授还积极参与社区康复活动,为患者和家属提供免费咨询和指导。

(18)林晓宇航
性别:女
出生年月:1990年7月
医生职称:副主任医师
所在科室:爱学习科
毕业院校:本科毕业于“华山医学学院”,硕士毕业于“峨眉医学研究院”,博士毕业于“少林医学大学”。
介绍:林晓宇航医生是爱学习科的骨干力量,专注于帮助患者建立积极的学习心态。她熟练掌握多种心理辅导技术和行为矫正方法,能够为患者提供全面的心理支持。林医生积极参与科室的科研工作,发表多篇学术论文。她多次参加国际学术交流活动,学习先进的医疗技术和理念,不断提升自己的专业水平。林医生还致力于学习障碍的科普宣传,通过线上线下多种渠道,为患者和公众提供健康咨询和指导。

(19)张云宇航
性别:男
出生年月:1988年2月
医生职称:主治医师
所在科室:学不会科
毕业院校:本科毕业于“恒山医学院”,硕士毕业于“衡山医学研究所”,博士毕业于“泰山医学大学”。
介绍:张云宇航医生毕业于多所知名院校,专业基础扎实。他在学不会科领域积累了丰富的临床经验,尤其擅长帮助患者克服学习障碍。张医生熟练掌握多种心理评估工具和康复治疗方法,能够为患者制定个性化的治疗方案。他积极参与科室的科研工作,发表多篇学术论文。张医生还致力于学习障碍的科普宣传,通过线上线下多种渠道,为患者和公众提供健康咨询和指导。

(20)李梦宇航
性别:女
出生年月:1992年11月
医生职称:主治医师
所在科室:学不好科
毕业院校:本科毕业于“华山医学学院”,硕士毕业于“峨眉医学研究院”,博士毕业于“少林医学大学”。
介绍:李梦宇航医生是学不好科的优秀青年医生,专注于帮助患者提升学习能力。她熟练掌握多种心理评估工具和康复治疗方法,能够为患者制定个性化的治疗方案。李医生积极参与科室的科研工作,发表多篇学术论文。她多次参与社区义诊活动,普及学习障碍防治知识,为提高公众健康意识做出了积极贡献。李医生还致力于学习障碍的科普宣传,通过线上线下多种渠道,为患者和公众提供健康咨询和指导。

五. 测试与验证

环境启动

确保docker部署的redis和ollama服务都正常运行,通过 docker ps查看
在这里插入图片描述
如果没有的话, 可以 通过docker start redis, docker start elasticsearch来启动

Spring 服务启动后,我们看看效果吧

我们Spring 项目中,开放了3个接口

数据写入的接口
http://127.0.0.1:8080/ai/v1/data/load
获取数据向量的接口
http://127.0.0.1:8080/ai/v1/select
连读对话的接口
http://127.0.0.1:8080/ai/v1/rag/chat
数据写入
数据写入的接口
http://127.0.0.1:8080/ai/v1/data/load

我们查看elastic中,存入了12条数据,也就证明我们接口把文件切分成了12个文件
在这里插入图片描述
在这里插入图片描述

数据查询

那我们用第二个接口检索一下数据吧

获取数据向量的接口
http://127.0.0.1:8080/ai/v1/select?query=不爱学习康复医院

在这里插入图片描述
看样子数据都已经存入,可以通过elasticsearch 搜索到医院信息,也就是这些信息会通过聊天接口上传给deepseek

RAG+ Tool Calling 调用验证

那我们用第三个接口来验证下核心功能吧

连读对话的接口
http://127.0.0.1:8080/ai/v1/rag/chat

以下是重新设计的一组问题,用于验证系统功能:

问题1:请介绍一下不爱学习康复医院的基本情况,包括医院的特色和主要科室

问题2:这个医院的学不好科有好大夫

问题3:帮我挂一下刘宇航宇医生2025年6月3日上午的号

问题4:请帮我查询一下我目前还剩下多少天年假

问题5:麻烦帮我请一天假,就是看病那天,原因是看病,我的工号是2025

问题6:不爱学习康复医院附近有什么适合病人食用的好饭店

问题7:帮我预定一家医院附近的丝绸之路餐馆饭店,时间是看病那天中午12点半

通过以上问题,可以全面验证系统的 RAG 检索能力、Tool Calling 功能以及对话连贯性和上下文管理能力。那我们看一下接口调用的结果吧
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

六. 补充点内容

通过本文介绍的步骤,你已经能够利用 Spring AISpring AI AlibabaDeepSeekRAG 等技术,结合阿里云百炼平台的强大能力,以及 Tool Calling 技术,搭建出一个支持连续对话的 AI 应用。这种技术组合的优势在于能够高效地处理对话中的信息检索与生成任务,同时通过 Tool Calling 实现复杂任务的自动化,从而提升对话系统的性能和用户体验。

在实际应用中,这种技术架构可以为企业知识库、教育问答系统、智能客服等场景提供有力支持。例如:

  • 企业知识库:快速构建内部知识问答平台,帮助员工快速获取所需信息。
  • 教育问答系统:开发智能辅导系统,为学生提供个性化的学习指导。
  • 智能客服:利用 Tool Calling 调用外部工具,实现复杂任务的自动化处理,提升响应效率,优化客户体验。

本文不仅记录了我学习 Spring AI 的过程,同时也希望能让在迷茫中的你能在 AI 应用开发中快速上手并探索更多可能性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值