【SpringAI 22】对话机器人,历史会话功能

延续上一次所讲,获取到了会话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次记录,这就实现了会话历史记忆功能

学到了这里是否理解前面讲的机器人有记忆概念,欢迎兄弟们留言

相关推荐
ywl47081208719 小时前
【SpringAI 09】SpringAI入门
人工智能·springai
ywl4708120871 天前
【SpringAI 15】会话记忆功能ChatMemory
对话机器人·springai
早春的树长在理想三旬1 天前
从LLM到Agent:ReAct推理模式的底层原理
人工智能·spring boot·springai·agent开发
早春的树长在理想三旬1 天前
工具抽象的艺术:可插拔Skill系统的设计哲学
人工智能·agent·springai
ywl4708120872 天前
【SpringAI 10】对话机器人快速入门
机器人·springai
无心水3 天前
【全域智能营销实战】10、三大引擎协同工作流:从用户消息到智能决策的完整链路
人工智能·springai·openclaw·顶尖架构师·全域智能营销·harmess·herness
重庆小透明5 天前
今日收获(一些个人思考)
java·spring·大模型·springai·prompt注入
张某布响丸辣1 个月前
Spring AI 极简入门:Java 开发者快速上手 AI 开发
java·人工智能·spring·springai
小沈同学呀1 个月前
SpringAI+MCPServer实战-StreamableHTTP协议打造企业级AI工具服务
人工智能·微服务架构·springai·mcpserver·javaai·streamablehttp