以开发一个高考志愿填报系统为例,入门大模型应用开发
一、Ollama
Ollama 是一个开源工具,允许用户在本地计算机上快速下载、运行和管理大型语言模型(LLMs)。它支持多种热门模型,无需依赖云端服务,适合开发、隐私保护或离线使用场景。
官网地址: https://ollama.com
以这个为例Thinking · Ollama Blog可知Ollama默认端口11434,本机部署调用模型API:

二、请求参数
大模型服务请求相关的配置选项
2.1 model(模型名称)
作用:指定要调用的模型(如 llama2、mistral、gemma 等)。
{
"model": "qwen-plus"
}
2.2 messages(对话消息)
作用:输入对话历史,通常是一个包含 role(角色)和 content(内容)的数组,用于多轮对话。
角色类型:
user: 用户输入的消息。
assistant: AI 助手之前的回复。
system: 系统指令(如设定 AI 行为)
{
"messages": [
{"role": "system", "content": "你是一个翻译助手,将中文翻译成英文。"},
{"role": "user", "content": "你好,世界"}
]
}
2.3 stream(流式响应)
作用:是否启用流式传输(逐字返回结果,类似 ChatGPT 的效果)。
默认值:false(关闭,一次性返回完整响应)。
{
"stream": true
}
2.4 enable_search(联网搜索)
作用:是否允许模型联网搜索最新信息(部分模型支持,如 llama3 的联网插件)。
默认值:false(禁用,仅依赖模型本地知识)。
注意:需模型本身支持此功能,且可能影响响应速度。
{
"enable_search": true
}
三、会话功能入门
大模型部署===>登录阿里云 https://www.aliyun.com/===\>开通 大模型服务平台百炼 服务===>申请百炼平台 API-KEY===>选择模型并使用
3.1 依赖引入
(1)引入Langchian4j依赖
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.0.1</version>
</dependency>
(2)构建OpenAiChatModel对象
在电脑用户变量中配置API-KEY

//构建 OpenAiChatModel 对象
OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey(System.getenv("API-KEY"))
.modelName("qwen-plus")
.build();
(3)调用chat方法与大模型交互
// 3.调用chat方法交互
String result = model.chat("你是谁");
System.out.println(result);
运行结果如图所示:

3.2 打印日志信息
项目缺少 SLF4J 的日志实现库(如 Logback、Log4j2)。
解决方案:添加日志实现依赖(推荐 Logback)
<!-- Maven -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.18</version>
</dependency>
引入logback依赖后,并设置logRequests和logResponses,代码部分如下:
//构建 OpenAiChatModel 对象
OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.apiKey(System.getenv("API-KEY"))
.modelName("qwen-plus")
.logRequests(true)
.logResponses(true)
.build();
代码运行结果显示:

四、项目开发
4.1 springboot项目创建
1.构建springboot项目
2.引入起步依赖
<!--langchain4j起步依赖 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>1.0.1-beta6</version>
</dependency>
3.application.yml中配置大模型
langchain4j:
open-ai:
chat-model:
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: qwen-plus
4.开发接口,调用大模型
@RestController
public class ChatController {
@Autowired
private OpenAiChatModel model;
@RequestMapping("/chat")
public String chat(String message){//浏览器传递的用户问题
String result = model.chat(message);
return result;
}
}
运行结果截图:

打印日志
langchain4j:
open-ai:
chat-model:
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: qwen-plus
log-requests: true
log-responses: true
logging:
level.dev.langchain4j: debug
运行截图如下:

4.2 AiServices工具类
1.引入依赖
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.0.1-beta6</version>
2.声明接口
public interface ConsultantService {
//用于聊天的方法
public String chat(String message);
}
3.使用AiServices为接口手动创建代理对象
@Configuration
public class CommonConfig {
@Autowired
private OpenAiChatModel model;
@Bean
public ConsultantService consultantService(){
ConsultantService cs = AiServices.builder(ConsultantService.class)
.chatModel(model)
.build();
return cs;
}
}
4.在Controller中注入并使用
@RestController
public class ChatController {
@Autowired
private ConsultantService consultantService;
@RequestMapping("/chat")
public String chat(String message){
String result = consultantService.chat(message);
return result;
}
}
运行结果如下:

注释
@Configuration
public class CommonConfig {
@Autowired
private OpenAiChatModel model;
/*@Bean
public ConsultantService consultantService(){
ConsultantService cs = AiServices.builder(ConsultantService.class)
.chatModel(model)
.build();
return cs;
}*/
}
使用 @AiService 注解接口
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT, // 手动装配
chatModel = "openAiChatModel" // 指定模型
)
public interface ConsultantService {
//用于聊天的方法
public String chat(String message);
}
查看@AiService注解:默认自动装配

4.3 流式调用
1.引入依赖
<!-- 引入流式调用相关的依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
<version>1.0.1-beta6</version>
</dependency>
2.配置流式模型对象
streaming-chat-model:
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
api-key: ${API-KEY}
model-name: qwen-plus
log-requests: true
log-responses: true
3.切换接口中方法的返回值类型
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT, // 手动装配
chatModel = "openAiChatModel" , // 指定模型
streamingChatModel = "openAiStreamingChatModel"
)
public interface ConsultantService {
//用于聊天的方法
//public String chat(String message);
public Flux<String> chat(String message);
}
4.修改Controller中的代码
@RestController
public class ChatController {
@Autowired
private ConsultantService consultantService;
@RequestMapping(value = "/chat",produces = "text/html;charset=utf-8")
public Flux<String> chat(String message){
Flux<String> result = consultantService.chat(message);
return result;
}
}
运行截图:

运行截图:
如果没设置@RequestMapping(value = "/chat",produces = "text/html;charset=utf-8")返回的字符类型,那么运行结果如下:

添加前端页面:

4.4 消息注解
在AI对话系统或聊天应用中,消息注解(Message Annotations) 是指为消息添加的额外元数据或标记,用于控制消息的处理方式、显示效果或业务逻辑。
@SystemMessage
@UserMessage
区别
-
@SystemMessage:设定 AI 角色
-
效果:所有对话都会基于这个角色设定生成回答。
-
注意:通常只需定义一次,类似"系统提示词"。
@SystemMessage("""
你是一名高考志愿填报专家,熟悉全国高校的录取分数线和就业情况。
回答需满足:
1. 按【冲稳保】三档推荐学校
2. 优先考虑省内院校
3. 给出具体分数线参考
""")
public interface GaokaoAdvisor {
// ...
} -
@UserMessage:动态用户输入
public interface GaokaoAdvisor {
@UserMessage("""
我的分数是{{score}}分,{{province}}省{{subject}}科,
请推荐适合的学校和专业。
""")
String recommend(int score, String province, String subject);
}
4.4.1 @SystemMessage
通过 @SystemMessage 注解定义 AI 角色,并声明一个返回 Flux<String> 的流式聊天方法
@SystemMessage("高考志愿填报助手")
public Flux<String> chat(String message);
运行结果如下:

查看日志信息:

通过 @SystemMessage 注解定义 AI 角色,并声明一个返回 Flux<String> 的流式聊天方法
@SystemMessage(fromResource = "system.txt")
public Flux<String> chat(String message);
查看system.txt文件:

运行结果如下:

4.4.2 @UserMessage
默认规则:{{it}} 的用途
{{it}} 是 Kotlin 风格的默认参数占位符,会自动绑定到方法的第一个参数
@UserMessage("你是高考填报志愿助手{{it}}")
public Flux<String> chat(String message);
运行结果如下:

如果不使用默认{{it}}

显式命名参数--直接使用参数名
@UserMessage("你是高考填报志愿助手{{message}}")
Flux<String> chat(String message);
4.5 会话功能
4.5.1 会话记忆
大模型是不具备记忆能力的,要想让大模型记住之前聊天的内容,唯一的办法就是把之前聊天的内容与新的提示词一起发给大模型。

LangChain4j提供了会话记忆(Memory)功能,允许对话系统记住之前的交互历史。以下是配置会话记忆功能的方式:
ChatMemory 接口是 LangChain4j 中会话记忆功能的基础接口。
public interface ChatMemory {
Object id(); // 记忆存储对象的唯一标识
void add(ChatMessage var1); // 添加一条会话记忆
List<ChatMessage> messages(); // 获取所有会话记忆
void clear(); // 清除所有会话记忆
}
1.定义会话记忆对象
//构建会话记忆对象
@Bean
public ChatMemory chatMemory(){
return MessageWindowChatMemory.builder()
.maxMessages(20)//最多保留最近的 20 条消息
.build();
}
2.配置会话记忆对象
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT, // 手动装配
chatModel = "openAiChatModel" , // 指定模型
streamingChatModel = "openAiStreamingChatModel",
chatMemory = "chatMemory"//配置会话记忆对象
)
运行截图如下:

查看日志信息:

4.5.2 会话记忆隔离
刚才我们做的会话记忆,所有会话使用的是同一个记忆存储对象,因此不同会话之间的记忆并没有做到隔离。例如:

正常情况应该这样:

实现会话记忆隔离:
ChatMemoryProvider 是 LangChain4j 中一个重要的接口,它负责提供和管理 ChatMemory 实例。这个接口通常用于需要根据不同会话/用户动态获取对应记忆的场景。
public interface ChatMemoryProvider {
ChatMemory get(Object var1);
}
1.定义会话记忆对象提供者
@Bean
public ChatMemoryProvider chatMemoryProvider(){
ChatMemoryProvider chatMemoryProvider = new ChatMemoryProvider() {
@Override
public ChatMemory get(Object memoryId) {
return MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(20)
.build();
}
};
return chatMemoryProvider;
}
2.配置会话记忆对象提供者
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT, // 手动装配
chatModel = "openAiChatModel" , // 指定模型
streamingChatModel = "openAiStreamingChatModel",
//chatMemory = "chatMemory",//配置会话记忆对象
chatMemoryProvider = "chatMemoryProvider"//配置会话记忆提供者
)
3.ConsultantService接口方法中添加参数memoryId
@SystemMessage(fromResource = "system.txt")
public Flux<String> chat(@MemoryId String memoryId,@UserMessage String message);
4.Controller中chat接口接收memoryId
@RequestMapping(value = "/chat",produces = "text/html;charset=utf-8")
public Flux<String> chat(String memoryId,String message){
Flux<String> result = consultantService.chat(memoryId,message);
return result;
}
5.前端页面请求时传递memoryId

运行结果如下:

发现会话记忆隔离:

4.5.3 会话记忆持久化
刚才我们做的会话记忆,只要后端重启,会话记忆就没有了,由于服务重启时,内存中的会话数据会丢失。

实现持久化的会话记忆方法如下:

这里选用使用Redis持久化:
1.准备redis环境

2.引入redis起步依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
3.配置redis连接信息
spring:
data:
redis:
host: localhost
port: 6379
4.提供ChatMemoryStore实现类
@Repository
public class RedisChatMemoryStore implements ChatMemoryStore {
//注入redisTemplate
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public List<ChatMessage> getMessages(Object memoryId) {
//获取会话消息
String json = redisTemplate.opsForValue().get(memoryId);
//把json字符串转成list
return ChatMessageDeserializer.messagesFromJson(json);
}
@Override
public void updateMessages(Object memoryId, List<ChatMessage> list) {
//更新会话
//1.把list转换成json数据
String json = ChatMessageSerializer.messagesToJson(list);
//2.把json数据存储到redis中
redisTemplate.opsForValue().set(memoryId.toString(),json, Duration.ofDays(1));
}
@Override
public void deleteMessages(Object memoryId) {
redisTemplate.delete(memoryId.toString());
}
}
5.配置ChatMemoryStore
@Autowired
private ChatMemoryStore redisChatMemoryStore ;
@Bean
public ChatMemoryProvider chatMemoryProvider(){
ChatMemoryProvider chatMemoryProvider = new ChatMemoryProvider() {
@Override
public ChatMemory get(Object memoryId) {
return MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(20)
.chatMemoryStore(redisChatMemoryStore)
.build();
}
};
return chatMemoryProvider;
}
运行结果如下:

后端重启,会话记忆从redis获取

五、RAG知识库
5.1 原理
没有使用检索增强生成(RAG)的情况,那么意味着系统完全依赖大语言模型(LLM)的内部参数化知识,而不从外部知识库检索信息。对时效性强的查询(如最新新闻、政策变化)可能给出过时或错误的回答。当模型遇到训练数据中未涵盖的问题时,可能生成看似合理但错误的答案。

RAG, Retrieval Augmented Generation, 检索增强生成。通过检索外部知识库的方式增强大模型的生成能力。

向量数据库包括Milvus、Chroma、Pinecone、RedisSearch(Reids)、pgvector(PostgreSQL)
向量余弦相似度,用于表示坐标系中两个点之间的距离远近


在第一象限中, cosθ(向量余弦相似度)的取值范围为(0,1)
余弦相似度越大,说明向量方向越接近,两点之间的距离越小
例如:

用户输入的内容,借助于向量模型转化为向量后,与数据库中的向量通过计算余弦相似度的方式,找出相似度比较高的文本片段。

例如:

两个向量的余弦相似度越高,说明向量对应的文本相似度越高
5.2 依赖引入
1.存储(构建向量数据库操作对象)
引入依赖
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-easy-rag</artifactId>
<version>1.0.1-beta6</version>
</dependency>
加载知识数据文档==>构建向量数据库操作对象==>把文档切割、向量化并存储到向量数据库中
@Bean
public EmbeddingStore store(){
//1.加载文档进内存
List<Document> documents = ClassPathDocumentLoader.loadDocuments("content");
//2.构建向量数据库操作对象
InMemoryEmbeddingStore store = new InMemoryEmbeddingStore();
//3.构建一个EmbeddingStoreIngestor对象,完成文本数据切割,向量化,存储
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingStore(store)
.build();
ingestor.ingest(documents);
return store;
}
2.检索(构建向量数据库检索对象)
构建向量数据库检索对象
//构建向量数据库检索对象
@Bean
public ContentRetriever contentRetriever(EmbeddingStore store){
return EmbeddingStoreContentRetriever.builder()
.embeddingStore(store)
.minScore(0.5)
.maxResults(3)
.build();
}
配置向量数据库检索对象
@AiService(
wiringMode = AiServiceWiringMode.EXPLICIT, // 手动装配
chatModel = "openAiChatModel" , // 指定模型
streamingChatModel = "openAiStreamingChatModel",
//chatMemory = "chatMemory",//配置会话记忆对象
chatMemoryProvider = "chatMemoryProvider",//配置会话记忆提供者
contentRetriever = "contentRetriever"//配置向量数据库检索对象
)
运行结果如下:

查看日志,后面加入了一些我们文档提供的信息

5.3 核心API

5.3.1 文档加载器
文档加载器,用于把磁盘或者网络中的数据加载进程序
FileSystemDocumentLoader, 根据本地磁盘绝对路径加载
ClassPathDocumentLoader ,相对于类路径加载
UrlDocumentLoader ,根据 url 路径加载
5.3.2 文档解析器
文档解析器,用于解析使用文档加载器加载进内存的内容,把非纯文本数据转化成纯文本
TextDocumentParser,解析纯文本格式的文件
ApachePdfBoxDocumentParser,解析pdf格式文件
ApachePoiDocumentParser ,解析微软的 office 文件,例如 DOC 、 PPT 、 XLS
ApacheTikaDocumentParser (默认),几乎可以解析所有格式的文件
未完继续。。。。