下面为你提供一个基于JBoltAI框架的完整实操案例,帮助你理解如何在Java生态中快速构建大模型应用。这个案例将展示如何利用JBoltAI实现一个智能客服系统,包括需求分析、环境搭建、代码实现和部署测试等环节。
基于JBoltAI的智能客服系统实现
1. 需求分析与方案设计
我们要构建一个面向电商平台的智能客服系统,具备以下功能:
- 自动回答常见问题(如订单查询、物流追踪、退换货政策)
- 识别用户意图并提供精准回答
- 支持多轮对话上下文理解
- 复杂问题自动转接人工客服
系统架构设计:
- 前端:HTML+JavaScript界面
- 后端:Spring Boot + JBoltAI框架
- 知识库:采用向量数据库存储常见问题和答案
- 大模型:集成文心一言或通义千问(可根据需要切换)
2. 环境搭建
首先,创建一个新的Spring Boot项目,添加JBoltAI依赖。在pom.xml
中添加以下内容:
<dependencies>
<!-- Spring Boot 基础依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- JBoltAI 核心依赖 -->
<dependency>
<groupId>com.jbolt</groupId>
<artifactId>jbolt-ai-spring-boot-starter</artifactId>
<version>2.0.5</version>
</dependency>
<!-- 向量数据库依赖 -->
<dependency>
<groupId>com.zilliz</groupId>
<artifactId>milvus-sdk-java</artifactId>
<version>2.3.5</version>
</dependency>
</dependencies>
3. 配置大模型服务
在application.yml
中配置大模型服务信息:
jbolt:
ai:
enabled: true
model:
type: wenxin # 可选择 wenxin、tongyi、openai 等
wenxin:
api-key: your-wenxin-api-key
secret-key: your-wenxin-secret-key
base-url: https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions
vector-db:
enabled: true
type: milvus
milvus:
host: localhost
port: 19530
database: default
collection-name: faq_embeddings
4. 构建知识库管理模块
创建知识库实体类:
package com.example.demo.entity;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.IBean;
/**
* 知识库实体类,存储常见问题和答案
*/
public class KnowledgeBase extends Model<KnowledgeBase> implements IBean {
private static final long serialVersionUID = 1L;
public static final KnowledgeBase dao = new KnowledgeBase().dao();
// 问题
public String getQuestion() {
return getStr("question");
}
public void setQuestion(String question) {
set("question", question);
}
// 答案
public String getAnswer() {
return getStr("answer");
}
public void setAnswer(String answer) {
set("answer", answer);
}
// 分类
public String getCategory() {
return getStr("category");
}
public void setCategory(String category) {
set("category", category);
}
// 向量表示(由大模型生成)
public byte[] getEmbedding() {
return getBytes("embedding");
}
public void setEmbedding(byte[] embedding) {
set("embedding", embedding);
}
}
5. 实现智能客服核心服务
创建客服服务类,处理用户提问并生成回答:
package com.example.demo.service;
import com.example.demo.entity.KnowledgeBase;
import com.jbolt.ai.LLMService;
import com.jbolt.ai.embedding.EmbeddingResult;
import com.jbolt.ai.vectorstore.VectorStore;
import com.jbolt.ai.vectorstore.VectorStoreQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 智能客服核心服务
*/
@Service
public class CustomerService {
@Autowired
private LLMService llmService;
@Autowired
private VectorStore vectorStore;
/**
* 处理用户提问并生成回答
*/
public String handleQuestion(String question, List<Map<String, String>> conversationHistory) {
// 1. 将用户问题转换为向量表示
EmbeddingResult embeddingResult = llmService.createEmbedding(question);
float[] embedding = embeddingResult.getEmbeddings().get(0);
// 2. 在知识库中查找相似问题
VectorStoreQuery query = new VectorStoreQuery();
query.setEmbedding(embedding);
query.setTopK(3); // 返回最相似的3个问题
List<Map<String, Object>> similarQuestions = vectorStore.similaritySearch(query);
// 3. 构建提示模板,包含用户问题、历史对话和相似问题
StringBuilder prompt = new StringBuilder();
prompt.append("你是一个电商平台的智能客服,擅长回答用户关于订单、物流、商品和售后的问题。\n\n");
// 添加历史对话
if (conversationHistory != null && !conversationHistory.isEmpty()) {
prompt.append("历史对话:\n");
for (Map<String, String> message : conversationHistory) {
prompt.append("用户: ").append(message.get("user")).append("\n");
prompt.append("客服: ").append(message.get("assistant")).append("\n");
}
prompt.append("\n");
}
// 添加相似问题和答案作为参考
if (!similarQuestions.isEmpty()) {
prompt.append("参考问题和答案:\n");
for (Map<String, Object> item : similarQuestions) {
String similarQuestion = (String) item.get("question");
String similarAnswer = (String) item.get("answer");
prompt.append("问题: ").append(similarQuestion).append("\n");
prompt.append("答案: ").append(similarAnswer).append("\n\n");
}
}
// 添加用户当前问题
prompt.append("用户当前问题: ").append(question);
// 4. 调用大模型生成回答
String answer = llmService.generateText(prompt.toString());
// 5. 分析回答是否需要转接人工客服
if (needHumanSupport(answer)) {
return "很抱歉,您的问题比较复杂,我将为您转接人工客服,请稍候...";
}
return answer;
}
/**
* 判断是否需要转接人工客服
*/
private boolean needHumanSupport(String answer) {
// 简单实现,实际应用中可以使用更复杂的判断逻辑
return answer.contains("转接人工客服") ||
answer.contains("无法回答") ||
answer.contains("请联系客服");
}
/**
* 更新知识库
*/
public void updateKnowledgeBase(String question, String answer, String category) {
// 1. 生成问题的向量表示
EmbeddingResult embeddingResult = llmService.createEmbedding(question);
float[] embedding = embeddingResult.getEmbeddings().get(0);
// 2. 将向量转换为字节数组存储
byte[] embeddingBytes = new byte[embedding.length * 4];
for (int i = 0; i < embedding.length; i++) {
int bits = Float.floatToIntBits(embedding[i]);
embeddingBytes[i * 4] = (byte) (bits & 0xff);
embeddingBytes[i * 4 + 1] = (byte) ((bits >> 8) & 0xff);
embeddingBytes[i * 4 + 2] = (byte) ((bits >> 16) & 0xff);
embeddingBytes[i * 4 + 3] = (byte) ((bits >> 24) & 0xff);
}
// 3. 保存到知识库
KnowledgeBase kb = new KnowledgeBase();
kb.setQuestion(question);
kb.setAnswer(answer);
kb.setCategory(category);
kb.setEmbedding(embeddingBytes);
kb.save();
// 4. 同时更新向量数据库
Map<String, Object> metadata = new HashMap<>();
metadata.put("question", question);
metadata.put("answer", answer);
metadata.put("category", category);
vectorStore.addEmbedding(embedding, metadata);
}
}
6. 创建REST API接口
创建控制器类,提供对外服务接口:
package com.example.demo.controller;
import com.example.demo.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 智能客服API接口
*/
@RestController
@RequestMapping("/api/customer-service")
public class CustomerServiceController {
@Autowired
private CustomerService customerService;
// 存储会话历史,实际应用中应使用Redis等分布式缓存
private Map<String, List<Map<String, String>>> conversationHistoryMap = new HashMap<>();
/**
* 处理用户提问
*/
@PostMapping("/ask")
public Map<String, Object> askQuestion(@RequestBody Map<String, String> request) {
String userId = request.get("userId");
String question = request.get("question");
// 获取会话历史
List<Map<String, String>> conversationHistory = conversationHistoryMap.computeIfAbsent(
userId, k -> new ArrayList<>());
// 调用客服服务处理问题
String answer = customerService.handleQuestion(question, conversationHistory);
// 保存对话历史
Map<String, String> userMessage = new HashMap<>();
userMessage.put("user", question);
userMessage.put("assistant", answer);
conversationHistory.add(userMessage);
// 返回结果
Map<String, Object> result = new HashMap<>();
result.put("answer", answer);
result.put("conversationId", userId);
result.put("timestamp", System.currentTimeMillis());
return result;
}
/**
* 更新知识库
*/
@PostMapping("/knowledge-base")
public Map<String, Object> updateKnowledgeBase(@RequestBody Map<String, String> request) {
String question = request.get("question");
String answer = request.get("answer");
String category = request.get("category");
customerService.updateKnowledgeBase(question, answer, category);
Map<String, Object> result = new HashMap<>();
result.put("success", true);
result.put("message", "知识库更新成功");
return result;
}
}
7. 前端界面实现
创建一个简单的HTML页面,实现与后端的交互:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能客服系统</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#165DFF',
secondary: '#00B42A',
neutral: '#F5F7FA',
dark: '#1D2129',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.chat-bubble-user {
@apply bg-primary text-white rounded-tl-lg rounded-tr-2xl rounded-br-2xl;
}
.chat-bubble-bot {
@apply bg-neutral text-dark rounded-tl-2xl rounded-tr-2xl rounded-bl-2xl;
}
.typing-indicator {
@apply inline-flex space-x-1;
}
.typing-indicator span {
@apply w-2 h-2 bg-gray-400 rounded-full animate-bounce;
}
.typing-indicator span:nth-child(2) {
@apply animate-bounce delay-100;
}
.typing-indicator span:nth-child(3) {
@apply animate-bounce delay-200;
}
}
</style>
</head>
<body class="bg-gray-50 font-sans">
<div class="min-h-screen flex flex-col">
<!-- 顶部导航 -->
<header class="bg-white shadow-sm sticky top-0 z-10">
<div class="container mx-auto px-4 py-3 flex items-center justify-between">
<div class="flex items-center space-x-2">
<i class="fa fa-comments text-primary text-2xl"></i>
<h1 class="text-xl font-bold text-dark">智能客服助手</h1>
</div>
<div class="flex items-center space-x-4">
<button id="toggle-theme" class="text-gray-500 hover:text-primary transition-colors">
<i class="fa fa-moon-o"></i>
</button>
<button id="btn-help" class="text-gray-500 hover:text-primary transition-colors">
<i class="fa fa-question-circle"></i>
</button>
</div>
</div>
</header>
<!-- 主内容区 -->
<main class="flex-grow container mx-auto px-4 py-6 flex flex-col lg:flex-row gap-6">
<!-- 左侧知识库面板 -->
<aside class="lg:w-1/4 bg-white rounded-xl shadow-sm p-4 hidden lg:block">
<h2 class="text-lg font-semibold mb-4 flex items-center">
<i class="fa fa-book text-primary mr-2"></i>常见问题
</h2>
<div class="space-y-2">
<div class="faq-item p-3 rounded-lg bg-neutral hover:bg-gray-200 cursor-pointer transition-colors">
<h3 class="font-medium">如何查询我的订单状态?</h3>
<p class="text-sm text-gray-600 mt-1">您可以在"我的订单"页面查看所有订单的当前状态...</p>
</div>
<div class="faq-item p-3 rounded-lg bg-neutral hover:bg-gray-200 cursor-pointer transition-colors">
<h3 class="font-medium">如何申请退换货?</h3>
<p class="text-sm text-gray-600 mt-1">在订单完成后7天内,您可以在订单详情页申请退换货...</p>
</div>
<div class="faq-item p-3 rounded-lg bg-neutral hover:bg-gray-200 cursor-pointer transition-colors">
<h3 class="font-medium">如何修改收货地址?</h3>
<p class="text-sm text-gray-600 mt-1">在订单发货前,您可以在订单详情页修改收货地址...</p>
</div>
<div class="faq-item p-3 rounded-lg bg-neutral hover:bg-gray-200 cursor-pointer transition-colors">
<h3 class="font-medium">支付方式有哪些?</h3>
<p class="text-sm text-gray-600 mt-1">我们支持微信支付、支付宝、银行卡等多种支付方式...</p>
</div>
</div>
<h2 class="text-lg font-semibold mt-6 mb-4 flex items-center">
<i class="fa fa-folder text-primary mr-2"></i>问题分类
</h2>
<div class="space-y-1">
<button class="w-full text-left p-2 rounded-lg hover:bg-neutral transition-colors">
<i class="fa fa-shopping-cart mr-2"></i>订单相关
</button>
<button class="w-full text-left p-2 rounded-lg hover:bg-neutral transition-colors">
<i class="fa fa-truck mr-2"></i>物流配送
</button>
<button class="w-full text-left p-2 rounded-lg hover:bg-neutral transition-colors">
<i class="fa fa-credit-card mr-2"></i>支付方式
</button>
<button class="w-full text-left p-2 rounded-lg hover:bg-neutral transition-colors">
<i class="fa fa-refresh mr-2"></i>退换货政策
</button>
<button class="w-full text-left p-2 rounded-lg hover:bg-neutral transition-colors">
<i class="fa fa-user mr-2"></i>账户管理
</button>
</div>
</aside>
<!-- 中间聊天区域 -->
<section class="lg:w-2/4 bg-white rounded-xl shadow-sm flex flex-col h-[80vh] overflow-hidden">
<div class="p-4 border-b border-gray-200">
<h2 class="text-lg font-semibold">在线客服</h2>
<p class="text-sm text-gray-500">工作时间: 9:00-21:00 (周一至周日)</p>
</div>
<div id="chat-container" class="flex-grow p-4 overflow-y-auto space-y-4">
<!-- 欢迎消息 -->
<div class="flex items-start space-x-3">
<div class="w-8 h-8 rounded-full bg-primary/20 flex items-center justify-center text-primary">
<i class="fa fa-robot"></i>
</div>
<div class="max-w-[80%]">
<div class="chat-bubble-bot p-3">
<p>您好!我是智能客服助手,很高兴为您服务。请问有什么可以帮助您的吗?</p>
</div>
<div class="text-xs text-gray-500 mt-1">刚刚</div>
</div>
</div>
</div>
<div class="p-4 border-t border-gray-200">
<div class="relative">
<textarea id="user-input" rows="3" placeholder="请输入您的问题..."
class="w-full p-3 pr-12 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary transition-all resize-none"></textarea>
<button id="send-button" class="absolute right-3 bottom-3 text-primary hover:text-primary/80 transition-colors">
<i class="fa fa-paper-plane text-xl"></i>
</button>
</div>
<div class="flex justify-between mt-2 text-sm">
<div class="text-gray-500">
<i class="fa fa-info-circle mr-1"></i>输入"转接人工"可转人工客服
</div>
<div class="text-gray-500">
<i class="fa fa-star mr-1"></i>评价客服
</div>
</div>
</div>
</section>
<!-- 右侧客服信息面板 -->
<aside class="lg:w-1/4 bg-white rounded-xl shadow-sm p-4 hidden lg:block">
<h2 class="text-lg font-semibold mb-4 flex items-center">
<i class="fa fa-info-circle text-primary mr-2"></i>客服信息
</h2>
<div class="bg-neutral rounded-lg p-4 mb-4">
<div class="flex items-center space-x-3">
<div class="w-12 h-12 rounded-full bg-primary/20 flex items-center justify-center text-primary">
<i class="fa fa-robot text-xl"></i>
</div>
<div>
<h3 class="font-medium">智能客服助手</h3>
<p class="text-xs text-gray-500">随时为您服务</p>
</div>
</div>
<div class="mt-3">
<p class="text-sm">我可以回答您关于订单、物流、支付和退换货等方面的问题。</p>
<p class="text-sm mt-1">如果我无法解答,将为您转接人工客服。</p>
</div>
</div>
<h2 class="text-lg font-semibold mb-4 flex items-center">
<i class="fa fa-line-chart text-primary mr-2"></i>服务数据
</h2>
<div class="space-y-3">
<div>
<div class="flex justify-between text-sm mb-1">
<span>响应速度</span>
<span>98%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-primary h-2 rounded-full" style="width: 98%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span>问题解决率</span>
<span>95%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-secondary h-2 rounded-full" style="width: 95%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span>用户满意度</span>
<span>97%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2">
<div class="bg-yellow-500 h-2 rounded-full" style="width: 97%"></div>
</div>
</div>
</div>
<h2 class="text-lg font-semibold mt-6 mb-4 flex items-center">
<i class="fa fa-headphones text-primary mr-2"></i>其他联系方式
</h2>
<div class="space-y-2">
<a href="#" class="flex items-center p-2 rounded-lg hover:bg-neutral transition-colors">
<i class="fa fa-phone text-primary mr-2"></i>
<span>400-123-4567</span>
</a>
<a href="#" class="flex items-center p-2 rounded-lg hover:bg-neutral transition-colors">
<i class="fa fa-envelope text-primary mr-2"></i>
<span>support@example.com</span>
</a>
<a href="#" class="flex items-center p-2 rounded-lg hover:bg-neutral transition-colors">
<i class="fa fa-weixin text-primary mr-2"></i>
<span>关注公众号:客服小助手</span>
</a>
</div>
</aside>
</main>
<!-- 底部 -->
<footer class="bg-white border-t border-gray-200 py-4">
<div class="container mx-auto px-4 text-center text-sm text-gray-500">
<p>© 2025 智能客服系统 | 隐私政策 | 使用条款</p>
</div>
</footer>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const chatContainer = document.getElementById('chat-container');
const userInput = document.getElementById('user-input');
const sendButton = document.getElementById('send-button');
const toggleTheme = document.getElementById('toggle-theme');
// 生成唯一用户ID
const userId = Math.random().toString(36).substring(2, 15);
// 发送消息
function sendMessage() {
const message = userInput.value.trim();
if (!message) return;
// 添加用户消息到聊天界面
addUserMessage(message);
// 清空输入框
userInput.value = '';
// 显示"正在输入"状态
showTypingIndicator();
// 发送消息到服务器
fetch('/api/customer-service/ask', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
userId: userId,
question: message
})
})
.then(response => response.json())
.then(data => {
// 移除"正在输入"状态
removeTypingIndicator();
// 添加AI回复到聊天界面
addBotMessage(data.answer);
})
.catch(error => {
console.error('Error:', error);
removeTypingIndicator();
addBotMessage('抱歉,发生了错误,请稍后再试。');
});
}
// 添加用户消息到聊天界面
function addUserMessage(message) {
const now = new Date();
const timeString = now.getHours() + ':' + (now.getMinutes() < 10 ? '0' : '') + now.getMinutes();
const userMessageHtml = `
<div class="flex items-start justify-end space-x-3">
<div class="max-w-[80%]">
<div class="chat-bubble-user p-3">
<p>${
message}</p>
</div>
<div class="text-xs text-gray-500 mt-1 text-right">${
timeString}</div>
</div>
<div class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center">
<i class="fa fa-user text-gray-500"></i>
</div>
</div>
`;
chatContainer.insertAdjacentHTML('beforeend', userMessageHtml);
chatContainer.scrollTop = chatContainer.scrollHeight;
}
// 添加AI回复到聊天界面
function addBotMessage(message) {
const now = new Date();
const timeString = now.getHours() + ':' + (now.getMinutes() < 10 ? '0' : '') + now.getMinutes();
const botMessageHtml = `
<div class="flex items-start space-x-3">
<div class="w-8 h-8 rounded-full bg-primary/20 flex items-center justify-center text-primary">
<i class="fa fa-robot"></i>
</div>
<div class="max-w-[80%]">
<div class="chat-bubble-bot p-3">
<p>${
message}</p>
</div>
<div class="text-xs text-gray-500 mt-1">${
timeString}</div>
</div>
</div>
`;
chatContainer.insertAdjacentHTML('beforeend', botMessageHtml);
chatContainer.scrollTop = chatContainer.scrollHeight;
}
// 显示"正在输入"状态
function showTypingIndicator() {
const typingHtml = `
<div id="typing-indicator" class="flex items-start space-x-3">
<div class="w-8 h-8 rounded-full bg-primary/20 flex items-center justify-center text-primary">
<i class="fa fa-robot"></i>
</div>
<div class="max-w-[80%]">
<div class="chat-bubble-bot p-3">
<div class="typing-indicator">
<span></span>
<span></span>
<span></span>
</div>
</div>
</div>
</div>
`;
chatContainer.insertAdjacentHTML('beforeend', typingHtml);
chatContainer.scrollTop = chatContainer.scrollHeight;
}
// 移除"正在输入"状态
function removeTypingIndicator() {
const typingIndicator = document.getElementById('typing-indicator');
if (typingIndicator) {
typingIndicator.remove();
}
}
// 绑定发送按钮点击事件
sendButton.addEventListener('click', sendMessage);
// 绑定回车键发送消息
userInput.addEventListener('keydown', function(event) {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault();
sendMessage();
}
});
// 切换主题
toggleTheme.addEventListener('click', function() {
document.body.classList.toggle('dark');
const icon = toggleTheme.querySelector('i');
if (icon.classList.contains('fa-moon-o')) {
icon.classList.remove('fa-moon-o');
icon.classList.add('fa-sun-o');
} else {
icon.classList.remove('fa-sun-o');
icon.classList.add('fa-moon-o');
}
});
// 知识库项目点击事件
document.querySelectorAll('.faq-item').forEach(item => {
item.addEventListener('click', function() {
const question = this.querySelector('h3').textContent;
userInput.value = question;
sendMessage();
});
});
});
</script>
</body>
</html>
8. 系统部署与测试
首先,确保你已经安装了以下环境:
- JDK 17+
- Maven 3.8+
- Docker(可选,用于部署向量数据库)
部署步骤:
- 启动向量数据库(以Milvus为例):
# 使用Docker启动Milvus轻量版
docker run -d --name milvus-lite -p 19530:19530 -p 9091:9091 milvusdb/milvus:2.3.5-lite
配置大模型API密钥:
在application.yml
中填写你选择的大模型的API密钥。启动Spring Boot应用:
mvn spring-boot:run
- 访问前端界面:
打开浏览器,访问http://localhost:8080
即可看到智能客服界面。
测试场景:
- 尝试输入常见问题,如"如何查询订单状态?"
- 测试多轮对话,如"我的订单号是123456,现在状态如何?"
- 输入复杂问题,触发转接人工客服流程
通过以上步骤,你就成功实现了一个基于JBoltAI框架的智能客服系统。这个系统可以根据企业需求进一步扩展,如添加更多知识库、集成更多大模型、优化对话流程等。
JBoltAI,AI 框架,大
代码获取方式
https://pan.quark.cn/s/14fcf913bae6