作为一名长期奋战在Java开发一线的工程师,我最近半年深度参与了公司AI大模型应用的落地实践。从最初的迷茫摸索到现在的游刃有余,我想把这段实战经验完整记录下来,帮助更多Java开发者快速掌握LLM应用开发的核心技能。
在当前的AI浪潮中,大语言模型正在重塑软件开发的范式。根据2024年Stack Overflow开发者调查报告,已有67%的企业在业务中集成LLM能力,而Java作为企业级开发的主力语言,与大模型的结合显得尤为重要。
我们团队在实际开发中发现,LLM能为Java应用带来三大核心价值:
对于Java开发者来说,Spring AI是目前最成熟的LLM开发框架,相比Python系的LangChain,它具有以下独特优势:
| 对比维度 | Spring AI | LangChain |
|---|---|---|
| 语言生态 | 深度集成Spring生态 | Python技术栈 |
| 开发效率 | 注解驱动开发 | 需要编写更多胶水代码 |
| 企业适配 | 完善的微服务支持 | 更适合研究场景 |
| 性能表现 | JVM优化后的高吞吐 | 解释型语言性能局限 |
首先需要在项目中引入Spring AI依赖:
xml复制<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
<version>0.8.1</version>
</dependency>
配置文件示例(application.yml):
yaml复制spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: deepseek-r1:7b
temperature: 0.7
max-tokens: 1024
关键参数说明:
- temperature:控制生成随机性(0-1)
- max-tokens:限制单次响应长度
- top-p:核采样概率阈值
多轮对话的核心是上下文记忆管理。Spring AI提供了三种存储方案:
以下是带记忆功能的ChatClient配置:
java复制@Bean
public ChatClient chatClient(ChatModel chatModel) {
return ChatClient.builder(chatModel)
.defaultSystem("你是一个专业的Java技术顾问")
.defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory()))
.build();
}
@Bean
public ChatMemory chatMemory() {
return new InMemoryChatMemory();
}
对于长时间对话,流式响应能显著提升用户体验:
java复制@GetMapping("/chat/stream")
public SseEmitter chatStream(@RequestParam String message) {
SseEmitter emitter = new SseEmitter();
chatClient.prompt()
.user(message)
.stream()
.subscribe(
content -> emitter.send(content),
error -> emitter.completeWithError(error),
() -> emitter.complete()
);
return emitter;
}
通过Function Calling可以让LLM动态调用外部API。以下是百度搜索服务的完整实现:
java复制@Tool(name="baiduSearch", description="使用百度进行网页搜索")
public class BaiduSearchService implements Function<SearchRequest, SearchResponse> {
private final WebClient webClient;
public BaiduSearchService() {
this.webClient = WebClient.builder()
.defaultHeader("User-Agent", "Mozilla/5.0")
.build();
}
@Override
public SearchResponse apply(SearchRequest request) {
String html = webClient.get()
.uri("https://www.baidu.com/s?wd=" + request.query())
.retrieve()
.bodyToMono(String.class)
.block();
return parseHtml(html);
}
private SearchResponse parseHtml(String html) {
// 使用Jsoup解析HTML...
}
public record SearchRequest(
@JsonProperty(required=true) String query,
@JsonProperty(defaultValue="10") int limit) {}
public record SearchResponse(List<Result> results) {}
}
在ChatClient中注册功能工具:
java复制@Bean
public ChatClient toolChatClient(
ChatModel chatModel,
BaiduSearchService searchService) {
return ChatClient.builder(chatModel)
.defaultTools(searchService)
.build();
}
当用户提问"最近有什么AI新闻"时,LLM会自动:
我们对比了主流向量数据库的Java支持:
| 数据库 | Java客户端 | 性能 | 易用性 |
|---|---|---|---|
| Redis | Jedis | ★★★★ | ★★★★ |
| Milvus | Java SDK | ★★★ | ★★★ |
| Pinecone | HTTP API | ★★ | ★★★★ |
最终选择RedisVectorStore作为存储方案:
java复制@Bean
public VectorStore vectorStore(
EmbeddingModel embeddingModel,
JedisConnectionFactory jedisConn) {
return RedisVectorStore.builder()
.withConnectionFactory(jedisConn)
.withEmbeddingModel(embeddingModel)
.build();
}
完整的RAG数据处理流程:
java复制public void ingestDocument(Resource resource) {
// 1. 文档解析
List<Document> docs = pdfReader.read(resource);
// 2. 文本分割
List<Document> chunks = textSplitter.split(docs);
// 3. 向量化存储
vectorStore.add(chunks);
}
使用Tika处理多种文档格式:
xml复制<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>
实现知识问答的核心逻辑:
java复制public String answerQuestion(String question) {
// 1. 向量检索
List<Document> docs = vectorStore.similaritySearch(question);
// 2. 构建Prompt
String context = docs.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n\n"));
Prompt prompt = new Prompt(
"基于以下上下文回答问题:\n" + context + "\n\n问题:" + question);
// 3. 调用LLM生成
return chatClient.prompt(prompt).call().content();
}
java复制vectorStore.add(documents); // 优于循环add
java复制@Cacheable("qa-cache")
public String getAnswer(String question) {
// RAG处理逻辑
}
java复制@Async
public void asyncIngest(Resource resource) {
// 文档处理逻辑
}
问题1:响应时间过长
问题2:回答质量不稳定
问题3:内存泄漏
对于专业领域应用,可以使用LoRA进行轻量级微调:
java复制LoraConfig config = new LoraConfig()
.r(8)
.alpha(16)
.dropout(0.05);
FineTuningJob job = ollamaAdapter.fineTune()
.baseModel("deepseek-r1:7b")
.trainingData(trainDataset)
.loraConfig(config)
.start();
实现自主Agent的示例架构:
java复制@Bean
public Agent myTechAgent(
ChatModel chatModel,
BaiduSearchService search,
JiraService jira) {
return Agent.builder()
.tools(search, jira)
.memory(new RedisChatMemory())
.executor(new ParallelTaskExecutor())
.build();
}
在实际项目中,我们通过Agent系统实现了:
经过半年的实践验证,这套基于Spring AI的技术栈已经支撑了我们公司三个核心业务的智能化改造。从最初的简单问答到现在复杂的业务流程自动化,LLM确实为Java开发带来了全新的可能性。