【LangChain4j快速入門】5分鐘用Java玩轉GPT-4o-mini,Spring Boot整合實戰!
前言:當Java遇上大模型
在AI浪潮席卷全球的今天,Java開發者如何快速擁抱大語言模型?LangChain4j作為專為Java打造的AI開發框架,以極簡的API設計和強大的擴展能力,讓集成ChatGPT、GPT-4o-mini等模型變得異常輕松!本文將帶你通過實戰代碼+圖文詳解,5分鐘完成Spring Boot與GPT-4o-mini的對接,開啟你的AI應用開發之旅!
一、環境準備:閃電戰配置
1.1 添加關鍵依賴
在Spring Boot項目的pom.xml
中加入LangChain4j核心庫與OpenAI擴展:
<dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-open-ai</artifactId><version>1.0.0-beta3</version>
</dependency>
<dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j</artifactId><version>1.0.0-beta3</version>
</dependency>
1.2 申請密鑰(零門檻!)
- 正式環境:通過OpenAI平臺獲取API Key
- 嘗鮮體驗:直接使用官方Demo Key(配額有限,僅支持gpt-4o-mini)
// 配置類中直接使用demo密鑰
.baseUrl("http://langchain4j.dev/demo/openai/v1")
.apiKey("demo")
- ??如果你沒有API密鑰怎么辦?
如果你沒有自己的OpenAI API密鑰,別擔心。你可以臨時使用官方免費提供的演示密鑰,用于演示目的。請注意,當使用演示密鑰時,所有對OpenAI API的請求都需要通過官方的代理服務器,該代理會在將你的請求轉發給OpenAI API之前注入真實的密鑰。官方不會以任何方式收集或使用你的數據。演示密鑰有配額限制,僅限于gpt-4o-mini模型,并且只應用于演示目的。
OpenAiChatModel model = OpenAiChatModel.builder().baseUrl("http://langchain4j.dev/demo/openai/v1").apiKey("demo").modelName("gpt-4o-mini").build();
1.3配置application.yml
spring:application:name: AIai:openai:api-key: "demo"base-url: "http://langchain4j.dev/demo/openai/v1"
二、核心實現:3步構建AI聊天接口
2.1 模型配置(智能引擎)
@Configuration
public class LangChain4jConfig {@Beanpublic ChatLanguageModel chatLanguageModel() {return OpenAiChatModel.builder().baseUrl("http://langchain4j.dev/demo/openai/v1").apiKey("demo") // 替換為真實KEY時移除baseUrl.modelName("gpt-4o-mini") // 最新輕量級模型.build();}
}
關鍵點說明:
baseUrl
僅在使用Demo Key時需要modelName
指定模型版本,推薦性能優異的gpt-4o-mini
2.2 聊天控制器(對話大腦)
@RestController
@RequestMapping("/ai")
public class ChatController {private final ChatLanguageModel model;private final ChatMemory chatMemory; // 自動記憶上下文@GetMapping(value = "/chat", produces = "text/plain;charset=utf-8")public Mono<String> chat(@RequestParam String message) {UserMessage userMsg = UserMessage.from("你叫小智,是一個人工智能\n" + message);chatMemory.add(userMsg);AiMessage aiMsg = model.chat(chatMemory.messages()).aiMessage();chatMemory.add(aiMsg);return Mono.just(aiMsg.text());}
}
package org.example.ai.config;import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class CommonConfiguration {/*** 定義一個基于消息數量限制的 ChatMemory Bean*/@Beanpublic ChatMemory messageWindowChatMemory(ChatMemoryStore chatMemoryStore) {return MessageWindowChatMemory.builder().id("session-1") // 會話 ID.maxMessages(10) // 最大消息數量.chatMemoryStore(chatMemoryStore) // 持久化存儲.build();}/*** 定義一個簡單的內存存儲實現*/@Beanpublic ChatMemoryStore inMemoryChatMemoryStore() {return new InMemoryChatMemoryStore();}
}
亮點功能:
ChatMemory
自動維護對話上下文- 強制UTF-8編碼解決中文亂碼
- 響應式編程支持(Mono)
三、效果驗證:你的第一個AI接口
啟動應用后訪問:
http://localhost:8080/ai/chat?message=講個程序員笑話
預期響應:
好的,主人!為什么程序員總把萬圣節和圣誕節搞混?
因為 Oct 31 == Dec 25!(Octal 31 = Decimal 25)
加入前端代碼
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>小智AI助手</title><script src="https://unpkg.com/vue@3/dist/vue.global.js"></script><style>/* 現代聊天界面樣式 */:root {--primary: #4CAF50;--bg: #f5f5f5;--user-bg: #e3f2fd;--ai-bg: #ffffff;}body {margin: 0;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;background: var(--bg);}.chat-container {max-width: 800px;margin: 20px auto;border-radius: 12px;box-shadow: 0 2px 15px rgba(0,0,0,0.1);background: white;height: 90vh;display: flex;flex-direction: column;}.messages {flex: 1;overflow-y: auto;padding: 20px;display: flex;flex-direction: column;gap: 15px;}.message {max-width: 70%;padding: 12px 16px;border-radius: 18px;animation: fadeIn 0.3s ease;}.user-message {background: var(--user-bg);align-self: flex-end;border-bottom-right-radius: 4px;}.ai-message {background: var(--ai-bg);align-self: flex-start;border-bottom-left-radius: 4px;box-shadow: 0 2px 4px rgba(0,0,0,0.05);}.loading-dots {display: inline-block;font-size: 24px;}.loading-dots::after {content: '...';animation: dots 1.5s infinite;}.input-area {padding: 20px;border-top: 1px solid #eee;display: flex;gap: 10px;}input {flex: 1;padding: 12px;border: 1px solid #ddd;border-radius: 25px;font-size: 16px;outline: none;transition: 0.3s;}input:focus {border-color: var(--primary);box-shadow: 0 0 0 3px rgba(76,175,80,0.1);}button {padding: 12px 24px;background: var(--primary);border: none;border-radius: 25px;color: white;cursor: pointer;transition: 0.3s;}button:disabled {opacity: 0.7;cursor: not-allowed;}@keyframes dots {0%, 20% { content: '.'; }40% { content: '..'; }60%, 100% { content: '...'; }}@keyframes fadeIn {from { opacity: 0; transform: translateY(10px); }to { opacity: 1; transform: translateY(0); }}</style>
</head>
<body>
<div id="app"><div class="chat-container"><div class="messages"><div v-for="(msg, index) in messages":key="index":class="['message', msg.role === 'user' ? 'user-message' : 'ai-message']">{{ msg.content }}</div><div v-if="loading" class="message ai-message"><span class="loading-dots"></span></div></div><div class="input-area"><inputv-model="inputMessage"@keyup.enter="sendMessage"placeholder="和小智聊天吧~":disabled="loading"><button @click="sendMessage" :disabled="!inputMessage || loading">{{ loading ? '思考中' : '發送' }}</button></div></div>
</div><script>const { createApp } = Vue;createApp({data() {return {messages: [],inputMessage: '',loading: false}},methods: {async sendMessage() {if (!this.inputMessage.trim() || this.loading) return;const userMessage = this.inputMessage;this.messages.push({ role: 'user', content: userMessage });this.inputMessage = '';this.loading = true;try {const response = await fetch(`/ai/chat?message=${encodeURIComponent(userMessage)}`);const text = await response.text();this.messages.push({ role: 'assistant', content: text });} catch (error) {this.messages.push({role: 'assistant',content: '哎呀,小智暫時無法連接,請稍后再試~'});} finally {this.loading = false;this.scrollToBottom();}},scrollToBottom() {this.$nextTick(() => {const container = document.querySelector('.messages');container.scrollTop = container.scrollHeight;});}},mounted() {// 初始歡迎語this.messages.push({role: 'assistant',content: '你好!我是小智,有什么可以幫您的?'});}}).mount('#app');
</script>
</body>
</html>
完整代碼
package org.example.ai.config;import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class LangChain4jConfig {@Beanpublic ChatLanguageModel chatLanguageModel() {return OpenAiChatModel.builder().baseUrl("http://langchain4j.dev/demo/openai/v1").apiKey("demo").modelName("gpt-4o-mini").build();}
}
package org.example.ai.config;import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class CommonConfiguration {/*** 定義一個基于消息數量限制的 ChatMemory Bean*/@Beanpublic ChatMemory messageWindowChatMemory(ChatMemoryStore chatMemoryStore) {return MessageWindowChatMemory.builder().id("session-1") // 會話 ID.maxMessages(10) // 最大消息數量.chatMemoryStore(chatMemoryStore) // 持久化存儲.build();}/*** 定義一個簡單的內存存儲實現*/@Beanpublic ChatMemoryStore inMemoryChatMemoryStore() {return new InMemoryChatMemoryStore();}
}
package org.example.ai.controller;import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;@RestController
@RequestMapping("/ai")
@RequiredArgsConstructor
public class ChatController {private final ChatLanguageModel chatLanguageModel;private final ChatMemory chatMemory;@RequestMapping (value = "/chat", produces = "text/plain;charset=utf-8")public Mono<String> chat(@RequestParam(required = false, defaultValue = "") String message) {UserMessage userMessage = UserMessage.from("你叫小智,是一個人工智能\n" + message);chatMemory.add(userMessage);AiMessage aiMessage = chatLanguageModel.chat(chatMemory.messages()).aiMessage();chatMemory.add(aiMessage);return Mono.just(aiMessage.text());}
}
四、生產級優化建議
- 密鑰安全:通過
application.yml
配置,避免硬編碼langchain4j:openai:api-key: ${OPENAI_API_KEY}
- 限流降級:集成Resilience4j實現請求限流
- 性能監控:通過Micrometer對接Prometheus
- 上下文管理:使用
PersistentChatMemory
實現對話持久化
總結:為什么選擇LangChain4j?
通過本文實戰,我們體驗到了:
? 極簡集成:5行代碼對接GPT-4o-mini
? 開箱即用:自動記憶管理、流式響應支持
? 生態豐富:支持20+模型廠商,輕松切換
? Spring Boot友好:自動配置+依賴注入
下一步探索:
- 嘗試AI服務(Assistant API)實現復雜邏輯
- 結合Embedding實現RAG知識庫
- 使用Tools API讓模型調用外部服務
立即訪問LangChain4j官網開啟你的AI應用開發之旅!如果你在實踐過程中遇到任何問題,歡迎在評論區留言交流~