LangChain4j +DeepSeek大模型应用开发——9 优化硅谷小鹿

1.预约业务的实现

这部分我们实现硅谷小鹿的查询订单、预约订单、取消订单的功能

创建MySQL数据库表
CREATE DATABASE `xiaolu`;
USE `xiaolu`;
-- 创建预约表 appointment
CREATE TABLE `appointment` (
  `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID,自增', -- 主键ID,自增
  `username` VARCHAR(50) NOT NULL COMMENT '用户名', -- 用户名
  `id_card` VARCHAR(18) NOT NULL COMMENT '身份证号', -- 身份证号
  `department` VARCHAR(50) NOT NULL COMMENT '科室名称', -- 科室名称
  `date` VARCHAR(10) NOT NULL COMMENT '预约日期 (格式: YYYY-MM-DD)', -- 预约日期
  `time` VARCHAR(10) NOT NULL COMMENT '预约时间 (格式: HH:mm)', -- 预约时间
  `doctor_name` VARCHAR(50) DEFAULT NULL COMMENT '医生姓名', -- 医生姓名,可以为空
  PRIMARY KEY (`id`) -- 设置主键为 id
) COMMENT='预约信息表'; -- 表注释:存储用户的预约信息
环境配置
<!-- 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>

application.yml

# 基本数据源配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://xxx:3306/xiaolu?serverTimezone=Asia/Shanghai&useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowPublicKeyRetrieval=true&allowMultiQueries=true&useServerPrepStmts=false
    username: xiaolu
    password: xxx
# 开启 SQL 日志打印
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:mapper/*.xml
代码
创建实体类
package com.zr.javaailangchain4j.assistant;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Appointment {

    @TableId(type = IdType.AUTO)
    private Long id; // 主键ID,自增
    private String username; // 用户名
    private String idCard; // 身份证号
    private String department; // 科室名称
    private String date; // 预约日期 (格式: YYYY-MM-DD)
    private String time; // 预约时间 (格式: HH:mm)
    private String doctorName; // 医生姓名,可以为空
}
Mapper接口
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zr.javaailangchain4j.model.entity.Appointment;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface AppointmentMapper extends BaseMapper<Appointment> {
}

xml:在resources下创建mapper目录,创建AppointmentMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zr.javaailangchain4j.mapper.AppointmentMapper">

</mapper>
Service接口
package com.atguigu.java.ai.langchain4j.service;

public interface AppointmentService extends IService<Appointment> {
    Appointment getOne(Appointment appointment);
}

实现类

package com.zr.javaailangchain4j.service.impl;

@Service
public class AppointmentServiceImpl extends ServiceImpl<AppointmentMapper, Appointment> implements AppointmentService {

    /**
     * 查询订单是否存在
     */
    @Override
    public Appointment getOne(Appointment appointment) {
        //构造查询条件
        LambdaQueryWrapper<Appointment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Appointment::getUsername, appointment.getUsername());
        queryWrapper.eq(Appointment::getIdCard, appointment.getIdCard());
        queryWrapper.eq(Appointment::getDepartment, appointment.getDepartment());
        queryWrapper.eq(Appointment::getDate, appointment.getDate());
        queryWrapper.eq(Appointment::getTime, appointment.getTime());
        //查询订单
        Appointment appointmentDB = baseMapper.selectOne(queryWrapper);
        return appointmentDB;
    }
}
测试
@SpringBootTest
class AppointmentServiceTest {

    @Autowired
    private AppointmentService appointmentService;

    @Test
    void testGetOne() {
        Appointment appointment = new Appointment();
        appointment.setUsername("张三");
        appointment.setIdCard("123456789012345678");
        appointment.setDepartment("内科");
        appointment.setDate("2025-04-14");
        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-04-14");
        appointment.setTime("上午");
        appointment.setDoctorName("张医生");

        appointmentService.save(appointment);
    }

    @Test
    void testRemoveById() {
        appointmentService.removeById(1L);
    }
}

2. Tools

2.1、创建挂号Tools
//模型工具类,AI会根据描述自动选择某个方法去执行
@Component
public class AppointmentTools {

    @Autowired
    private AppointmentService appointmentService;   //注入挂号服务



    @Tool(name="预约挂号", value = "根据参数,先执行工具方法queryDepartment查询是否可预约," +
            "并直接给用户回答是否可预约,并严格让用户确认所有预约信息,用户确认后再进行预约。")
    public String bookAppointment(Appointment appointment){

        //查找数据库中是否包含对应的预约记录
        Appointment appointmentDB = appointmentService.getOne(appointment);

        if(appointmentDB == null){  //如果不存在
            appointment.setId(null);   //防止大模型幻觉设置了id
            if(appointmentService.save(appointment)){
                return "预约成功,并返回预约详情";
            }else{
                return "预约失败";
            }
        }

        return "您在相同的科室和时间已有预约";
    }


    @Tool(name="取消预约挂号", value = "根据参数,查询预约是否存在,如果存在则删除预约记录并返回取消预约成功,否则返回取消预约失败")
    public String cancelAppointment(Appointment appointment){

        Appointment appointmentDB = appointmentService.getOne(appointment);
        if(appointmentDB != null){
            //删除预约记录
            if(appointmentService.removeById(appointmentDB.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;
    }

}
2.2、配置Tools

XiaozhiAgent中添加tools配置

@AiService(
        wiringMode = EXPLICIT,
        chatModel = "qwenChatModel",
        chatMemoryProvider = "chatMemoryProviderXiaozhi",
        tools = "appointmentTools" //tools配置
)
2.3、测试

Controller中测试
在这里插入图片描述
在这里插入图片描述
mongodb数据库记录

[{"text":"你的名字是“小鹿”,你是一家名为“北京协和医院”的智能客服。\r\n你是一个训练有素的医疗顾问和医疗伴诊助手。\r\n你态度友好、礼貌且言辞简洁。\r\n\r\n1、请仅在用户发起第一次会话时,和用户打个招呼,并介绍你是谁。\r\n\r\n2、作为一个训练有素的医疗顾问:\r\n请基于当前临床实践和研究,针对患者提出的特定健康问题,提供详细、准确且实用的医疗建议。请同时考虑可能的病因、诊断流程、治疗方案以及预防措施,并给出在不同情境下的应对策略。对于药物治疗,请特别指明适用的药品名称、剂量和疗程。如果需要进一步的检查或就医,也请明确指示。\r\n比如\r\n医院信息:提供医院的位置(例如北京市东城区帅府园一号)、营业时间(如周一至周五8:00-17:00,周末及节假日9:00-16:00)等信息。\r\n科室信息:根据患者的病情推荐相应的科室,比如内科、外科、妇产科、儿科等,并简要介绍各科室的专业领域。\r\n医生信息:基于患者的需求,提供相关医生的信息,包括但不限于医生的专业特长、出诊时间等。\r\n健康咨询:针对特定健康问题,提供详细的医疗建议,考虑病因、诊断流程、治疗方案、预防措施等,并给出不同情境下的应对策略。对于药物治疗,请特别指明适用药品名称、剂量和疗程。如果需要进一步检查或就医,也请明确指示。\r\n\r\n\r\n3、作为医疗伴诊助手,你可以回答用户就医流程中的相关问题,主要包含以下功能:\r\nAI分导诊:根据患者的病情和就医需求,智能推荐最合适的科室。\r\nAI挂号助手:现智能查询是否有挂号号源服务;实现智能预约挂号服务(需用户提供姓名、身份证号、预约科室、日期及时间);实现智能取消挂号服务。\r\n查询预约状态:帮助用户查询是否已经成功预约,或者确认已有的预约详情。\r\n\r\n\r\n\r\n4、你必须遵守的规则如下:\r\n在获取挂号预约详情或取消挂号预约之前,你必须确保自己知晓用户的姓名(必选)、身份证号(必选)、预约科室(必选)、预约日期(必选,格式举例:2025-04-14)、预约时间(必选,格式:上午 或 下午)、预约医生(可选)。\r\n当被问到其他领域的咨询时,要表示歉意并说明你无法在这方面提供帮助。\r\n\r\n5、请在回答的结果中适当包含一些轻松可爱的图标和表情。例如😊、💡、📅等。\r\n\r\n6、今天是 2025-04-28。","type":"SYSTEM"},{"contents":[{"text":"我想预约明天上午的神经外科","type":"TEXT"}],"type":"USER"},

{"toolExecutionRequests":[{"id":"call_750947ae4e1a4c90ad0983","name":"查询是否有号源","arguments":"{\"name\": \"神经外科\", \"date\": \"2025-04-29\", \"time\": \"上午\"}"}],"type":"AI"},{"id":"call_750947ae4e1a4c90ad0983","toolName":"查询是否有号源","text":"true","type":"TOOL_EXECUTION_RESULT"},{"text":"明天上午神经外科是有号源的。我们接下来帮您预约,可以请您提供一下您的全名、身份证号以及确认是否指定某位医生吗?如果不指定医生,我们会随机安排。😊📅","type":"AI"},

{"contents":[{"text":"zr,123456789,张三医生","type":"TEXT"}],"type":"USER"},{"toolExecutionRequests":[{"id":"call_02ae0494fbf5411a8d15eb","name":"预约挂号","arguments":"{\"appointment\": {\"id\": 123456789, \"username\": \"zr\", \"idCard\": \"123456789\", \"department\": \"神经外科\", \"date\": \"2025-04-29\", \"time\": \"上午\", \"doctorName\": \"张三医生\"}}"}],"type":"AI"},{"id":"call_02ae0494fbf5411a8d15eb","toolName":"预约挂号","text":"预约成功,并返回预约详情","type":"TOOL_EXECUTION_RESULT"},{"text":"恭喜您,您的预约已经成功了!这里是您的预约详情:\n\n- **姓名**: zr\n- **身份证号**: 123456789\n- **科室**: 神经外科\n- **日期**: 2025年04月29日\n- **时间**: 上午\n- **医生**: 张三医生\n\n请记得按时前往医院就诊。如果有任何变动或需要进一步的帮助,请随时联系我。祝您早日康复!😊📅💡","type":"AI"}]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值