延续上一次所讲,获取到了会话id,我们这次就实现一些获取历史会话消息
1,编写controller
java
package com.example.chatai.controller;
import com.example.chatai.repository.ChatHistoryRepository;
import com.example.chatai.service.ChatService;
import com.example.chatai.vo.MessageVo;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import java.util.List;
@RequiredArgsConstructor
@RestController
@RequestMapping("/ai/history")
public class ChatHistoryController {
private final ChatHistoryRepository chatHistoryRepository;
@GetMapping("/{type}")
public List<String> getChatIds(@PathVariable("type") String type) {
return chatHistoryRepository.getChatIds(type);
}
@GetMapping("/{type}/{chatId}")
public List<MessageVo> getChatHistory(@PathVariable("type") String type, @PathVariable("chatId") String chatId) {
return chatHistoryRepository.getChatHistory(type,chatId);
}
}
2,会话记忆Message源码解读
java
public interface Message extends Content {
/**
* Get the message type.
* @return the message type
*/
MessageType getMessageType();
}
java
/*
* Copyright 2023-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.chat.messages;
/**
* Enumeration representing types of {@link Message Messages} in a chat application. It
* can be one of the following: USER, ASSISTANT, SYSTEM, FUNCTION.
*/
public enum MessageType {
/**
* A {@link Message} of type {@literal user}, having the user role and originating
* from an end-user or developer.
* @see UserMessage
*/
USER("user"),
/**
* A {@link Message} of type {@literal assistant} passed in subsequent input
* {@link Message Messages} as the {@link Message} generated in response to the user.
* @see AssistantMessage
*/
ASSISTANT("assistant"),
/**
* A {@link Message} of type {@literal system} passed as input {@link Message
* Messages} containing high-level instructions for the conversation, such as behave
* like a certain character or provide answers in a specific format.
* @see SystemMessage
*/
SYSTEM("system"),
/**`/*
* Copyright 2023-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.content;
import java.util.Map;
import org.jspecify.annotations.Nullable;
/**
* Data structure that contains content and metadata. Common parent for the
* {@link org.springframework.ai.document.Document} and the
* {@link org.springframework.ai.chat.messages.Message} classes.
*
* @author Mark Pollack
* @author Christian Tzolov
* @since 1.0.0
*/
public interface Content {
/**
* Get the content of the message.
* @return the content of the message
*/
@Nullable String getText();
/**
* Get the metadata associated with the content.
* @return the metadata associated with the content
*/
Map<String, Object> getMetadata();
}
`
* A {@link Message} of type {@literal function} passed as input {@link Message
* Messages} with function content in a chat application.
* @see ToolResponseMessage
*/
TOOL("tool");
private final String value;
MessageType(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
}
3,编写Vo:
java
package com.example.chatai.vo;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.MessageType;
@NoArgsConstructor
@Data
public class MessageVo {
private String role;
private String context;
public MessageVo(Message message) {
MessageType messageType = message.getMessageType();
switch (messageType) {
case USER:
role="user";
break;
case ASSISTANT:
role="assistant";
break;
case SYSTEM:
role="system";
break;
case TOOL:
role="tool";
break;
default:
role="unknow";
break;
}
this.context = message.getText();
}
}
4,编写service
java
List<MessageVo> getChatHistory(String type, String chatId);
java
package com.example.chatai.repository.impl;
import com.example.chatai.repository.ChatHistoryRepository;
import com.example.chatai.vo.MessageVo;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.*;
@Service
public class ChatHistoryRepositoryImpl implements ChatHistoryRepository {
private final Map<String, List<String>> chatHistory =new HashMap<>();
private final ChatMemory chatMemory;
public ChatHistoryRepositoryImpl(ChatMemory chatMemory) {
this.chatMemory = chatMemory;
}
@Override
public void sava(String type, String chatId) {
// if(!chatHistory.containsKey(type)) {
// chatHistory.put(type,new ArrayList<>());
// }
// List<String> chatIds = chatHistory.get(type);
List<String> chatIds = chatHistory.computeIfAbsent(type, k -> new ArrayList<>());
if(chatIds.contains(chatId)) {
return;
}
chatIds.add(chatId);
}
@Override
public List<String> getChatIds(String type) {
// List<String> chatIds = chatHistory.get(type);
// return chatIds==null? new ArrayList<>():chatIds;
return chatHistory.getOrDefault(type, List.of());
}
@Override
public List<MessageVo> getChatHistory(String type, String chatId) {
List<Message> messages = chatMemory.get(chatId);
if(CollectionUtils.isEmpty(messages)) {
return List.of();
}
return messages.stream().map(MessageVo::new).toList();
}
}
5,测试



会话1给机器人发送了3个问题。都得到了回答,我们看看机器人历史记忆功能,我调用
http://localhost:8080/ai/history/chat/1 接口

返回了之前的3次记录,这就实现了会话历史记忆功能
学到了这里是否理解前面讲的机器人有记忆概念,欢迎兄弟们留言