Spring AI Alibaba 从入门到实战:构建企业级 AI 应用
目录
07-Spring AI Alibaba 小试牛刀_1:项目初始化与配置
08-Spring AI Alibaba 小试牛刀_2:编写第一个对话接口
09-Spring AI Alibaba 小试牛刀_3:使用 ChatModel 进行更细粒度控制
37-Milvus 代码实操-创建 Collection 和 Schema
摘要部分
本文是一份基于用户提供的课程目录整理的 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 等术语。
速成课推荐:
- 【狂神说】SpringBoot 最新教程(快速上手 Spring Boot)
- 【尚硅谷】大模型入门导论(建立 AI 认知)
- Spring AI 官方文档(核心框架参考)
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、百度文心等。
- 统一抽象:通过
ChatClient、ChatModel等接口屏蔽模型差异。 - 便捷配置:通过
application.yml轻松配置 API Key、Base URL、模型参数。 - 流式响应:支持 Server-Sent Events (SSE) 流式输出,提升用户体验。
- 扩展组件:集成提示词模板、对话记忆、向量存储、函数调用等高级功能。
06-大模型的使用
使用大模型的核心步骤:
- 获取 API 密钥:在相应模型平台(如阿里云百炼、DeepSeek 开放平台)注册并获取。
- 明确输入与输出:设计清晰的提示词(Prompt),定义你希望模型完成的任务。
- 调用与解析:通过框架或 SDK 发送请求,并处理返回的响应。
- 评估与优化:根据结果调整提示词或模型参数,以达到最佳效果。
07-Spring AI Alibaba 小试牛刀_1:项目初始化与配置
1. 创建 Spring Boot 项目
使用 Spring Initializr 或 IDE 创建项目,依赖选择:
- Spring Web
- Spring AI Alibaba(需手动添加依赖)
2. 添加依赖(Maven 示例)
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-spring-boot-starter</artifactId>
<version>最新版本</version> <!-- 请查看GitHub获取最新版本 -->
</dependency>
3. 配置 application.yml
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 进行对话。
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 更底层的控制,可以设置系统提示词、调整温度等参数。
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)。
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<String> 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-key 和 model,框架会自动使用对应的默认 base-url。
12-多模型共存
在实际项目中,可能需要同时连接多个模型(例如,一个用于创意生成,一个用于代码审查)。Spring AI Alibaba 支持通过定义多个 ChatModel Bean 来实现。
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 为例:
# 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:
spring:
ai:
alibaba:
chat:
enabled: true
options:
api-key: "ollama" # Ollama不需要真正的API Key,但属性需要存在
model: llama3 # 你本地运行的模型名称
base-url: http://localhost:11434/v1 # Ollama 的 OpenAI 兼容端点
之后,你的 ChatClient 或 ChatModel 就会将请求发送到本地 Ollama 服务。
16-Java 微服务对接本地大模型
将上述配置集成到 Spring Boot 微服务中,即可实现业务系统与本地大模型的对接。关键步骤:
- 在微服务的配置中心(如 Nacos)中管理 Ollama 的
base-url和模型名称。 - 使用 Spring Cloud LoadBalancer(如果有多台模型服务器)或直接配置。
- 在业务 Service 中注入
ChatClient,封装具体的 AI 能力(如智能客服、内容审核、代码生成)。 - 添加熔断、降级、限流(通过 Sentinel)等保障措施,防止模型服务不稳定影响主业务。
这样,你的微服务就具备了本地 AI 能力,且完全可控。
17-ChatClient 与 ChatModel 的对比
在 Spring AI 中,ChatClient 和 ChatModel 是两个核心的对话抽象,但它们的定位和使用方式有明显区别。简单来说,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. 基础对话
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. 流式输出
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<String> stream(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.stream()
.content();
}
}
3. 使用提示词模板
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. 设置模型参数
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)。下面演示如何组合使用这些角色。
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)允许你定义带占位符的模板,运行时动态填充变量,避免重复拼接字符串。
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
你是一名专业的内容编辑。请阅读以下文本,并生成一段简洁的摘要。
文本内容:
{content}
要求:
摘要不超过三句话。
保留核心信息。
使用中文回答。
2. 加载并渲染模板
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
最基础的对话记忆实现,是在每次请求时手动拼接历史消息。
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<org.springframework.ai.chat.messages.Message> history = new ArrayList<>();
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 轮对话。
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<org.springframework.ai.chat.messages.Message> history = new ArrayDeque<>();
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() > 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() > MAX_MESSAGES) {
history.removeFirst();
}
return response;
}
}
通过 ArrayDeque 和最大消息数限制,避免了上下文无限膨胀的问题。
26-对话记忆手动实现 3
更进一步,可以为每个用户维护独立的对话历史,实现多用户隔离。
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<String, Deque<org.springframework.ai.chat.messages.Message>> sessions = new ConcurrentHashMap<>();
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<org.springframework.ai.chat.messages.Message> history = sessions.computeIfAbsent(sessionId, k -> new ArrayDeque<>());
history.addLast(new UserMessage(message));
while (history.size() > 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() > MAX_MESSAGES) {
history.removeFirst();
}
return response;
}
}
使用 ConcurrentHashMap 按 sessionId 隔离对话历史,支持多用户并发访问。
27-对话记忆自动实现
Spring AI 提供了 ChatMemory 接口和 MessageWindowChatMemory 实现,可以自动管理对话历史,无需手动维护消息列表。
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 调用多模态模型,实现图像理解功能。
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 接口调用向量化模型。
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<Double> 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 文件
wget https://github.com/milvus-io/milvus/releases/download/v2.4.0/milvus-standalone-docker-compose.yml -O docker-compose.yml
2. 启动 Milvus
docker-compose up -d
3. 验证服务
docker ps
# 确认 milvus-standalone、etcd、minio 三个容器正常运行
Milvus 默认监听 http://localhost:19530,可以通过 attu 可视化工具或 SDK 连接。
35-attu 可视化工具安装
Attu 是 Milvus 的图形化管理界面,可以方便地查看集合、执行查询、管理数据。
1. 通过 Docker 安装 Attu
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 并创建集合。
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 代码实操-插入数据
创建集合后,可以向其中插入向量数据。
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&lt;Long&gt; ids = Arrays.asList(1L, 2L);
List&lt;List&lt;Float&gt;&gt; vectors = Arrays.asList(
generateVector(1),
generateVector(2)
);
List&lt;String&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<Float> generateVector(int seed) {
Float[] vector = new Float[1024];
for (int i = 0; i < 1024; i++) {
vector[i] = (float) Math.sin(seed * 0.01 + i);
}
return Arrays.asList(vector);
}
}
插入数据时,向量维度必须与集合 Schema 中定义的维度一致。
39-Milvus 代码实操-查询数据&删除数据
下面演示如何根据向量相似度查询数据,以及如何删除指定数据。
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&lt;Float&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<Float> generateVector(int seed) {
Float[] vector = new Float[1024];
for (int i = 0; i < 1024; i++) {
vector[i] = (float) Math.sin(seed * 0.01 + i);
}
return Arrays.asList(vector);
}
}
通过 SearchParam 指定查询向量和检索参数,即可返回最相似的 TopK 条记录。
40-RAG&知识库的引入
RAG(Retrieval-Augmented Generation,检索增强生成)是一种将信息检索与大模型生成相结合的技术。它解决了大模型的两个核心问题:
- 知识时效性:大模型训练数据有截止日期,无法回答最新信息。
- 领域知识缺失:大模型缺乏企业内部的私有知识。
RAG 的核心流程:
- 文档入库:将企业文档切分、向量化后存入向量数据库。
- 检索召回:用户提问时,将问题向量化,在向量库中检索最相关的文档片段。
- 增强生成:将检索到的片段与用户问题一起交给大模型,生成基于事实的回答。
RAG 让大模型能够“基于你的数据回答问题”,是当前企业落地 AI 应用的主流方案。
41-RAG 系统全流程架构图
下面用 Mermaid 展示一个完整的 RAG 系统架构:
flowchart TD
A[用户提问] --> B[问题向量化]
B --> C[向量数据库检索]
C --> D[召回相关文档片段]
D --> E[拼接提示词]
E --> F[大模型生成回答]
F --> G[返回用户]
H[企业文档] --> I[文档切分]
I --> J[文档向量化]
J --> 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<Long> ids = new ArrayList<>();
List<List<Float>> vectors = new ArrayList<>();
List<String> texts = new ArrayList<>();
for (int i = 0; i &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;lt;Double&amp;gt; embedding = response.getResult().getOutput();
// 3. 转换为 Float 列表
List&amp;lt;Float&amp;gt; floatVector = new ArrayList&amp;lt;&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<String> 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<Double> embedding = response.getResult().getOutput();
List&lt;Float&gt; floatVector = new ArrayList&lt;&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&lt;String&gt; chunks = new ArrayList&lt;&gt;();
for (int i = 0; i &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<String> 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 项目描述,应当让面试官快速理解你做了什么、怎么做的、效果如何。更多推荐


所有评论(0)