Java后端AI集成实战:Spring AI、LangChain4j与智能体构建指南
在实际 Java 后端开发中,集成 AI 大模型能力正从一个前沿探索变为工程标配。无论是构建智能客服、文档分析助手,还是实现复杂的多步骤推理 Agent,开发者都需要一套稳定、高效且符合 Java 生态的解决方案。面对 Spring AI、Spring AI Alibaba、LangChain4j 等多个框架,如何选择、如何整合、如何从零搭建一个可运行、可调试、可扩展的 AI 应用,是许多团队正在面临的实际问题。本文将以一个工程实践者的视角,带你梳理 Java 生态下的 AI 集成方案,通过对比核心框架、手把手搭建一个融合多种能力的 Agent 案例,并深入探讨生产环境中必须考虑的配置、排错与优化策略。无论你是希望将 AI 能力引入现有 Spring Boot 项目,还是计划从零开始构建一个 AI 驱动的服务,本文提供的思路和代码都将为你提供一个坚实的起点。
1. 核心框架对比与选型:Spring AI、Spring AI Alibaba 与 LangChain4j
在 Java 中集成 AI,目前主要有三个活跃的框架选项:Spring AI、Spring AI Alibaba 和 LangChain4j。它们的设计理念、抽象层次和适用场景各有不同,选型错误可能导致后期开发成本陡增。
1.1 Spring AI:Spring 生态的官方尝试
Spring AI 是 Spring 官方团队推出的项目,旨在为 Spring 应用提供一套统一的 AI 抽象。它的核心思想是“Portable Service API”,即定义一套标准的接口(如 ChatClient 、 EmbeddingClient ),让开发者可以像切换数据库驱动一样,在不同的大模型提供商(OpenAI、Azure OpenAI、Ollama 等)之间切换,而无需重写业务代码。
核心优势:
- 无缝 Spring 集成 :与 Spring Boot 的自动配置、属性绑定、依赖注入完美融合,学习成本低。
- 声明式配置 :通过
application.yml即可完成模型连接、参数设置。 - 功能模块化 :提供了 Chat、Embedding、Image Generation、Vector Store 等模块,结构清晰。
潜在考量:
- 发展早期 :相比 Python 的 LangChain,其生态和社区成熟度仍在快速发展中。
- 抽象程度 :高级功能(如复杂的 Agent、工作流)的抽象和支持还在完善中。
对于已经深度使用 Spring 技术栈,且需求集中在模型调用、向量检索等基础能力的团队,Spring AI 是首选的集成路径。
1.2 Spring AI Alibaba:阿里云模型的深度集成
Spring AI Alibaba 可以看作是 Spring AI 的一个扩展实现,专门为阿里云的通义千问(Qwen)系列大模型以及灵积平台(DashScope)进行了深度适配和优化。它实现了 Spring AI 定义的标准接口,因此可以几乎无感地替换掉 Spring AI 中默认的 OpenAI 客户端。
核心价值:
- 专有模型优化 :针对通义千问模型的参数、调用方式、流式响应等做了专门处理,性能更优。
- 阿里云生态集成 :天然支持阿里云的 AK/SK 认证、服务网格等云原生能力。
- 符合国内合规要求 :对于数据不出境、使用国产化模型有硬性要求的场景,这是关键选择。
如果你的项目明确要求使用通义千问、千问 VL 等阿里系模型,或者部署在阿里云上,Spring AI Alibaba 是最直接的方案。
1.3 LangChain4j:Java 版的 LangChain
LangChain4j 是著名 AI 应用框架 LangChain 的 Java 移植版本。它不完全遵循 Spring 那套“约定大于配置”的哲学,而是提供了一套更灵活、功能更丰富的 API 来构建复杂的 AI 应用,特别是在智能体(Agent)、工具(Tool)调用、链(Chain)式编排方面非常强大。
核心优势:
- 功能强大且成熟 :直接继承了 LangChain 的设计理念,在 Agent、RAG、复杂工作流方面有深厚的积累和丰富的模式。
- 模型无关性 :支持数十种模型和嵌入服务,包括本地模型(Ollama)。
- 丰富的工具集成 :可以轻松地将搜索引擎、计算器、数据库查询等封装成工具供 AI 调用。
潜在考量:
- 与 Spring 集成需要额外配置 :虽然提供了 Spring Boot Starter,但其核心 API 并非完全 Spring 风格,需要一定的适配。
- 学习曲线 :概念更多(Agent, Chain, Memory, Tool),需要理解其设计模式。
当你需要构建超越简单问答的复杂 AI 应用,例如一个能自动调用 API、查询知识库、进行多轮规划决策的智能体时,LangChain4j 是目前 Java 生态中最有力的工具。
选型决策速查表:
| 场景需求 | 推荐框架 | 关键理由 |
|---|---|---|
| 现有 Spring Boot 项目快速接入 GPT/Claude | Spring AI | 配置简单,与 Spring 生态无缝融合。 |
| 必须使用通义千问等阿里云模型 | Spring AI Alibaba | 官方深度适配,功能与性能有保障。 |
| 构建复杂的、多步骤的智能体(Agent)应用 | LangChain4j | 在 Agent、Tool、Chain 方面功能最完善。 |
| 项目技术栈自由,追求 AI 功能的最大灵活性 | LangChain4j | 模型和工具支持最广泛,社区活跃。 |
| 团队熟悉 Spring,需求以基础模型调用和 RAG 为主 | Spring AI 或 Spring AI Alibaba | 开发模式最符合团队习惯。 |
在实际项目中,它们并非互斥。一个常见的混合架构是: 使用 Spring AI Alibaba 作为底层模型调用客户端(实现 ChatClient ),同时利用 LangChain4j 来构建上层的复杂 Agent 逻辑 。这样既能享受 Spring 生态的便利,又能使用 LangChain4j 强大的编排能力。
2. 环境准备与项目初始化
在开始编码前,我们需要一个干净的 Spring Boot 工程环境。这里我们选择 Spring Boot 3.x 和 Java 17 作为基础,因为它们是当前主流且被这些 AI 框架良好支持的版本。
2.1 基础环境检查
首先,确保你的开发环境满足以下要求:
- JDK : 17 或更高版本(推荐 17 或 21 LTS)。
- 构建工具 : Maven 3.6+ 或 Gradle 7.x+。
- IDE : IntelliJ IDEA(推荐)或 VS Code with Spring Boot 插件。
可以通过命令行验证:
java -version
# 应输出类似:openjdk version "17.0.10" ...
mvn -v
# 应输出 Maven 版本信息
2.2 创建 Spring Boot 项目
使用 Spring Initializr 生成项目骨架,选择以下依赖:
- Project : Maven
- Language : Java
- Spring Boot : 3.2.x (最新稳定版)
- Packaging : Jar
- Java : 17
- Dependencies :
Spring Web(用于构建 REST API)Lombok(简化代码,可选但推荐)Spring Boot DevTools(开发热加载,可选)
生成并下载项目,解压后用 IDE 打开。你的 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 https://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.5</version> <!-- 版本可能更新 -->
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>java-ai-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>java-ai-demo</name>
<description>Demo project for Java AI Integration</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- ... 构建插件等 ... -->
</project>
2.3 引入 AI 框架依赖
接下来,我们将 Spring AI Alibaba 和 LangChain4j 的依赖加入项目。 注意 :由于 Spring AI 和 Spring AI Alibaba 在 ChatClient 等接口上可能存在冲突,我们这里选择以 Spring AI Alibaba 作为模型客户端,并引入 LangChain4j 的 Spring Boot Starter 来使用其高级功能。
在 pom.xml 的 <dependencies> 部分添加:
<!-- Spring AI Alibaba: 用于连接通义千问等模型 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-ai-spring-boot-starter</artifactId>
<version>2023.0.1.0</version> <!-- 请检查最新版本 -->
</dependency>
<!-- LangChain4j Spring Boot Starter -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>0.31.0</version> <!-- 请检查最新版本 -->
</dependency>
<!-- LangChain4j 对阿里云模型的支持 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-alibaba-qianfan</artifactId> <!-- 注意:此模块名可能随版本变化 -->
<version>0.31.0</version>
</dependency>
注意 :AI 框架版本迭代较快,上述版本号在编写时是稳定的,但在你实际实践时,务必去 Maven Central 或项目的 GitHub Release 页面查看最新稳定版本。版本不匹配是后续各种
ClassNotFoundException或NoSuchMethodError的常见根源。
添加依赖后,执行 mvn clean compile 确保依赖下载成功且无冲突。
3. 基础配置与第一个 AI 对话接口
配置是连接模型服务的第一步,也是最容易出错的一步。我们将分别配置 Spring AI Alibaba 和 LangChain4j,并创建两个简单的 REST 端点来验证连通性。
3.1 配置 Spring AI Alibaba 连接通义千问
首先,你需要获取阿里云 DashScope 平台的 API Key。访问阿里云官网,开通灵积(DashScope)服务并创建 API Key。
在项目的 src/main/resources/application.yml 文件中进行配置:
# 应用基础配置
server:
port: 8080
spring:
application:
name: java-ai-demo
# Spring AI Alibaba 配置
ai:
alibaba:
# 通义千问 Turbo 模型
chat:
options:
# 从阿里云控制台获取
api-key: ${ALIBABA_API_KEY:your-api-key-here}
# 模型名称,如 qwen-turbo, qwen-max, qwen-plus 等
model: qwen-turbo
# 温度参数,控制随机性 (0.0 ~ 1.0)
temperature: 0.7
# 最大生成长度
max-tokens: 2000
# 基础连接配置
base:
# DashScope API 端点,通常无需修改
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
关键参数解释:
api-key: 切勿硬编码在代码或配置文件中提交到版本库 。推荐使用环境变量ALIBABA_API_KEY传入。model:指定要使用的模型。qwen-turbo响应快成本低,适合对话;qwen-max能力更强但更贵。temperature:影响输出的创造性。值越高(接近1.0),回答越多样、随机;值越低(接近0.0),回答越确定、保守。对于事实性问答,建议设低(如0.1);对于创意写作,可以设高。base-url:Spring AI Alibaba 已经适配了 DashScope 的接口,通常使用这个兼容模式端点即可。
3.2 创建 Spring AI Alibaba 的对话服务
创建一个简单的 Service 来使用配置好的 ChatClient 。
package com.example.javaaidemo.service;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class SimpleChatService {
// Spring AI Alibaba 会自动配置一个 ChatClient Bean
private final ChatClient chatClient;
public String chat(String message) {
// 调用 ChatClient 进行同步对话
return chatClient.prompt()
.user(message)
.call()
.content();
}
public String chatWithSystem(String userMessage, String systemInstruction) {
// 可以指定系统指令,塑造 AI 的角色
return chatClient.prompt()
.system(systemInstruction) // 例如:“你是一个专业的Java工程师助手”
.user(userMessage)
.call()
.content();
}
}
创建一个 REST 控制器来暴露接口:
package com.example.javaaidemo.controller;
import com.example.javaaidemo.service.SimpleChatService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/ai")
@RequiredArgsConstructor
public class ChatController {
private final SimpleChatService chatService;
@PostMapping("/chat")
public String chat(@RequestBody ChatRequest request) {
return chatService.chat(request.getMessage());
}
@PostMapping("/chat-with-role")
public String chatWithRole(@RequestBody RoleChatRequest request) {
return chatService.chatWithSystem(request.getUserMessage(), request.getSystemInstruction());
}
// 简单的请求体
public static class ChatRequest {
private String message;
// getter and setter ...
}
public static class RoleChatRequest {
private String userMessage;
private String systemInstruction;
// getter and setter ...
}
}
启动应用,使用 curl 或 Postman 测试:
curl -X POST http://localhost:8080/api/ai/chat \
-H "Content-Type: application/json" \
-d '{"message": "用Java写一个Hello World程序"}'
如果配置正确,你将收到通义千问模型生成的 Java 代码。这一步验证了 Spring AI Alibaba 的基础集成是成功的。
3.3 配置与使用 LangChain4j 进行对话
LangChain4j 的配置相对独立。我们需要在 application.yml 中补充它的配置,并创建一个使用其 ChatLanguageModel 的服务。
在 application.yml 中追加:
# LangChain4j 配置
langchain4j:
alibaba:
qianfan:
# 使用同一个 API Key
api-key: ${ALIBABA_API_KEY:your-api-key-here}
# 模型名称,与上面保持一致
model-name: ${spring.ai.alibaba.chat.options.model:qwen-turbo}
# 温度、最大token等参数
temperature: ${spring.ai.alibaba.chat.options.temperature:0.7}
max-tokens: ${spring.ai.alibaba.chat.options.max-tokens:2000}
top-p: 0.9 # 另一个采样参数,与 temperature 配合使用
# 请求超时时间
timeout: 60s
创建 LangChain4j 的对话服务:
package com.example.javaaidemo.service;
import dev.langchain4j.model.chat.ChatLanguageModel;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class LangChain4jChatService {
// LangChain4j 会自动注入配置好的模型 Bean
private final ChatLanguageModel chatLanguageModel;
public String chat(String message) {
return chatLanguageModel.generate(message);
}
public String chatWithMemory(String message) {
// LangChain4j 的一个优势是内置了简单的对话记忆管理
// 这里演示一个最简单的单次调用
return chatLanguageModel.generate(message);
// 更复杂的多轮记忆需要用到 ChatMemory 和 AiServices,下文会介绍
}
}
在控制器中增加一个端点:
@RestController
@RequestMapping("/api/ai")
@RequiredArgsConstructor
public class ChatController {
// ... 之前的 SimpleChatService 注入 ...
private final LangChain4jChatService langChain4jChatService;
@PostMapping("/langchain-chat")
public String langchainChat(@RequestBody ChatRequest request) {
return langChain4jChatService.chat(request.getMessage());
}
}
测试这个端点,功能上与第一个端点类似,但底层使用的是 LangChain4j 的抽象。至此,我们完成了两个框架的基础接入。接下来,我们将利用 LangChain4j 更强大的能力,构建一个真正的智能体(Agent)。
4. 构建智能体(Agent)案例实战
智能体的核心是让大模型能够“使用工具”。我们将创建一个“业务数据分析助手”Agent,它可以根据用户描述,调用我们预定义的工具(例如,查询本周销售额、查询热门商品)来回答问题,而不是仅仅基于训练数据生成文本。
4.1 定义工具(Tools)
工具是 Agent 可以调用的函数。在 LangChain4j 中,工具就是一个普通的 Java 方法,加上 @Tool 注解。
首先,创建一个工具类 BusinessDataTools :
package com.example.javaaidemo.agent.tools;
import dev.langchain4j.agent.tool.Tool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
@Component
@Slf4j
public class BusinessDataTools {
/**
* 查询指定日期范围的销售额。
* @param startDate 开始日期 (YYYY-MM-DD)
* @param endDate 结束日期 (YYYY-MM-DD)
* @return 销售额描述
*/
@Tool("根据开始日期和结束日期查询销售额。日期格式必须是 YYYY-MM-DD。")
public String querySales(String startDate, String endDate) {
log.info("工具被调用: querySales, 参数: startDate={}, endDate={}", startDate, endDate);
// 这里应该是真实的数据库或API调用,此处模拟返回
// 实际项目中,这里可以注入 Repository 或 Service
double simulatedSales = 150000.0 + Math.random() * 50000;
return String.format("从 %s 到 %s 的销售额约为 %.2f 元。", startDate, endDate, simulatedSales);
}
/**
* 查询本周的销售额(从周一到今天)。
*/
@Tool("查询本周(周一到今天)的销售额。")
public String queryThisWeekSales() {
log.info("工具被调用: queryThisWeekSales");
LocalDate today = LocalDate.now();
LocalDate monday = today.with(DayOfWeek.MONDAY);
return querySales(monday.toString(), today.toString());
}
/**
* 查询热门商品列表。
* @param topN 返回前N名,默认是5
* @return 热门商品列表描述
*/
@Tool("查询最畅销的前N个商品。")
public String queryTopProducts(@Tool("返回的商品数量") int topN) {
log.info("工具被调用: queryTopProducts, 参数: topN={}", topN);
// 模拟数据
List<Map.Entry<String, Integer>> products = List.of(
Map.entry("智能手机", 1200),
Map.entry("无线耳机", 850),
Map.entry("笔记本电脑", 600),
Map.entry("智能手表", 450),
Map.entry("平板电脑", 300)
);
StringBuilder sb = new StringBuilder("热门商品排名:\n");
products.stream().limit(topN).forEach(entry ->
sb.append(String.format("- %s: 销量 %d 件\n", entry.getKey(), entry.getValue()))
);
return sb.toString();
}
/**
* 一个简单的计算器工具,展示 Agent 可以处理逻辑。
*/
@Tool("执行简单的数学计算,支持加(+)、减(-)、乘(*)、除(/)。")
public String calculate(String expression) {
log.info("工具被调用: calculate, 参数: expression={}", expression);
try {
// 警告:这是一个极其简化的示例,生产环境必须使用安全的表达式求值库!
String[] parts = expression.split("\\s+");
if (parts.length != 3) {
return "表达式格式错误,请使用 'a + b' 这样的格式。";
}
double a = Double.parseDouble(parts[0]);
double b = Double.parseDouble(parts[2]);
double result;
switch (parts[1]) {
case "+": result = a + b; break;
case "-": result = a - b; break;
case "*": result = a * b; break;
case "/":
if (b == 0) return "错误:除数不能为零。";
result = a / b;
break;
default: return "不支持的操作符: " + parts[1];
}
return String.format("%s = %.2f", expression, result);
} catch (Exception e) {
return "计算失败: " + e.getMessage();
}
}
}
关键点说明:
-
@Tool注解 :标记一个方法可以作为工具被 Agent 调用。注解中的字符串描述非常重要,AI 模型会阅读这个描述来决定何时以及如何调用该工具。 - 方法参数 :工具方法的参数名和类型也会被模型感知。可以使用
@Tool注解在参数上提供更详细的描述。 - 模拟实现 :示例中返回了模拟数据。在实际项目中,这里应该注入你的 Service 或 Repository,执行真实的业务逻辑。
- 日志 :在工具方法开始处打日志,对于调试 Agent 的决策过程至关重要。
4.2 创建 AI 服务(AiServices)与 Agent
LangChain4j 的 AiServices 是一个强大的抽象,它能够自动将工具、记忆(Memory)和模型绑定在一起,创建一个可以对话的 AI 服务接口。
首先,定义这个 AI 服务接口:
package com.example.javaaidemo.agent;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
public interface BusinessAnalystAgent {
/**
* 与业务分析师对话。
* @param userMessage 用户消息
* @return Agent 的回复,可能包含工具调用结果。
*/
@SystemMessage("""
你是一个专业的业务数据分析助手。你的职责是帮助用户分析业务数据。
你可以调用工具来查询销售额、热门商品等信息,也可以进行简单的计算。
如果用户的问题需要查询数据,请主动调用合适的工具。
你的回答应该专业、清晰,并基于工具返回的数据。
如果工具返回了数据,请在回答中总结并解释这些数据。
""")
String chat(@UserMessage String userMessage);
/**
* 一个更复杂的例子,使用动态变量。
* @param question 用户问题
* @param userName 用户名
* @return 个性化的回复
*/
@SystemMessage("你是{{userName}}的专属业务顾问。")
String personalizedChat(@V("userName") String userName, @UserMessage String question);
}
接口设计解析:
@SystemMessage:定义了 AI 的“系统提示词”(System Prompt),即它的角色和行事规则。这是塑造 Agent 行为的关键。@UserMessage:标记哪个参数是用户的输入。@V:用于在@SystemMessage或@UserMessage中引用方法参数,实现动态提示词。
接下来,在配置类或主应用类中,创建这个 AiService 的 Bean:
package com.example.javaaidemo.config;
import com.example.javaaidemo.agent.BusinessAnalystAgent;
import com.example.javaaidemo.agent.tools.BusinessDataTools;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.service.AiServices;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AgentConfig {
@Bean
public BusinessAnalystAgent businessAnalystAgent(
ChatLanguageModel chatLanguageModel, // 注入之前配置的模型
BusinessDataTools businessDataTools // 注入工具类
) {
// 创建聊天记忆,保留最近10轮对话
ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
return AiServices.builder(BusinessAnalystAgent.class)
.chatLanguageModel(chatLanguageModel)
.chatMemory(chatMemory) // 为Agent绑定记忆,实现多轮对话
.tools(businessDataTools) // 注册工具类,其内部所有@Tool方法都会被自动发现
.build();
}
}
4.3 创建 Agent 控制器并测试
现在,我们可以通过 REST API 来与这个智能体交互了。
package com.example.javaaidemo.controller;
import com.example.javaaidemo.agent.BusinessAnalystAgent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/agent")
@RequiredArgsConstructor
@Slf4j
public class AgentController {
private final BusinessAnalystAgent businessAnalystAgent;
@PostMapping("/analyze")
public String analyze(@RequestBody AgentRequest request) {
log.info("收到Agent分析请求: {}", request.getQuestion());
String response = businessAnalystAgent.chat(request.getQuestion());
log.info("Agent回复: {}", response);
return response;
}
public static class AgentRequest {
private String question;
// getter and setter ...
}
}
启动应用,进行测试。以下是几个测试用例和预期的 Agent 行为:
测试 1:查询本周销售额
curl -X POST http://localhost:8080/api/agent/analyze \
-H "Content-Type: application/json" \
-d '{"question": "本周的销售情况怎么样?"}'
- 预期 :Agent 会识别出需要查询本周销售额,调用
queryThisWeekSales工具。你会在应用日志中看到工具被调用: queryThisWeekSales。然后 Agent 会将工具返回的模拟销售额数据整合到它的自然语言回复中,例如:“根据查询,从2024-05-20到2024-05-26的销售额约为 178,345.12 元。本周销售表现稳健。”
测试 2:混合查询与计算
curl -X POST http://localhost:8080/api/agent/analyze \
-H "Content-Type: application/json" \
-d '{"question": "帮我查一下最热门的3个商品,然后计算一下如果它们的单价都上涨10%,总销售额会增加多少?假设当前平均单价分别是2000、800、5000。"}'
- 预期 :这是一个多步骤任务。Agent 可能会:
- 先调用
queryTopProducts(3)获取商品列表。 - 然后,它需要“计算”。它可能会尝试调用
calculate工具,但需要先组织好计算表达式。高级的模型能够进行规划,它可能会分别计算每个商品的增长额再求和,或者直接计算总增长额。观察日志,你会看到多个工具被依次调用。
- 先调用
测试 3:多轮对话(依赖记忆) 连续发送两条消息:
# 第一轮
curl -X POST ... -d '{"question": "我是张三,我想了解业务。"}'
# 第二轮
curl -X POST ... -d '{"question": "那我本周的销售额呢?"}'
- 预期 :由于我们为 Agent 配置了
ChatMemory,在第二轮对话中,Agent 能记住上下文(用户是“张三”),并在回答中体现出来。这展示了 Agent 的对话连贯性。
通过这个案例,你已经构建了一个能够理解用户意图、自主选择并调用工具、整合信息后回复的真正智能体。这远比简单的模型调用强大。
5. 生产环境关键配置、排错与最佳实践
将 AI 应用部署到生产环境,会面临与开发环境不同的问题。以下是必须关注的要点。
5.1 配置管理:安全与灵活性
1. API Key 管理:
- 绝对禁止硬编码 :如前所述,使用环境变量或配置中心(如 Spring Cloud Config, Apollo, Nacos)。
- 使用配置 Profile :在
application-prod.yml中配置生产环境的 Key 和端点,与开发环境隔离。 - 密钥轮换 :制定流程,定期轮换 API Key。
2. 连接与超时配置: 在 application-prod.yml 中调整超时和重试策略,防止网络抖动导致服务雪崩。
spring:
ai:
alibaba:
base:
connect-timeout: 5s
read-timeout: 30s # 大模型响应可能较慢
max-retries: 2 # 谨慎设置重试,某些错误重试无效且浪费token
langchain4j:
alibaba:
qianfan:
timeout: 30s
log-requests: true # 生产环境建议开启,用于审计和调试
log-responses: false # 响应可能包含敏感数据,生产环境谨慎开启
5.2 常见问题排查清单
当你的 AI 接口出现问题时,请按以下顺序排查:
| 问题现象 | 可能原因 | 检查点与解决方案 |
|---|---|---|
启动报错 NoSuchBeanDefinitionException (ChatClient/ChatLanguageModel) |
1. 依赖未正确引入。 2. 配置项缺失或错误。 3. 版本冲突。 |
1. 检查 pom.xml 依赖,运行 mvn dependency:tree 查看是否拉取成功。 2. 检查 application.yml 中 spring.ai.alibaba 或 langchain4j.alibaba 配置项,特别是 api-key 。 3. 确认 Spring Boot、Spring AI Alibaba、LangChain4j 版本兼容性。 |
| 调用接口返回 401/403 错误 | API Key 无效、过期或没有对应模型的权限。 | 1. 去阿里云控制台确认 API Key 状态和额度。 2. 确认配置的 model 名称是否正确,且该 Key 有权访问此模型。 3. 检查环境变量是否生效。 |
| 调用超时 (Timeout) | 1. 网络问题。 2. 模型响应慢。 3. 请求的 max-tokens 设置过大。 |
1. 检查服务器网络连通性。 2. 适当调大 read-timeout 。 3. 降低 max-tokens 或 temperature ,简化用户问题。 |
| Agent 不调用工具,直接回答“我不知道” | 1. 工具描述 ( @Tool 注解) 不清晰。 2. 系统提示词 ( @SystemMessage ) 未明确指示使用工具。 3. 模型能力不足。 |
1. 优化工具描述,确保清晰说明功能、输入格式和用途。 2. 强化系统提示词,例如:“你必须优先考虑使用工具来获取数据回答用户问题。” 3. 尝试更换更强的基础模型(如 qwen-max )。 |
| 工具被调用,但参数解析错误 | 模型未能正确理解用户问题并提取参数。 | 1. 在工具方法内增加更严格的参数校验和日志。 2. 优化系统提示词,指导模型如何提取参数。 3. 考虑在工具层做参数的后处理和兜底逻辑。 |
| 多轮对话中,Agent 忘记上下文 | ChatMemory 配置不当或未生效。 |
1. 确认 AiServices.builder() 时绑定了 ChatMemory Bean。 2. 检查 MessageWindowChatMemory.withMaxMessages(10) 中的消息数量是否足够。 3. 对于 Web 应用,需要为每个用户/会话创建独立的 ChatMemory 实例,通常需要自定义实现或使用 TokenWindowChatMemory 。 |
5.3 性能、成本与监控最佳实践
1. 优化 Token 使用以控制成本:
- 精简提示词 :系统提示词和工具描述要精炼准确,减少不必要的 Token 消耗。
- 缓存结果 :对于重复性高、结果变化不频繁的查询(如“公司介绍”),可以将 AI 的回复缓存起来(使用 Redis 或 Caffeine),避免重复调用模型。
- 设置最大 Token 限制 :在配置中明确设置
max-tokens,防止生成过长内容。
2. 引入熔断与降级: 使用 Resilience4j 或 Sentinel 为 AI 服务调用配置熔断器。当模型服务连续超时或失败时,快速失败并返回预设的降级内容(如“系统繁忙,请稍后再试”),保护自身服务不被拖垮。
// 伪代码示例
@CircuitBreaker(name = "aiChatService", fallbackMethod = "fallbackResponse")
public String chatWithCircuitBreaker(String message) {
return businessAnalystAgent.chat(message);
}
private String fallbackResponse(String message, Throwable t) {
log.warn("AI服务降级,原问题: {}", message, t);
return "当前AI服务暂时不可用,请稍后重试。";
}
3. 完善的日志与监控:
- 记录请求与响应摘要 :记录用户问题、调用的工具、消耗的 Token 数(如果 API 返回)、响应时间。 注意脱敏 ,不要记录完整的 API Key 和可能包含用户隐私的响应内容。
- 监控关键指标 :使用 Micrometer 暴露指标,如
ai.request.count,ai.request.duration,ai.token.usage,并接入 Prometheus 和 Grafana。 - 工具调用审计 :所有工具调用(特别是涉及数据修改或敏感查询的)必须有清晰的审计日志,记录操作人、时间、参数和结果。
4. 处理速率限制(Rate Limiting): 模型服务商都有调用频率限制。在客户端(你的应用)实现简单的限流,避免突发流量触发服务商限流导致整体失败。可以使用 Guava 的 RateLimiter 或 Resilience4j 的 RateLimiter 。
从简单的模型调用到复杂的智能体构建,Java 生态通过 Spring AI Alibaba 和 LangChain4j 提供了坚实的支撑。成功的集成关键在于理解框架的抽象层次,做出正确的选型,并像对待任何外部服务一样,为 AI 调用配置好超时、重试、熔断、监控和审计。本文的案例提供了一个从零到一的完整路径,但每个生产系统都需要在此基础上,根据自身的业务逻辑、数据安全和性能要求进行深度定制。下一步,你可以探索更复杂的 Agent 模式(如 ReAct、Plan-and-Execute),集成向量数据库实现 RAG,或者将 AI 能力与你现有的业务工作流引擎相结合,创造出真正智能化的业务应用。
更多推荐




所有评论(0)