🌟 在這系列文章中,我們將一起探索如何搭建一個支持大模型集成項目 NexLM 的開發過程,從 架構設計 到 代碼實戰,逐步搭建一個支持 多種大模型(GPT-4、DeepSeek 等) 的 一站式大模型集成與管理平臺,并集成 認證中心、微服務、流式對話 等核心功能。
🔍 從架構設計到代碼實現,一起探討如何應對不同技術挑戰,最終打造出高效、可擴展的大模型平臺,目前項目基礎架構已經搭建完成。
系列目錄規劃:
- NexLM:從零開始打造你的專屬大模型集成平臺 ?
- Spring Boot + OpenAI/DeepSeek:如何封裝多個大模型 API 調用 ?
- 微服務 + 認證中心:如何保障大模型 API 的安全調用
- 支持流式對話 SSE & WebSocket:讓 AI 互動更絲滑
- 緩存與性能優化:提高 LLM API 響應速度
- NexLM 開源部署指南(Docker)
第二篇:Spring Boot + OpenAI/DeepSeek:如何封裝多個大模型 API 調用
🎯 如何讓你的項目支持 OpenAI、DeepSeek、本地大模型等多種 LLM?
🎯 如何封裝 API,做到擴展性強、調用方便?
🎯 這篇文章帶你一步步搭建通用 LLM 調用服務!
為什么要封裝 LLM API?
在大模型開發中,我們往往需要 支持多個模型,例如:
- GPT-4(OpenAI) :行業最強模型之一,但 API 價格較貴
- DeepSeek:性價比高,部分場景效果接近 GPT-4
- 本地大模型(如 ChatGLM) :適合私有化部署,數據安全
如果在代碼里直接寫多個 API 請求,會導致 代碼冗余、擴展性差。我們需要一個 統一封裝的 LLM API 調用層,讓項目可以隨時切換模型,甚至同時支持多個模型。
效果展示
DeepSeek API 調用交互稍微有點點耗時…目前還沒有支持流式輸出效果(下一期優化),代碼倉庫地址:https://github.com/pitt1997/NexLM
代碼實現
實現簡單的 AI 接口調用還是比較簡單,定義接口和具體接口的調用邏輯即可,下面是代碼演示。
1)Controller 層
ChatController 定義一個頁面的路由地址
@RestController
public class ChatController {/*** chat頁面*/@GetMapping("/auth/chat")public ModelAndView chat(ModelAndView modelAndView) {modelAndView.setViewName("ftl/chat");return modelAndView;}
}
ChatApiController 定義一個 API 交互接口。
@RestController
@RequestMapping("/api/ai")
public class ChatApiController {@Autowiredprivate ChatService chatService;@Autowiredprivate JwtTokenProvider jwtTokenProvider;@PostMapping("/chat")public ResponseEntity<String> chat(@RequestBody ChatRequest request, @RequestHeader("Authorization") String token) {// TODO 測試放行(后續加上JWT票據認證)if (token.startsWith("Bearer ")) {return ResponseEntity.ok(chatService.callAIModel(request.getMessage(), request.getModelType()));}// 認證中心解析 JWT 驗證權限SessionUser sessionUser = jwtTokenProvider.validateUserToken(token);if (sessionUser == null) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized");}return ResponseEntity.ok(chatService.callAIModel(request.getMessage(), request.getModelType()));}
}
2)VO 層
請求對象,主要定義輸入的消息和模型的類型。
@Data
public class ChatRequest {private String message; // 用戶輸入的消息private String modelType; // 選擇的大模型,例如 "chatgpt" 或 "local"
}
3)Service 層
這里封裝不同模型的調用實現。
@Service
public class ChatService {@Autowiredprivate OpenAIClient openAIClient;@Autowiredprivate DeepSeekClient deepSeekClient;@Autowiredprivate LocalLLMClient localLLMClient;public String callAIModel(String prompt, String modelType) {if ("chatgpt".equalsIgnoreCase(modelType)) {return openAIClient.chat(prompt);} else if ("deepseek".equalsIgnoreCase(modelType)) {return deepSeekClient.chat(prompt);} else if ("local".equalsIgnoreCase(modelType)) {return localLLMClient.chat(prompt);}return "Invalid Model Type";}
}
4)調用大模型接口 API
實現具體大模型的 API 調用邏輯。以 DeepSeek 為例,注意 DeepSeek 需要提前在官網注冊密鑰。(注:按照官網要求的請求參數格式進行請求即可,注意需要正確解析返回結果中的內容)。
@Component
public class DeepSeekClient {private static final String API_URL = "https://api.deepseek.com/chat/completions"; // DeepSeek API 地址private static final String API_KEY = "你的 DeepSeek API Key"; // 替換為你的 API Keyprivate static final String MODEL = "deepseek-chat"; // deepseek-v3 / deepseek-r1public String chat(String prompt) {RestTemplate restTemplate = new RestTemplate();HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);headers.add("Authorization", "Bearer " + API_KEY);Map<String, Object> body = new HashMap<>();body.put("model", MODEL); // deepseek-v3 / deepseek-r1body.put("temperature", 0.7); // 可調整溫度body.put("max_tokens", 2048); // 控制回復長度List<Map<String, String>> messages = Arrays.asList(new HashMap<String, String>() {{put("role", "user");put("content", prompt);}});body.put("messages", messages);HttpEntity<Map<String, Object>> request = new HttpEntity<>(body, headers);ResponseEntity<String> response = restTemplate.exchange(API_URL, HttpMethod.POST, request, String.class);return extractContent(response.getBody());}// 解析一下大模型返回結果的json參數。private String extractContent(String responseBody) {try {ObjectMapper objectMapper = new ObjectMapper();JsonNode root = objectMapper.readTree(responseBody);return root.path("choices").get(0).path("message").path("content").asText();} catch (Exception e) {e.printStackTrace();return "Error parsing response";}}
}
OpenAI 調用邏輯基本一致。
@Component
public class OpenAIClient {private static final String API_URL = "https://api.openai.com/v1/chat/completions";private static final String API_KEY = "你的 OpenAI API Key"; // 請替換為你的 API Keypublic String chat(String prompt) {RestTemplate restTemplate = new RestTemplate();HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);headers.add("Authorization", "Bearer " + API_KEY);Map<String, Object> body = new HashMap<>();body.put("model", "gpt-4");List<Map<String, String>> messages = Arrays.asList(new HashMap<String, String>() {{put("role", "user");put("content", prompt);}});body.put("messages", messages);HttpEntity<Map<String, Object>> request = new HttpEntity<>(body, headers);ResponseEntity<String> response = restTemplate.exchange(API_URL, HttpMethod.POST, request, String.class);return response.getBody();}
}
5)調用本地模型
也可以調用本地部署的大模型(需要提前部署本地大模型,可以看我之前的文章部署方法)。
@Component
public class LocalLLMClient {private static final String LOCAL_MODEL_URL = "http://localhost:5000/api/chat";public String chat(String prompt) {RestTemplate restTemplate = new RestTemplate();Map<String, String> requestBody = new HashMap<>();requestBody.put("prompt", prompt);ResponseEntity<String> response = restTemplate.postForEntity(LOCAL_MODEL_URL, requestBody, String.class);return response.getBody();}
}
3. 前端頁面(HTML + JavaScript)
一個簡單的 HTML 頁面,輸入問題后,調用后端 API 獲取大模型的回答(暫時使用 HTML 做一個演示)。
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>AI 聊天</title><style>body {font-family: Arial, sans-serif;background: #f4f4f4;margin: 0;padding: 0;display: flex;justify-content: center;align-items: center;height: 100vh;}.chat-container {width: 500px;background: #fff;padding: 20px;border-radius: 10px;box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);}h1 {text-align: center;color: #333;}.input-group {margin: 15px 0;}input, select, button {width: 100%;padding: 10px;margin-top: 5px;border: 1px solid #ccc;border-radius: 5px;}button {background: #007bff;color: white;cursor: pointer;}button:hover {background: #0056b3;}.response {margin-top: 20px;background: #eef;padding: 10px;border-radius: 5px;min-height: 50px;}</style>
</head>
<body>
<div class="chat-container"><h1>大模型 AI 聊天</h1><div class="input-group"><label>輸入你的問題:</label><input type="text" id="message" placeholder="請輸入問題"></div><div class="input-group"><label>選擇模型:</label><select id="modelType"><option value="chatgpt">ChatGPT</option><option value="deepseek">DeepSeek</option><option value="local">本地模型</option></select></div><button onclick="sendMessage()">發送</button><div class="response" id="response">AI 回復將在這里顯示...</div>
</div><script>async function sendMessage() {const message = document.getElementById('message').value;const modelType = document.getElementById('modelType').value;// 你的 JWT 令牌const token = getCookie('JSESSIONID'); // 這里應從登錄系統獲取console.log('JWT Token:', token); // 打印 token 值const response = await fetch('/web/api/ai/chat', {method: 'POST',headers: {'Content-Type': 'application/json','Authorization': `Bearer B6FC7391D7856A16391F9860DA5DA3B8}`},body: JSON.stringify({ message, modelType })});const text = await response.text();document.getElementById('response').innerText = text;}function getCookie(name) {const cookies = document.cookie.split(';');for (let cookie of cookies) {const [cookieName, cookieValue] = cookie.trim().split('=');if (cookieName === name) {return decodeURIComponent(cookieValue);}}return null;}
</script>
</body>
</html>
4. 認證中心(JWT 解析示例)
接口調用時應當校驗當前用戶的票據(登錄時會存儲用戶會話票據信息)。
// 認證中心解析 JWT 驗證權限SessionUser sessionUser = jwtTokenProvider.validateUserToken(token);if (sessionUser == null) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized");}
5. 效果測試
🔥 現在,你的 AI 聊天前后端已完成!
- 直接訪問登錄
http://localhost:8080/web/auth/login
頁面 - 輸出用戶名/密碼:admin/123456
- 跳轉大模型頁面,選擇對應大模型,開始對話
6. 總結
- 架構:微服務 + 認證中心 + API 網關 + 本地/遠程大模型
- Java 代碼:完整的 Controller、Service、API 調用示例
- 前端:簡單 HTML + JS 渲染
- 認證:JWT 校驗
這樣,你的系統可以支持用戶認證,并調用本地或第三方大模型進行 AI 交互。
結語
本篇文章,我們介紹了 如何封裝多個 LLM(大模型) API 調用 。
但是,目前的 對話是一次性返回的,后續我們將完善 微服務 + 認證中心:如何保障大模型 API 的安全調用, 并且支持流式對話(SSE)增加 WebSocket 實時消息實現 實時輸出 AI 回復!敬請期待!
📌 下一章預告:SSE + WebSocket 實現流式對話!
📢 你對這個項目感興趣嗎?歡迎 Star & 關注! 📌 GitHub 項目地址