大模型: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 "天晴";
}

1445

被折叠的 条评论
为什么被折叠?



