Spring AI Alibaba 从入门到实战:构建企业级 AI 应用

目录

摘要部分

01-前置知识&速成课推荐

02-程序员近况&未来趋势

[03-为什么要学习 Spring AI Alibaba](#03-为什么要学习 Spring AI Alibaba)

[04-Java AI 应用开发框架的选择](#04-Java AI 应用开发框架的选择)

[05-Spring AI Alibaba 介绍](#05-Spring AI Alibaba 介绍)

06-大模型的使用

[07-Spring AI Alibaba 小试牛刀_1:项目初始化与配置](#07-Spring AI Alibaba 小试牛刀_1:项目初始化与配置)

[08-Spring AI Alibaba 小试牛刀_2:编写第一个对话接口](#08-Spring AI Alibaba 小试牛刀_2:编写第一个对话接口)

[09-Spring AI Alibaba 小试牛刀_3:使用 ChatModel 进行更细粒度控制](#09-Spring AI Alibaba 小试牛刀_3:使用 ChatModel 进行更细粒度控制)

10-流式输出

[11-默认的模型名和 baseUrl](#11-默认的模型名和 baseUrl)

12-多模型共存

[13-Ollama 的介绍&下载](#13-Ollama 的介绍&下载)

[14-Ollama 的安装](#14-Ollama 的安装)

[15-使用 Ollama 本地部署大模型](#15-使用 Ollama 本地部署大模型)

[16-Java 微服务对接本地大模型](#16-Java 微服务对接本地大模型)

[17-ChatClient 与 ChatModel 的对比](#17-ChatClient 与 ChatModel 的对比)

[18-ChatClient 小试牛刀](#18-ChatClient 小试牛刀)

19-提示词介绍

20-提示词角色代码展示

21-提示词模版实操

22-提示词模版提取文件实操

23-对话记忆概念介绍

[24-对话记忆手动实现 1](#24-对话记忆手动实现 1)

[25-对话记忆手动实现 2](#25-对话记忆手动实现 2)

[26-对话记忆手动实现 3](#26-对话记忆手动实现 3)

27-对话记忆自动实现

28-多模态模型概念说明

29-多模态模型代码实现

30-向量和向量化解释

31-为什么要向量化

32-向量化代码实操

33-向量数据库作用

[34-Milvus Standalone 搭建](#34-Milvus Standalone 搭建)

[35-attu 可视化工具安装](#35-attu 可视化工具安装)

[36-Milvus 核心概念介绍](#36-Milvus 核心概念介绍)

[37-Milvus 代码实操-创建 Collection 和 Schema](#37-Milvus 代码实操-创建 Collection 和 Schema)

[38-Milvus 代码实操-插入数据](#38-Milvus 代码实操-插入数据)

[39-Milvus 代码实操-查询数据&删除数据](#39-Milvus 代码实操-查询数据&删除数据)

40-RAG&知识库的引入

[41-RAG 系统全流程架构图](#41-RAG 系统全流程架构图)


摘要部分

本文是一份基于用户提供的课程目录整理的 Spring AI Alibaba 详细学习教程。教程涵盖了从 AI 基础认知、框架选择、Spring AI Alibaba 核心功能(模型调用、流式输出、多模型共存、提示词工程、对话记忆、多模态、向量化与 RAG)到本地模型部署(Ollama)、向量数据库(Milvus)集成以及完整 RAG 系统实战的全流程。文中将穿插关键代码示例、官方文档链接及学习资源渠道,旨在帮助 Java 开发者系统掌握大模型应用开发技能。

01-前置知识&速成课推荐

在学习 Spring AI Alibaba 之前,建议具备以下基础知识:

  • Java 基础:熟悉 Java 8+ 特性,了解 Maven/Gradle 项目管理工具。
  • Spring Boot:掌握 Spring Boot 基础,能独立创建 Web 应用。
  • RESTful API:理解 HTTP 协议及 API 调用方式。
  • AI 基础概念:了解大模型、Token、Embedding、RAG 等术语。

速成课推荐

02-程序员近况&未来趋势

当前,AI 大模型技术正深刻改变软件开发范式。传统 CRUD 开发岗位竞争加剧,而掌握 AI 应用开发能力的"AI 原生程序员"需求激增。未来趋势包括:

  • AI 赋能传统软件:为现有系统添加智能问答、内容生成、数据分析能力。
  • Agent(智能体)开发:构建能自主理解、规划、执行复杂任务的 AI 应用。
  • 垂直领域深挖:金融、医疗、法律、教育等行业的专业化 AI 解决方案。
  • 工程化与落地:关注成本、性能、安全、可观测性,让 AI 应用稳定服务于业务。

学习 Spring AI Alibaba 等框架,正是 Java 开发者拥抱这一趋势、提升竞争力的关键一步。

03-为什么要学习 Spring AI Alibaba

Spring AI Alibaba 是阿里巴巴基于 Spring AI 生态提供的增强实现,针对国内开发者进行了深度优化:

  • 开箱即用:简化通义千问、DeepSeek 等国内主流大模型的接入配置。
  • 符合国情:网络、鉴权、计费方式更贴合国内云服务环境。
  • 生态整合:与 Spring Cloud Alibaba、Nacos、Sentinel 等阿里云原生组件无缝集成。
  • 降低门槛 :提供高层级的抽象(如 ChatClient),让开发者更关注业务逻辑而非底层通信。

04-Java AI 应用开发框架的选择

Java 生态中主要的 AI 应用开发框架/库对比如下:

框架 特点 适用场景
Spring AI Spring 官方出品,抽象统一,生态强大,学习曲线平缓。 企业级应用,需要与 Spring 生态深度集成。
Spring AI Alibaba 基于 Spring AI,针对国内模型和阿里云优化。 国内团队,使用通义千问、DeepSeek 等模型。
LangChain4j Java 版 LangChain,链式编排能力强,社区活跃。 需要复杂 AI 工作流编排(如 RAG、Agent)。
直接调用 SDK 使用各模型厂商提供的官方 SDK(如阿里云 DashScope SDK)。 简单调用,无需框架抽象,追求极致控制。

对于大多数希望快速构建稳定企业级 AI 应用的 Java 团队,Spring AI Alibaba 是平衡效率、稳定性和国内适配性的优选。

05-Spring AI Alibaba 介绍

Spring AI Alibaba 项目地址:GitHub - alibaba/spring-ai-alibaba

核心特性:

  • 多模型支持:通义千问、DeepSeek、智谱 AI、百度文心等。
  • 统一抽象 :通过 ChatClientChatModel 等接口屏蔽模型差异。
  • 便捷配置 :通过 application.yml 轻松配置 API Key、Base URL、模型参数。
  • 流式响应:支持 Server-Sent Events (SSE) 流式输出,提升用户体验。
  • 扩展组件:集成提示词模板、对话记忆、向量存储、函数调用等高级功能。

06-大模型的使用

使用大模型的核心步骤:

  1. 获取 API 密钥:在相应模型平台(如阿里云百炼、DeepSeek 开放平台)注册并获取。
  2. 明确输入与输出:设计清晰的提示词(Prompt),定义你希望模型完成的任务。
  3. 调用与解析:通过框架或 SDK 发送请求,并处理返回的响应。
  4. 评估与优化:根据结果调整提示词或模型参数,以达到最佳效果。

07-Spring AI Alibaba 小试牛刀_1:项目初始化与配置

1. 创建 Spring Boot 项目

使用 Spring Initializr 或 IDE 创建项目,依赖选择:

  • Spring Web
  • Spring AI Alibaba(需手动添加依赖)

2. 添加依赖(Maven 示例)

xml 复制代码
<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-spring-boot-starter</artifactId>
    <version>最新版本</version> <!-- 请查看GitHub获取最新版本 -->
</dependency>

3. 配置 application.yml

yaml 复制代码
spring:
  ai:
    alibaba:
      chat:
        enabled: true
        options:
          api-key: your-api-key-here # 替换为你的API Key
          model: qwen-turbo # 模型名称,例如 qwen-turbo, deepseek-chat
          base-url: https://dashscope.aliyuncs.com/compatible-mode/v1 # 通义千问兼容端点

08-Spring AI Alibaba 小试牛刀_2:编写第一个对话接口

创建一个简单的 REST 控制器,使用 ChatClient 进行对话。

java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ChatController {
private final ChatClient chatClient;

public ChatController(ChatClient chatClient) {
    this.chatClient = chatClient;
}

@GetMapping("/chat")
public String chat(@RequestParam String message) {
    return chatClient.prompt()
            .user(message)
            .call()
            .content();
}
}

启动应用,访问 http://localhost:8080/chat?message=你好,请介绍一下你自己,即可获得模型回复。

09-Spring AI Alibaba 小试牛刀_3:使用 ChatModel 进行更细粒度控制

ChatModel 提供了比 ChatClient 更底层的控制,可以设置系统提示词、调整温度等参数。

java 复制代码
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class AdvancedChatController {
private final ChatModel chatModel;

public AdvancedChatController(ChatModel chatModel) {
    this.chatModel = chatModel;
}

@GetMapping("/chat/advanced")
public String advancedChat() {
    SystemMessage systemMessage = new SystemMessage("你是一个专业的Java技术专家,回答要简洁准确。");
    UserMessage userMessage = new UserMessage("Spring Boot 的核心优势是什么?");
    Prompt prompt = new Prompt(List.of(systemMessage, userMessage));

    // 可以在这里设置更多参数,如 temperature, topP 等
    // prompt.getOptions().setTemperature(0.7);

    return chatModel.call(prompt).getResult().getOutput().getContent();
}
}

10-流式输出

流式输出允许服务器将响应内容分块发送给客户端,实现打字机效果,提升用户体验。Spring AI Alibaba 支持 Server-Sent Events (SSE)。

java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@RestController
public class StreamChatController {
private final ChatClient chatClient;

public StreamChatController(ChatClient chatClient) {
    this.chatClient = chatClient;
}

@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux&lt;String&gt; streamChat(@RequestParam String message) {
    return chatClient.prompt()
            .user(message)
            .stream()
            .content();
}
}

前端可以使用 EventSource 来接收流式响应。

11-默认的模型名和 baseUrl

Spring AI Alibaba 为不同模型提供了默认配置,减少冗余配置。常见模型的默认值:

模型提供商 默认 spring.ai.alibaba.chat.options.model 默认 spring.ai.alibaba.chat.options.base-url
通义千问 (DashScope) qwen-turbo https://dashscope.aliyuncs.com/compatible-mode/v1
DeepSeek deepseek-chat https://api.deepseek.com

application.yml 中,如果只配置 api-keymodel,框架会自动使用对应的默认 base-url

12-多模型共存

在实际项目中,可能需要同时连接多个模型(例如,一个用于创意生成,一个用于代码审查)。Spring AI Alibaba 支持通过定义多个 ChatModel Bean 来实现。

java 复制代码
import org.springframework.ai.alibaba.chat.AlibabaChatModel;
import org.springframework.ai.alibaba.chat.AlibabaChatOptions;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MultiModelConfig {
@Bean
public AlibabaChatModel qwenChatModel() {
    AlibabaChatOptions options = AlibabaChatOptions.builder()
            .apiKey("your-qwen-api-key")
            .model("qwen-max")
            .build();
    return new AlibabaChatModel(options);
}

@Bean
public AlibabaChatModel deepSeekChatModel() {
    AlibabaChatOptions options = AlibabaChatOptions.builder()
            .apiKey("your-deepseek-api-key")
            .model("deepseek-chat")
            .baseUrl("https://api.deepseek.com")
            .build();
    return new AlibabaChatModel(options);
}
}

在 Service 中,可以通过 @Qualifier 注入指定的模型 Bean 进行调用。

13-Ollama 的介绍&下载

Ollama 是一个用于在本地运行、管理和部署大型语言模型(LLM)的开源工具。它简化了模型下载、运行和提供 API 的过程。

核心优势

  • 本地运行:数据不出境,隐私和安全有保障。
  • 模型丰富:支持 Llama 3、Mistral、Gemma、Qwen 等众多开源模型。
  • 易于使用:命令行工具,一键拉取和运行模型。
  • 提供 API:提供兼容 OpenAI API 的接口,便于集成。

下载地址Ollama 官网,支持 macOS、Linux、Windows。

14-Ollama 的安装

以 macOS 为例:

bash 复制代码
# 1. 使用 Homebrew 安装(推荐)
brew install ollama
2. 启动 Ollama 服务
ollama serve
3. 打开新的终端窗口,拉取一个模型,例如 Llama 3
ollama pull llama3
4. 运行模型进行对话
ollama run llama3

安装完成后,Ollama 会在本地 http://localhost:11434 提供一个 API 服务。

15-使用 Ollama 本地部署大模型

Ollama 运行后,即可通过其 API 调用本地模型。Spring AI Alibaba 可以配置为连接 Ollama。

配置 application.yml

yaml 复制代码
spring:
  ai:
    alibaba:
      chat:
        enabled: true
        options:
          api-key: "ollama" # Ollama不需要真正的API Key,但属性需要存在
          model: llama3 # 你本地运行的模型名称
          base-url: http://localhost:11434/v1 # Ollama 的 OpenAI 兼容端点

之后,你的 ChatClientChatModel 就会将请求发送到本地 Ollama 服务。

16-Java 微服务对接本地大模型

将上述配置集成到 Spring Boot 微服务中,即可实现业务系统与本地大模型的对接。关键步骤:

  1. 在微服务的配置中心(如 Nacos)中管理 Ollama 的 base-url 和模型名称。
  2. 使用 Spring Cloud LoadBalancer(如果有多台模型服务器)或直接配置。
  3. 在业务 Service 中注入 ChatClient,封装具体的 AI 能力(如智能客服、内容审核、代码生成)。
  4. 添加熔断、降级、限流(通过 Sentinel)等保障措施,防止模型服务不稳定影响主业务。

这样,你的微服务就具备了本地 AI 能力,且完全可控。

17-ChatClient 与 ChatModel 的对比

在 Spring AI 中,ChatClientChatModel 是两个核心的对话抽象,但它们的定位和使用方式有明显区别。简单来说,ChatModel 是底层模型调用接口,而 ChatClient 是构建在其之上的高层流式 API,提供了更友好的链式调用体验。

特性 ChatClient ChatModel
定位 高层流式 API,面向业务开发,提供链式调用 底层模型抽象,直接封装模型调用逻辑
易用性 高,通过 prompt()user()call() 链式构建请求 较低,需要手动构造 Prompt 和消息列表
流式输出 内置支持,通过 stream() 返回 Flux 需要额外调用 stream() 方法并处理响应流
提示词模板 内置 PromptTemplate 支持,可快速填充变量 需要手动创建 PromptTemplate 并渲染
对话记忆 可通过 ChatMemory 自动管理历史消息 需要手动维护消息列表并传入 Prompt
参数控制 通过 options() 设置,但封装较深 更直接,可精细控制 temperature、topP 等参数
适用场景 快速开发对话接口、智能客服、内容生成等业务功能 需要深度定制模型行为、研究模型特性、多模型切换

选择建议 :日常业务开发优先使用 ChatClient,它更简洁、更符合 Spring 生态的声明式风格;当需要精细控制模型参数、研究模型行为或构建底层能力时,再使用 ChatModel

18-ChatClient 小试牛刀

下面通过一个完整的示例,演示 ChatClient 的常用能力,包括基础对话、流式输出、提示词模板和参数设置。

1. 基础对话

java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ChatClientDemoController {
private final ChatClient chatClient;

public ChatClientDemoController(ChatClient chatClient) {
    this.chatClient = chatClient;
}

@GetMapping("/demo/chat")
public String chat(@RequestParam String message) {
    return chatClient.prompt()
            .user(message)
            .call()
            .content();
}
}

2. 流式输出

java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@RestController
public class ChatClientStreamController {
private final ChatClient chatClient;
public ChatClientStreamController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@GetMapping(value = "/demo/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux&lt;String&gt; stream(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.stream()
.content();
}
}

3. 使用提示词模板

java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class ChatClientTemplateController {
private final ChatClient chatClient;
public ChatClientTemplateController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@GetMapping("/demo/template")
public String template(@RequestParam String topic) {
PromptTemplate template = new PromptTemplate("请用三句话介绍{topic},要求通俗易懂。");
return chatClient.prompt(template.create(Map.of("topic", topic)))
.call()
.content();
}
}

4. 设置模型参数

java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ChatClientOptionsController {
private final ChatClient chatClient;
public ChatClientOptionsController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@GetMapping("/demo/options")
public String options(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.options(org.springframework.ai.chat.client.ChatClient.ChatClientRequestSpec
.defaults()
.getOptions())
.call()
.content();
}
}

以上示例展示了 ChatClient 的核心用法。实际项目中,你可以根据业务需求组合使用这些能力,快速构建功能丰富的 AI 应用。

19-提示词介绍

提示词(Prompt)是与大模型交互的核心。一个精心设计的提示词,能显著提升模型输出的质量和准确性。提示词通常包含以下要素:

  • 角色设定:告诉模型它应该扮演什么角色,例如"你是一名资深 Java 架构师"。
  • 任务描述:明确说明需要模型完成的任务,例如"请解释 Spring 的依赖注入机制"。
  • 上下文信息:提供必要的背景资料,帮助模型理解问题。
  • 输出格式:指定期望的输出格式,例如"请用列表形式回答"。
  • 约束条件:限制回答的范围、长度或风格。

在 Spring AI 中,提示词通过 Prompt 对象封装,可以包含系统消息、用户消息和模型参数。

20-提示词角色代码展示

在 Spring AI 中,消息分为系统消息(SystemMessage)、用户消息(UserMessage)和助手消息(AssistantMessage)。下面演示如何组合使用这些角色。

java 复制代码
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class PromptRoleController {
private final ChatModel chatModel;
public PromptRoleController(ChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/prompt/roles")
public String roles() {
SystemMessage systemMessage = new SystemMessage("你是一位严谨的代码审查专家,擅长发现潜在问题并给出改进建议。");
UserMessage userMessage = new UserMessage("请审查以下代码:\npublic int divide(int a, int b) { return a / b; }");
Prompt prompt = new Prompt(List.of(systemMessage, userMessage));
return chatModel.call(prompt).getResult().getOutput().getContent();
}
}

通过合理设置系统消息,可以引导模型以特定角色和风格回答问题,从而获得更符合预期的输出。

21-提示词模版实操

提示词模板(PromptTemplate)允许你定义带占位符的模板,运行时动态填充变量,避免重复拼接字符串。

java 复制代码
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class PromptTemplateController {
private final ChatModel chatModel;
public PromptTemplateController(ChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/prompt/template")
public String template(@RequestParam String language, @RequestParam String topic) {
String templateText = "请用{language}写一段关于{topic}的简介,要求不超过100字。";
PromptTemplate template = new PromptTemplate(templateText);
Prompt prompt = template.create(Map.of("language", language, "topic", topic));
return chatModel.call(prompt).getResult().getOutput().getContent();
}
}

模板中的 {language}{topic} 会被 Map 中的值替换。这种方式让提示词更易维护和复用。

22-提示词模版提取文件实操

在实际项目中,提示词模板通常存放在资源文件中,便于统一管理和修改。下面演示如何从 classpath 加载模板文件。

1. 创建模板文件 src/main/resources/prompts/summary.st

text 复制代码
你是一名专业的内容编辑。请阅读以下文本,并生成一段简洁的摘要。
文本内容:
{content}
要求:
摘要不超过三句话。
保留核心信息。
使用中文回答。

2. 加载并渲染模板

java 复制代码
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
@RestController
public class PromptFileController {
private final ChatModel chatModel;
public PromptFileController(ChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/prompt/file")
public String file(@RequestParam String content) throws IOException {
ClassPathResource resource = new ClassPathResource("prompts/summary.st");
String templateText = new String(resource.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
PromptTemplate template = new PromptTemplate(templateText);
Prompt prompt = template.create(Map.of("content", content));
return chatModel.call(prompt).getResult().getOutput().getContent();
}
}

将模板外置到文件后,业务人员可以直接修改提示词而无需改动代码,大大提升了协作效率。

23-对话记忆概念介绍

大模型本身是无状态的,每次调用都是独立的。要实现多轮对话,需要将历史消息一并传给模型。对话记忆(Chat Memory)就是管理这些历史消息的机制。

对话记忆的核心价值:

  • 上下文连贯:让模型理解对话的来龙去脉,回答更准确。
  • 个性化体验:记住用户偏好,提供更贴心的服务。
  • 多轮任务:支持需要多步交互的复杂任务。

在 Spring AI 中,对话记忆可以通过手动管理消息列表,或使用 ChatMemory 自动管理。

24-对话记忆手动实现 1

最基础的对话记忆实现,是在每次请求时手动拼接历史消息。

java 复制代码
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
public class ManualMemoryController {
private final ChatModel chatModel;
private final List&lt;org.springframework.ai.chat.messages.Message&gt; history = new ArrayList&lt;&gt;();
public ManualMemoryController(ChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/memory/manual1")
public String chat(@RequestParam String message) {
history.add(new UserMessage(message));
Prompt prompt = new Prompt(history);
String response = chatModel.call(prompt).getResult().getOutput().getContent();
history.add(new AssistantMessage(response));
return response;
}
}

这种方式简单直接,但存在两个问题:一是历史消息无限增长,可能超出模型上下文窗口;二是并发场景下存在线程安全问题。

25-对话记忆手动实现 2

针对历史消息无限增长的问题,可以限制保留的消息数量,只保留最近 N 轮对话。

java 复制代码
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
@RestController
public class ManualMemoryController2 {
private final ChatModel chatModel;
private final Deque&lt;org.springframework.ai.chat.messages.Message&gt; history = new ArrayDeque&lt;&gt;();
private static final int MAX_MESSAGES = 10;
public ManualMemoryController2(ChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/memory/manual2")
public String chat(@RequestParam String message) {
history.addLast(new UserMessage(message));
while (history.size() &gt; MAX_MESSAGES) {
history.removeFirst();
}
Prompt prompt = new Prompt(List.copyOf(history));
String response = chatModel.call(prompt).getResult().getOutput().getContent();
history.addLast(new AssistantMessage(response));
while (history.size() &gt; MAX_MESSAGES) {
history.removeFirst();
}
return response;
}
}

通过 ArrayDeque 和最大消息数限制,避免了上下文无限膨胀的问题。

26-对话记忆手动实现 3

更进一步,可以为每个用户维护独立的对话历史,实现多用户隔离。

java 复制代码
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@RestController
public class ManualMemoryController3 {
private final ChatModel chatModel;
private final Map&lt;String, Deque&lt;org.springframework.ai.chat.messages.Message&gt;&gt; sessions = new ConcurrentHashMap&lt;&gt;();
private static final int MAX_MESSAGES = 10;
public ManualMemoryController3(ChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/memory/manual3")
public String chat(@RequestParam String sessionId, @RequestParam String message) {
Deque&lt;org.springframework.ai.chat.messages.Message&gt; history = sessions.computeIfAbsent(sessionId, k -&gt; new ArrayDeque&lt;&gt;());
history.addLast(new UserMessage(message));
while (history.size() &gt; MAX_MESSAGES) {
history.removeFirst();
}
Prompt prompt = new Prompt(List.copyOf(history));
String response = chatModel.call(prompt).getResult().getOutput().getContent();
history.addLast(new AssistantMessage(response));
while (history.size() &gt; MAX_MESSAGES) {
history.removeFirst();
}
return response;
}
}

使用 ConcurrentHashMapsessionId 隔离对话历史,支持多用户并发访问。

27-对话记忆自动实现

Spring AI 提供了 ChatMemory 接口和 MessageWindowChatMemory 实现,可以自动管理对话历史,无需手动维护消息列表。

java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Configuration
public class ChatMemoryConfig {
@Bean
public ChatMemory chatMemory() {
    return MessageWindowChatMemory.builder()
            .maxMessages(20)
            .build();
}
}
@RestController
public class AutoMemoryController {
private final ChatClient chatClient;
public AutoMemoryController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@GetMapping("/memory/auto")
public String chat(@RequestParam String sessionId, @RequestParam String message) {
return chatClient.prompt()
.user(message)
.memory(chatMemory -> chatMemory.id(sessionId))
.call()
.content();
}
}

通过 ChatMemory,框架会自动保存和加载指定会话的历史消息,开发者无需关心消息列表的维护细节。

28-多模态模型概念说明

多模态模型(Multimodal Model)能够同时处理和理解多种类型的数据,例如文本、图像、音频和视频。相比纯文本模型,多模态模型可以:

  • 图像理解:识别图片内容、分析图表、提取文字信息。
  • 图文生成:根据文本描述生成图像,或为图像生成描述。
  • 音频处理:语音识别、语音合成、音频内容分析。
  • 视频理解:分析视频内容,提取关键帧和语义信息。

在 Spring AI Alibaba 中,可以通过统一的接口调用支持多模态的模型(如通义千问 VL 系列),实现图文混合输入。

29-多模态模型代码实现

下面演示如何使用 Spring AI Alibaba 调用多模态模型,实现图像理解功能。

java 复制代码
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.ai.chat.messages.Media;
import org.springframework.core.io.ByteArrayResource;
import java.net.URI;
import java.util.List;
@RestController
public class MultimodalController {
private final ChatModel chatModel;
public MultimodalController(ChatModel chatModel) {
this.chatModel = chatModel;
}
@GetMapping("/multimodal/image")
public String analyzeImage(@RequestParam String imageUrl, @RequestParam String question) throws Exception {
URI uri = URI.create(imageUrl);
byte[] imageBytes = uri.toURL().openStream().readAllBytes();
Media media = new Media(ByteArrayResource.class, imageBytes, "image/png");
UserMessage userMessage = new UserMessage(question, List.of(media));
Prompt prompt = new Prompt(List.of(userMessage));
return chatModel.call(prompt).getResult().getOutput().getContent();
}
}

通过 Media 对象将图片数据附加到用户消息中,模型即可结合图片和文本进行回答。

30-向量和向量化解释

向量(Vector)是数学中表示方向和大小的一组数值。在 AI 领域,向量化(Embedding)是将文本、图像等非结构化数据转换为固定长度的数值数组的过程。

向量化的核心思想:

  • 语义编码:语义相近的内容,其向量在空间中的距离也更近。
  • 维度固定:无论原始文本多长,向量维度通常是固定的(如 1024 维)。
  • 计算相似度:通过余弦相似度等算法,可以量化两个向量的语义相似程度。

向量化是 RAG(检索增强生成)、语义搜索、推荐系统等应用的基础。

31-为什么要向量化

向量化的价值主要体现在以下几个方面:

  • 语义搜索:传统关键词搜索无法理解同义词和语义关联,向量搜索可以找到"苹果"和"水果"这类语义相近的内容。
  • 知识库检索:在 RAG 系统中,将文档向量化后存入向量数据库,查询时通过向量相似度召回最相关的片段。
  • 去重与聚类:通过向量距离判断内容相似度,实现文本去重、主题聚类。
  • 推荐系统:将用户和物品向量化,通过向量运算实现个性化推荐。

简单来说,向量化让机器能够"理解"语义,而不仅仅是匹配字符。

32-向量化代码实操

在 Spring AI Alibaba 中,可以通过 EmbeddingModel 接口调用向量化模型。

java 复制代码
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.EmbeddingRequest;
import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class EmbeddingController {
private final EmbeddingModel embeddingModel;
public EmbeddingController(EmbeddingModel embeddingModel) {
this.embeddingModel = embeddingModel;
}
@GetMapping("/embedding")
public List&lt;Double&gt; embed(@RequestParam String text) {
EmbeddingRequest request = new EmbeddingRequest(List.of(text), org.springframework.ai.embedding.EmbeddingOptions.EMPTY);
EmbeddingResponse response = embeddingModel.call(request);
return response.getResult().getOutput();
}
}

调用后返回一个数值数组,即文本的向量表示。你可以将多个文本向量化后,计算它们之间的余弦相似度来实现语义搜索。

33-向量数据库作用

向量数据库(Vector Database)专门用于存储和检索高维向量数据。它解决了传统数据库无法高效进行向量相似度搜索的问题。

向量数据库的核心能力:

  • 高效检索:使用 ANN(近似最近邻)算法,在海量向量中快速找到最相似的记录。
  • 元数据过滤:支持按标签、时间等元数据过滤后再进行向量搜索。
  • 混合查询:同时支持向量相似度和传统结构化查询。
  • 水平扩展:支持分布式部署,应对大规模数据。

常见的向量数据库包括 Milvus、Qdrant、Weaviate、Pinecone 等。在 RAG 系统中,向量数据库是知识库的核心存储组件。

34-Milvus Standalone 搭建

Milvus 是一个开源的分布式向量数据库。下面演示如何通过 Docker 搭建 Milvus Standalone 单机版。

1. 下载 docker-compose 文件

bash 复制代码
wget https://github.com/milvus-io/milvus/releases/download/v2.4.0/milvus-standalone-docker-compose.yml -O docker-compose.yml

2. 启动 Milvus

bash 复制代码
docker-compose up -d

3. 验证服务

bash 复制代码
docker ps
# 确认 milvus-standalone、etcd、minio 三个容器正常运行

Milvus 默认监听 http://localhost:19530,可以通过 attu 可视化工具或 SDK 连接。

35-attu 可视化工具安装

Attu 是 Milvus 的图形化管理界面,可以方便地查看集合、执行查询、管理数据。

1. 通过 Docker 安装 Attu

bash 复制代码
docker run -p 8000:3000 -e MILVUS_URL=localhost:19530 zilliz/attu:latest

2. 访问控制台

浏览器打开 http://localhost:8000,在连接配置中填写 Milvus 地址 localhost:19530,点击连接即可。

Attu 支持集合管理、向量检索、数据导入导出等功能,是调试 Milvus 的得力工具。

36-Milvus 核心概念介绍

使用 Milvus 前,需要理解以下核心概念:

  • Collection(集合):类似于关系数据库中的表,用于存储一组向量及其元数据。
  • Schema(模式):定义集合的字段结构,包括主键、向量字段、标量字段等。
  • Field(字段):集合中的列,分为向量字段和标量字段。
  • Index(索引):为向量字段建立的索引,用于加速相似度检索。
  • Partition(分区):将集合按某个字段划分为多个分区,提升查询效率。
  • Entity(实体):集合中的一行数据,包含向量和标量字段值。

理解这些概念,是正确使用 Milvus 进行向量检索的前提。

37-Milvus 代码实操-创建 Collection 和 Schema

下面演示如何使用 Java SDK 连接 Milvus 并创建集合。

java 复制代码
import io.milvus.client.MilvusServiceClient;
import io.milvus.param.ConnectParam;
import io.milvus.param.collection.CreateCollectionParam;
import io.milvus.param.collection.FieldType;
import io.milvus.param.collection.CollectionSchemaParam;
import io.milvus.common.clientenum.ConsistencyLevelEnum;
import io.milvus.param.IndexType;
import io.milvus.param.MetricType;
public class MilvusCreateCollection {
public static void main(String[] args) {
    MilvusServiceClient client = new MilvusServiceClient(
            ConnectParam.newBuilder()
                    .withHost("localhost")
                    .withPort(19530)
                    .build());
FieldType idField = FieldType.newBuilder()
        .withName("id")
        .withDataType(io.milvus.grpc.DataType.Int64)
        .withPrimaryKey(true)
        .withAutoID(false)
        .build();
FieldType vectorField = FieldType.newBuilder()
.withName("embedding")
.withDataType(io.milvus.grpc.DataType.FloatVector)
.withDimension(1024)
.build();
FieldType textField = FieldType.newBuilder()
.withName("text")
.withDataType(io.milvus.grpc.DataType.VarChar)
.withMaxLength(65535)
.build();
CollectionSchemaParam schema = CollectionSchemaParam.newBuilder()
.withName("knowledge_base")
.withDescription("知识库集合")
.addFieldType(idField)
.addFieldType(vectorField)
.addFieldType(textField)
.build();
CreateCollectionParam createParam = CreateCollectionParam.newBuilder()
.withCollectionName("knowledge_base")
.withSchema(schema)
.withConsistencyLevel(ConsistencyLevelEnum.STRONG)
.build();
client.createCollection(createParam);
System.out.println("集合创建成功");
client.close();
}
}

创建集合后,还需要为向量字段建立索引,才能进行高效的相似度检索。

38-Milvus 代码实操-插入数据

创建集合后,可以向其中插入向量数据。

java 复制代码
import io.milvus.client.MilvusServiceClient;
import io.milvus.param.ConnectParam;
import io.milvus.param.dml.InsertParam;
import java.util.Arrays;
import java.util.List;
public class MilvusInsertData {
public static void main(String[] args) {
    MilvusServiceClient client = new MilvusServiceClient(
            ConnectParam.newBuilder()
                    .withHost("localhost")
                    .withPort(19530)
                    .build());
List&amp;lt;Long&amp;gt; ids = Arrays.asList(1L, 2L);
List&amp;lt;List&amp;lt;Float&amp;gt;&amp;gt; vectors = Arrays.asList(
        generateVector(1),
        generateVector(2)
);
List&amp;lt;String&amp;gt; texts = Arrays.asList("Spring AI 是 Spring 官方推出的 AI 应用开发框架。", "Milvus 是一个高性能的向量数据库。");
InsertParam insertParam = InsertParam.newBuilder()
.withCollectionName("knowledge_base")
.withFields(Arrays.asList(
new InsertParam.Field("id", ids),
new InsertParam.Field("embedding", vectors),
new InsertParam.Field("text", texts)
))
.build();
client.insert(insertParam);
System.out.println("数据插入成功");
client.close();
}
private static List&lt;Float&gt; generateVector(int seed) {
Float[] vector = new Float[1024];
for (int i = 0; i &lt; 1024; i++) {
vector[i] = (float) Math.sin(seed * 0.01 + i);
}
return Arrays.asList(vector);
}
}

插入数据时,向量维度必须与集合 Schema 中定义的维度一致。

39-Milvus 代码实操-查询数据&删除数据

下面演示如何根据向量相似度查询数据,以及如何删除指定数据。

java 复制代码
import io.milvus.client.MilvusServiceClient;
import io.milvus.param.ConnectParam;
import io.milvus.param.dml.SearchParam;
import io.milvus.param.dml.DeleteParam;
import io.milvus.response.SearchResultsWrapper;
import java.util.Arrays;
import java.util.List;
public class MilvusQueryDelete {
public static void main(String[] args) {
    MilvusServiceClient client = new MilvusServiceClient(
            ConnectParam.newBuilder()
                    .withHost("localhost")
                    .withPort(19530)
                    .build());
// 1. 向量相似度查询
List&amp;lt;Float&amp;gt; queryVector = generateVector(1);
SearchParam searchParam = SearchParam.newBuilder()
        .withCollectionName("knowledge_base")
        .withVectors(Arrays.asList(queryVector))
        .withVectorFieldName("embedding")
        .withTopK(2)
        .withMetricType(io.milvus.param.MetricType.COSINE)
        .build();
SearchResultsWrapper results = client.search(searchParam).getData();
System.out.println("查询结果:" + results);
// 2. 删除数据
DeleteParam deleteParam = DeleteParam.newBuilder()
.withCollectionName("knowledge_base")
.withExpr("id in [1]")
.build();
client.delete(deleteParam);
System.out.println("数据删除成功");
client.close();
}
private static List&lt;Float&gt; generateVector(int seed) {
Float[] vector = new Float[1024];
for (int i = 0; i &lt; 1024; i++) {
vector[i] = (float) Math.sin(seed * 0.01 + i);
}
return Arrays.asList(vector);
}
}

通过 SearchParam 指定查询向量和检索参数,即可返回最相似的 TopK 条记录。

40-RAG&知识库的引入

RAG(Retrieval-Augmented Generation,检索增强生成)是一种将信息检索与大模型生成相结合的技术。它解决了大模型的两个核心问题:

  • 知识时效性:大模型训练数据有截止日期,无法回答最新信息。
  • 领域知识缺失:大模型缺乏企业内部的私有知识。

RAG 的核心流程:

  1. 文档入库:将企业文档切分、向量化后存入向量数据库。
  2. 检索召回:用户提问时,将问题向量化,在向量库中检索最相关的文档片段。
  3. 增强生成:将检索到的片段与用户问题一起交给大模型,生成基于事实的回答。

RAG 让大模型能够"基于你的数据回答问题",是当前企业落地 AI 应用的主流方案。

41-RAG 系统全流程架构图

下面用 Mermaid 展示一个完整的 RAG 系统架构:

flowchart TD A[用户提问] --> B[问题向量化] B --> C[向量数据库检索] C --> D[召回相关文档片段] D --> E[拼接提示词] E --> F[大模型生成回答] F --> G[返回用户] H[企业文档] --&gt; I[文档切分] I --&gt; J[文档向量化] J --&gt; C</code></pre> 整个流程分为离线入库和在线检索两条链路。离线阶段将文档向量化入库,在线阶段根据用户问题检索并生成回答。 42-导游考试 RAG 系统代码实现 1 下面通过一个导游考试问答系统,完整演示 RAG 的落地实现。首先创建文档入库服务。 import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.EmbeddingRequest; import org.springframework.ai.embedding.EmbeddingResponse; import org.springframework.stereotype.Service; import io.milvus.client.MilvusServiceClient; import io.milvus.param.ConnectParam; import io.milvus.param.dml.InsertParam; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @Service public class DocumentIngestService { private final EmbeddingModel embeddingModel; private final MilvusServiceClient milvusClient; public DocumentIngestService(EmbeddingModel embeddingModel) { this.embeddingModel = embeddingModel; this.milvusClient = new MilvusServiceClient( ConnectParam.newBuilder() .withHost("localhost") .withPort(19530) .build()); } public void ingestDocument(String text, Long docId) { // 1. 将文档切分为片段(这里简化为按句号切分) String[] chunks = text.split("。"); List&lt;Long&gt; ids = new ArrayList&lt;&gt;(); List&lt;List&lt;Float&gt;&gt; vectors = new ArrayList&lt;&gt;(); List&lt;String&gt; texts = new ArrayList&lt;&gt;(); for (int i = 0; i &amp;lt; chunks.length; i++) { String chunk = chunks[i].trim(); if (chunk.isEmpty()) continue; // 2. 向量化 EmbeddingRequest request = new EmbeddingRequest(List.of(chunk), org.springframework.ai.embedding.EmbeddingOptions.EMPTY); EmbeddingResponse response = embeddingModel.call(request); List&amp;amp;lt;Double&amp;amp;gt; embedding = response.getResult().getOutput(); // 3. 转换为 Float 列表 List&amp;amp;lt;Float&amp;amp;gt; floatVector = new ArrayList&amp;amp;lt;&amp;amp;gt;(); for (Double d : embedding) { floatVector.add(d.floatValue()); } ids.add(docId * 1000L + i); vectors.add(floatVector); texts.add(chunk); } // 4. 插入 Milvus InsertParam insertParam = InsertParam.newBuilder() .withCollectionName("guide_exam_kb") .withFields(Arrays.asList( new InsertParam.Field("id", ids), new InsertParam.Field("embedding", vectors), new InsertParam.Field("text", texts) )) .build(); milvusClient.insert(insertParam); } } 该服务将文档切分、向量化并写入 Milvus,完成知识库的离线构建。 43-导游考试 RAG 系统代码实现 2 接下来实现检索服务,根据用户问题从向量库中召回相关文档片段。 import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.EmbeddingRequest; import org.springframework.ai.embedding.EmbeddingResponse; import org.springframework.stereotype.Service; import io.milvus.client.MilvusServiceClient; import io.milvus.param.ConnectParam; import io.milvus.param.dml.SearchParam; import io.milvus.response.SearchResultsWrapper; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @Service public class RetrievalService { private final EmbeddingModel embeddingModel; private final MilvusServiceClient milvusClient; public RetrievalService(EmbeddingModel embeddingModel) { this.embeddingModel = embeddingModel; this.milvusClient = new MilvusServiceClient( ConnectParam.newBuilder() .withHost("localhost") .withPort(19530) .build()); } public List&lt;String&gt; retrieve(String question, int topK) { // 1. 问题向量化 EmbeddingRequest request = new EmbeddingRequest(List.of(question), org.springframework.ai.embedding.EmbeddingOptions.EMPTY); EmbeddingResponse response = embeddingModel.call(request); List&lt;Double&gt; embedding = response.getResult().getOutput(); List&amp;lt;Float&amp;gt; floatVector = new ArrayList&amp;lt;&amp;gt;(); for (Double d : embedding) { floatVector.add(d.floatValue()); } // 2. 向量检索 SearchParam searchParam = SearchParam.newBuilder() .withCollectionName("guide_exam_kb") .withVectors(Arrays.asList(floatVector)) .withVectorFieldName("embedding") .withTopK(topK) .withMetricType(io.milvus.param.MetricType.COSINE) .build(); SearchResultsWrapper results = milvusClient.search(searchParam).getData(); // 3. 提取文本片段 List&amp;lt;String&amp;gt; chunks = new ArrayList&amp;lt;&amp;gt;(); for (int i = 0; i &amp;lt; results.getRowCount(); i++) { String text = (String) results.getFieldData("text", i).get(0); chunks.add(text); } return chunks; } } 检索服务将用户问题向量化后,在 Milvus 中检索最相似的文档片段并返回。 44-导游考试 RAG 系统代码实现 3 最后,将检索结果与用户问题一起交给大模型,生成最终回答。 import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.Map; @Service public class RagAnswerService { private final ChatClient chatClient; private final RetrievalService retrievalService; public RagAnswerService(ChatClient chatClient, RetrievalService retrievalService) { this.chatClient = chatClient; this.retrievalService = retrievalService; } public String answer(String question) { // 1. 检索相关文档 List&lt;String&gt; chunks = retrievalService.retrieve(question, 3); String context = String.join("\n", chunks); // 2. 构造提示词 String templateText = """ 你是一名专业的导游考试辅导老师。请根据以下参考资料回答用户问题。 如果参考资料中没有相关信息,请如实说明。 参考资料: {context} 用户问题:{question} 请用中文回答,要求准确、简洁。 """; PromptTemplate template = new PromptTemplate(templateText); return chatClient.prompt(template.create(Map.of("context", context, "question", question))) .call() .content(); } } @RestController class RagController { private final RagAnswerService ragAnswerService; public RagController(RagAnswerService ragAnswerService) { this.ragAnswerService = ragAnswerService; } @GetMapping("/rag/ask") public String ask(@RequestParam String question) { return ragAnswerService.answer(question); } } 至此,一个完整的导游考试 RAG 问答系统已经实现:文档入库、向量检索、增强生成三个环节全部打通。 AI 大模型马士集团课程优势 马士集团(Mars Group)的 AI 大模型课程以工程化落地为核心,强调从理论到实战的完整闭环。课程优势主要体现在: 实战驱动:以真实业务场景为案例,学员在项目中掌握技能。 全栈覆盖:从模型选型、提示词工程、RAG 到微服务集成,覆盖 AI 应用开发全链路。 企业级标准:融入 Nacos、Sentinel、Milvus 等企业级组件,贴近生产环境。 就业导向:课程内容与岗位需求对齐,帮助学员快速进入 AI 开发领域。 大模型工程化落地技术技能详解 大模型工程化落地需要掌握以下核心技术技能: 模型接入与抽象:使用 Spring AI 等框架统一接入多家模型,降低切换成本。 提示词工程:设计高质量提示词,提升模型输出质量。 RAG 系统构建:掌握文档切分、向量化、向量检索、增强生成全流程。 对话记忆管理:实现多轮对话的上下文管理,提升用户体验。 性能与成本优化:通过流式输出、模型缓存、降级熔断等手段控制成本和延迟。 可观测性:监控模型调用日志、Token 消耗、响应时间,保障系统稳定。 大模型就业市场与未来趋势 当前大模型就业市场呈现以下特点: 需求旺盛:AI 应用开发、大模型微调、RAG 工程师等岗位需求快速增长。 技能溢价:掌握大模型应用开发的工程师薪资显著高于传统 CRUD 开发。 行业渗透:金融、医疗、教育、制造等行业都在探索 AI 应用,岗位覆盖面广。 未来趋势:Agent 智能体、多模态应用、行业大模型将成为下一阶段热点。 大模型面试官最新考点 大模型相关岗位面试中,以下考点出现频率较高: RAG 原理与实现:检索增强的流程、向量数据库选型、切分策略。 提示词工程:如何设计系统提示词、处理长上下文、避免幻觉。 对话记忆:多轮对话的状态管理、窗口策略、持久化方案。 模型选型:不同模型的适用场景、成本对比、私有化部署方案。 工程化能力:流式输出、并发控制、熔断降级、可观测性。 大模型适合哪些年龄段 大模型技术学习没有严格的年龄限制,关键在于基础和学习意愿: 在校学生:计算机相关专业学生,具备编程基础,学习速度快。 初级开发者:1-3 年经验的 Java/Python 开发者,转型 AI 应用开发。 资深工程师:有丰富架构经验,向 AI 架构师方向进阶。 转行人员:非技术背景但逻辑思维强,可从提示词工程、产品方向切入。 只要具备基本的编程能力和持续学习的热情,任何年龄段都可以掌握大模型应用开发。 岗位搜索城市选择与薪资 大模型相关岗位的分布和薪资受城市影响较大: 城市 岗位特点 薪资范围(月薪) 北京 大厂总部集中,AI 岗位最多,竞争激烈。 25K-60K 上海 金融、互联网企业多,AI 应用场景丰富。 25K-55K 深圳 硬件与互联网结合,AI 落地项目多。 22K-50K 杭州 阿里系企业带动,AI 生态活跃。 20K-45K 成都/武汉 二线城市中 AI 岗位较多,性价比高。 15K-30K 建议根据自身技术栈和职业规划,结合城市产业特点选择目标城市。 简历项目数量与写法 在简历中展示 AI 项目时,建议遵循以下原则: 数量适中:精选 2-3 个高质量项目,突出深度而非数量。 突出业务价值:说明项目解决了什么业务问题,带来了什么收益。 技术栈清晰:明确列出使用的框架、模型、数据库等关键技术。 量化成果:用数据说话,例如"检索准确率提升 20%""响应时间降低 50%"。 体现思考:描述技术选型理由、遇到的挑战和解决方案。 一个优秀的 AI 项目描述,应当让面试官快速理解你做了什么、怎么做的、效果如何。
相关推荐
小易测试笔记1 小时前
芯片ESD测试仪是什么?主要有哪几种不同类型?
人工智能
科技每日热闻1 小时前
AI 赋能财务资金管理、风险预警、经营数据分析,合适的云上财务智能 Agent 有哪些?—— 优先采用 Amazon Quick 四链路解决方案
人工智能·ai·数据挖掘·数据分析
Linguwen1 小时前
外贸GEO06|AI搜索引擎怎么工作?理解原理才能做好优化
人工智能·搜索引擎
DS随心转APP1 小时前
生成word文档的DeepSeek底层解码与“AI导出鸭”工程化方案:一份技术架构师的全维度测评
人工智能·ai·chatgpt·word·deepseek·ai导出鸭
小猴子下山1231 小时前
2026年无锡滨湖区健康管理公司解析:全周期服务与细胞技术如何匹配需求
人工智能·精选
武子康1 小时前
Pi 怎样决定模型看见什么:AGENTS.md、SYSTEM.md 与 Skills 的加载边界
人工智能·llm·agent
深念Y1 小时前
Opencode Event 表写入优化方案
数据库·人工智能·ai·node.js·bug·优化·opencode
橘和柠1 小时前
YOLOv8 目标检测:从训练到部署全流程(接单高频需求)
人工智能
原野池予1 小时前
深入Java集合框架:数组与List互转底层原理剖析(JDK 8)
java·数据结构·list