feat(chat): 为AI陪聊增加历史消息上下文支持

- ChatServiceImpl#message 现在会读取最近20条聊天记录作为LLM上下文
- 新增 callLLMWithHistory 方法,使用 Spring AI Message 构造对话历史
- KeyboardAiChatMessageService 新增 getRecentMessages 接口及实现,按时间正序返回指定条数消息
- 保持原有分页查询接口不变,仅补充上下文所需方法
This commit is contained in:
2026-01-26 20:25:04 +08:00
parent aaf5d3bea4
commit ac9a352004
3 changed files with 54 additions and 4 deletions

View File

@@ -5,6 +5,8 @@ import com.yolo.keyborad.model.entity.KeyboardAiChatMessage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yolo.keyborad.model.vo.ChatMessageHistoryVO;
import java.util.List;
/*
* @author: ziin
* @date: 2026/1/26 17:00
@@ -21,4 +23,14 @@ public interface KeyboardAiChatMessageService extends IService<KeyboardAiChatMes
* @return 分页结果
*/
IPage<ChatMessageHistoryVO> pageHistory(Long userId, Long companionId, Integer pageNum, Integer pageSize);
/**
* 获取最近的聊天记录按时间正序用于LLM上下文
*
* @param userId 用户ID
* @param companionId AI陪聊角色ID
* @param limit 获取条数
* @return 聊天记录列表(时间正序)
*/
List<KeyboardAiChatMessage> getRecentMessages(Long userId, Long companionId, int limit);
}

View File

@@ -25,6 +25,9 @@ import lombok.extern.slf4j.Slf4j;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.codec.ServerSentEvent;
@@ -371,7 +374,12 @@ public class ChatServiceImpl implements ChatService {
// 获取AI人设的系统提示词
String systemPrompt = aiCompanionService.getSystemPromptById(companionId);
String response = callLLM(content, systemPrompt);
// 获取最近20条聊天记录作为上下文
List<KeyboardAiChatMessage> historyMessages = aiChatMessageService.getRecentMessages(
Long.parseLong(userId), companionId, 20);
log.info("获取历史消息, userId: {}, companionId: {}, 数量: {}", userId, companionId, historyMessages.size());
String response = callLLMWithHistory(content, systemPrompt, historyMessages);
long llmDuration = System.currentTimeMillis() - startTime;
log.info("LLM 完成, userId: {}, 耗时: {}ms, 响应长度: {}", userId, llmDuration, response.length());
@@ -423,13 +431,27 @@ public class ChatServiceImpl implements ChatService {
}
/**
* 调用 LLM 生成响应
* 调用 LLM 生成响应(带历史消息上下文)
*/
private String callLLM(String content, String systemPrompt) {
private String callLLMWithHistory(String content, String systemPrompt, List<KeyboardAiChatMessage> historyMessages) {
// 构建历史消息列表
List<Message> messages = new ArrayList<>();
for (KeyboardAiChatMessage msg : historyMessages) {
if (msg.getSender() == 1) {
// 用户消息
messages.add(new UserMessage(msg.getContent()));
} else {
// AI消息
messages.add(new AssistantMessage(msg.getContent()));
}
}
// 添加当前用户消息
messages.add(new UserMessage(content));
return client
.prompt()
.system(systemPrompt)
.user(content)
.messages(messages)
.call()
.content();
}

View File

@@ -11,6 +11,9 @@ import com.yolo.keyborad.model.vo.ChatMessageHistoryVO;
import com.yolo.keyborad.service.KeyboardAiChatMessageService;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
/*
* @author: ziin
* @date: 2026/1/26 17:00
@@ -28,4 +31,17 @@ public class KeyboardAiChatMessageServiceImpl extends ServiceImpl<KeyboardAiChat
IPage<KeyboardAiChatMessage> entityPage = this.page(page, queryWrapper);
return entityPage.convert(entity -> BeanUtil.copyProperties(entity, ChatMessageHistoryVO.class));
}
@Override
public List<KeyboardAiChatMessage> getRecentMessages(Long userId, Long companionId, int limit) {
LambdaQueryWrapper<KeyboardAiChatMessage> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(KeyboardAiChatMessage::getUserId, userId)
.eq(KeyboardAiChatMessage::getCompanionId, companionId)
.orderByDesc(KeyboardAiChatMessage::getCreatedAt)
.last("LIMIT " + limit);
List<KeyboardAiChatMessage> messages = this.list(queryWrapper);
// 反转列表,使其按时间正序排列(旧消息在前)
Collections.reverse(messages);
return messages;
}
}