← 返回首页

第1章: Spring AI 快速上手:9 个测试带你吃透核心 API

通过 9 个测试用例掌握 Spring AI 核心 API

🚧 准备篇:项目环境与基础配置(Step 00)

在开始写 Spring AI 的测试代码之前,你需要先有一个能正常启动的 Spring Boot 项目,并且已经正确接入通义千问。 如果你对 Spring Boot 还不熟悉,可以把本节当成"照着做"的安装说明,一步一步完成即可。

1️⃣ 准备开发环境

  • 电脑上已经安装 JDK 17 或以上版本,并能在终端输入 java -version 正常看到版本号。
  • 安装好一个 Java IDE(推荐 IntelliJ IDEA,也可以用 STS / Eclipse)。
  • 如果你习惯用命令行构建项目,建议安装 Maven,并在终端输入 mvn -v 能看到版本号。

2️⃣ 创建并配置 Spring AI 项目

  • 使用 Spring Initializr 创建一个新的 Spring Boot 项目,Group 建议为 com.example,Artifact 建议为 spring-ai-tutorial
  • pom.xml 中添加 Spring AI 相关依赖(见后文依赖示例)。
  • src/main/resources/application.yml 中配置 Spring AI 所需的 DASHSCOPE_API_KEY,让程序可以调用通义千问。
  • API Key 不要写死在 yml 里,推荐通过环境变量传入,这样更安全。

3️⃣ 运行主类,验证环境

  • 在 IDE 中找到项目主类(例如 AiChatbotApplication),点击运行按钮启动项目。
  • 等待控制台输出 Started AiChatbotApplication 类似的日志,说明 Spring Boot 已经启动成功。
  • 如果没有异常抛出,就说明当前 Spring 项目和 Spring AI 基础配置是 OK 的,可以开始本章的测试代码练习。

🧭 完整流程速览

  1. 检查本机环境:确认 JDK 17+、Maven(可选)和 IDE 安装正常。
  2. 在阿里云百炼控制台申请通义千问 API Key,并妥善保存。
  3. 创建项目目录或使用 Spring Initializr 生成 spring-ai-tutorial 项目。
  4. pom.xml 中添加 Spring Boot 与 Spring AI 相关依赖,执行构建确保无错误。
  5. src/main/java/com/example/chatbot 下创建 AiChatbotApplication 主类。
  6. src/main/resources 下创建 application.yml,配置应用名和 spring.ai.dashscope.api-key
  7. 在操作系统中配置 DASHSCOPE_API_KEY 环境变量(macOS 可通过 ~/.zshrc)。
  8. 运行主类,确认应用能正常启动且无报错日志。
  9. src/test/java/com/example/chatbot/knowledge 目录下准备测试类文件,为后续章节做准备。

📄 示例配置文件:application.yml

src/main/resources/application.yml 中,可以参考下面的配置:

spring: application: name: spring-ai-tutorial # ========== Spring AI 配置 ========== ai: dashscope: # API Key:从环境变量读取 api-key: ${DASHSCOPE_API_KEY:your-api-key-here} # 聊天模型配置 chat: options: model: qwen-plus # 或 qwen-turbo / qwen-max temperature: 0.7 # 控制随机性(0.0-2.0) # Embedding 模型配置(用于 RAG) embedding: options: model: text-embedding-v2 server: port: 8080 # 文件上传大小限制 servlet: multipart: max-file-size: 10MB # 单个文件最大大小 max-request-size: 50MB # 整个请求最大大小 logging: level: root: INFO com.example.chatbot: DEBUG

💡 这里的模型和端口都可以根据自己的需要调整,本教程后续示例默认使用 qwen-plus8080 端口。

🚀 示例启动类:AiChatbotApplication

src/main/java/com/example/chatbot/AiChatbotApplication.java 中,可以这样编写主类:

package com.example.chatbot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; /** * Spring AI 教学项目主类 */ @SpringBootApplication @ComponentScan(basePackages = "com.example") public class AiChatbotApplication { public static void main(String[] args) { SpringApplication.run(AiChatbotApplication.class, args); System.out.println("\n" + "╔══════════════════════════════════════════╗\n" + "║ Spring AI 教学项目启动成功! 🎉 ║\n" + "║ ║\n" + "║ 访问:http://localhost:8080 ║\n" + "║ ║\n" + "║ 开始你的 Spring AI 学习之旅! 🚀 ║\n" + "╚══════════════════════════════════════════╝\n"); } }

只要这个主类能正常启动,并且没有报错,就说明你的 Spring AI 项目骨架已经准备好了,可以进入本章后面的测试用例学习。

🧱 pom.xml(完整,可折叠)

点击展开查看完整 pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.0</version> <relativePath/> </parent> <groupId>com.example</groupId> <artifactId>spring-ai-tutorial</artifactId> <version>1.0.0</version> <name>Spring AI Tutorial</name> <description>Spring AI 教学项目</description> <properties> <java.version>17</java.version> <spring-ai.version>1.0.0-M6</spring-ai.version> </properties> <dependencies> <!-- Spring Boot Web:提供 Web 服务和 RESTful API 支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 阿里云百炼(通义千问):支持对话和 Embedding --> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter</artifactId> <version>1.0.0-M6.1</version> </dependency> <!-- Reactor(响应式编程,用于流式响应) --> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-core</artifactId> </dependency> <!-- Spring Boot 测试 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- Reactor 测试工具 --> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-bom</artifactId> <version>${spring-ai.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <!-- Spring Boot Maven 插件 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> </project>

⬇️ 示例前端文件下载

本章配套提供了一个极简的前端页面(index.html + app.js + style.css),你可以直接下载到本地后打开或按需改造。正式使用时,请将这 3 个文件放到你项目的 src/main/resources/static/ 目录下(不要再新建 data 子目录)。

📂 项目结构示意图

完成本章准备工作后,项目整体结构大致如下:

spring-ai-tutorial/ ├── pom.xml ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── chatbot/ │ │ │ └── AiChatbotApplication.java │ │ └── resources/ │ │ ├── application.yml │ │ └── static/ │ │ ├── index.html │ │ ├── app.js │ │ └── style.css │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── chatbot/ │ └── knowledge/ │ └── Test01_SpringAIBasics.java

你可以对照这个结构检查:如果目录和文件名都一致,那么复制本章和 Step01 的代码时,基本不会遇到路径问题。

📋 本章目标

本章通过 9 个完整的测试用例,带你从零开始掌握 Spring AI 的核心概念和基本用法。 你将学会如何注入 ChatModel、发送消息、处理响应,以及使用 System Prompt 定制 AI 角色。

✨ 你将学到什么?

  • ✅ 创建第一个 Spring AI 测试类
  • ✅ 理解 Spring Boot 测试的基本结构
  • ✅ 学会注入和使用 ChatModel
  • ✅ 掌握 PromptMessageChatResponse 等核心 API
  • ✅ 学会使用 System Prompt 定制 AI 角色
  • ✅ 理解如何设计结构化的 System Prompt

📚 测试用例索引

基础测试(1.1-1.6)

  • 测试 1.1:ChatModel 注入测试
  • 测试 1.2:简单对话测试
  • 测试 1.3:使用 Prompt 对象
  • 测试 1.4:使用 Message 列表
  • 测试 1.5:获取详细响应信息
  • 测试 1.6:空消息处理

进阶测试(1.7-1.9)- System Prompt

  • 测试 1.7:使用 System Prompt 定制 AI 角色
  • 测试 1.8:对比有无 System Prompt 的差异
  • 测试 1.9:System Prompt 最佳实践示例

🎯 前置准备

1. 项目依赖

pom.xml 中添加以下依赖:

<dependency> <groupId>org.springframework.ai</artifactId> <artifactId>spring-ai-alibaba-starter</artifactId> <version>1.0.0-M2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>

2. 配置 API Key

application.yml 中配置通义千问 API Key:

spring: ai: dashscope: api-key: ${DASHSCOPE_API_KEY} # 从环境变量读取

🔑 获取 API Key

访问 阿里云 DashScope 控制台 获取 API Key

📝 创建测试类

1. 测试类基本结构

创建文件:src/test/java/com/example/chatbot/knowledge/Test01_SpringAIBasics.java

package com.example.chatbot.knowledge; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.ArrayList; import java.util.List; import static org.junit.jupiter.api.Assertions.*; /** * 测试类:Spring AI 基础知识 * * 本测试类演示 Spring AI 的核心概念和基本用法 */ @SpringBootTest(classes = com.example.chatbot.AiChatbotApplication.class) @DisplayName("知识点1:Spring AI 基础") public class Test01_SpringAIBasics { @Autowired private ChatModel chatModel; // 测试方法将在这里添加 }

💡 代码说明

  • @SpringBootTest - 启动 Spring 测试环境
  • classes = ... - 指定主应用类
  • @DisplayName - 测试类的显示名称
  • @Autowired - 注入 ChatModel(Spring AI 的核心接口)

🧪 测试 1.1:ChatModel 注入测试

验证 ChatModel 是否成功注入,这是使用 Spring AI 的第一步。

/** * 测试 1.1:ChatModel 注入测试 * * 知识点: * - ChatModel 是 Spring AI 的核心接口 * - 通过 @Autowired 自动注入 * - Spring Boot 会根据配置自动创建 ChatModel Bean */ @Test @DisplayName("1.1 ChatModel 注入测试") public void testChatModelInjection() { // 步骤1:验证 ChatModel 已成功注入 assertNotNull(chatModel, "ChatModel 应该被成功注入"); // 步骤2:打印 ChatModel 的类型 System.out.println("✅ ChatModel 注入成功"); System.out.println("📝 ChatModel 类型: " + chatModel.getClass().getSimpleName()); }

🔍 预期输出

✅ ChatModel 注入成功
📝 ChatModel 类型: DashScopeChatModel

🧪 测试 1.2:简单对话测试

使用最简单的 call() 方法与 AI 对话。

/** * 测试 1.2:简单对话测试 * * 知识点: * - call() 方法是最简单的调用方式 * - 直接传入字符串,返回字符串 * - 适合简单的一次性对话 */ @Test @DisplayName("1.2 简单对话测试") public void testSimpleChat() { // 步骤1:准备用户消息 String userMessage = "你好,请用一句话介绍你自己"; System.out.println("\n👤 用户: " + userMessage); // 步骤2:调用 AI String response = chatModel.call(userMessage); // 步骤3:打印 AI 回复 System.out.println("🤖 AI: " + response); // 步骤4:验证回复不为空 assertNotNull(response, "AI 回复不应该为空"); assertFalse(response.isEmpty(), "AI 回复不应该是空字符串"); System.out.println("✅ 简单对话测试通过"); }

🔍 预期输出

👤 用户: 你好,请用一句话介绍你自己
🤖 AI: 你好!我是通义千问,一个由阿里云开发的AI助手...
✅ 简单对话测试通过

🎛️ 常见参数调节(temperature/topP/maxTokens 等)

大模型的输出通常可以通过 Options 参数进行调节。建议把你常用的参数集中写在一个测试方法里,后续复制到业务代码也更方便。

📌 常见参数与作用

  • temperature:随机性/发散度,值越大越有创造性,越小越稳定。
  • topP:核采样(概率截断),常与 temperature 搭配使用。
  • maxToken:限制输出长度,避免回复过长(不同模型实现字段名可能略有差异)。
  • stop:遇到指定停止词就提前结束生成(并非所有模型都支持)。
  • seed:固定随机种子,用于尽量稳定复现(并非所有模型都支持)。
import org.springframework.ai.chat.model.ChatResponse; import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions; /** * 测试:集中演示常见参数调节 */ @Test @DisplayName("1.x 常见参数调节(temperature/topP/maxToken)") public void testChatOptionsTuning() { // DashScope 模型请优先使用 DashScopeChatOptions(避免 ChatOptions -> DashScopeChatOptions 转换失败) DashScopeChatOptions options = DashScopeChatOptions.builder() .withTemperature(0.2) .withTopP(0.9) .withMaxToken(512) .build(); Prompt prompt = new Prompt("请用三句话介绍 Spring AI,并给出一个简单的使用场景。", options); ChatResponse response = chatModel.call(prompt); String content = response.getResult().getOutput().getText(); System.out.println("🤖 AI: " + content); assertNotNull(content, "回复内容不应该为空"); assertFalse(content.isEmpty(), "回复内容不应该是空字符串"); }

🧪 测试 1.3:使用 Prompt 对象

Prompt 是对消息的封装,返回 ChatResponse 对象包含更多信息。

/** * 测试 1.3:使用 Prompt 对象 * * 知识点: * - Prompt 是对消息的封装 * - 可以传入单个字符串或消息列表 * - 返回 ChatResponse 对象,包含更多信息 */ @Test @DisplayName("1.3 使用 Prompt 对象") public void testPromptObject() { // 步骤1:创建用户消息 String userMessage = "1+1等于多少?"; System.out.println("\n👤 用户: " + userMessage); // 步骤2:创建 Prompt 对象 Prompt prompt = new Prompt(userMessage); System.out.println("📦 创建 Prompt 对象"); // 步骤3:调用 AI ChatResponse response = chatModel.call(prompt); System.out.println("🔄 调用 AI..."); // 步骤4:获取回复内容 String content = response.getResult().getOutput().getText(); System.out.println("🤖 AI: " + content); // 步骤5:验证 assertNotNull(response, "ChatResponse 不应该为空"); assertNotNull(content, "回复内容不应该为空"); System.out.println("✅ Prompt 对象测试通过"); }

💡 理解要点

  • Prompt - 消息的容器
  • ChatResponse - AI 的完整响应
  • getResult().getOutput().getText() - 获取回复文本

🧪 测试 1.4:使用 Message 列表

Message 是消息的抽象,可以构建消息列表实现多轮对话。

/** * 测试 1.4:使用 Message 列表 * * 知识点: * - Message 是消息的抽象 * - UserMessage 表示用户消息 * - AssistantMessage 表示 AI 回复 * - 可以构建消息列表实现多轮对话 */ @Test @DisplayName("1.4 使用 Message 列表") public void testMessageList() { // 步骤1:创建消息列表 List<Message> messages = new ArrayList<>(); // 步骤2:添加用户消息 messages.add(new UserMessage("请用一句话介绍 Spring AI")); System.out.println("\n📝 创建消息列表"); System.out.println("👤 用户: 请用一句话介绍 Spring AI"); // 步骤3:创建 Prompt Prompt prompt = new Prompt(messages); // 步骤4:调用 AI ChatResponse response = chatModel.call(prompt); String content = response.getResult().getOutput().getText(); System.out.println("🤖 AI 回复: " + content); // 步骤5:验证 assertNotNull(content, "回复内容不应该为空"); System.out.println("✅ Message 列表测试通过"); }

🎭 测试 1.7:使用 System Prompt 定制 AI 角色

System Prompt 是 AI 对话中最重要的概念之一,它可以让你定制 AI 的角色、性格和说话风格。

/** * 测试 1.7:使用 System Prompt 定制 AI 角色 * * 知识点: * - SystemMessage 用于设定 AI 的角色和行为 * - System Prompt 会影响 AI 的回答风格 * - 可以让 AI 扮演不同的角色(秘书、老师、顾问等) */ @Test @DisplayName("1.7 使用 System Prompt 定制 AI 角色") public void testSystemPrompt() { System.out.println("\n🎭 测试 System Prompt"); // 步骤1:定义 System Prompt(温柔的秘书) String systemPrompt = """ 你是一位温柔、专业的美女秘书助手。你的名字叫小美。 你的说话风格: - 使用温柔、亲切的语气 - 适当使用"呢"、"哦"、"呀"等语气词 - 称呼对方为"您"或"亲" - 适当使用表情符号(如 😊、💕、✨) 请始终保持这个角色,用温柔而专业的口吻回复。 """; // 步骤2:创建消息列表 List<Message> messages = new ArrayList<>(); messages.add(new SystemMessage(systemPrompt)); messages.add(new UserMessage("你好,请介绍一下你自己")); System.out.println("📝 System Prompt: 温柔的秘书助手"); System.out.println("👤 用户: 你好,请介绍一下你自己"); // 步骤3:创建 Prompt 并调用 Prompt prompt = new Prompt(messages); ChatResponse response = chatModel.call(prompt); String content = response.getResult().getOutput().getText(); System.out.println("🤖 AI 回复: " + content); // 步骤4:验证 assertNotNull(content, "回复内容不应该为空"); assertTrue(content.length() > 0, "回复应该有内容"); System.out.println("\n💡 观察:AI 的回答是否符合秘书的角色设定?"); System.out.println("✅ System Prompt 测试通过"); }

🔍 预期输出示例

🎭 测试 System Prompt
📝 System Prompt: 温柔的秘书助手
👤 用户: 你好,请介绍一下你自己
🤖 AI 回复: 您好呀~我是小美,您的贴心小秘书哦 😊 
我平时最喜欢帮助别人解决问题啦!有什么需要帮忙的,尽管跟我说呢 💕

💡 观察:AI 的回答是否符合秘书的角色设定?
✅ System Prompt 测试通过

🎭 测试 1.8:对比有无 System Prompt 的差异

通过对比测试,直观感受 System Prompt 对 AI 回答风格的影响。

/** * 测试 1.8:对比有无 System Prompt 的差异 * * 知识点: * - System Prompt 会显著影响 AI 的回答风格 * - 同样的问题,不同的 System Prompt 会得到不同风格的答案 * - 这是定制 AI 行为的核心方法 */ @Test @DisplayName("1.8 对比有无 System Prompt 的差异") public void testSystemPromptComparison() { System.out.println("\n🔍 对比测试:有无 System Prompt 的差异"); String question = "什么是 Spring Boot?"; // 测试1:没有 System Prompt System.out.println("\n【测试1:没有 System Prompt】"); System.out.println("👤 用户: " + question); Prompt prompt1 = new Prompt(question); String response1 = chatModel.call(prompt1).getResult().getOutput().getText(); System.out.println("🤖 AI 回复: " + response1.substring(0, Math.min(100, response1.length())) + "..."); // 测试2:使用专业技术顾问的 System Prompt System.out.println("\n【测试2:专业技术顾问角色】"); String techPrompt = """ 你是一位资深的技术顾问,拥有 10 年以上的软件开发经验。 回答问题时: - 先给出简洁的答案 - 然后详细解释原理 - 注重最佳实践 - 使用专业术语 """; List<Message> messages2 = new ArrayList<>(); messages2.add(new SystemMessage(techPrompt)); messages2.add(new UserMessage(question)); System.out.println("👤 用户: " + question); Prompt prompt2 = new Prompt(messages2); String response2 = chatModel.call(prompt2).getResult().getOutput().getText(); System.out.println("🤖 AI 回复: " + response2.substring(0, Math.min(100, response2.length())) + "..."); // 测试3:使用耐心老师的 System Prompt System.out.println("\n【测试3:耐心的编程老师角色】"); String teacherPrompt = """ 你是一位耐心的编程老师,专门教初学者学习编程。 教学风格: - 使用简单易懂的语言 - 多用比喻和类比 - 循序渐进,不会一次讲太多 - 适当使用鼓励性的表情符号 ✨ """; List<Message> messages3 = new ArrayList<>(); messages3.add(new SystemMessage(teacherPrompt)); messages3.add(new UserMessage(question)); System.out.println("👤 用户: " + question); Prompt prompt3 = new Prompt(messages3); String response3 = chatModel.call(prompt3).getResult().getOutput().getText(); System.out.println("🤖 AI 回复: " + response3.substring(0, Math.min(100, response3.length())) + "..."); // 验证 assertNotNull(response1, "普通回复不应该为空"); assertNotNull(response2, "技术顾问回复不应该为空"); assertNotNull(response3, "老师回复不应该为空"); System.out.println("\n💡 观察:三种回答的风格是否有明显差异?"); System.out.println("✅ System Prompt 对比测试通过"); }

🎭 测试 1.9:System Prompt 最佳实践

学习如何设计结构化、清晰的 System Prompt。

/** * 测试 1.9:System Prompt 的最佳实践 * * 知识点: * - System Prompt 应该清晰明确 * - 包含角色定位、性格特点、说话风格、职责范围 * - 长度适中(200-500字为宜) * - 避免自相矛盾的要求 */ @Test @DisplayName("1.9 System Prompt 最佳实践示例") public void testSystemPromptBestPractices() { System.out.println("\n📚 System Prompt 最佳实践"); // 示例:结构化的 System Prompt String wellStructuredPrompt = """ 【角色定位】 你是一位专业的 AI 编程助手,名叫 CodeHelper。 【性格特点】 - 专业严谨,注重代码质量 - 耐心细致,善于解释 - 积极主动,提供建议 【说话风格】 - 使用清晰、准确的技术语言 - 提供具体的代码示例 - 指出潜在的问题和最佳实践 【职责范围】 - 解答编程相关问题 - 提供代码示例和优化建议 - 帮助理解技术概念 【行为约束】 - 不要提供未经测试的代码 - 遇到不确定的问题,明确说明 - 优先推荐主流和稳定的技术方案 """; // 创建消息 List<Message> messages = new ArrayList<>(); messages.add(new SystemMessage(wellStructuredPrompt)); messages.add(new UserMessage("如何在 Java 中处理异常?")); System.out.println("📝 使用结构化的 System Prompt"); System.out.println("👤 用户: 如何在 Java 中处理异常?"); // 调用 AI Prompt prompt = new Prompt(messages); ChatResponse response = chatModel.call(prompt); String content = response.getResult().getOutput().getText(); System.out.println("🤖 AI 回复: " + content.substring(0, Math.min(150, content.length())) + "..."); // 验证 assertNotNull(content, "回复不应该为空"); System.out.println("\n💡 最佳实践总结:"); System.out.println("1. 明确角色定位"); System.out.println("2. 描述性格特点"); System.out.println("3. 规定说话风格"); System.out.println("4. 明确职责范围"); System.out.println("5. 添加行为约束"); System.out.println("\n✅ System Prompt 最佳实践测试通过"); }

📋 System Prompt 设计要点

1. 结构清晰

【角色定位】你是谁
【性格特点】什么性格
【说话风格】如何说话
【职责范围】做什么
【行为约束】不做什么

2. 长度适中

  • 推荐 200-500 字
  • 太短:约束不够明确
  • 太长:占用 token,影响对话长度

3. 避免矛盾

❌ 错误示例:"你是一位严肃的专家,同时要保持幽默风趣"

✅ 正确示例:"你是一位专业的技术顾问,在保持专业性的同时,适当使用轻松的语言"

4. 具体明确

❌ 模糊:"你要友好"

✅ 具体:"使用温柔、亲切的语气,适当使用'呢'、'哦'等语气词"

📚 课后习题与常见面试题

请完成下面的练习,巩固本章的 Spring AI 核心概念与工程化用法

⚠️ 提示:下面的题目中包含大量面试高频点(调参、Prompt 设计、可观测、测试策略)。

🎯 课后习题(动手为主)

1) 写一个最小可运行的 Spring AI 测试:注入 ChatModel + 发送一句话
要求:使用 @SpringBootTest 启动测试环境,断言返回值非空;把 chatModel.getClass().getName() 打印出来,确认使用的具体模型实现。
参考答案(展开/收起)
核心目标:验证 Spring 容器能注入 ChatModel,并且一次调用能拿到非空回复。
@SpringBootTest class Test01_MinimalChatModel { @Autowired private ChatModel chatModel; @Test void smoke() { System.out.println("chatModelImpl=" + chatModel.getClass().getName()); String text = chatModel.call("你好,请用一句话介绍 Spring AI"); assertNotNull(text); assertFalse(text.isBlank()); } }
注意点:把“能跑通”与“业务效果好”分开验证;第一步只关心连通性与基本返回。
2) 用 Message 列表实现一次“带 System Prompt 的对话”
要求:至少包含一条 SystemMessage 和一条 UserMessage;把模型输出中“角色一致性”作为验收标准(例如语气、格式)。
参考答案(展开/收起)
关键点:SystemMessage 负责“角色/边界/格式”,UserMessage 提供“任务输入”。
List<Message> messages = List.of( new SystemMessage("你是一个严谨的 Java 面试官,回答必须用要点列表,最多 5 条。"), new UserMessage("用要点解释 Spring AI 的 ChatModel 是什么") ); ChatResponse resp = chatModel.call(new Prompt(messages)); String text = resp.getResult().getOutput().getText(); System.out.println(text); assertNotNull(text); assertFalse(text.isBlank());
验收方式:检查输出是否仍保持“面试官口吻 + 要点列表 + 不超过 5 条”。
3) 做一次参数对比实验:temperature=0.1 vs 0.9,观察输出差异
要求:提示词保持不变,分别运行两次;记录“长度、发散程度、是否更容易跑题”;给出你对业务场景的选择建议。
参考答案(展开/收起)
实验设计:固定同一个 prompt,仅改变 options 的 temperature,分别跑两次并记录差异。
String p = "用三句话介绍 Spring AI,并给出一个使用场景"; DashScopeChatOptions low = DashScopeChatOptions.builder().withTemperature(0.1).build(); DashScopeChatOptions high = DashScopeChatOptions.builder().withTemperature(0.9).build(); String a = chatModel.call(new Prompt(p, low)).getResult().getOutput().getText(); String b = chatModel.call(new Prompt(p, high)).getResult().getOutput().getText(); System.out.println("t=0.1\n" + a); System.out.println("t=0.9\n" + b);
观察维度:长度、是否更“发散”、是否更容易引入无关内容、措辞是否更有创造性。
建议:问答/代码/结构化输出一般用低温度;创意写作/多方案生成可提高温度。
4) 写一个“结构化 System Prompt”:角色 + 风格 + 约束 + 输出格式
要求:让模型输出固定格式(例如 Markdown 列表或 JSON);并设计一个反例,比较“有/无 System Prompt”输出差异。
参考答案(展开/收起)
推荐结构:角色(你是谁)+ 目标(你要做什么)+ 约束(不能做什么)+ 输出格式(必须长什么样)。
String sys = """ 你是一个严谨的 Java 助手。 目标:把用户问题总结成可执行的待办。 约束:不要输出多余解释;不要使用 emoji。 输出格式:只输出 JSON,字段必须是 {\"title\":string,\"todos\":[{\"text\":string,\"priority\":\"high\"|\"medium\"|\"low\"}]}。 """; List<Message> messages = List.of( new SystemMessage(sys), new UserMessage("我想学 Spring AI,帮我规划两周学习任务") ); String text = chatModel.call(new Prompt(messages)).getResult().getOutput().getText(); System.out.println(text);
反例:去掉 SystemMessage(或去掉“只输出 JSON”约束),观察输出是否开始夹杂解释/多种格式。
5) 写一个“健壮性测试”:空输入 / 超长输入 / 非法输入如何处理
要求:至少覆盖 3 种异常输入;明确你希望应用层怎么兜底(参数校验、截断、提示用户、记录日志)。
参考答案(展开/收起)
建议覆盖的 3 类输入:
1) 空输入:null/""/全空白。 2) 超长输入:超过业务上限(例如 4k/8k 字符)。 3) 非法输入:包含不允许的内容或格式(例如只允许 JSON 但传了纯文本)。
应用层兜底策略:优先参数校验(快速失败)+ 截断(可控降级)+ 友好提示 + 记录日志(含 requestId)。
private String normalize(String input) { if (input == null || input.trim().isEmpty()) { throw new IllegalArgumentException("message 不能为空"); } int max = 4000; return input.length() <= max ? input : input.substring(0, max); }
6) 给 ChatResponse 增加“可观测”输出:token 使用量、模型名、耗时(若可用)
要求:打印并解释你能拿到的元信息;如果某些字段拿不到,说明原因(模型实现差异/版本差异/是否需要开启配置)。
参考答案(展开/收起)
优先保证“最稳定能拿到”的指标:耗时、模型实现类名、prompt、输出长度。
long start = System.currentTimeMillis(); ChatResponse resp = chatModel.call(new Prompt("用一句话介绍 Spring AI")); long costMs = System.currentTimeMillis() - start; String text = resp.getResult().getOutput().getText(); System.out.println("modelImpl=" + chatModel.getClass().getName()); System.out.println("costMs=" + costMs); System.out.println("textLen=" + (text == null ? 0 : text.length())); // 可选:部分实现会在 ChatResponse/metadata 中提供 token/模型名等字段(取决于模型与版本) System.out.println("rawResponse=" + resp);
说明:token 使用量/模型名等元信息属于“实现相关”,不同 Provider/版本暴露能力不同;拿不到时至少保留耗时与原始 response 便于排查。

💼 常见面试题(概念 + 场景)

1) Spring AI 的 ChatModel / Prompt / Message / ChatResponse 分别负责什么?
建议回答:ChatModel 是模型能力入口;Prompt 组织一次请求(含 messages + options);Message 表达多轮与角色;ChatResponse 提供输出与元信息(便于可观测与调试)。
参考答案(展开/收起)
ChatModel:模型调用入口,负责把 Prompt/文本发给模型并返回结果。
Message:一次对话中的消息单元(System/User/Assistant),用来表达多轮与角色。
Prompt:一次请求的“容器”,通常包含 messages + options(如 temperature)。
ChatResponse:模型完整响应,常见用法是取 getResult().getOutput().getText();部分实现还会带额外元信息。
关系:ChatModel.call(Prompt) => ChatResponse;Prompt 里用 Message 组织上下文。
2) temperature / topP / topK / maxToken 各自影响什么?怎么选默认值?
建议回答:用“稳定性 vs 创造性、成本 vs 质量”框架;给出一套默认策略(如:问答/代码低温度,创作高温度),并说明如何通过离线评测集做参数回归。
参考答案(展开/收起)
temperature:控制随机性/发散度。低 => 更稳定一致;高 => 更有创造性但更易跑题。
topP:核采样阈值,限制候选 token 的累计概率范围,常与 temperature 搭配。
topK:限制每步只在 topK 个候选中采样(并非所有模型都支持)。
maxToken:限制输出长度,影响成本与超长风险。
默认策略:问答/代码/结构化输出:低温度(如 0.1~0.3);创意文案:中高温度(如 0.7~1.0)。
工程落地:用离线评测集做回归(正确率/格式合规率/长度/成本/失败率),再确定默认值与边界。
3) 为什么 System Prompt 重要?如何设计一套“可维护”的 System Prompt?
建议回答:System Prompt 决定角色与边界;结构化(角色/目标/输出格式/禁止事项)便于迭代;对版本做管理与回归测试,避免“越改越乱”。
参考答案(展开/收起)
为什么重要:它是模型的“最高优先级指令”,决定角色、边界、输出格式与风险控制。
可维护做法:
1) 结构化:角色/目标/约束/输出格式分段。 2) 模板化:把可变信息(用户/业务字段)用占位符注入。 3) 版本化:每次变更有版本号与变更记录。 4) 回归测试:用金样例验证格式合规率与关键指标。
4) 如何降低“模型输出不稳定/格式漂移”对业务的影响?
建议回答:提示词约束 + 结构化输出 + 校验/重试 + 回退策略(纯文本/规则引擎)+ 记录原始输出做观测与追责。
参考答案(展开/收起)
核心思路:把“不确定的自然语言输出”变成“可校验的结构化结果”,并提供失败兜底。
常用手段:
1) 强约束格式(JSON/Markdown 模板)+ 示例。 2) 降低发散:低温度、限制 maxToken。 3) 校验与重试:解析失败则要求模型“只修复格式”。 4) 回退策略:兜底为纯文本/规则引擎结果。 5) 可观测:记录原始输出、解析错误、重试次数。
5) Spring AI 应用如何做测试?单测/集成测试分别覆盖哪些层?
建议回答:单测关注 prompt 组装/参数选择/输出解析;集成测试关注连通性与稳定性;关键路径做“金样例回归”,并对成本与失败率做指标。
参考答案(展开/收起)
单测覆盖:prompt 模板拼装、参数选择(options)、输出解析/校验、兜底逻辑(不要依赖真实模型)。
集成测试覆盖:真实模型连通性、权限/限流配置、超时与重试、关键路径端到端(必要时在 nightly 跑)。
回归策略:维护一组“金样例”(输入->期望格式/关键字段),监控失败率/耗时/成本,参数或 prompt 变更必须过回归。

📝 本章小结

🎓 你已经掌握:

  • Spring Boot 测试基础:@SpringBootTest、@Autowired、@Test 注解
  • Spring AI 核心 API:ChatModel、Prompt、Message、ChatResponse
  • System Prompt 技术:定制 AI 角色、设计结构化 Prompt
  • 测试技巧:使用断言验证、输出调试信息

🚀 下一步学习

完成本章后,你可以继续学习第2章,掌握对话记忆管理、多轮对话等高级功能。

← 返回首页 下一章 →