Spring AI 学习篇

大模型:DeepSeek、阿里云百炼、ollama

下面以DeepSeek为例,进行学习

一、快速使用

1.添加依赖

在pom.xml添加

<dependencies>

        <dependency>

                <groupId>org.springframework.ai</groupId>

                <artifactId>spring-ai-starter-model-deepseek</artifactId>

        </dependency>

</dependencies>

2.配置API key和模型

在application.properties添加

spring.ai.deepseek.api-key = ${DEEP_SEEK_KEY}

spring.ai.deepseek.chat.options.model = deepseek-chat

3.测试

(1)同步阻塞式输出

@Test
public void testDeepseek(@Autowired DeepSeekChatModel deepSeekChatModel){
    String content = deepSeekChatModel.call("你好你是谁");
    System.out.println(content);
}

(2)流式输出

@Test
public void testDeepseekStream(@Autowired DeepSeekChatModel deepSeekChatModel){
    Flux<String> stream = deepSeekChatModel.stream("你好你是谁");
    stream.toIterable().forEach(System.out::println);
}

二、options配置选项

(1)temperature

范围:0-2,值越大,输出内容相似度越低-越热情;反之相似度越高-越冷淡

(2)maxTokens

限制生成的最大token数

(3)stop

截断你不想输出的内容

@Test
public void testChatOptions(@Autowired DeepSeekChatModel deepSeekChatModel{
    DeepSeekChatOptions options = DeepSeekChatOptions.builder()
            .model("deepseek-chat")    // 指定大模型
            //.maxTokens(5)    // 限制字数
            .stop(Arrays.asList(","))    // 从逗号截断
            .temperature(1.9).build();
    Prompt prompt = new Prompt("请写一句诗描述清晨。", options);
    ChatResponse res = deepSeekChatModel.call(prompt);
    System.out.println(res.getResult().getOutput().getText());
}

三、深度思考

1.修改application.properties

spring.ai.deepseek.api-key = ${DEEP_SEEK_KEY}

spring.ai.deepseek.chat.options.model = deepseek-reasoner

2.测试

(1)同步阻塞式输出

@Test
public void testDeepseekReasoning(@Autowired DeepSeekChatModel deepSeekChatModel{
    Prompt prompt = new Prompt("你好你是谁");
    ChatResponse res = deepSeekChatModel.call(prompt);
    DeepSeekAssistantMessage assistantMessage = (DeepSeekAssistantMessage)res.getResult().getOutput();
    System.out.println(assistantMessage.getReasoningContent);    // 思考内容
    System.out.println(assistantMessage.getText());    // 最终回答内容
}

(2)流式输出

@Test
public void testDeepseekStream(@Autowired DeepSeekChatModel deepSeekChatModel{
    Prompt prompt = new Prompt("你好你是谁");
    Flux<ChatResponse> stream = deepSeekChatModel.stream(prompt);
    stream.toIterable().forEach(chatResponse -> {
        DeepSeekAssistantMessage assistantMessage = (DeepSeekAssistantMessage)chatResponse.getResult().getOutput();
        System.out.println(assistantMessage.getReasoningContent());    // 思考内容
    });

    stream.toIterable().forEach(chatResponse -> {
        DeepSeekAssistantMessage assistantMessage = (DeepSeekAssistantMessage)chatResponse.getResult().getOutput();
        System.out.println(assistantMessage.getText());    // 最终回答内容
    });
}

插入一个概念

多模态:将图片、语音、视频传给大模型,让大模型识别后生成文本返回

四、ChatClient

由于我们对接大模型使用的ChatModel是不同的,而ChatClient适用所用的大模型,更加便捷

(1)只有一个大模型

@Test
public void testChatClient(@Autowired ChatClient.Builder chatClientBuilder){
    ChatClient chatClient = chatClientBuilder.build();
    String content = chatClient.prompt()
            .user("你好")
            .call()
            .content();
    System.out.println(content);
}

(2)有多个大模型

@Test
public void testChatClient(@Autowired DashScopeChatModel dashScopeChatModel){
    // 使用哪个模型就传入哪个模型
    ChatClient chatClient = ChatClient.builder(dashScopeChatModel).build();
    String content = chatClient.prompt()
            .user("你好")
            .call()
            .content();
    System.out.println(content);
}

五、提示词

1.系统提示词

为ChatClient设置提示词,只要用到这个chatCilent的对话都会用到这个提示词

@Test
public void testChatClient(@Autowired ChatClient.Builder chatClientBuilder){
    ChatClient chatClient = chatClientBuilder
            .defaultSystem("""
                #角色说明
                你是一名专业法律顾问AI..

                ## 回复格式
                1.问题分析
                2.相关依据
                3.梳理和建议

                **特别注意:**
                -不承担律师责任。
                -不生成涉敏、虚假内容。
             """)
            .build();
    String content = chatClient.prompt()
            .user("你好")
            .call()
            .content();
    System.out.println(content);
}
        

为当前对话设置提示词

@Test
public void testChatClient(@Autowired ChatClient.Builder chatClientBuilder){
    ChatClient chatClient = chatClientBuilder
            .build();
    String content = chatClient.prompt()
            .system("""
                #角色说明
                你是一名专业法律顾问AI..

                ## 回复格式
                1.问题分析
                2.相关依据
                3.梳理和建议

                **特别注意:**
                -不承担律师责任。
                -不生成涉敏、虚假内容。
             """)
            .user("你好")
            .call()
            .content();
    System.out.println(content);
}
        

2.动态传参

@Test
public void testChatClient(@Autowired ChatClient.Builder chatClientBuilder){
    ChatClient chatClient = chatClientBuilder
            .defaultSystem("""
                #角色说明
                你是一名专业法律顾问AI..

                ## 回复格式
                1.问题分析
                2.相关依据
                3.梳理和建议

                **特别注意:**
                -不承担律师责任。
                -不生成涉敏、虚假内容。

                当前服务的用户:
                姓名:{name},年龄:{age}
             """)
            .build();
    String content = chatClient.prompt()
            .system(p -> p.param("name","张三").param("age","22"))
            .user("你好")
            .call()
            .content();
    System.out.println(content);
}
        

3.提示词模版

(1)新建prompt.st,将提示词写入

(2)导入

@Test
public void testChatClient(@Autowired ChatClient.Builder chatClientBuilder,@Value("classpath:/files/prompt.st") Resource systemResource){
    ChatClient chatClient = chatClientBuilder
            .defaultSystem(systemResource)
            .build();
    String content = chatClient.prompt()
            .system(p -> p.param("name","张三").param("age","22"))
            .user("你好")
            .call()
            .content();
    System.out.println(content);
}

4.公式

「角色设定」+「具体任务(技能)」+「限制条件(约束)」+「示例参考」

六、Advisor

1.日志拦截器

ChatClient chatClient = chatClientBuilder
            .defaultAdvisors(new SimpleLoggerAdvisor())
            .build();

直接执行是没有日志的,需要打开日志级别,才会显示。在application.properties添加

logging.level.org.springframework.ai.chat.client.advisor = DEBUG

2.敏感词拦截器

当用户输入“李四”时,不会调用大模型,直接抛错,所以相应速度会很快

ChatClient chatClient = chatClientBuilder
            .defaultAdvisors(new SimpleLoggerAdvisor(),
                    new SafeGuardAdvisor(List.of("李四")))
            .build();

3.自定义拦截器

public class ReReadingAdvisor implements BaseAdvisor {
    private static final String DEFAULT_USER_TEXT_ADVISE = """
        {re2_input_query}
        Read the question again: {re2_input_query}
        """;

    @Override
    public ChatClientRequest before(ChatClientRequest chatClientRequest,AdvisorChain advisorChain){
        // 用户提示词
        String contents = chatClientRequest.prompt().getContents();

        // 替换占位符中的内容
        String re2InputQuery = PromptTemplate.builder()
                .template(DEFAULT_USER_TEXT_ADVISE)
                .render(Map.of("re2_input_query", contents));
        
        // 新建一个ChatClientRequest返回
        ChatClientRequest clientRequest = chatClientRequest.mutate()
                .prompt(Prompt.builder().content(re2InputQuery).build())
                .build();
        
        return clientRequest;
    }
}
ChatClient chatClient = chatClientBuilder
            .defaultAdvisors(new SimpleLoggerAdvisor(),
                    new ReReadingAdvisor())
            .build();

七、会话记忆

LLM是无状态的,不会保留先前的交互信息

通过defaultAdvisors(PromptChatMemoryAdvisor.builder(chatMemoryD.build())存储会话

1.添加依赖

<dependency>

    <groupId>org.springframework.ai</groupId>

    <artifactId>spring-ai-autoconfigure-model-chat-memory</artifactId>

</dependency>

2.测试

@Test
public void testMemoryAdvisor(@Autowired ChatClient.Builder builder,
@Autowired ChatMemory chatMemory) {
    ChatClient chatClient = builder
         .defaultAdvisors(PromptChatMemoryAdvisor.builder(chatMemoryD.build())
         .build();

    String content = chatclient.prompt()
            .user("我是张三")
            .call()
            .content();
    System.out.println(content);
    System.out.println("–----------------");

    content = chatClient.prompt()
            .user("我叫什么?")
            .call()
            .content();
    System.out.println(content);

}

3.记忆最大存储数量

默认的消息窗口大小为20条消息

如果第11条会话进来,那么就会从第2条会话开始展示,确保最大只展示10条(先进先出原则)

MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
    .maxMessages(10)
    .build();

4.多用户记忆隔离

如果没有配置记忆隔离,那么所有用户都会共享这一份聊天记录

通过advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION, "1"))进行配置

@Test
public void testMemoryAdvisor(@Autowired ChatClient.Builder builder,
@Autowired ChatMemory chatMemory) {
    ChatClient chatClient = builder
         .defaultAdvisors(PromptChatMemoryAdvisor.builder(chatMemoryD.build())
         .build();

    String content = chatclient.prompt()
            .user("我是张三")
            .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION, "1"))
            .call()
            .content();
    System.out.println(content);
    System.out.println("–----------------");

    content = chatClient.prompt()
            .user("我叫什么?")
            .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION, "1"))
            .call()
            .content();
    System.out.println(content);
    System.out.println("–----------------");

    content = chatClient.prompt()
            .user("我叫什么?")
            .advisors(advisorSpec -> advisorSpec.param(ChatMemory.CONVERSATION, "2"))
            .call()
            .content();

}

八、数据库存储对话记忆

Spring AI 通过方言抽象支持多种关系型数据库。开箱即支持以下数据库:

  • PostgreSQL

  • MySQL / MariaDB

  • SQL Server

  • HSQLDB

  • Oracle数据库

1.数据库存储

1.导入依赖

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<!--mysql驱动-->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

2.添加配置

spring.ai.chat.memory.repository.jdbc.initialize-schema=always
<!--如果要覆盖架构脚本的位置-->
spring.ai.chat.memory.repository.jdbc.schema=classpath:/custom/path/schema-mysql.sql

3.连接数据库

spring:
    datasource:
        username: root
        password: 123456
        url: jdbc:mysql://localhost:3306/springai?characterEncoding=utf8&useSSL=false
        driver-class-name: com.mysql.cj.jdbc.Driver

2.Redis存储

1.导入依赖

<properties>
    <jedis.version>5.2.0</jedis.version>
</properties>

<!--基于redis记忆存储-->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-memory-redis</artifactId>
</dependency>

2.连接数据库

ai:
    memory:
        redis: 
            host: localhost
            port: 6379
            timeout: 5000
            password: 123456

九、多层记忆架构

当记忆越多的时候,说明越聪明,同时带来的问题是token上限。为解决此问题,使用多层记忆架构,具体如下:

近期记忆:保留在上下文窗口中的最近几轮对话,每轮对话完成后立即存储(可通过
ChatMemory);

中期记忆:通过RAG检索的相关历史对话(每轮对话完成后,异步将对话内容转换为向量并存入
向量数据库) ------>向量数据库进行相似性检索,然后提取与对话相关的内容出来

长期记忆:关键信息的固化总结

方式一:定时批处理

  • 通过定时任务(如每天或每周)对积累的对话进行总结和提炼
  • 提取关键信息、用户偏好、重要事实等
  • 批处理方式降低计算成本,适合大规模处理

方式二:关键点实时处理

  • 在对话中识别出关键信息点时立即提取并存储
  • 例如,当用户明确表达偏好、提供个人信息或设置持久性指令时
  • 采用"写入触发器"机制,在特定条件下自动更新长期记忆

十、Tool

定义:用于提供大模型不具备的信息和能力

1.使用

(1)提供了什么工具@Tool

(2)使用工具需要什么参数@ToolParam

@Tool(description ="获取指定位置天气,根据位置自动推算经纬度")
public String getAirQuality(@ToolParam(description ="纬度") double latitude, @ToolParam(description ="经度") double longitude) {
    return "天晴";
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值