Article

Spring AI 文档

更新于:2026-07-15

第1章:Spring AI 概述

1.1 什么是 Spring AI

概念名称说明注意事项
Spring AISpring AI 是 Spring 生态系统中的一个项目,旨在为 Java 和 JVM 开发者提供一个简洁、一致的 API 来集成人工智能(AI)功能,特别是大语言模型(LLM)和生成式 AI 能力。Spring AI 并不训练模型,而是作为与各种 AI 平台(如 OpenAI、Azure、Bedrock 等)交互的抽象层。
核心定位提供统一的编程模型,屏蔽底层 AI 服务的差异,使开发者能够以声明式、非侵入的方式集成 AI 功能。开发者无需深入理解不同 AI 平台的 SDK 细节,即可实现跨平台迁移。
抽象层通过接口(如 AiClient、ChatClient)封装 AI 调用,支持同步、异步、流式响应等多种模式。所有调用最终由具体的平台实现(如 OpenAI 实现)完成。

1.2 Spring AI 的设计目标与核心理念

概念名称说明注意事项
简化集成降低 Java 开发者使用 AI 服务的门槛,避免直接操作 REST API 或复杂 SDK。设计目标是”开箱即用”,减少样板代码。
统一 API提供一致的接口抽象,无论后端是 OpenAI、Azure 还是本地 Ollama 模型。更换 AI 提供商时,只需修改配置,无需重写业务逻辑。
模块化设计功能按模块划分(如文本生成、聊天、嵌入、函数调用),便于按需引入。可单独使用 spring-ai-chat-spring-boot-starter 而不引入文本生成模块。
与 Spring 生态融合深度集成 Spring Boot、Spring Boot Actuator、Spring Security 等组件。支持自动配置、依赖注入、外部化配置等 Spring 特性。
可观测性内建对日志、监控、追踪的支持,便于生产环境调试与优化。可结合 Micrometer、OpenTelemetry 实现调用链追踪。

1.3 Spring AI 与其他 AI 框架的对比

对比维度Spring AILangChain4jSpring Integration AI原生 OpenAI SDK
所属生态Spring 官方项目,深度集成 Spring Boot第三方 Java 库,受 LangChain 启发Spring 生态的扩展,偏消息集成OpenAI 官方提供的 Java 客户端
抽象层次高层抽象,统一 API,支持多平台中高层抽象,功能丰富,支持工具调用中层集成,偏重消息流处理低层 REST API 封装,直接映射 OpenAI 接口
多平台支持原生支持 OpenAI、Azure、Bedrock、Vertex、Ollama 等主要支持 OpenAI,扩展需手动实现通过适配器支持多种服务仅支持 OpenAI
学习曲线对 Spring 开发者极低,配置即用中等,需理解其链式结构中等,需熟悉 Spring Integration 模型低,但需处理认证、重试、序列化等细节
社区与维护Spring 官方维护,长期支持预期高社区驱动,更新活跃Spring 生态支持,但 AI 功能较新OpenAI 官方维护
适用场景Spring 项目中快速集成 AI 功能Java 项目中构建复杂 AI 应用链已使用 Spring Integration 的系统集成 AI需要精细控制 OpenAI 调用的场景

1.4 Spring AI 的生态系统与模块结构

模块名称说明注意事项
spring-ai-core核心模块,定义 AiClient、ChatClient、Prompt、Message 等通用接口与抽象类。所有其他模块的依赖基础,必须引入。
spring-ai-openai-spring-boot-starterOpenAI 平台的自动配置与实现模块,支持文本生成、聊天、嵌入等。需配置 spring.ai.openai.api-key。
spring-ai-azure-openai-spring-boot-starterAzure OpenAI 服务的集成模块,支持部署模型、密钥认证等企业特性。适用于在 Azure 云环境中部署的应用。
spring-ai-amazon-bedrock-spring-boot-starter集成 Amazon Bedrock,支持调用 Titan、Claude 等模型。需 AWS 凭证配置,适合 AWS 生态用户。
spring-ai-google-vertex-spring-boot-starter集成 Google Vertex AI,支持 PaLM 2、Gemini 等模型。需 Google Cloud 凭证与项目配置。
spring-ai-ollama-spring-boot-starter集成本地运行的 Ollama 服务,支持 Llama 3、Mistral 等开源模型。适合本地开发、测试或隐私敏感场景。
spring-ai-spring-boot-starter聚合启动器,包含核心功能与常用配置,简化依赖管理。推荐初学者使用,可按需排除特定平台依赖。

第2章:环境搭建与快速入门

2.1 开发环境准备(JDK、Maven/Gradle、IDE)

环境项要求说明注意事项
JDK 版本Spring AI 要求 JDK 17 或更高版本。推荐使用 LTS 版本(如 JDK 17、21)。
构建工具支持 Maven 3.5+ 或 Gradle 7.6+。Spring Boot 3.x 要求 Gradle 7.6+。
IDE推荐使用 IntelliJ IDEA 或 Spring Tool Suite (STS)。确保 IDE 支持 Spring Boot 和 Java 17+。
网络环境需能访问所选 AI 平台(如 api.openai.com)。若使用代理,需在 JVM 或系统中配置网络代理。
AI 平台账号如使用 OpenAI,需注册账号并获取 API Key。API Key 需妥善保管,避免硬编码在代码中。

2.2 创建第一个 Spring AI 项目(Spring Initializr 配置)

配置项推荐值注意事项
ProjectMaven / Gradle根据团队习惯选择。
LanguageJava当前主要支持语言。
Spring Boot Version3.3.x 或更高Spring AI 需 Spring Boot 3.x。
Groupcom.example可自定义,遵循包命名规范。
Artifactspring-ai-demo项目名称。
PackagingJar推荐使用可执行 JAR。
Java Version17必须 ≥17。
DependenciesSpring Web, Spring Configuration ProcessorWeb 用于构建 REST API,配置处理器提升 IDE 提示。
添加 Spring AI 支持手动添加 spring-ai-spring-boot-starter 或具体平台 starterInitializr 当前未直接提供 Spring AI 选项,需手动添加依赖。

2.3 引入 Spring AI 依赖(BOM 与 Starter)

依赖类型Maven 配置示例说明注意事项
BOM(推荐)<dependencyManagement> 中添加 org.springframework.ai:spring-ai-bom:0.8.1(type=pom, scope=import)统一管理 Spring AI 所有模块的版本,避免版本冲突。应放在 <dependencyManagement> 中。
核心启动器添加 org.springframework.ai:spring-ai-spring-boot-starter 依赖包含核心功能,自动配置基础 Bean。适合快速启动。
OpenAI 启动器添加 org.springframework.ai:spring-ai-openai-spring-boot-starter 依赖提供 OpenAI 模型的实现与自动配置。需配置 API Key。
Ollama 启动器(本地)添加 org.springframework.ai:spring-ai-ollama-spring-boot-starter 依赖用于连接本地 Ollama 服务。需提前启动 Ollama 并拉取模型(如 ollama run llama3)。
排除不需要的模块<exclusions> 中排除特定 starter如仅用 Ollama,可排除 OpenAI starter 以减小包体积。避免冲突或冗余依赖。

2.4 运行一个简单的 AI 调用示例

步骤说明示例代码注意事项
1. 配置 AI 客户端application.properties 中配置平台参数。spring.ai.openai.api-key=sk-xxxAPI Key 不应提交到版本控制,使用环境变量替代。
spring.ai.openai.model=gpt-3.5-turbo
2. 注入 AiClient使用 @Autowired 注入 AiClient。@Autowired private AiClient aiClient;AiClient 是 Spring 管理的 Bean。
3. 调用生成方法调用 aiClient.generate() 方法。String response = aiClient.generate("Tell me a joke about programming.");默认返回纯文本响应。
4. 返回结果获取生成的文本内容。System.out.println(response);实际应用中应通过 REST API 返回给前端。
完整示例类创建一个简单的 REST 控制器。见下方代码示例启动应用后访问 /joke 即可看到 AI 生成的笑话。

完整示例代码:

@RestController
public class AiController {
    @Autowired
    private AiClient aiClient;

    @GetMapping("/joke")
    public String getJoke() {
        return aiClient.generate("Tell me a joke about programming.");
    }
}

第3章:核心抽象与编程模型

3.1 AiClient 接口概述

方法名称语法用途代码示例注意事项
generate(String prompt)String generate(String prompt)根据字符串提示词生成文本响应。String response = aiClient.generate("Explain quantum computing.");最简单调用方式,返回纯文本结果。
generate(Prompt prompt)Response<Generation> generate(Prompt prompt)使用 Prompt 对象进行更复杂的文本生成调用。Prompt prompt = new Prompt("Explain AI.", new Metadata());
Response<Generation> response = aiClient.generate(prompt);
可携带元数据、消息历史等上下文信息。
embed(String text)List<Double> embed(String text)生成单个文本的嵌入向量(Embedding)。List<Double> embedding = aiClient.embed("Hello world");返回浮点数列表,用于语义相似度计算。
embed(List texts)List<List<Double>> embed(List<String> texts)批量生成多个文本的嵌入向量。List<List<Double>> embeddings = aiClient.embed(Arrays.asList("Hi", "Bye"));提高批量处理效率,适用于文档索引场景。

说明:AiClient 是 Spring AI 中最基础的接口,用于执行文本生成、嵌入等通用 AI 操作。它屏蔽了底层模型平台的差异。

3.2 Prompt 与 PromptTemplate

概念/方法语法说明代码示例注意事项
Prompt 构造函数new Prompt(String text)创建一个包含纯文本的提示对象。Prompt prompt = new Prompt("Tell me a story.");适用于简单场景。
Prompt(带消息列表)new Prompt(List<Message> messages)使用消息列表构建提示,支持多轮对话结构。List<Message> msgs = Arrays.asList(new UserMessage("Hello"), new SystemMessage("You are helpful."));
Prompt prompt = new Prompt(msgs);
更接近聊天模型的输入格式。
PromptTemplate 创建PromptTemplate.of(String template)从字符串模板创建提示模板。PromptTemplate pt = PromptTemplate.of("Tell me a joke about {topic}.");{} 中为占位符,可被参数替换。
绑定参数promptTemplate.apply(Map<String, Object> variables)将变量映射应用到模板,生成 Prompt 对象。Map<String, Object> vars = Map.of("topic", "Java");
Prompt prompt = pt.apply(vars);
支持复杂对象绑定,如 Map.of("user", userObj)
消息类型支持new SystemMessage(...), new UserMessage(...), new AssistantMessage(...)定义不同角色的消息,影响模型行为。new SystemMessage("You are a poet.")系统消息通常用于设定角色或规则。

3.3 Response 与 Generation

类/属性语法说明代码示例注意事项
Response<T>interface Response<T>包装 AI 调用的响应结果,包含生成内容和元数据。Response<Generation> response = aiClient.generate(prompt);泛型 T 通常为 Generation 或其子类。
Generationclass Generation表示一次生成的结果,包含文本内容。String content = response.getResult().getOutput().getContent();content 即模型返回的文本。
获取内容response.getResult().getOutput().getContent()从响应中提取生成的文本。同上链式调用需注意空指针风险。
元数据获取response.getMetadata()获取响应的附加信息,如 token 数量、模型名称等。Double tokenUsage = (Double) response.getMetadata().get("token.usage.total");具体键名依赖于实现平台(如 OpenAI)。
多生成结果response.getResults()某些模型支持返回多个候选生成(n > 1)。List<Generation> gens = response.getResults();需在 Prompt 中设置生成数量参数。

3.4 ChatClient 与 ChatResponse

方法名称语法用途代码示例注意事项
call(String message)<T> T call(String message)发送字符串消息并同步返回结果。String reply = chatClient.call("Hello!");默认返回 String,可通过泛型指定返回类型。
call(Message message)<T> T call(Message message)发送 Message 对象(如 UserMessage)。UserMessage msg = new UserMessage("Explain LLMs.");
String reply = chatClient.call(msg);
支持结构化消息传递。
call(Prompt prompt)<T> T call(Prompt prompt)发送完整的 Prompt(含多条消息)。Prompt prompt = new Prompt(Arrays.asList(new SystemMessage("..."), new UserMessage("...")));
ChatResponse response = chatClient.call(prompt);
适用于复杂对话场景。
stream(…)Stream<T> stream(...)流式发送请求,返回 Stream 对象,支持逐块处理响应。chatClient.stream("Tell a long story").forEach(System.out::println);适用于长文本生成,提升用户体验。
ChatResponseinterface ChatResponse聊天调用的响应接口,包含多个 ChatCompletionChoice。chatResponse.getResults().get(0).getOutput().getContent()结构与 Response<Generation> 类似但更丰富。

3.5 FunctionCalling 与工具调用支持

概念/方法语法说明代码示例注意事项
@Tool 注解@Tool(description = "...")标记一个方法为可被 AI 调用的工具。@Tool(description = "Get current weather") public String getWeather(String city) { ... }方法必须是 Spring Bean 中的公共方法。
工具注册自动扫描 @Tool 方法并注册Spring AI 自动将标注 @Tool 的 Bean 方法注册为可用工具。无需手动注册,启动时自动完成。确保类被 Spring 管理(如 @Component)。
函数调用触发AI 模型决定是否调用工具当用户请求需要外部操作时,模型返回函数调用指令。用户问:“北京天气如何?” → 模型返回调用 getWeather("Beijing")依赖模型支持函数调用能力(如 gpt-3.5-turbo-0613+)。
执行与回调框架自动执行工具方法并将结果返回模型工具执行后,返回值会作为上下文传回模型,由其生成最终回复。return "Sunny, 25°C"; → 模型生成:“北京今天晴朗,气温25°C。“工具方法应快速响应,避免阻塞。
参数传递支持基本类型、String、POJOAI 解析用户意图并构造参数调用工具方法。public String getWeather(CityRequest cityReq)POJO 需有默认构造函数和 getter/setter。

第4章:文本生成(Text Generation)

4.1 文本生成基本调用流程

步骤说明示例注意事项
1. 创建 Prompt构建输入提示,可以是字符串或 Prompt 对象。"Summarize the following text: ..."提示质量直接影响输出效果。
2. 调用 AiClient使用 aiClient.generate() 方法发起请求。aiClient.generate(prompt)同步调用会阻塞线程。
3. 获取响应Response<Generation> 中提取内容。response.getResult().getOutput().getContent()检查响应是否成功,避免空值。
4. 处理结果将生成文本返回给前端或用于后续处理。return ResponseEntity.ok(content);可结合缓存、过滤等策略优化体验。

4.2 使用 AiClient 进行文本生成

方法语法用途代码示例注意事项
generate(String)String generate(String prompt)快速生成文本,适合简单场景。String summary = aiClient.generate("Summarize: Spring AI simplifies AI integration.");不支持高级配置如温度、topP 等。
generate(Prompt)Response<Generation> generate(Prompt prompt)支持配置生成参数(通过 Metadata)。Prompt prompt = new Prompt("...", Metadata.builder().withTemperature(0.7).build());可精细控制生成行为。
异常处理try-catch 包裹调用处理网络错误、API 限流等异常。try { ... } catch (Exception e) { log.error("AI call failed", e); }生产环境必须添加容错机制。

4.3 提示词模板(PromptTemplate)的构建与参数绑定

方法语法用途代码示例注意事项
of(String template)static PromptTemplate of(String template)从字符串创建模板。PromptTemplate pt = PromptTemplate.of("Write a {genre} story about {topic}.");占位符用 {} 包围。
apply(Map vars)Prompt apply(Map<String, Object> variables)应用变量生成 Prompt。Map<String, Object> vars = Map.of("genre", "sci-fi", "topic", "robots");
Prompt prompt = pt.apply(vars);
变量名需与模板中一致。
apply(Object pojo)Prompt apply(Object object)使用 POJO 对象填充模板。prompt = pt.apply(new StoryRequest("fantasy", "dragons"));POJO 属性名需匹配占位符。
消息模板new PromptTemplate(List<Message>)创建包含多角色消息的模板。new PromptTemplate(Arrays.asList(new SystemMessage("{role}"), new UserMessage("{query}")))适用于聊天场景。

4.4 响应解析与元数据获取

属性/方法语法说明代码示例注意事项
getContent()generation.getContent()获取生成的文本内容。String text = response.getResult().getOutput().getContent();主要输出结果。
getFinishReason()choice.getFinishReason()获取生成结束原因(如 “stop”, “length”)。(String) response.getMetadata().get("finish.reason")有助于判断是否完整生成。
Token 使用量metadata.get("token.usage.total")获取总 token 消耗。Double totalTokens = (Double) response.getMetadata().get("token.usage.total");用于成本监控和限流。
模型名称metadata.get("model.name")获取实际使用的模型名称。String model = (String) response.getMetadata().get("model.name");验证配置是否生效。
原始响应实现特定类提供某些客户端支持获取原始 API 响应(如 JSON)。需查看具体实现(如 OpenAiChatResponse)用于调试或特殊处理。

提示:元数据的键名可能因 AI 平台而异,建议查阅对应 starter 的文档。

第5章:聊天模型(Chat Models)

5.1 ChatClient 接口详解

方法名称语法用途代码示例注意事项
call(String)<T> T call(String message)发送字符串消息并同步获取响应,返回类型由泛型决定。String reply = chatClient.call("Hello");默认返回 String,可指定为 ChatResponse。
call(Message)<T> T call(Message message)发送结构化消息对象(如 UserMessage)。UserMessage msg = new UserMessage("Explain AI.");
String reply = chatClient.call(msg);
更精确控制消息角色。
call(Prompt)<T> T call(Prompt prompt)发送包含多条消息的 Prompt,支持复杂对话上下文。Prompt prompt = new Prompt(messages);
ChatResponse response = chatClient.call(prompt);
推荐用于多轮对话。
stream(String)Stream<T> stream(String message)流式发送请求,返回 Stream 对象,逐块接收响应。chatClient.stream("Tell a story")
.forEach(System.out::println);
避免长时间等待,提升用户体验。
stream(Message)Stream<T> stream(Message message)流式发送结构化消息。chatClient.stream(new UserMessage("..."))
.forEach(chunk -> {...});
支持实时显示生成内容。
stream(Prompt)Stream<T> stream(Prompt prompt)流式发送完整提示(含历史消息)。chatClient.stream(prompt).forEach(System.out::print);适用于长对话流式输出。

说明:ChatClient 是专为聊天模型设计的核心接口,支持同步与流式调用,是构建对话系统的基础。

5.2 消息类型:UserMessage、SystemMessage、AssistantMessage

消息类型语法说明代码示例注意事项
SystemMessagenew SystemMessage(String content)设置系统级指令,影响模型行为(如角色设定)。new SystemMessage("You are a helpful assistant.");通常放在消息列表首位,仅发送一次。
UserMessagenew UserMessage(String content)表示用户输入,最常见的消息类型。new UserMessage("What is Java?");可多次发送,构成对话历史。
AssistantMessagenew AssistantMessage(String content)表示模型之前的回复,用于维护对话上下文。new AssistantMessage("Java is a programming language.");必须准确记录模型输出,避免误导。
消息构造(带元数据)new UserMessage(Content content)支持富内容(如文本+图像),但文本生成中较少用。new UserMessage(new TextContent("Describe this image"))当前主要用于多模态场景。

提示:消息顺序至关重要,通常为 [SystemMessage, UserMessage, AssistantMessage, ...],模型根据上下文生成回复。

5.3 多轮对话管理与消息历史维护

方法/策略语法说明代码示例注意事项
手动维护消息列表List<Message> conversation = new ArrayList<>()在服务类中维护会话消息列表。conversation.add(new UserMessage(userInput));
conversation.add(new AssistantMessage(aiReply));
简单场景可用,但需注意线程安全。
使用 Prompt 构造new Prompt(conversation)将完整消息历史传入 Prompt。Prompt prompt = new Prompt(conversation);
ChatResponse response = chatClient.call(prompt);
确保模型”看到”全部上下文。
会话作用域 Bean@Scope("session")为每个用户会话创建独立的消息历史实例。@Component @Scope("session") class ChatService { ... }适合 Web 应用,避免用户间消息混淆。
截断长历史保留最近 N 条消息防止 token 超限,提升性能。List<Message> recent = conversation.subList(Math.max(0, size - 10), size);平衡上下文完整性与成本。
外部存储(Redis)将消息列表序列化存储实现跨实例会话持久化。使用 StringRedisTemplate 存储 JSON 格式消息列表。适用于分布式系统,需处理序列化性能。

注意:消息历史越长,消耗的 token 越多,可能导致请求失败或成本上升,建议合理管理。

5.4 流式响应(Streaming)支持

方法语法用途代码示例注意事项
stream(String)Stream<String> stream(String message)流式接收字符串响应块。chatClient.stream("Long text...")
.forEach(System.out::print);
响应块大小由模型决定,非固定。
stream(Prompt)Stream<ChatResponse> stream(Prompt prompt)流式接收 ChatResponse 对象流。chatClient.stream(prompt)
.map(r -> r.getResult().getOutput().getContent())
.forEach(System.out::print);
可获取每块的元数据。
WebFlux 响应return chatClient.stream(prompt);在 Spring WebFlux 中直接返回 Flux。@GetMapping(value="/chat", produces=TEXT_EVENT_STREAM)
public Flux<String> chat() { ... }
需使用 text/event-stream 内容类型。
异常处理try-catch 或 onError处理流式过程中的网络或服务异常。stream.onErrorContinue((err, val) -> log.error(err));流式调用需特别注意错误恢复。
资源释放stream.close() 或 try-with-resources确保流关闭,释放连接资源。使用 Flux 时由框架自动管理。避免连接泄漏。

提示:流式响应适用于聊天机器人、长文本生成等需要”边生成边显示”的场景。

第6章:函数调用与工具集成(Function Calling)

6.1 函数调用(Function Calling)概念解析

概念名称说明注意事项
函数调用(Function Calling)允许大模型在生成响应前,决定是否调用预定义的外部函数(工具)来获取信息或执行操作。模型不直接执行代码,而是返回调用指令,由框架执行。
工具(Tool)一个 Java 方法,通过 @Tool 注解暴露给 AI 模型,可执行查询、计算、调用 API 等操作。工具应具有明确的输入输出和副作用控制。
调用流程用户提问 → 模型分析是否需要工具 → 若需要,返回函数调用请求 → 框架执行工具 → 将结果返回模型 → 模型生成最终回复。是一个”AI 决策 + 外部执行 + AI 总结”的闭环。
支持的模型并非所有模型都支持函数调用,如 OpenAI 的 gpt-3.5-turbo 需指定支持版本(如 0613)。配置时需确认模型能力。
安全性工具方法可能访问数据库或外部服务,需严格验证输入,防止注入攻击。避免暴露敏感操作(如删除、支付)作为工具。

6.2 定义可调用函数(@Tool 注解)

属性语法说明代码示例注意事项
description@Tool(description = "...")描述工具用途,供模型理解其功能。@Tool(description = "Get current weather by city name")描述越清晰,模型调用越准确。
方法参数支持基本类型、String、POJO定义工具所需的输入参数。public String getWeather(String city)POJO 需有默认构造函数和 getter/setter。
返回类型String 或 POJO工具执行结果,将作为上下文传回模型。return "Sunny, 20°C";字符串最常用,POJO 会自动序列化为 JSON。
方法位置必须在 Spring Bean 中@Component、@Service 等注解的类中。@Service class WeatherService { @Tool(...) public String getWeather(...) { ... } }非 Bean 中的方法不会被扫描注册。
多个工具可在多个 Bean 中定义多个 @Tool 方法实现功能解耦。分别定义 WeatherTool、StockTool 等服务类。避免单个类职责过重。

6.3 将工具注册到 AI 客户端

方式说明代码示例注意事项
自动注册(推荐)Spring AI 启动时自动扫描所有 @Tool 注解的方法并注册。无需代码,只要 @Tool 方法在 Spring 管理的 Bean 中即可。确保组件扫描路径包含工具类。
手动注册通过 FunctionCallingHelper 或客户端配置手动添加工具。chatClient.withFunctions(Arrays.asList(weatherTool, stockTool))适用于动态或条件注册场景。
配置文件控制暂不支持通过 application.properties 开启/关闭工具。需通过代码或条件 Bean 实现。可结合 @Profile 注解按环境启用工具。
工具可见性所有注册工具对模型”可见”,但是否调用由模型决策。模型会根据描述和上下文判断。避免注册过多无关工具,增加决策复杂度。

6.4 函数调用的执行流程与响应处理

步骤说明代码/行为示例注意事项
1. 用户提问用户输入需要外部数据的问题。“上海现在的天气怎么样?“问题需明确指向可工具化操作。
2. 模型决策模型识别到需要调用 getWeather 工具。返回 {"tool_calls": [{"name": "getWeather", "arguments": {"city": "Shanghai"}}]}依赖模型的指令遵循能力。
3. 框架执行Spring AI 框架调用 getWeather("Shanghai") 方法。框架通过反射调用并获取返回值。方法执行异常将中断流程。
4. 结果回传工具返回结果(如 “Cloudy, 18°C”)作为新消息传回模型。模型收到系统消息:“工具 getWeather 执行结果:Cloudy, 18°C”模型知晓外部操作结果。
5. 生成最终回复模型结合工具结果生成自然语言回复。“上海现在是多云,气温18°C。“完成”AI + 外部能力”的协同。
异常处理工具执行失败(如网络错误)框架可配置失败策略(如重试、忽略、返回错误)建议工具内部捕获异常并返回友好错误信息。
多工具调用模型可同时请求调用多个工具。tool_calls 数组包含多个条目。框架通常按顺序执行,可优化为并行。

提示:可通过日志观察 ToolExecutionRequest 和 ToolExecutionResult 来调试函数调用流程。

第7章:数据转换与内容处理

7.1 TextTransformer 接口与实现

方法名称语法用途代码示例注意事项
transform(String text)String transform(String text)对输入文本进行转换处理,返回处理后的文本。String cleaned = textTransformer.transform(" Hello! ");可用于清洗、格式化、摘要等操作。
transform(Prompt prompt)Prompt transform(Prompt prompt)转换整个 Prompt 对象,适用于复杂结构处理。Prompt enhanced = textTransformer.transform(prompt);可修改提示词内容或添加上下文。
内置实现:DefaultTextTransformernew DefaultTextTransformer()提供默认文本处理能力,通常作为基类。可继承并重写 transform 方法。实际应用中常自定义实现。
自定义实现class MyTransformer implements TextTransformer实现特定业务逻辑的文本转换器。见下方代码示例需注册为 Spring Bean 才能注入使用。
链式处理组合多个 TextTransformer构建文本处理流水线。transformer1.transform(transformer2.transform(text))可结合策略模式或责任链模式实现。

自定义实现示例:

public class UppercaseTransformer implements TextTransformer {
    public String transform(String text) {
        return text.toUpperCase();
    }
}

说明:TextTransformer 是一个通用接口,可用于预处理输入或后处理输出,增强 AI 应用的灵活性。

7.2 文本嵌入(Embedding)支持

方法名称语法用途代码示例注意事项
embed(String text)List<Double> embed(String text)生成单个文本的嵌入向量(浮点数列表)。List<Double> embedding = aiClient.embed("Hello world");向量表示文本的语义特征。
embed(List<String> texts)List<List<Double>> embed(List<String> texts)批量生成多个文本的嵌入向量。List<List<Double>> embeddings = aiClient.embed(Arrays.asList("Hi", "Bye"));提高效率,适用于文档库处理。
EmbeddingClientinterface EmbeddingClient专门用于嵌入操作的客户端接口(部分实现提供)。@Autowired EmbeddingClient embeddingClient;并非所有平台都单独暴露此接口。
嵌入维度依赖模型(如 text-embedding-ada-002 为 1536 维)向量长度固定,需与模型匹配。assert embedding.size() == 1536;存储和计算时需注意维度一致性。
用途:语义搜索计算向量相似度(如余弦相似度)找出与查询语义最接近的文本。将用户问题嵌入,与文档库向量比对。是构建 RAG(检索增强生成)的基础。

提示:嵌入操作通常消耗 token,但成本低于生成任务,适合高频调用。

7.3 向量存储集成基础

概念/方法说明示例注意事项
向量数据库专门存储和检索向量数据的数据库(如 Pinecone、Milvus、Weaviate、Chroma)。用于持久化文本嵌入向量。选择时考虑性能、成本、部署方式(云/本地)。
存储流程文本 → 嵌入 → 向量存储构建向量索引。for (doc : docs) { vec = aiClient.embed(doc); vectorStore.save(doc, vec); }
检索流程查询 → 嵌入 → 向量搜索 → 返回相似文本实现语义检索。List<String> results = vectorStore.findSimilar(queryEmbedding, topK=3);
VectorStore 接口Spring AI 提供的向量存储抽象(如 SimpleVectorStore)。vectorStore.add(documents);
vectorStore.findSimilar(embedding);
SimpleVectorStore 为内存实现,适合测试。
集成第三方通过具体实现类集成 Pinecone、Azure AI Search 等。需引入对应 starter(如 spring-ai-pinecone-spring-boot-starter)。配置认证信息和连接参数。

注意:生产环境应使用专业的向量数据库,内存存储仅用于演示。

7.4 内容提取与结构化输出

方法/技术语法/说明用途代码示例注意事项
提示词引导在提示中要求 JSON 格式输出强制模型返回结构化数据。"Return result as JSON: {name: string, age: number}"模型可能不严格遵守格式。
@Schema 注解结合 FunctionCalling 定义输出结构更可靠地生成结构化响应。@Tool(outputSchema = @Schema(type = "object", properties = {...}))依赖模型支持结构化输出。
响应解析使用 ObjectMapper 解析 JSON 响应将字符串转换为 POJO。MyData data = objectMapper.readValue(jsonString, MyData.class);需捕获 JsonProcessingException。
错误重试解析失败时重新调用 AI提高结构化输出可靠性。循环调用直至获得有效 JSON。设置最大重试次数避免无限循环。
输出验证验证解析后的对象字段完整性确保数据可用。if (data.getName() == null) throw new IllegalStateException();防御性编程,避免空值异常。

提示:结合函数调用(Function Calling)是实现结构化输出最可靠的方式,模型会生成符合 schema 的 JSON。

第8章:提示工程(Prompt Engineering)

8.1 提示词设计原则

原则说明示例注意事项
明确具体避免模糊,清晰表达需求。❌ “写点东西” → ✅ “写一篇关于气候变化的 200 字科普文章”越具体,输出越可控。
提供上下文给出背景信息或角色设定。“你是一位资深 Java 工程师,请解释 Spring Bean 的生命周期。“上下文影响回答的专业性和风格。
分步指令复杂任务拆解为多个步骤。“1. 分析问题 2. 列出解决方案 3. 推荐最佳方案”提高复杂任务的完成质量。
示例引导(Few-shot)提供输入输出示例。“输入:‘happy’ → 输出:’😊‘;输入:‘sad’ → 输出:’😢‘;输入:‘angry‘“模型模仿示例模式生成。
避免歧义使用无歧义词汇,避免双重否定。避免 “不要不写” → 改为 “请写”减少模型误解风险。
设置约束限制长度、格式、风格等。“用不超过 50 字,以诗歌形式回答。“确保输出符合下游处理要求。

8.2 动态提示模板与变量注入

方法语法用途代码示例注意事项
占位符 {var}PromptTemplate.of("Summarize: {text}")定义可变部分。PromptTemplate pt = PromptTemplate.of("Translate '{text}' to {lang}");大括号包围变量名。
apply(Map)promptTemplate.apply(variables)注入变量生成 Prompt。Map<String, Object> vars = Map.of("text", "AI is great", "lang", "fr");
Prompt prompt = pt.apply(vars);
变量名需与模板一致。
apply(Object)promptTemplate.apply(pojo)使用 POJO 注入多个字段。prompt = pt.apply(new TranslationRequest("Hello", "es"));POJO 属性名匹配占位符。
条件逻辑模板中使用 #if 等(需模板引擎)实现条件内容插入。当前 Spring AI 原生不支持,需结合 Thymeleaf 等。可在 Java 代码中实现条件逻辑。
消息模板new PromptTemplate(List<Message>)动态构建多角色提示。new PromptTemplate(Arrays.asList(new SystemMessage("{role}"), new UserMessage("{query}")))适用于聊天机器人角色切换。

8.3 提示词版本管理与外部化配置

策略说明实现方式注意事项
外部文件存储将提示词存于 resources/prompts/ 目录下的 .txt 文件。String template = Files.readString(Path.of("classpath:prompts/summarize.txt"));
PromptTemplate pt = PromptTemplate.of(template);
便于非开发人员(如产品经理)修改。
配置文件使用 application.yml 存储提示词。app.prompts.summary: "Summarize the text: {text}"可结合 @Value 注入。
数据库存储将提示词存入数据库,支持动态更新。PromptEntity entity = promptRepo.findByName("summary");
PromptTemplate pt = PromptTemplate.of(entity.getContent());
实现热更新,无需重启应用。
版本控制为提示词添加版本号(如 summary_v2)。文件命名 summarize_v2.txt 或数据库字段 version便于回滚和 A/B 测试。
环境区分不同环境(dev/test/prod)使用不同提示词。结合 @Profile 或配置中心实现。避免测试提示影响生产。

8.4 提示词测试与评估

方法说明工具/示例注意事项
单元测试编写测试用例验证提示词输出。assertEquals(true, response.contains("Java"));测试关键字段是否存在或格式正确。
人工评估由人工判断输出质量(相关性、准确性、流畅性)。设计评分表(1-5 分)进行打分。主观性强,但最直接。
自动化指标使用 BLEU、ROUGE 等指标评估与标准答案的相似度。需有”标准答案”作为基准。仅适用于有固定答案的场景。
A/B 测试对比两个提示词版本的效果。同一问题用 prompt_v1 和 prompt_v2 分别调用,比较结果。需足够样本量才有统计意义。
日志分析记录提示词和输出,分析失败案例。将 Prompt 和 Response 存入日志或数据库。用于持续优化提示词。
提示词调试工具使用 LangSmith、PromptLayer 等第三方工具。可视化调用链、评估性能。需集成额外服务。

提示:提示词是 AI 应用的”程序代码”,应像代码一样进行测试、版本控制和持续优化。

第9章:支持的 AI 平台集成

9.1 集成 OpenAI(ChatGPT)

配置项配置方式示例值说明注意事项
依赖引入Mavenorg.springframework.ai:spring-ai-openai-spring-boot-starter引入 OpenAI 自动配置模块。确保 BOM 管理版本。
API Keyapplication.ymlspring.ai.openai.api-key: sk-xxxOpenAI 账户的 API 密钥。切勿硬编码,推荐使用环境变量 OPENAI_API_KEY
模型名称application.ymlspring.ai.openai.model: gpt-3.5-turbo指定调用的模型(如 gpt-4, gpt-4o)。确保模型支持所需功能(如函数调用)。
基础 URL(可选)application.ymlspring.ai.openai.base-url: https://api.openai.com/v1默认为官方地址,可替换为代理或企业网关。用于网络受限环境。
超时设置application.ymlspring.ai.openai.timeout: 30s连接与读取超时。复杂请求建议适当延长。
使用示例Java@Autowired ChatClient chatClient; String response = chatClient.call("Hello");自动注入配置好的 ChatClient。无需手动创建客户端。

注意:OpenAI 是最广泛支持的平台,功能完整,适合快速原型开发。

9.2 集成 Azure OpenAI

配置项配置方式示例值说明注意事项
依赖引入Mavenorg.springframework.ai:spring-ai-azure-openai-spring-boot-starterAzure 专用 starter。与 OpenAI starter 不兼容,避免共存。
API Keyapplication.ymlspring.ai.azure.openai.api-key: your-keyAzure 资源的密钥。可在 Azure 门户的”密钥和终结点”中找到。
模型部署名称application.ymlspring.ai.azure.openai.deployment-name: gpt-35-turboAzure 中为模型创建的部署名称(非模型名)。必须与 Azure 门户中部署的名称一致。
基础 URLapplication.ymlspring.ai.azure.openai.base-url: https://your-resource.openai.azure.comAzure OpenAI 服务的终结点 URL。格式为 https://<资源名>.openai.azure.com
API 版本application.ymlspring.ai.azure.openai.api-version: 2024-02-15-preview指定使用的 API 版本。需与 Azure 服务支持的版本匹配。
认证方式可选使用 azure-identity 实现 AAD 认证更安全的企业级认证。需额外依赖和配置,适合云原生部署。

提示:Azure OpenAI 适合企业用户,提供数据驻留、VNet 集成等高级功能。

9.3 集成 Amazon Bedrock

配置项配置方式示例值说明注意事项
依赖引入Mavenorg.springframework.ai:spring-ai-amazon-bedrock-spring-boot-starterBedrock 集成模块。需 AWS 凭证。
AWS 凭证环境变量/配置文件AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY标准 AWS 认证机制。推荐使用 IAM 角色(EC2/ECS)或临时凭证。
区域application.ymlspring.ai.aws.region: us-east-1Bedrock 服务所在区域。模型可用性因区域而异。
模型 IDapplication.ymlspring.ai.bedrock.model-id: anthropic.claude-3-sonnet-20240229-v1:0Bedrock 中的完整模型标识符。需从 Bedrock 控制台获取准确 ID。
基础 URL(可选)application.ymlspring.ai.bedrock.base-url: https://bedrock-runtime.us-east-1.amazonaws.com自定义终结点。通常使用默认。
使用模型支持模型Claude、Titan、Llama 3、Jurassic 等Bedrock 提供多家厂商模型。需确保 IAM 策略允许访问目标模型。

注意:Bedrock 适合 AWS 生态用户,支持多模型选择和企业级安全。

9.4 集成 Google Vertex AI

配置项配置方式示例值说明注意事项
依赖引入Mavenorg.springframework.ai:spring-ai-google-vertex-spring-boot-starterVertex AI 集成模块。需 Google Cloud 凭证。
凭证文件环境变量GOOGLE_APPLICATION_CREDENTIALS=path/to/key.json指向服务账号密钥文件。必须下载 JSON 密钥并安全存储。
项目 IDapplication.ymlspring.ai.vertex.project-id: your-project-idGoogle Cloud 项目 ID。在 GCP 控制台查看。
区域application.ymlspring.ai.vertex.location: us-central1Vertex AI 服务区域。模型部署需在同一区域。
模型名称application.ymlspring.ai.vertex.model: gemini-pro支持 gemini-pro, gemini-pro-vision, text-bison 等。Gemini 系列为最新模型。
端点(可选)application.ymlspring.ai.vertex.base-url: https://us-central1-aiplatform.googleapis.com自定义 API 端点。通常使用默认。

提示:Vertex AI 集成 Google 的先进模型(如 Gemini),适合 GCP 用户。

9.5 集成 Ollama(本地大模型)

配置项配置方式示例值说明注意事项
依赖引入Mavenorg.springframework.ai:spring-ai-ollama-spring-boot-starterOllama 集成模块。无需云服务,本地运行。
Ollama 服务本地运行ollama serve启动 Ollama 服务。需先安装 Ollama(https://ollama.com)。
拉取模型CLI 命令ollama run llama3下载并运行模型。常用模型:llama3, mistral, phi3, gemma。
服务地址application.ymlspring.ai.ollama.base-url: http://localhost:11434Ollama 的 HTTP 服务地址。默认端口 11434。
模型名称application.ymlspring.ai.ollama.model: llama3指定本地运行的模型名称。必须与 ollama run 的名称一致。
GPU 支持Ollama 配置依赖 CUDA/Metal利用 GPU 加速推理。需安装对应驱动(NVIDIA/AMD/Mac)。
优势说明数据隐私、低成本、离线可用适合开发、测试、隐私敏感场景。性能依赖本地硬件。

注意:Ollama 是理想的本地开发和测试工具,可快速验证功能。

第10章:异步与流式处理

10.1 异步调用:AiClient 与 ChatClient 的异步方法

方法语法用途代码示例注意事项
callAsync(String)CompletableFuture<String> callAsync(String message)异步发送消息,立即返回 CompletableFuture。CompletableFuture<String> future = chatClient.callAsync("Hello");
future.thenAccept(System.out::println);
非阻塞主线程,提升吞吐量。
callAsync(Message)CompletableFuture<T> callAsync(Message message)异步发送结构化消息。future = chatClient.callAsync(new UserMessage("..."));与同步方法参数一致。
callAsync(Prompt)CompletableFuture<T> callAsync(Prompt prompt)异步发送完整提示(含历史)。CompletableFuture<ChatResponse> respFuture = chatClient.callAsync(prompt);适用于耗时较长的请求。
异常处理future.exceptionally(e -> {...})处理异步调用中的异常。future.exceptionally(e -> "Error: " + e.getMessage());必须处理,否则异常会静默丢失。
组合多个异步调用CompletableFuture.allOf(f1, f2)并行执行多个 AI 调用。CompletableFuture<Void> combined = CompletableFuture.allOf(future1, future2);提高整体效率。

提示:异步调用适合后台任务、批处理或高并发 Web 服务。

10.2 流式生成:stream 方法与响应处理

方法语法用途代码示例注意事项
stream(String)Stream<String> stream(String message)流式接收响应块(字符串)。chatClient.stream("Long story")
.forEach(System.out::print);
响应块大小由模型决定。
stream(Message)Stream<T> stream(Message message)流式发送结构化消息。chatClient.stream(new UserMessage("..."))
.forEach(chunk -> log.info("Chunk: {}", chunk));
支持实时日志记录。
stream(Prompt)Stream<ChatResponse> stream(Prompt prompt)流式接收 ChatResponse 对象流。stream.map(r -> r.getResult().getOutput().getContent())
.forEach(System.out::print);
可获取每块的元数据。
异常处理try-catch 或 onError捕获流处理中的异常。在 forEach 外层包裹 try-catch。流式调用需谨慎处理网络中断。
资源管理try-with-resources 或显式关闭确保流关闭,释放连接。对于 InputStream 等需手动管理。Spring WebFlux 中由框架管理。
Web 场景结合 @ResponseBody在 REST API 中返回流式响应。需使用 text/event-stream 内容类型。详见 10.3 节。

注意:流式响应适用于聊天机器人、实时字幕、长文本生成等需要”渐进式”输出的场景。

10.3 响应式编程支持(Project Reactor)

方法语法用途代码示例注意事项
stream(String) 返回 Flux<String>Flux<String> stream(String message)在 WebFlux 中直接返回响应流。见下方代码示例需使用 Spring WebFlux。
stream(Prompt) 返回 Flux<ChatResponse>Flux<ChatResponse> stream(Prompt prompt)流式接收结构化响应。Flux<ChatResponse> flux = chatClient.stream(prompt);可使用 map, filter 等操作符。
错误处理.onErrorReturn("Error").onErrorResume(...)处理流中的错误。flux.onErrorResume(e -> Flux.just(new ErrorResponse(e)));避免流因异常中断。
超时控制.timeout(Duration.ofSeconds(30))设置流式响应超时。flux.timeout(Duration.ofSeconds(30));防止客户端长时间等待。
背压支持Reactor 内建支持处理高速生产与低速消费的场景。使用 Flux.create() 时注意 Sink 的背压策略。Netty 服务器自动处理。
与 Mono 结合Mono<String> 用于单次响应异步获取单个结果。Mono<String> result = Mono.fromFuture(chatClient.callAsync("Hello"));统一响应式编程模型。

WebFlux 流式响应示例:

@GetMapping(value="/chat", produces=MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> chat(@RequestParam String msg) {
    return chatClient.stream(msg);
}

提示:Project Reactor 是构建高性能、非阻塞微服务的理想选择,与 Spring AI 的流式 API 天然契合。

总结:通过响应式编程,可构建高并发、低延迟的 AI 服务,特别适合现代云原生架构。

第11章:配置管理与生产最佳实践

11.1 配置文件中的 AI 客户端配置

配置项示例(application.yml)说明注意事项
模型名称spring.ai.openai.model: gpt-4o指定使用的模型。生产环境避免使用实验性模型。
API 密钥spring.ai.openai.api-key: ${OPENAI_API_KEY}使用环境变量注入密钥。严禁硬编码,使用 vault 或 KMS 更佳。
基础 URLspring.ai.openai.base-url: https://api.openai.com/v1可替换为代理或企业网关。用于网络隔离或审计场景。
超时设置spring.ai.openai.timeout: 30s连接和读取超时。复杂任务(如长文本生成)建议设为 60s+。
温度(temperature)spring.ai.openai.options.temperature: 0.7控制输出随机性(0-2)。生产环境建议 0.3~0.7,避免过高随机性。
最大 Token 数spring.ai.openai.options.max-tokens: 1500限制生成内容长度。防止响应过长导致成本激增或超时。
系统消息spring.ai.openai.options.system-message: You are a helpful assistant.设置默认角色行为。可统一服务风格,减少重复设置。

提示:使用 @ConfigurationProperties 可自定义配置绑定,实现更灵活的管理。

11.2 多客户端管理与命名实例

方法说明代码/配置示例注意事项
命名配置为不同用途的客户端使用不同配置前缀。spring.ai.openai.chat.model: gpt-3.5-turbo
spring.ai.openai.summary.model: gpt-4o
Spring AI 支持 chat, embedding 等命名空间。
自定义 Bean手动定义多个 ChatClient 实例。见下方代码示例使用 @Qualifier("gpt4Client") 注入。
场景分离按功能划分客户端(如聊天、摘要、嵌入)。embeddingClient 用于向量生成,chatClient 用于对话。提高可维护性,避免配置冲突。
条件注册按环境或条件注册客户端。@Profile("prod") @Bean ChatClient prodClient()实现多环境差异化配置。

自定义 ChatClient Bean 示例:

@Bean("gpt4Client")
ChatClient gpt4Client() {
    return ChatClient.builder(openAiApi)
        .options(...)
        .build();
}

注意:命名实例需明确用途,避免创建过多无意义的客户端。

11.3 超时、重试与容错机制

机制配置/实现方式说明注意事项
超时设置spring.ai.openai.timeout: 30s防止请求无限等待。设置应略大于模型平均响应时间。
重试机制结合 Spring Retry 或 Resilience4j自动重试失败请求。配置示例见下方代码。
断路器Resilience4j CircuitBreaker在服务不稳定时快速失败。配置 failureRateThreshold 和 waitDurationInOpenState。
降级策略提供备用响应或本地逻辑。调用失败时返回缓存结果或默认提示。确保核心功能可用。
异常分类区分 ClientException(4xx)和 ServerException(5xx)5xx 错误适合重试,4xx 通常不重试。提高重试策略精准度。

重试配置示例:

@Retryable(value = {ApiException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000))

最佳实践:生产环境必须实现重试 + 断路器组合,确保服务韧性。

11.4 日志、监控与追踪(Observability)

类别工具/方法说明注意事项
日志记录Logger 输出请求/响应记录关键信息用于调试。脱敏处理,避免记录 API 密钥或用户隐私数据。
指标监控Micrometer + Prometheus收集调用次数、延迟、错误率。创建仪表盘监控 ai_client_request_duration_seconds
分布式追踪OpenTelemetry / Zipkin追踪 AI 调用在微服务中的链路。与 Jaeger 集成,可视化调用路径。
请求 ID 传递MDC 或 TraceId关联日志与追踪信息。便于问题定位和审计。
成本监控记录 token 使用量监控输入/输出 token 消耗。结合账单预警,防止费用超支。
健康检查/actuator/health检查 AI 客户端连接状态。可自定义 HealthIndicator。

提示:可观测性是生产系统的基石,必须与 AI 集成紧密结合。

11.5 安全与密钥管理

措施实现方式说明注意事项
密钥外置环境变量、KMS、Vault避免密钥进入代码库。使用 HashiCorp Vault 或云 KMS(如 AWS KMS、GCP KMS)。
最小权限原则为 API Key 分配最小必要权限如仅允许 chat 调用,禁用 delete 操作。降低密钥泄露后的风险。
密钥轮换定期更换 API Key减少长期密钥暴露风险。自动化轮换流程,避免服务中断。
网络安全VPC、防火墙、IP 白名单限制 AI 服务访问来源。Azure/AWS/GCP 均支持网络级控制。
输入输出过滤内容安全扫描防止生成或接收有害内容。集成内容审核 API(如 Azure Content Moderator)。
审计日志记录所有 AI 调用用于安全审计和合规检查。保留日志至少 90 天。

警告:AI 服务是新的攻击面,必须像对待数据库一样严格保护。

第12章:测试与调试

12.1 单元测试 AI 调用逻辑

方法说明代码示例注意事项
测试服务层逻辑验证业务逻辑是否正确调用 AI 客户端。@Test void shouldCallAiForSummary() { String result = service.summarize("Long text..."); assertThat(result).isNotEmpty(); }不真正调用 AI 服务,依赖 Mock。
验证参数传递检查是否正确构造 Prompt 或消息。使用 ArgumentCaptor 捕获 ChatClient.call() 的参数。确保系统消息、温度等设置正确。
结构化输出测试验证 JSON 解析或 POJO 映射。MyData data = objectMapper.readValue(json, MyData.class); assertThat(data.getName()).isEqualTo("Test");覆盖边界情况(null、空字符串)。

提示:单元测试应快速、隔离,不依赖外部服务。

12.2 使用 MockAiClient 进行模拟测试

方法说明代码示例注意事项
Mockito Mock模拟 ChatClient 行为。@Mock ChatClient chatClient; @Test void testWithMock() { when(chatClient.call("Hello")).thenReturn("Hi!"); assertEquals("Hi!", service.greet("Hello")); }最常用方式,灵活控制返回值。
MockAiClientSpring AI 提供的专用测试工具。MockAiClient mockAiClient = new MockAiClient(); mockAiClient.chatClient().addResponse("Mock response");更贴近真实 API,支持流式模拟。
模拟流式响应返回 Flux 或 Stream。when(chatClient.stream("...")).thenReturn(Flux.just("part1", "part2"));测试流式处理逻辑。
模拟异常测试错误处理路径。when(chatClient.call("error")).thenThrow(new ApiException("Test"));确保服务能优雅处理失败。

最佳实践:在 @SpringBootTest 中使用 @MockBean 替换真实客户端。

12.3 集成测试策略

策略说明实现方式注意事项
真实服务调用连接真实 AI 平台进行测试。使用测试专用 API Key 和模型(如 gpt-3.5-turbo)。成本低,但依赖网络,可能不稳定。
持续集成(CI)在 CI/CD 流水线中运行测试。GitHub Actions / GitLab CI 调用测试脚本。设置超时和重试,避免因网络问题失败。
测试环境隔离使用独立的测试配置。application-test.yml 配置测试密钥和模型。避免影响生产或开发环境。
断言输出质量验证生成内容的相关性和格式。使用模糊匹配或语义相似度库(如 SimHash)。不宜过度依赖精确字符串匹配。
性能测试测试高并发下的表现。使用 JMeter 或 Gatling 模拟多用户请求。评估响应时间和错误率。

注意:集成测试是验证端到端流程的关键,建议定期运行。

12.4 调试技巧与常见错误分析

问题现象可能原因解决方法调试技巧
401 UnauthorizedAPI Key 错误或缺失检查密钥配置,确认环境变量加载。打印密钥前几位(脱敏)确认是否为空。
429 Too Many Requests请求频率超限实现重试(带退避)或降低调用频率。查看平台限流文档,监控调用速率。
500 Internal Server Error模型服务端错误重试请求,或切换模型/平台。检查 AI 平台状态页面(如 status.openai.com)。
响应为空或截断max-tokens 过小或内容被截断增加 max-tokens 或检查流式处理逻辑。启用详细日志,观察完整响应。
函数调用未触发模型未识别需要调用工具优化工具描述,确保问题明确指向工具功能。检查 tool_calls 是否在响应中出现。
token 超限消息历史过长截断历史,仅保留最近 N 条消息。计算输入 token 数(可用 tiktoken 等库)。
本地 Ollama 无法连接服务未启动或端口错误运行 ollama serve,确认 localhost:11434 可访问。使用 curl http://localhost:11434/api/tags 测试。

调试建议:

  • 启用 DEBUG 日志级别(logging.level.org.springframework.ai=DEBUG)。
  • 使用 ChatClient 的 Prompt 和 ChatResponse 对象打印完整输入输出。
  • 借助 LangSmith、PromptLayer 等专业调试工具进行深度分析。

总结:AI 应用调试需结合日志、模拟、真实测试和专业工具,形成完整闭环。

第13章:实战案例

13.1 构建智能客服机器人

核心需求

  • 用户通过文本提问(如”订单怎么退货?”)
  • 系统自动检索知识库并生成自然语言回答
  • 支持多轮对话,保持上下文
  • 可识别意图并转接人工

技术架构

用户 → Web/APP → Spring Boot Controller → ChatClient + VectorStore → 知识库检索 → AI 生成回答 → 返回用户

关键代码实现

知识库准备与向量化:

// 将 FAQ 文档嵌入并存入向量数据库
List<Document> faqDocs = loadFaqDocuments(); // 加载文本
List<TextSegment> segments = faqDocs.stream()
    .map(doc -> TextSegment.from(doc.getContent()))
    .collect(Collectors.toList());
vectorStore.add(segments); // 存入 SimpleVectorStore 或 Pinecone

对话服务(支持上下文):

@Service
public class CustomerSupportService {

    @Autowired
    private ChatClient chatClient;

    @Autowired
    private VectorStore vectorStore;

    // 使用 Map 存储用户会话(生产环境应使用 Redis)
    private final Map<String, List<Message>> conversationHistory = new ConcurrentHashMap<>();

    public String handleQuery(String userId, String userMessage) {
        // 1. 检索相关知识
        List<Document> relevantDocs = vectorStore.findSimilar(userMessage, 3);
        String context = relevantDocs.stream()
            .map(Document::getContent)
            .collect(Collectors.joining("\n"));

        // 2. 构建提示词
        String prompt = """
            你是一个电商客服助手。
            根据以下知识回答问题,不要编造信息:
            ${context}

            历史对话:
            ${getHistory(userId)}

            用户:${userMessage}
            客服:
            """;

        // 3. 调用 AI 生成回答
        String response = chatClient.call(prompt);

        // 4. 更新对话历史
        addToHistory(userId, new UserMessage(userMessage));
        addToHistory(userId, new AiMessage(response));

        return response;
    }

    private String getHistory(String userId) {
        return conversationHistory.getOrDefault(userId, List.of()).stream()
            .map(msg -> msg.getClass().getSimpleName() + ": " + msg.getContent())
            .collect(Collectors.joining("\n"));
    }

    private void addToHistory(String userId, Message message) {
        conversationHistory.computeIfAbsent(userId, k -> new ArrayList<>()).add(message);
        // 限制历史长度,避免 token 超限
        if (conversationHistory.get(userId).size() > 10) {
            conversationHistory.get(userId).remove(0);
        }
    }
}

最佳实践建议

  • ✅ 使用 RAG(检索增强生成)提高回答准确性
  • ✅ 限制对话历史长度,防止 token 超限
  • ✅ 添加意图识别(如”转人工”),可使用 @Tool 定义转接逻辑
  • ✅ 部署后持续收集用户反馈,优化知识库

13.2 实现文档摘要生成器

核心需求

  • 用户上传长文本(如报告、论文)
  • 系统生成简洁、准确的摘要
  • 支持不同长度(短摘要/长摘要)
  • 可提取关键词

技术架构

用户上传 → 文件解析 → 文本分块 → AI 摘要生成 → 结构化输出(JSON)→ 返回

关键代码实现

文档解析与分块:

@Service
public class DocumentSummarizer {

    @Autowired
    private ChatClient chatClient;

    // 使用 Spring AI 的 DocumentReader(如 PdfDocumentReader)
    public String summarizePdf(InputStream pdfStream) {
        DocumentReader reader = new PdfDocumentReader(pdfStream,
            PdfDocumentReader.Options.builder().build());
        List<Document> documents = reader.get();

        // 合并内容(或分块处理长文档)
        String fullText = documents.stream()
            .map(Document::getContent)
            .collect(Collectors.joining(" "));

        return generateSummary(fullText, "concise");
    }
}

生成结构化摘要:

// 定义摘要结构
public class SummaryResult {
    private String summary;
    private List<String> keywords;
    // getter/setter
}

public SummaryResult generateStructuredSummary(String text) {
    String prompt = """
        请对以下文本生成摘要和关键词:
        ${text}

        要求:
        - 摘要不超过 100 字
        - 提取 3-5 个关键词
        - 以 JSON 格式输出:{"summary": "...", "keywords": ["...", "..."]}
        """;

    String jsonResponse = chatClient.call(prompt);

    try {
        ObjectMapper mapper = new ObjectMapper();
        return mapper.readValue(jsonResponse, SummaryResult.class);
    } catch (JsonProcessingException e) {
        // 解析失败时重试或返回默认值
        throw new RuntimeException("Failed to parse summary JSON", e);
    }
}

最佳实践建议

  • ✅ 对长文档进行分块处理,避免单次输入过长
  • ✅ 使用 temperature=0.3 提高摘要一致性
  • ✅ 添加超时和重试机制,防止大文档处理失败
  • ✅ 提供摘要长度选项(如”一句话摘要”、“段落摘要”)

13.3 开发基于自然语言的数据库查询接口

核心需求

  • 用户用自然语言提问(如”上个月销售额最高的产品”)
  • 系统自动生成 SQL 并执行
  • 返回结构化数据或自然语言描述

技术架构

用户提问 → NLP → AI 生成 SQL → 执行查询 → 格式化结果 → 返回

关键代码实现

定义 SQL 生成工具:

@Component
public class SqlGenerator {

    @Autowired
    private ChatClient chatClient;

    @Value("${app.database.schema}")
    private String dbSchema; // 数据库结构描述

    public String generateSql(String naturalQuery) {
        String prompt = """
            你是一个 SQL 专家。
            根据以下数据库结构,将自然语言转换为 SQL:
            ${dbSchema}

            要求:
            - 只返回 SQL 语句,不要解释
            - 使用标准 SQL 语法
            - 避免 SELECT *

            问题:${naturalQuery}
            SQL:
            """;

        return chatClient.call(prompt).trim();
    }
}

安全执行 SQL:

@Service
public class NaturalQueryService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private SqlGenerator sqlGenerator;

    public Object queryByNaturalLanguage(String question) {
        // 1. 生成 SQL
        String sql = sqlGenerator.generateSql(question);

        // 2. 安全校验(防止恶意 SQL)
        if (!isSafeSql(sql)) {
            throw new IllegalArgumentException("Invalid SQL generated");
        }

        // 3. 执行查询
        try {
            return jdbcTemplate.queryForList(sql);
        } catch (DataAccessException e) {
            throw new RuntimeException("Query execution failed", e);
        }
    }

    private boolean isSafeSql(String sql) {
        // 简单校验:禁止 DELETE/UPDATE/DROP 等
        String upperSql = sql.toUpperCase();
        return !upperSql.contains("DELETE")
            && !upperSql.contains("UPDATE")
            && !upperSql.contains("DROP")
            && upperSql.startsWith("SELECT");
    }
}

最佳实践建议

  • ✅ 严格限制 SQL 类型,仅允许 SELECT
  • ✅ 使用数据库视图暴露有限数据,避免直接访问基表
  • ✅ 添加查询超时
  • ✅ 对于复杂需求,可结合 LangChain Expression Language (LCEL) 实现多步推理

13.4 构建 AI 驱动的邮件助手

核心需求

  • 用户输入邮件主题和要点
  • AI 生成专业、得体的邮件草稿
  • 支持不同风格(正式、简洁、友好)
  • 可自动添加签名

技术架构

用户输入 → 风格选择 → AI 生成 → 内容过滤 → 返回邮件草稿

关键代码实现

邮件生成服务:

@Service
public class EmailAssistant {

    @Autowired
    private ChatClient chatClient;

    public String draftEmail(String subject, String points, String tone) {
        String prompt = """
            请根据以下信息撰写一封邮件:
            主题:${subject}
            内容要点:
            ${points}

            要求:
            - 语气:${tone}(可选:正式、简洁、友好)
            - 包含开头问候和结尾致意
            - 长度适中
            - 使用专业商务英语

            邮件:
            """;

        return chatClient.call(prompt);
    }
}

集成到 Web 控制器:

@RestController
@RequestMapping("/api/email")
public class EmailController {

    @Autowired
    private EmailAssistant emailAssistant;

    @PostMapping("/draft")
    public ResponseEntity<String> createDraft(@RequestBody EmailRequest request) {
        String draft = emailAssistant.draftEmail(
            request.getSubject(),
            String.join("\n", request.getPoints()),
            request.getTone()
        );
        return ResponseEntity.ok(draft);
    }
}

// 请求 DTO
public class EmailRequest {
    private String subject;
    private List<String> points;
    private String tone = "正式";
    // getter/setter
}

最佳实践建议

  • ✅ 提供预设模板(如”会议邀请”、“项目更新”)
  • ✅ 支持多语言生成(添加”语言”参数)
  • ✅ 集成拼写检查和敏感词过滤
  • ✅ 允许用户编辑草稿后再发送,避免完全自动化

本章总结

案例核心技术适用场景
智能客服RAG + 对话历史企业客服、知识问答
文档摘要文本分块 + 结构化输出报告处理、信息提取
自然语言查库SQL 生成 + 安全校验BI 分析、数据探索
邮件助手风格化生成 + 模板办公自动化、效率工具

通用建议:

  • 所有案例均需考虑错误处理和用户体验
  • 生产环境务必进行充分测试和性能评估
  • 结合可观测性工具(日志、监控)持续优化
  • 遵循安全最佳实践,防止数据泄露和滥用