找回密码
 注册

微信登录

微信扫一扫,快速登录

查看: 256|回复: 0

AI 项目实战:AI 智能体实现智能预约挂号

[复制链接]
发表于 2025-7-10 21:49 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册 微信登录

×
作者:微信文章

说明:该实战项目是基于前面几篇文章的基础下进行的,一些基础知识不懂可以看看前面几篇AI相关的文章。

其中比较核心的,一个是记忆聊天,二个是Aiservice使用,三个是Tool的使用

其中涉及到Tool的使用中,提示模版的章节未补充,后面慢慢完善~~
一、新建数据库和表

CREATE TABLE `appointment` (  `id` bigint(20) NOT NULL AUTO_INCREMENT,  `username` varchar(50) NOT NULL,  `id_card` varchar(18) NOT NULL,  `department` varchar(50) NOT NULL,  `date` varchar(10) NOT NULL,  `time` varchar(10) NOT NULL,  `doctor_name` varchar(50) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
二、添加POM依赖

<mybatis-plus.version>3.5.11</mybatis-plus.version><!-- Mysql Connector --><dependency>    <groupId>com.mysql</groupId>    <artifactId>mysql-connector-j</artifactId></dependency><!--mybatis-plus 持久层--><dependency>    <groupId>com.baomidou</groupId>    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>    <version>${mybatis-plus.version}</version></dependency>        三、配置文件

spring:  data:    mongodb:      uri: mongodb://admin:123456@192.168.10.109:27017/chat_memory_db?authSource=admin  datasource:    url: jdbc:mysql://192.168.10.109:3306/xuewei?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false    driver-class-name: com.mysql.cj.jdbc.Driver    username: root    password: rootmybatis-plus:  configuration:    log-impl: org.apache.ibatis.logging.stdout.StdOutImpllangchain4j:  open-ai:    chat-model:      # api-key: demo      # base-url: http://langchain4j.dev/demo/openai/v1      # model-name: gpt-4o-mini
      # deepseek      #base-url: https://api.deepseek.com      #api-key: sk-851e968414c947c6be86427b1014xxxx      #model-name: deepseek-chat      #model-name: =deepseek-reasoner
      # 阿里白练通义千问      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1      api-key: sk-09c7b571687b46d5a2e25a03fbddxxxx      model-name: deepseek-v3      log-requests: true      log-responses: true  # 阿里白练通义千问  community:    dashscope:      chat-model:        api-key: sk-09c7b571687b46d5a2e25a03fbddxxxx        model-name: qwen-maxlogging:  level:    root: info四、MP代码生成

1.entity

package com.zhan.chat.entity;
import com.baomidou.mybatisplus.annotation.IdType;import com.baomidou.mybatisplus.annotation.TableId;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;
/** * @author zhanxuewei */@Data@AllArgsConstructor@NoArgsConstructorpublic class Appointment {    @TableId(type = IdType.AUTO)    private Long id;    private String username;    private String idCard;    private String department;    private String date;    private String time;    private String doctorName;}2.mapper

package com.zhan.chat.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.zhan.chat.entity.Appointment;import org.apache.ibatis.annotations.Mapper;
@Mapperpublic interface AppointmentMapper extends BaseMapper<Appointment> {}3.service

package com.zhan.chat.service;
import com.baomidou.mybatisplus.extension.service.IService;import com.zhan.chat.entity.Appointment;
/** * @author zhanxuewei */public interface AppointmentService extends IService<Appointment> {
    Appointment getOne(Appointment appointment);
}package com.zhan.chat.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.zhan.chat.entity.Appointment;import com.zhan.chat.mapper.AppointmentMapper;import com.zhan.chat.service.AppointmentService;import org.springframework.stereotype.Service;
/** * @author zhanxuewei */@Servicepublic class AppointmentServiceImpl extends ServiceImpl<AppointmentMapper, Appointment> implements AppointmentService {    @Override    public Appointment getOne(Appointment appointment) {        return baseMapper.selectOne(new LambdaQueryWrapper<Appointment>()                .eq(Appointment::getUsername, appointment.getUsername())                .eq(Appointment::getIdCard, appointment.getIdCard())                .eq(Appointment::getDepartment, appointment.getDepartment())                .eq(Appointment::getDate, appointment.getDate())                .eq(Appointment::getTime, appointment.getTime()));    }}

4.controller

package com.zhan.chat.controller;
import com.zhan.chat.assistant.XueweiAgent;import com.zhan.chat.bean.ChatForm;import io.swagger.v3.oas.annotations.Operation;import io.swagger.v3.oas.annotations.tags.Tag;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;
@Tag(name = "智能医生助手")@RestController@RequestMapping("/doctor/assistant")public class XueweiController {
    @Autowired    private XueweiAgent xueweiAgent;
    @Operation(summary = "对话")    @PostMapping("/chat")    public String chat(@RequestBody ChatForm chatForm) {        return xueweiAgent.chat(chatForm.getMemoryId(), chatForm.getMessage());    }}

五、测试CRUD

package com.zhan.chat;
import com.zhan.chat.entity.Appointment;import com.zhan.chat.service.AppointmentService;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTestpublic class AppointmentServiceTest {
    @Autowired    private AppointmentService appointmentService;
    @Test    void testGetOne() {        Appointment appointment = new Appointment();        appointment.setUsername("张三");        appointment.setIdCard("123456789012345678");        appointment.setDepartment("内科");        appointment.setDate("2025-06-07");        appointment.setTime("上午");        Appointment appointmentDB = appointmentService.getOne(appointment);        System.out.println(appointmentDB);    }
    @Test    void testSave() {        Appointment appointment = new Appointment();        appointment.setUsername("张三");        appointment.setIdCard("123456789012345678");        appointment.setDepartment("内科");        appointment.setDate("2025-06-07");        appointment.setTime("上午");        appointment.setDoctorName("詹医生");        appointmentService.save(appointment);    }
    @Test    void testRemoveById() {        appointmentService.removeById(1L);    }}
六、编写智能体

package com.zhan.chat.assistant;
import dev.langchain4j.service.MemoryId;import dev.langchain4j.service.SystemMessage;import dev.langchain4j.service.UserMessage;import dev.langchain4j.service.spring.AiService;import dev.langchain4j.service.spring.AiServiceWiringMode;
/** * @author zhanxuewei */@AiService(        wiringMode = AiServiceWiringMode.EXPLICIT,        chatModel = "qwenChatModel",        chatMemory = "chatMemory",        chatMemoryProvider = "chatMemoryProviderXuewei", tools = "appointmentTools")public interface XueweiAgent {
    @SystemMessage(fromResource = "xuewei-prompt-template.txt")    String chat(@MemoryId Long memoryId, @UserMessage String userMessage);}
消息模版:
w1.jpg

七、编写ChatMemoryProvider

package com.zhan.chat.config;
import com.zhan.chat.store.MongoChatMemoryStore;import dev.langchain4j.memory.chat.ChatMemoryProvider;import dev.langchain4j.memory.chat.MessageWindowChatMemory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;
/** * @author zhanxuewei */@Configurationpublic class XueweiAgentConfig {
    @Autowired    private MongoChatMemoryStore mongoChatMemoryStore;
    @Bean    ChatMemoryProvider chatMemoryProviderXuewei() {        return memoryId -> MessageWindowChatMemory.builder()                .id(memoryId)                .maxMessages(20)                .chatMemoryStore(mongoChatMemoryStore)                .build();    }}
八、编写AppointmentTools

package com.zhan.chat.tools;
import com.zhan.chat.entity.Appointment;import com.zhan.chat.service.AppointmentService;import dev.langchain4j.agent.tool.P;import dev.langchain4j.agent.tool.Tool;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;
/** * @author zhanxuewei */@Componentpublic class AppointmentTools {
    @Autowired    private AppointmentService appointmentService;
    @Tool(name = "预约挂号", value = "根据参数,先执行工具方法queryDepartment查询是否可预约,并直 接给用户回答是否可预约,并让用户确认所有预约信息,用户确认后再进行预约。")    public String bookAppointment(Appointment appointment) {        //查找数据库中是否包含对应的预约记录        Appointment existAppointment = appointmentService.getOne(appointment);        if (existAppointment == null) {            appointment.setId(null);            if (appointmentService.save(appointment)) {                return "预约成功,并返回预约详情";            } else {                return "预约失败";            }        }        return "您在相同的科室和时间已有预约";    }
    @Tool(name = "取消预约挂号", value = "根据参数,查询预约是否存在,如果存在则删除预约记录并返回取 消预约成功,否则返回取消预约失败")    public String cancelAppointment(Appointment appointment) {        Appointment one = appointmentService.getOne(appointment);        if (one != null) {            //删除预约记录            if (appointmentService.removeById(one.getId())) {                return "取消预约成功";            } else {                return "取消预约失败";            }        }        //取消失败        return "您没有预约记录,请核对预约科室和时间";    }

    @Tool(name = "查询是否有号源", value = "根据科室名称,日期,时间和医生查询是否有号源,并返回给用户")    public boolean queryDepartment(@P(value = "科室名称") String name, @P(value = "日期") String date, @P(value = "时间,可选值:上午、下午") String time, @P(value = "医生名称", required = false) String doctorName) {        System.out.println("查询是否有号源");        System.out.println("科室名称:" + name);        System.out.println("日期:" + date);        System.out.println("时间:" + time);        System.out.println("医生名称:" + doctorName);        //TODO 维护医生的排班信息:        //如果没有指定医生名字,则根据其他条件查询是否有可以预约的医生(有返回true,否则返回false;        //如果指定了医生名字,则判断医生是否有排班(没有排版返回false)        //如果有排班,则判断医生排班时间段是否已约满(约满返回false,有空闲时间返回true)        return true;    }}

九、测试智能挂号

第一轮对话:

w2.jpg

第二轮对话:

w3.jpg

第三轮对话:

w4.jpg

第四轮对话:

w5.jpg

第五轮对话:

w6.jpg

第六轮对话:

w7.jpg



十、结果

六轮对话完成后,挂号成功,看数据库:

w8.jpg
Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
您需要登录后才可以回帖 登录 | 注册 微信登录

本版积分规则

Archiver|手机版|AGB|Impressum|Datenschutzerklärung|萍聚社区-德国热线-德国实用信息网

GMT+2, 2025-10-12 01:39 , Processed in 0.127919 second(s), 31 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表