1. 为什么Java开发者需要关注大模型技术?
在2023年大模型技术爆发后,Python凭借其丰富的AI生态迅速成为大模型开发的主流语言,这让很多Java开发者感到焦虑。但实际情况是,企业级应用开发中Java仍占据主导地位,特别是在金融、电商、ERP等传统领域。Spring AI和LangChain4j的出现,正是为了解决Java开发者在大模型时代的工具链缺失问题。
我最近在一个银行智能客服系统项目中就深有体会:核心系统用Java编写,但AI模块却要用Python开发,导致系统架构复杂、维护成本高。有了Spring AI和LangChain4j后,我们终于可以在Java生态内完成所有开发。
1.1 Spring AI vs LangChain4j 技术选型
这两个框架虽然目标相似,但设计哲学不同:
| 特性 | Spring AI | LangChain4j |
|---|---|---|
| 设计理念 | Spring生态原生集成 | 移植Python LangChain到Java生态 |
| 学习曲线 | 对Spring开发者友好 | 需要理解LangChain概念体系 |
| 功能完整性 | 基础功能完善,扩展性强 | 功能更接近Python原版 |
| 企业级特性 | 支持Spring安全、监控等企业特性 | 更侧重模型能力整合 |
| 最佳适用场景 | 需要与企业现有Spring系统深度整合的项目 | 需要快速复现Python LangChain能力的项目 |
提示:如果你的团队已经大量使用Spring技术栈,建议优先考虑Spring AI;如果需要与Python团队保持技术栈一致,LangChain4j可能是更好选择。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境搭建与快速入门
2.1 基础环境准备
以Spring AI为例,我们需要以下环境配置:
- JDK 17+(大模型相关库对新版Java特性有依赖)
- Maven 3.6+或Gradle 7.x
- IDE推荐IntelliJ IDEA(对大模型开发有更好的支持)
在pom.xml中添加Spring AI starter依赖:
xml复制<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>0.8.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
2.2 第一个大模型交互程序
创建一个简单的Chat服务:
java复制@RestController
public class ChatController {
private final OpenAiChatClient chatClient;
public ChatController(OpenAiChatClient chatClient) {
this.chatClient = chatClient;
}
@GetMapping("/chat")
public String chat(@RequestParam String message) {
return chatClient.call(message);
}
}
配置application.yml:
yaml复制spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
model: gpt-3.5-turbo
这个简单的例子已经展示了Spring AI的核心优势 - 通过熟悉的Spring Boot方式集成大模型能力。
3. 核心功能深度解析
3.1 提示词工程实践
与Python生态不同,Java开发者更习惯类型安全的方式。Spring AI提供了PromptTemplate:
java复制PromptTemplate promptTemplate = new PromptTemplate("""
你是一个专业的{role},请用{style}风格回答以下问题:
{question}
""");
Map<String, Object> model = Map.of(
"role", "Java架构师",
"style", "简洁专业",
"question", "如何设计高并发支付系统?"
);
Prompt prompt = promptTemplate.create(model);
String response = chatClient.call(prompt.getContents());
这种方式比Python中常见的字符串拼接更安全、更易维护。
3.2 RAG实现方案
检索增强生成(RAG)是企业应用中最有价值的场景之一。以下是使用LangChain4j实现RAG的典型代码:
java复制EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
// 文档处理
List<TextSegment> segments = FileUtils.readTextSegments("data.pdf");
List<Embedding> embeddings = embeddingModel.embedAll(segments).content();
embeddingStore.addAll(embeddings, segments);
// 检索流程
String query = "Spring AI的核心特性是什么?";
Embedding queryEmbedding = embeddingModel.embed(query).content();
List<EmbeddingMatch<TextSegment>> relevant = embeddingStore.findRelevant(queryEmbedding, 3);
// 构建提示词
String context = relevant.stream()
.map(match -> match.embedded().text())
.collect(joining("\n\n"));
String answer = chatClient.call("基于以下上下文回答:\n" + context + "\n\n问题:" + query);
3.3 流式响应处理
对于需要长时间运行的模型调用,流式响应至关重要:
java复制@GetMapping("/stream")
public SseEmitter streamChat(@RequestParam String message) {
SseEmitter emitter = new SseEmitter();
chatClient.stream(message)
.subscribe(
chunk -> {
try {
emitter.send(chunk.getContents());
} catch (IOException e) {
throw new RuntimeException(e);
}
},
emitter::completeWithError,
emitter::complete
);
return emitter;
}
4. 企业级应用实践
4.1 安全与权限控制
在金融等行业应用中,我们需要严格控制大模型的访问:
java复制@Configuration
class AiSecurityConfig {
@Bean
OpenAiChatClient secureChatClient(
OpenAiApi openAiApi,
@Value("${app.ai.access-role}") String requiredRole
) {
return new OpenAiChatClient(openAiApi) {
@Override
public ChatResponse call(Prompt prompt) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!auth.getAuthorities().contains(new SimpleGrantedAuthority(requiredRole))) {
throw new AccessDeniedException("AI access denied");
}
return super.call(prompt);
}
};
}
}
4.2 监控与可观测性
Spring AI天然支持Spring Micrometer,只需添加依赖:
xml复制<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
关键指标自动采集:
- ai_requests_count:请求次数
- ai_requests_duration:请求耗时
- ai_tokens_usage:token使用量
4.3 性能优化技巧
- 连接池配置:
yaml复制spring:
ai:
openai:
rest:
connect-timeout: 10s
read-timeout: 30s
max-connections: 100
- 批量处理:
java复制List<Prompt> prompts = ... // 多个提示词
List<String> responses = chatClient.batchCall(prompts);
- 本地模型缓存:
java复制@Bean
EmbeddingModel cachedEmbeddingModel() {
EmbeddingModel original = new AllMiniLmL6V2EmbeddingModel();
return new CachingEmbeddingModel(original, 10000); // 缓存10000个embedding
}
5. 常见问题与解决方案
5.1 依赖冲突问题
典型错误:
code复制Multiple HTTP clients have been found in the classpath
解决方案:
xml复制<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</exclusion>
</exclusions>
</dependency>
5.2 中文处理优化
默认配置可能对中文支持不够理想,可以通过以下方式改进:
- 调整tokenizer:
java复制@Bean
Tokenizer tokenizer() {
return new OpenAiTokenizer("gpt-3.5-turbo") {
@Override
public int count(String text) {
// 更准确的中文token计数
return text.length() / 2; // 近似估算
}
};
}
- 提示词中加入语言指定:
java复制String prompt = """
请始终使用中文回答,保持专业但易懂的风格。
问题:{question}
""";
5.3 成本控制策略
- 监控仪表盘配置:
java复制@Bean
MeterRegistryCustomizer<MeterRegistry> aiMetrics() {
return registry -> {
registry.config().meterFilter(
new MeterFilter() {
@Override
public DistributionStatisticConfig configure(
Meter.Id id,
DistributionStatisticConfig config
) {
if (id.getName().startsWith("ai_")) {
return DistributionStatisticConfig.builder()
.percentiles(0.5, 0.95)
.build()
.merge(config);
}
return config;
}
}
);
};
}
- 请求限流:
java复制@Bean
RateLimiter aiRateLimiter(
@Value("${app.ai.rate-limit:10}") int permitsPerSecond
) {
return RateLimiter.create(permitsPerSecond);
}
@Around("@annotation(aiRateLimited)")
public Object rateLimit(ProceedingJoinPoint pjp) {
if (aiRateLimiter.tryAcquire()) {
return pjp.proceed();
}
throw new RateLimitExceededException();
}
6. 项目实战:智能文档分析系统
让我们通过一个完整案例展示Spring AI在企业中的应用。这个系统能够:
- 解析上传的PDF/Word文档
- 建立向量索引
- 提供智能问答功能
6.1 系统架构
code复制[前端] -> [Spring Boot] -> [向量数据库]
| ^
v |
[大模型API] <- [文档处理]
6.2 核心实现代码
文档处理服务:
java复制@Service
public class DocumentService {
private final EmbeddingModel embeddingModel;
private final EmbeddingStore<TextSegment> embeddingStore;
public void processDocument(MultipartFile file) {
List<TextSegment> segments = PdfUtils.splitDocument(file);
List<Embedding> embeddings = embeddingModel.embedAll(segments).content();
embeddingStore.addAll(embeddings, segments);
}
}
问答服务:
java复制@Service
public class QaService {
public String answerQuestion(String question) {
Embedding queryEmbedding = embeddingModel.embed(question).content();
List<EmbeddingMatch<TextSegment>> relevant = embeddingStore
.findRelevant(queryEmbedding, 3);
String context = relevant.stream()
.map(match -> match.embedded().text())
.collect(joining("\n\n"));
Prompt prompt = new PromptTemplate("""
基于以下上下文回答问题,如果不知道就说不知道:
上下文:{context}
问题:{question}
""")
.create(Map.of(
"context", context,
"question", question
));
return chatClient.call(prompt.getContents());
}
}
6.3 性能优化实践
- 异步处理:
java复制@Async
public CompletableFuture<Void> asyncProcessDocument(MultipartFile file) {
// 文档处理逻辑
return CompletableFuture.completedFuture(null);
}
- 分级缓存:
java复制@Cacheable(value = "aiResponses", key = "#question.hashCode()")
public String getCachedAnswer(String question) {
// 正常问答逻辑
}
在实际项目中,这套架构帮助我们将文档处理效率提升了60%,同时通过缓存和异步处理将响应时间控制在2秒以内。
