一、工作内容描述:
1. 动态问诊模式触发
详情: 通过调用大模型来判断用户输入是否涉及医疗询问,动态触发问诊模式。如果用户的输入涉及医疗问题,系统进入问诊模式,开始一系列的交互问题收集病人信息。
创新点: 这种动态触发机制使得系统能够智能区分一般咨询和医疗咨询,从而切换不同的处理逻辑,提高交互的智能性和针对性。
2. 多步问诊流程
详情: 在问诊模式下,系统会根据预设的问题逐步引导用户提供详细的病人信息,包括个人基本信息、症状、发作细节、生活方式、病史、过敏药物和正在使用的药物等。
创新点: 逐步引导的问诊流程模拟了医生的诊断过程,系统性地收集全面的病人信息,有助于生成更加准确和有针对性的建议。
3. 问诊模式的信息保存与整合
详情: 在每一步用户回答之后,系统会将信息保存到一个PatientInfo
对象中,并在最后一步整合所有信息用于生成最终的诊断建议。
创新点: 将多次交互的信息统一保存和整合,模拟了实际医疗问诊中的信息记录过程,确保所有病人信息能够被综合考虑。
4. 生成模型的调用和结果处理
详情: 利用大模型的生成能力,通过API调用生成响应,包括判断是否为医疗查询和生成问诊过程中的对话内容。
创新点: 结合生成模型的能力,系统不仅能够理解和处理复杂的自然语言输入,还能根据输入生成专业和上下文相关的输出,提高系统的智能化程度。
5. 灵活的问答模式
详情: 系统不仅能够进行一般的问答(通过直接调用大模型),还能够在特定情况下进入问诊模式,灵活应对不同类型的用户需求。
创新点: 这种灵活的模式使得系统不仅可以作为一个通用的问答助手,还可以在医疗领域发挥专业作用,拓展了应用场景。
整体而言
这个系统通过动态触发问诊模式、多步问诊流程、信息保存与整合、生成模型调用和灵活的问答模式,创新性地实现了一个智能问诊服务,能够智能地识别和处理医疗相关的用户询问,并给出专业的诊断建议。
二、具体实现代码:
1. 记录和整合病人具体信息类的具体实现:
private static class PatientInfo {
private String firstQuery;//第一次询问信息
private String personalInfo;//个人基本信息,如年龄、性别、身高、体重
private String symptoms;//症状
private String episodeDetails;//病情发作相关细节,如发作时间,持续时间,发作频率
private String lifestyleFactors;//表示生活方式因素,包括饮食、运动、睡眠等
private String medicalHistory;//病史
private String allergicDrugs;//过敏药物
private String usingDrugs;//正在使用的药物
@Override
public String toString() {
return "病人信息{" +
"病人第一次询问为:'" + firstQuery + '\'' +//第一次询问信息
", 一般信息:'" + personalInfo + '\'' +//个人基本信息,如年龄、性别、身高、体重
", 症状:'" + symptoms + '\'' +//症状
", 发作细节:'" + episodeDetails + '\'' +//病情发作相关细节,如发作时间,持续时间,发作频率
", 生活方式:'" + lifestyleFactors + '\'' +//表示生活方式因素,包括饮食、运动、睡眠等
", 病史:'" + medicalHistory + '\'' +//病史
", 过敏药物:'" + allergicDrugs + '\'' +//过敏药物
", 正在使用的药物:'" + usingDrugs + '\'' +//正在使用的药物
'}';
}
public void setLifestyleFactors(String lifestyleFactors) {
this.lifestyleFactors = lifestyleFactors;
}
public void setUsingDrugs(String usingDrugs) {
this.usingDrugs = usingDrugs;
}
public void setAllergicDrugs(String allergicDrugs) {
this.allergicDrugs = allergicDrugs;
}
public void setMedicalHistory(String medicalHistory) {
this.medicalHistory = medicalHistory;
}
public void setEpisodeDetails(String episodeDetails) {
this.episodeDetails = episodeDetails;
}
public void setSymptoms(String symptoms) {
this.symptoms = symptoms;
}
public void setPersonalInfo(String personalInfo) {
this.personalInfo = personalInfo;
}
public void setFirstQuery(String firstQuery) {
this.firstQuery = firstQuery;
}
}
2. 调用大模型的接口来判断用户的问题是否应该进入问诊模式收集用户病情信息。
//通过调用大模型来判断用户是否正在咨询自身病情。
public static boolean isMedicalQuery(String queryMessage) throws NoApiKeyException, InputRequiredException {
Generation gen = new Generation();
MessageManager msgManager = new MessageManager(10);
Message systemMsg =
Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.下面的问题只能回答一个0~1之间的小数,其余内容都不用回答").build();
Message userMsg = Message.builder().role(Role.USER.getValue()).content(queryMessage+",请你根据用户的询问给出用户此时身体不舒服的概率(0~1之间的小数),依据是出现疾病之类的词,只需要返回一个小数就行").build();
msgManager.add(systemMsg);
msgManager.add(userMsg);
QwenParam param =
QwenParam.builder().model(Generation.Models.QWEN_TURBO).messages(msgManager.get())
.resultFormat(QwenParam.ResultFormat.MESSAGE)
.build();
GenerationResult result = gen.call(param);
System.out.println("获取概率内容"+result.getOutput().getChoices().get(0).getMessage().getContent());
float probability= Float.parseFloat(result.getOutput().getChoices().get(0).getMessage().getContent());
System.out.println("概率"+probability);
return probability > 0.84;
}
3. 多步问诊收集信息流程实现
private String getNextQueryMessage() {
queryStep++;
switch (queryStep) {
case 1:
return "请提供您的个人基本信息,包括年龄、性别、身高和体重。";
case 2:
return "您目前有哪些症状?请详细描述。";
case 3:
return "请描述病情发作的相关细节,如发作时间、持续时间和发作频率。";
case 4:
return "您的生活方式因素如何?包括饮食、运动、睡眠等方面。";
case 5:
return "请描述您的病史,包括曾经患过的疾病、手术史等。";
case 6:
return "您是否对某些药物过敏?如果有,请提供过敏药物的信息。";
case 7:
return "您目前正在使用哪些药物?请提供正在使用的药物清单。";
default:
break;
}
return null;
}
private void savePatientInfo(String queryMessage) {
switch (queryStep) {
case 0:
patientInfo.setFirstQuery(queryMessage);// 第一次询问信息
break;
case 1:
patientInfo.setPersonalInfo(queryMessage);// 个人基本信息,如年龄、性别、身高、体重
break;
case 2:
patientInfo.setSymptoms(queryMessage);// 症状
break;
case 3:
patientInfo.setEpisodeDetails(queryMessage);// 病情发作相关细节,如发作时间,持续时间,发作频率
break;
case 4:
patientInfo.setLifestyleFactors(queryMessage);// 生活方式因素,包括饮食、运动、睡眠等
break;
case 5:
patientInfo.setMedicalHistory(queryMessage);// 病史
break;
case 6:
patientInfo.setAllergicDrugs(queryMessage);// 过敏药物
break;
case 7:
queryStep++;
patientInfo.setUsingDrugs(queryMessage);// 正在使用的药物
break;
}
}
4. 全部实现代码:
package com.SmartMed_Connect.service;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationOutput;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.aigc.generation.models.QwenParam;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.MessageManager;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.Constants;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class ApiService {
static {
// 设置 API key
com.alibaba.dashscope.utils.Constants.apiKey = "sk-******************************";
}
private final List<Message> messages = new ArrayList<>();
private int queryStep = 0;
private PatientInfo patientInfo = new PatientInfo();
private boolean isTriggering=false;
public String query(String queryMessage) {
try {
if(messages.isEmpty())
{
messages.add(createMessage(Role.SYSTEM, "你是一名智能医生,请结合上下文,回答病人的问题,不许回答其他问题。"));
}
if(!isTriggering)//如果当前不在问诊模式
{
isTriggering=isMedicalQuery(queryMessage);//判断用户的问题是否触发问诊模式
if(isTriggering)//如果用户的问题会触发问诊模式,调用触发问诊模式第一步询问
{
System.out.println("触发问诊模式");
patientInfo= new PatientInfo();
savePatientInfo(queryMessage);
String response = getNextQueryMessage();
return response;
}
else//否则,使用通义千问的一般问答模式
{
messages.add(createMessage(Role.USER, queryMessage));
GenerationParam param = createGenerationParam(messages);
GenerationResult result = callGenerationWithMessages(param);
messages.add(result.getOutput().getChoices().get(0).getMessage());
GenerationOutput output = result.getOutput();
return output.getChoices().get(0).getMessage().getContent();
}
}
else //已经进入问诊模式了
{
if(queryStep==7)
{
savePatientInfo(queryMessage);//保存用户最后一次回答
isTriggering=false;
queryStep=0;
messages.add(createMessage(Role.USER, patientInfo.toString()+"请你根据病人信息给出建议"));
GenerationParam param = createGenerationParam(messages);
GenerationResult result = callGenerationWithMessages(param);
messages.add(result.getOutput().getChoices().get(0).getMessage());
GenerationOutput output = result.getOutput();
printMessages();
return output.getChoices().get(0).getMessage().getContent();
}
savePatientInfo(queryMessage);//保存上一次提问的用户回答
String response = getNextQueryMessage();//获得AI下一次的问题
return response;
}
} catch (Exception e) {
return "发生错误,请稍后再试。";
}
}
public void printMessages() {
for (Message message : messages) {
System.out.println("Role: " + message.getRole() + ", Content: " + message.getContent());
}
}
private String getNextQueryMessage() {
queryStep++;
switch (queryStep) {
case 1:
return "请提供您的个人基本信息,包括年龄、性别、身高和体重。";
case 2:
return "您目前有哪些症状?请详细描述。";
case 3:
return "请描述病情发作的相关细节,如发作时间、持续时间和发作频率。";
case 4:
return "您的生活方式因素如何?包括饮食、运动、睡眠等方面。";
case 5:
return "请描述您的病史,包括曾经患过的疾病、手术史等。";
case 6:
return "您是否对某些药物过敏?如果有,请提供过敏药物的信息。";
case 7:
return "您目前正在使用哪些药物?请提供正在使用的药物清单。";
default:
break;
}
return null;
}
private void savePatientInfo(String queryMessage) {
switch (queryStep) {
case 0:
patientInfo.setFirstQuery(queryMessage);// 第一次询问信息
break;
case 1:
patientInfo.setPersonalInfo(queryMessage);// 个人基本信息,如年龄、性别、身高、体重
break;
case 2:
patientInfo.setSymptoms(queryMessage);// 症状
break;
case 3:
patientInfo.setEpisodeDetails(queryMessage);// 病情发作相关细节,如发作时间,持续时间,发作频率
break;
case 4:
patientInfo.setLifestyleFactors(queryMessage);// 生活方式因素,包括饮食、运动、睡眠等
break;
case 5:
patientInfo.setMedicalHistory(queryMessage);// 病史
break;
case 6:
patientInfo.setAllergicDrugs(queryMessage);// 过敏药物
break;
case 7:
queryStep++;
patientInfo.setUsingDrugs(queryMessage);// 正在使用的药物
break;
}
}
private static GenerationParam createGenerationParam(List<Message> messages) {
return GenerationParam.builder()
.model("qwen-turbo")
.messages(messages)
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.topP(0.8)
.build();
}
private static GenerationResult callGenerationWithMessages(GenerationParam param) throws ApiException, NoApiKeyException, InputRequiredException {
Generation gen = new Generation();
return gen.call(param);
}
private static Message createMessage(Role role, String content) {
return Message.builder().role(role.getValue()).content(content).build();
}
//通过调用大模型来判断用户是否正在咨询自身病情。
public static boolean isMedicalQuery(String queryMessage) throws NoApiKeyException, InputRequiredException {
Generation gen = new Generation();
MessageManager msgManager = new MessageManager(10);
Message systemMsg =
Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.下面的问题只能回答一个0~1之间的小数,其余内容都不用回答").build();
Message userMsg = Message.builder().role(Role.USER.getValue()).content(queryMessage+",请你根据用户的询问给出用户此时身体不舒服的概率(0~1之间的小数),依据是出现疾病之类的词,只需要返回一个小数就行").build();
msgManager.add(systemMsg);
msgManager.add(userMsg);
QwenParam param =
QwenParam.builder().model(Generation.Models.QWEN_TURBO).messages(msgManager.get())
.resultFormat(QwenParam.ResultFormat.MESSAGE)
.build();
GenerationResult result = gen.call(param);
System.out.println("获取概率内容"+result.getOutput().getChoices().get(0).getMessage().getContent());
float probability= Float.parseFloat(result.getOutput().getChoices().get(0).getMessage().getContent());
System.out.println("概率"+probability);
return probability > 0.84;
}
private static class PatientInfo {
private String firstQuery;//第一次询问信息
private String personalInfo;//个人基本信息,如年龄、性别、身高、体重
private String symptoms;//症状
private String episodeDetails;//病情发作相关细节,如发作时间,持续时间,发作频率
private String lifestyleFactors;//表示生活方式因素,包括饮食、运动、睡眠等
private String medicalHistory;//病史
private String allergicDrugs;//过敏药物
private String usingDrugs;//正在使用的药物
@Override
public String toString() {
return "病人信息{" +
"病人第一次询问为:'" + firstQuery + '\'' +//第一次询问信息
", 一般信息:'" + personalInfo + '\'' +//个人基本信息,如年龄、性别、身高、体重
", 症状:'" + symptoms + '\'' +//症状
", 发作细节:'" + episodeDetails + '\'' +//病情发作相关细节,如发作时间,持续时间,发作频率
", 生活方式:'" + lifestyleFactors + '\'' +//表示生活方式因素,包括饮食、运动、睡眠等
", 病史:'" + medicalHistory + '\'' +//病史
", 过敏药物:'" + allergicDrugs + '\'' +//过敏药物
", 正在使用的药物:'" + usingDrugs + '\'' +//正在使用的药物
'}';
}
public void setLifestyleFactors(String lifestyleFactors) {
this.lifestyleFactors = lifestyleFactors;
}
public void setUsingDrugs(String usingDrugs) {
this.usingDrugs = usingDrugs;
}
public void setAllergicDrugs(String allergicDrugs) {
this.allergicDrugs = allergicDrugs;
}
public void setMedicalHistory(String medicalHistory) {
this.medicalHistory = medicalHistory;
}
public void setEpisodeDetails(String episodeDetails) {
this.episodeDetails = episodeDetails;
}
public void setSymptoms(String symptoms) {
this.symptoms = symptoms;
}
public void setPersonalInfo(String personalInfo) {
this.personalInfo = personalInfo;
}
public void setFirstQuery(String firstQuery) {
this.firstQuery = firstQuery;
}
}
}