系統整體架構設計
基于 LangChain4j 框架構建的智能對話系統采用 "前后端分離 + 大模型中樞" 的三層架構設計,實現了與豆包類似的智能交互體驗。系統架構圖如下所示:
┌──────────────────────────────────────────────────────────┐
│ 前端展示層 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 對話界面 │ │ 輸入組件 │ │ 歷史記錄 │ │ 用戶操作 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
├──────────────────────────────────────────────────────────┤
│ 通信與協議層 │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ SSSE │ │ REST API │ │ 消息格式 │ │
│ └────────────┘ └────────────┘ └────────────┘ │
├──────────────────────────────────────────────────────────┤
│ 后端邏輯層 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 模型調用 │ │ 上下文 │ │ 提示工程 │ │ 檢索增強 │ │
│ │ (LLM) │ │ 管理 │ │ 模塊 │ │ (RAG) │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
├──────────────────────────────────────────────────────────┤
│ 數據持久層 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 對話歷史 │ │ 向量存儲 │ │ 知識庫 │ │ 用戶信息 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
└──────────────────────────────────────────────────────────┘
圖 1:LangChain4j 智能對話系統架構圖
該架構的核心優勢在于:
- 前后端解耦:前端采用 Vue3 構建交互界面,后端基于 LangChain4j 處理 AI 邏輯,分工明確
- 大模型能力封裝:通過 LangChain4j 標準化接口,屏蔽不同 LLM 提供商的差異
- 企業級擴展:支持集群部署、負載均衡和數據持久化,滿足高并發場景
前端功能模塊詳解
1. 對話界面模塊
前端界面采用 Vue3 實現,模仿豆包的 UI 設計風格,主要包含三大區域:
頂部導航區,中部對話區以及底部輸入區。
<template><!-- 整體容器 --><div class="doubao-layout"><!-- 1. 頂部導航區 --><header class="doubao-header"><div class="header-inner"><!-- 標題與新對話 --><div class="left-group "><el-button type="primary" icon="Plus" size="mini" class="mr-4" @click="handleNewChat">新對話</el-button><h2 class="header-title">{{ chatTitle }}</h2></div><!-- 操作與頭像 --><div class="right-group"><el-icon @click="handleShare"><Share /></el-icon><el-icon @click="handleFavorite"><Star /></el-icon><el-avatar size="medium"src="https://img0.baidu.com/it/u=2648433959,1760892301&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500"class="cursor-pointer" @click="handleUserCenter" /></div></div></header><!-- 2. 對話內容區 --><div class="chat-container"><!-- 對話內容區 --><section class="doubao-chat" ref="chatContainer"><div class="chat-inner"><!-- 對話歷史列表 --><div v-for="(msg, index) in chatHistory" :key="index" class="message-container"><!-- 用戶消息 - 居右對齊 --><div v-if="msg.isUser" class="user-message"><div class="message-bubble"><div style="display: flex;align-items: center;" class="message-content"><p style="text-align: left;margin-right: 7px;" class="message-text">{{ msg.content}}</p><el-avatar size="medium"src="https://img0.baidu.com/it/u=2648433959,1760892301&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500"class="avatar-fixed" @click="handleUserCenter" /></div></div></div><!-- AI消息 - 居左對齊 --><div v-else class="ai-message"><div class="message-bubble"><div style="display: flex;align-items: center;" class="message-content"><el-avatar size="medium" src="/doubao.png" @click="handleUserCenter"class="avatar-fixed" /><p style="text-align: left;margin-left: 7px;" class="message-text">{{ msg.content }}</p></div></div></div></div></div></section></div><!-- 3. 輸入對話框 --><footer class="doubao-input"><div class="input-inner"><el-input v-model="prompt" class="input-main" placeholder="請輸入內容..." clearable@keyup.enter="sendMessage" /><el-button type="primary" icon="Search" size="mini" class="ml-2" @click="sendMessage"style="margin-left: 10px;">發送</el-button></div></footer></div>
</template>
核心交互邏輯:
- 自動滾動:通過監聽
chatHistory
變化,使用scrollTop = scrollHeight
實現新消息自動定位 - 對話標題:根據歷史記錄動態更新標題,使用
computed
屬性實現響應式 - 用戶操作:集成分享(復制鏈接)、收藏(引導快捷鍵)、新建對話等功能
2. 狀態管理模塊
采用組合式 API 管理對話狀態,核心代碼如下:
import { ref, computed, watch } from 'vue';
import { useRoute } from 'vue-router';
import { ElMessage } from 'element-plus';// 對話狀態
const chatHistory = ref([]);
const prompt = ref('');
const isLoading = ref(false);
const currentAIResponse = ref('');// 動態標題
const route = useRoute();
const chatTitle = computed(() => {if (chatHistory.value.length > 1) {const firstUserMsg = chatHistory.value.find(msg => msg.isUser);return firstUserMsg?.content || '新對話';}return '新對話';
});// 自動滾動
const chatContainer = ref(null);
const scrollToBottom = () => {if (chatContainer.value) {chatContainer.value.scrollTop = chatContainer.value.scrollHeight;}
};
watch(chatHistory, () => nextTick(scrollToBottom));
3. 主要功能展示
創建新對話:
對話詳情:
后端核心功能實現
后端基于 LangChain4j 框架構建,核心功能模塊包括:
配置文件:
server:port: 9000servlet:encoding:charset: UTF-8enabled: trueforce: true# openai相關配置
openai:apiKey: #替換成自己的apiKeymodel: gpt-4o-minibaseUrl: https://api.chatanywhere.tech/v1/temperature: 0.7# 單條對話最多存儲多少條對話歷史記錄maxMessages: 100spring:application:name: llm_appdatasource:druid:url: jdbc:mysql://localhost:3306/llm_app?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=trueusername: # 數據庫用戶名password: # 數據庫密碼 不存儲到數據庫就不需要driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourcedata:redis:password: # 你的redis密碼 如果設置了database: 1host: localhostport: 6379timeout: 5000
1. 大模型交互模塊
通過LLMConfig進行統一配置,統一管理大模型調用,支持多模型切換:
package com.example.config;import com.example.entity.ChatLLM;
import com.example.service.*;
import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.memory.chat.TokenWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.model.openai.OpenAiTokenCountEstimator;
import dev.langchain4j.service.AiServices;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @Author: znly* @Description:* @Date: 2025/7/2 9:08*/
@Configuration
public class LLMConfig {@Autowiredprivate ApplicationContext context;@Resourceprivate RedisChatMemoryStore redisChatMemoryStore;@Autowiredprivate OpenAIProperties openAIProperties;@Beanpublic ChatModel chatModel() {return OpenAiChatModel.builder().modelName(openAIProperties.getModel()).baseUrl(openAIProperties.getBaseUrl()).apiKey(openAIProperties.getApiKey()).temperature(openAIProperties.getTemperature()).build();}/*** 創建一個流式模型** @return*/@Beanpublic StreamingChatModel streamingChatModel() {return OpenAiStreamingChatModel.builder().modelName(openAIProperties.getModel()).baseUrl(openAIProperties.getBaseUrl()).apiKey(openAIProperties.getApiKey()).temperature(openAIProperties.getTemperature()).maxTokens(openAIProperties.getMaxTokens()).build();}@Beanpublic ChatLLMService chatLLMService(StreamingChatModel streamingChatModel) {return AiServices.builder(ChatLLMService.class).streamingChatModel(streamingChatModel).chatMemoryProvider(memoryId -> {return MessageWindowChatMemory.withMaxMessages(10);}).build();}@Bean(name = "chatMessageWindowChatMemory")public ChatMemoryAssistant chatMessageWindowChatMemory(ChatModel chatModel) {return AiServices.builder(ChatMemoryAssistant.class).chatModel(chatModel).chatMemoryProvider(memoryId -> {return MessageWindowChatMemory.withMaxMessages(10);}).build();}@Bean(name = "chatTokenWindowChatMemory")public ChatMemoryAssistant chatTokenWindowChatMemory(ChatModel chatModel) {return AiServices.builder(ChatMemoryAssistant.class).chatModel(chatModel).chatMemoryProvider(memoryId -> {return TokenWindowChatMemory.withMaxTokens(1000, new OpenAiTokenCountEstimator("gpt-4o-mini"));}).build();}@Bean(name = "chatRedisChatMemory")public ChatMemoryAssistant chatRedisChatMemory(ChatModel chatModel) {ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder().id(memoryId).maxMessages(10).chatMemoryStore(redisChatMemoryStore).build();return AiServices.builder(ChatMemoryAssistant.class).chatModel(chatModel).chatMemoryProvider(chatMemoryProvider).build();}@Bean(name = "chatExternal")public ChatLLMServiceSimple chatLLMServiceExternal(ChatModel chatModel) {return AiServices.builder(ChatLLMServiceSimple.class).chatModel(chatModel).tools(new WeatherService()).build();}@Bean(name = "chatLLM")public ChatMemoryAssistant chatLLM(ChatModel chatModel) {ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder().id(memoryId).maxMessages(10).chatMemoryStore(redisChatMemoryStore).build();return AiServices.builder(ChatMemoryAssistant.class).chatModel(chatModel).chatMemoryProvider(chatMemoryProvider).tools(new ExternalService()).build();}@Bean(name = "chatLLMStream")public ChatMemoryAssistant chatLLMStream(StreamingChatModel streamingChatModel) {ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder().id(memoryId).maxMessages(openAIProperties.getMaxMessages()).chatMemoryStore(redisChatMemoryStore).build();return AiServices.builder(ChatMemoryAssistant.class).streamingChatModel(streamingChatModel).chatMemoryProvider(chatMemoryProvider).tools(new ExternalService()).build();}}
2. 上下文管理模塊
實現對話歷史的存儲與檢索,支持會話級和用戶級上下文:
本系統通過redis實現臨時存儲,不存儲至數據庫,可以在配置文件中中對存儲上限進行動態修改。
@Bean(name = "chatLLMStream")public ChatMemoryAssistant chatLLMStream(StreamingChatModel streamingChatModel) {ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder().id(memoryId).maxMessages(openAIProperties.getMaxMessages()).chatMemoryStore(redisChatMemoryStore).build();return AiServices.builder(ChatMemoryAssistant.class).streamingChatModel(streamingChatModel).chatMemoryProvider(chatMemoryProvider).tools(new ExternalService()).build();}
3. 提示工程模塊
封裝提示詞模板與解析邏輯,提升大模型輸出質量:
例如,可以利用@SystemMessage來定義你的提示詞,確保大模型只回復相關領域的知識內容。
package com.example.service;import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import reactor.core.publisher.Flux;/*** @Author: znly* @Description:* @Date: 2025/7/3 10:43*/
public interface ChatMemoryAssistant {/*** 帶記憶緩存的對話* @param userId* @param prompt* @return*/
@SystemMessage("你是一位本科和研究生均畢業于北京大學的專業后端開發工程師,擁有十年大廠后端開發工作經驗,你的主要編程語言是java和python。" +
"你只能回答你的業務領域內的問題,如果問題涉及到其他領域請回復不知道")String chat(@MemoryId String memoryId, @UserMessage String prompt);Flux<String> chatStream(@MemoryId String memoryId, @UserMessage String prompt);}
4. 函數調用
針對大模型對于相關城市天氣,當天時間等需要聯網查詢,或者是用戶自己相關的知識,可以通過@Tool這個注解來實現函數調用。
例如:針對天氣和時間問題,會調用以下兩個函數來執行,大模型不會直接回答。
package com.example.service;import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import org.springframework.stereotype.Service;import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;/*** @Author: znly* @Description: 外部服務類* @Date: 2025/7/3 22:18*/
@Service
public class ExternalService {@Tool(value = "今天天氣怎么樣")public String getWeather(@P("城市") String city) {System.out.println("城市:" + city);//調用外部 服務return "今天" + city + "的天氣是晴天";}@Tool(value = "今天日期是多少")public String getDate() {System.out.println("今天日期" + LocalDate.now().toString());return LocalDate.now().toString();}@Tool(value = "告訴我現在的北京時間")public String getTime() {// 獲取當前時間LocalDateTime now = LocalDateTime.now();// 定義日期時間格式DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");// 格式化時間String formattedDateTime = now.format(formatter);// 輸出格式化后的時間System.out.println("當前時間: " + formattedDateTime);return "當前時間是:" + formattedDateTime;}
}
5. 檢索增強生成 (RAG) 模塊
結合向量檢索與大模型生成,提升專業領域回答準確性:
// 文檔加載與處理
DocumentLoader loader = new FileSystemDocumentLoader("knowledge-base");
DocumentParser parser = new MarkdownDocumentParser();
TextSplitter splitter = new RecursiveCharacterTextSplitter(RecursiveCharacterTextSplitterConfig.builder().chunkSize(800).chunkOverlap(100).build()
);
List<Document> documents = splitter.split(parser.parse(loader.load()));// 向量存儲
EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder().apiKey(API_KEY).build();
EmbeddingStore embeddingStore = PineconeEmbeddingStore.builder().apiKey(PINECONE_KEY).environment("us-west1-gcp").indexName("knowledge-index").build();
embeddingStore.storeDocuments(documents, embeddingModel);// RAG服務
Rag rag = Rag.builder().embeddingModel(embeddingModel).embeddingStore(embeddingStore).documentLoader(loader).textSplitter(splitter).build();// 生成回答
String userQuery = "如何配置LangChain4j的RAG模塊?";
List<Document> relevantDocs = rag.relatedDocuments(userQuery, 3);
String response = rag.chain().promptTemplate(PromptTemplate.builder().template("根據以下文檔回答用戶問題:\n{documents}\n用戶問題:{userQuery}\n回答:").build()).languageModel(model).build().invoke(Map.of("documents", relevantDocs, "userQuery", userQuery));
技術亮點與創新點
1. 多模態對話增強
在標準文本對話基礎上,擴展支持:
- 富文本處理:解析 Markdown 格式輸出,支持加粗、列表等樣式
- 代碼塊處理:自動識別代碼塊并高亮顯示,提升技術對話體驗
- 數學公式支持:通過 KaTeX 渲染 LaTeX 公式,滿足學術交流需求
2. 智能對話控制
實現多種對話策略:
- 追問策略:當用戶問題不明確時,自動生成追問提示(如 "你能具體說明一下嗎?")
- 多輪上下文:智能截斷過長對話歷史,保留關鍵信息(基于令牌數統計)
- 敏感詞過濾:集成內容安全模塊,自動識別并處理敏感信息
3. 企業級能力集成
與企業系統深度整合:
- OA 系統集成:對接企業 OA 系統,自動提取日程、審批等信息
- CRM 集成:根據客戶歷史訂單生成個性化推薦
- 知識庫對接:連接企業內部知識庫,提供專業領域支持
應用場景與典型案例
1. 企業智能客服
某電商平臺集成該系統后,實現:
- 85% 的常見問題自動解答,減少客服人力成本
- 基于購買歷史的個性化推薦,提升轉化率 15%
- 多輪對話上下文保持,客戶滿意度提升 20%
2. 技術支持助手
為軟件開發團隊提供:
- 代碼問題解答(基于官方文檔和項目代碼庫)
- 錯誤日志分析與解決方案推薦
- 技術選型建議(如 "Spring Boot 與 Quarkus 如何選擇")
3. 學術研究助手
服務科研人員:
- 文獻摘要生成與關鍵信息提取
- 實驗方案設計建議
- 論文寫作輔助(語法檢查、引用建議)
總結與未來規劃
基于 LangChain4j 構建的智能對話系統,充分發揮了 Java 的企業級優勢和 LangChain4j 的大模型集成能力,在功能完整性、性能表現和可擴展性方面均達到生產級水平。系統不僅實現了豆包的核心對話功能,還通過 RAG 技術、多模態支持和企業級集成,拓展了智能對話的應用邊界。
未來規劃包括:
- 多模態增強:支持語音、圖像輸入輸出,實現更自然的交互
- 聯邦學習集成:保護企業數據隱私,支持跨機構協作
- 邊緣計算優化:針對邊緣設備進行模型輕量化和推理優化
- 低代碼平臺:提供可視化流程編排工具,降低使用門檻
該系統的成功實踐證明,Java 與 LangChain4j 的組合不僅適用于企業級大模型應用開發,還能在用戶體驗、性能優化和系統集成方面超越傳統 Python 方案,為智能對話技術的工業化落地提供了新的技術路徑。