使用springAI发起与大模型的对话
在这里插入图片描述

本地配置Ollama

  1. 下载Ollama软件到本地,ollama官网下载

  2. 选择所需的ai model 进行下载,可以根据想要选择的model在页面上方进行搜索

  3. 这里下载的是qwen3:1.7b,可以在ollama中设置model的下载位置
    在这里插入图片描述

  4. 选择适合自己的版本和大小
    在这里插入图片描述

  5. 在本地命令行执行该命令,就可以实现在本地和模型聊天了
    在这里插入图片描述

添加依赖

	 <properties>
        <java.version>17</java.version>
        <spring-ai.version>1.0.9</spring-ai.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-ollama</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <!--spring ai 统一管理库-->
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

配置

配置文件

spring:
    application:
        name: spring-ai-demo
    ai:
        ollama:
            base-url: http://localhost:11434
            chat:
                options:
                    model: qwen3:1.7b
                    temperature: 0.7
                    max-tokens: 1024
                    top-p: 1.0
# 配置日志
logging:
    level:
      org:
        springframework:
          ai:
            chat:
              client: debug

前后端跨域设置

package cn.demo.conf;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//配置跨域设置
@Configuration
public class MvcCommonConfiguration implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .exposedHeaders("Content-Disposition");
    }
}

配置Ollama AI连接

package cn.demo.conf;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.ChatMemoryRepository;
import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CommonConfiguration {

    //手动把chatClient放到ioc中  defaultSystem-设置全局系统设置
    @Bean
    public ChatClient ollamaChatClient(OllamaChatModel ollamaChatModel,ChatMemory chatMemory) {
        ChatClient client = ChatClient.builder(ollamaChatModel)
                .defaultSystem("您是一名资深导游,你的名字叫{systemName}。请以友好、专业和愉快的方式解答各种问题")
                .defaultAdvisors(
                        new SimpleLoggerAdvisor(),
                        MessageChatMemoryAdvisor.builder(chatMemory).build()
                )//添加日志
                .build();
        return client;
    }

    //聊天信息存储位置
    @Bean
    public ChatMemoryRepository chatMemoryRepository(){
        return new InMemoryChatMemoryRepository();
    }

    //服务层 设置参数
    @Bean
    public ChatMemory chatMemory(ChatMemoryRepository chatMemoryRepository){
        return MessageWindowChatMemory.builder()
                .chatMemoryRepository(chatMemoryRepository)
                .maxMessages(100)//单个会话保留最近的100条数据
                .build();
    }
}

实现回复功能

package cn.demo.controller;

import cn.demo.repository.ChatHistoryRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
//final修饰的变量自动注入  不需要再编写@autowired  需要是final修饰并且没有默认值可以进行自动注入
@RequiredArgsConstructor
@RequestMapping("/ai")
public class ChatController {

    private final ChatClient ollamaChatClient;

    private final ChatHistoryRepository inMemoryChatHistoryRepository;

    //同步调用 call
    @GetMapping("/chatCall")
    public String chat(String prompt) {
        //prompt-- 提示词开始  user--用户的问题  call--同步调用模型  content--ai返回响应的文本内容
        String content = ollamaChatClient.prompt()
                .user(prompt)
                .call()
                .content();
        return content;
    }

    /*
    返回值中
    "nativeUsage" : {
        "promptTokens" : 45,  输入token
        "totalTokens" : 881,  总token
        "completionTokens" : 836  输出token
      }
     */
    //流式调用 stream 有思考写出的效果
    @PostMapping(value = "/chat",produces = "text/html;charset=UTF-8")
    public Flux<String> chatFlux(String prompt, String chatId) {

        //保存会话记忆
        inMemoryChatHistoryRepository.save("chat",chatId);

        //stream--流式调用  system--系统设置  advisors--传入记忆id
        Flux<String> content = ollamaChatClient.prompt()
                .system(p->p.param("systemName","小小"))//为全局变量赋值
                .user(prompt)
                .advisors(p->p.param( ChatMemory.CONVERSATION_ID, chatId))
                .stream()
                .content();
        return content;
    }
}

实现历史对话功能

实现保存和查询会话记忆接口

package cn.demo.repository;

import java.util.List;

public interface ChatHistoryRepository {

    void save(String type,String chatId);

    List<String> getChatIds(String type);
}

实现类

package cn.demo.repository.impl;

import cn.demo.repository.ChatHistoryRepository;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class InMemoryChatHistoryRepository implements ChatHistoryRepository {

	//存储会话历史
    private Map<String,List<String>> chatHistory = new HashMap<>();

    @Override
    public void save(String type, String chatId) {
        //根据type进行查找,如果存在对应的集合数据 则计算,如果没有使用第二个参数执行
        List<String> list = chatHistory.computeIfAbsent(type, k -> new ArrayList<>());
        //如果当前list已经包含该chatId;直接结束无需操作
        if (list.contains(chatId)) {
            return;
        }
        list.add(chatId);
    }

    @Override
    public List<String> getChatIds(String type) {
        return chatHistory.getOrDefault(type, List.of());
    }
}

返回vo

package cn.demo.vo;

import lombok.Data;
import org.springframework.ai.chat.messages.Message;

@Data
public class MessageVO {
    private String role;
    private String content;

    public MessageVO(Message message) {
        this.content = message.getText();
        this.role = switch (message.getMessageType()){
            case USER -> "user";
            case ASSISTANT -> "assistant";
            case SYSTEM -> "system";
            default -> "";
        };

    }
}

实现会话历史查询controller

package cn.demo.controller;

import cn.demo.repository.ChatHistoryRepository;
import cn.demo.vo.MessageVO;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/ai/history")
@RequiredArgsConstructor
public class ChatHistoryController {

    private final ChatHistoryRepository chatHistoryRepository;
    private final ChatMemory chatMemory;

    //获取会话id列表
    @GetMapping("/{type}")
    public List<String> getHistory(@PathVariable String type) {
        return chatHistoryRepository.getChatIds(type);
    }

    //获取会话内容列表
    @GetMapping("/{type}/{chatId}")
    public List<MessageVO> getChatHistory(@PathVariable("type") String type, @PathVariable("chatId") String chatId) {
//        List<String> ids = chatHistoryRepository.getChatIds(type);
        List<Message> messages = chatMemory.get(chatId);
        if(messages == null) {
            return List.of();
        }
        return messages.stream().map(message -> new MessageVO(message)).toList();
    }

}

在这里插入图片描述
在这里插入图片描述

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐