MING本身作为医疗大模型,其对于医疗领域问题的回答质量要比Qwen好,专业性也更强(毕竟是基于Qwen微调的),因此使用智能问诊反而显得有点冗余。但即便如此,搜集病人的病历信息加入对话信息里,仍然是增强对话质量的选择之一。
1、对话的实现
query函数首先将必要参数以及用户的问答文本格式化为能被api_server接受的json格式。这里可以通过将这些参数使用Map包装起来,并放入request Body中,并使用FastJson进行转化
JSONObject result = ClientUtil.sendPostRequest(mingURL,params);
之前的发送Post请求的功能,修改之后放到ClientUtil中,以和地理信息增强的功能进行解耦
messageCacheList起到一个消息缓存的作用,当其为空时,首先从数据库中按顺序拉取消息历史记录出来,发送请求时,会将messageCacheList中的所有消息作为参数发送
MessageWrapper userMessage = new MessageWrapper("user",queryContent);
messageCacheList.add(userMessage);
params.put("messages",messageCacheList);
解析得到的json,并从中提取消息,加入消息缓存列表和数据库中
JSONArray choices = result.getJSONArray("choices");
if(choices==null){
return "choice == null"+result.toJSONString();
}
MessageWrapper responseMessage = new MessageWrapper();
for(int i =0;i<choices.size();++i){
JSONObject messageJson = choices.getJSONObject(i).getJSONObject("message");
String role = messageJson.getString("role");
String content = messageJson.getString("content");
responseMessage.setRole(role);
responseMessage.setContent(content);
}
messageCacheList.add(responseMessage);
saveUserChatHistory(userId,messageCacheList);
String resultContent = responseMessage.getContent();
2、消息的存储与删除
将消息缓存列表中的MessageWrapper转化成ChatMessage并插入数据库中,取出则反之
需要注意的是取出消息时可能会出现role为null的情况,推测是save时出了bug,这种情况下要排除,因为role为null时ming_api_server无法解析
private void saveUserChatHistory(Integer userId,List<MessageWrapper> messageList){
for(MessageWrapper message: messageList){
ChatMessage chatMessage = new ChatMessage(null, userId, message.getRole(), message.getContent());
chatMessageMapper.insert(chatMessage);
}
}
private void fetchUserChatHistory(int userId){
List<ChatMessage> userChatHistory = chatMessageMapper.findChatMessageByUserId(userId);
if(userChatHistory==null){
System.out.println("fetch chat history failed");
return ;
}
for(ChatMessage chatMessage:userChatHistory){
MessageWrapper messageWrapper = new MessageWrapper(chatMessage.getRole(),chatMessage.getContent());
if(messageWrapper.getRole() !=null&& messageWrapper.getContent()!=null){
messageCacheList.add(messageWrapper);
}
}
}
3、信息增强
正如前面提到的,在函数createQueryContent函数中,加入了用户的病历信息辅助判断
当病人第一次与ming对话时,加入用户病历信息辅助判断。
还有一个点就是前面博客提到的地理信息提供,这里通过正则表达式判断用户的问题里有没有关键词“医院”,若有,在模型的回答文本中加入所在区域的医院信息
private boolean checkIfNeedHospitalLocationInfo(String content){
String keyword = "医院";
Pattern pattern = Pattern.compile(keyword);
Matcher matcher = pattern.matcher(content);
boolean containsKeyword = matcher.find();
if (containsKeyword) {
return true;
}
else{
return false;
}
}
MingAPIService完整代码如下
package com.SmartMed_Connect.service;
import com.SmartMed_Connect.controller.UserController;
import com.SmartMed_Connect.dao.ChatMessageDao;
import com.SmartMed_Connect.dto.MessageWrapper;
import com.SmartMed_Connect.entity.ChatMessage;
import com.SmartMed_Connect.entity.PatientHistory;
import com.SmartMed_Connect.utils.ClientUtil;
import com.SmartMed_Connect.utils.IpUtil;
import com.SmartMed_Connect.utils.MapUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Service
public class MingAPIService {
@Autowired
protected PatientHistoryService patientHistoryService;
@Autowired
private UserController userController;
@Autowired
protected UserService userService;
@Autowired
private ChatMessageDao chatMessageMapper;
@Autowired
private HttpServletRequest request;
@Value("${ming.url}")
String mingURL;
private final List<MessageWrapper> messageCacheList = new ArrayList<>();
private String createQueryContent(Integer userId,String queryMessage){
PatientHistory patientHistory = patientHistoryService.findByUserId(userId).get(0);
String historyString = patientHistory.toString();
String patientHistoryInfo = "病人的以往病史是:"+historyString+"请你结合这些信息给出相应的建议";
return queryMessage+patientHistoryInfo;
}
public String query(String queryMessage){
Map<String,Object> params = new HashMap<>();
params.put("model","ming-moe-4B");
params.put("n",1);
params.put("temperature",0.5);
params.put("max_tokens",3072);
Integer userId = userController.loginUser.getId();
String queryContent = queryMessage;
// List<MessageWrapper> messages;
if(messageCacheList.isEmpty()){
fetchUserChatHistory(userId);
if(messageCacheList.isEmpty()){
queryContent = createQueryContent(userId,queryMessage);
}
}
if(queryMessage.equals("/newchat")){
messageCacheList.clear();
clearUserChatHistory(userId);
return "已清空聊天记录";
}
MessageWrapper userMessage = new MessageWrapper("user",queryContent);
messageCacheList.add(userMessage);
params.put("messages",messageCacheList);
for(MessageWrapper messageWrapper:messageCacheList){
System.out.println(messageWrapper);
}
JSONObject result = ClientUtil.sendPostRequest(mingURL,params);
System.out.println(result);
if(result==null){
return "错误:连接失败";
}
JSONArray choices = result.getJSONArray("choices");
if(choices==null){
return "choice == null"+result.toJSONString();
}
MessageWrapper responseMessage = new MessageWrapper();
for(int i =0;i<choices.size();++i){
JSONObject messageJson = choices.getJSONObject(i).getJSONObject("message");
String role = messageJson.getString("role");
String content = messageJson.getString("content");
responseMessage.setRole(role);
responseMessage.setContent(content);
}
messageCacheList.add(responseMessage);
saveUserChatHistory(userId,messageCacheList);
String resultContent = responseMessage.getContent();
if(checkIfNeedHospitalLocationInfo(queryMessage)){
String userIP = IpUtil.getIpAddress(request);
String mapInfo = MapUtil.getAddressByIP(userIP);
resultContent += mapInfo;
}
return resultContent;
}
private boolean checkIfNeedHospitalLocationInfo(String content){
String keyword = "医院";
// 编译正则表达式
Pattern pattern = Pattern.compile(keyword);
// 创建匹配器对象
Matcher matcher = pattern.matcher(content);
// 使用 find() 方法查找是否包含关键词
boolean containsKeyword = matcher.find();
if (containsKeyword) {
return true;
}
else{
return false;
}
}
private void clearUserChatHistory(int userId){
chatMessageMapper.clearChatMessageByUserId(userId);
}
private void saveUserChatHistory(Integer userId,List<MessageWrapper> messageList){
for(MessageWrapper message: messageList){
ChatMessage chatMessage = new ChatMessage(null, userId, message.getRole(), message.getContent());
chatMessageMapper.insert(chatMessage);
}
}
private void fetchUserChatHistory(int userId){
List<ChatMessage> userChatHistory = chatMessageMapper.findChatMessageByUserId(userId);
// List<MessageWrapper> messageCache = new ArrayList<>();
if(userChatHistory==null){
System.out.println("fetch chat history failed");
return ;
}
for(ChatMessage chatMessage:userChatHistory){
MessageWrapper messageWrapper = new MessageWrapper(chatMessage.getRole(),chatMessage.getContent());
if(messageWrapper.getRole() !=null&& messageWrapper.getContent()!=null){
messageCacheList.add(messageWrapper);
}
}
}
}