行业资讯
📅 2026/7/13 22:46:31
企业解决方案二十-企微消息监听与房源、车源、救援信息提炼分析存储转化使用方案
一、项目背景与技术选型1.1 业务场景分析在汽车销售与客户服务领域企业微信已成为连接客户的重要渠道。销售人员每天需要处理大量客户咨询其中包含大量潜在的购车需求信息。传统的人工处理方式存在以下痛点消息量大单个销售顾问每天可能接收数百条客户消息信息分散购车意向、图片资料、联系方式分散在不同对话中响应滞后无法第一时间识别高价值客户需求信息遗漏重要信息可能被淹没在海量消息中本项目通过监听企业微信消息结合AI大模型和图像识别技术实现客户购车意向的自动识别与车源信息提炼。1.2 核心技术架构┌─────────────────────────────────────────────────────────────────┐ │ 技术架构总览 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 企业微信客户端 ←→ Python监听服务 → Java SpringBoot后端 │ │ ↓ │ │ 消息解析与分类 │ │ ↓ │ │ ┌──────────┴──────────┐ │ │ ↓ ↓ │ │ 文本消息处理 图片消息处理 │ │ ↓ ↓ │ │ 大模型意图分析 OSS上传图像识别 │ │ ↓ ↓ │ │ 信息整合与过滤 车源判定 │ │ ↓ │ │ 数据库存储定时任务 │ │ │ └─────────────────────────────────────────────────────────────────┘1.3 技术栈详述技术组件选型用途说明开发语言Java 8 / Python主逻辑/监听服务Web框架Spring BootRESTful API服务ORM框架MyBatis-Plus数据库操作简化JSON处理Fastjson / Gson消息序列化图像识别自研AI模型车源图片判定大模型扣子智能体信息提炼与答复文件存储阿里云OSS图片持久化并发控制ReentrantReadWriteLock文件读写安全定时任务Spring Scheduled数据同步刷新二、核心功能模块详解2.1 消息监听与解析模块2.1.1 消息入口设计消息监听入口通过/receive_python_msg接口接收来自Python监听服务的消息PostMapping(/receive_python_msg) public void receive_python_msg(RequestBody PythonMsg pythonMsg) throws Exception { String listenMsg pythonMsg.getGet_internal_contacts_res(); // 解析JSON消息 JsonParseInnerFriend jsonParseInnerFriend gson.fromJson(listenMsg, JsonParseInnerFriend.class); Integer type jsonParseInnerFriend.type; // 根据消息类型分发处理 }2.1.2 消息类型分类处理企业微信消息包含多种类型系统对不同类型的消息进行差异化处理类型码消息类型处理策略11041文本消息直接提取文本内容送入大模型分析11042图片消息下载图片→上传OSS→图像识别判定车源11046位置消息提取经纬度、地址信息11078群信息变更同步更新群名称2.1.3 图片处理完整链路图片消息的处理是系统中的关键环节涉及多个步骤case 11042: // 1. 生成唯一文件名并下载图片 String savePath Constants.IMAGE_SAVE_PATH \\ System.currentTimeMillis() .jpg; MapString, Object result1 downloadImage(1, 1, chatInfoJson.data.cdn.url, chatInfoJson.data.cdn.auth_key, chatInfoJson.data.cdn.aes_key, chatInfoJson.data.cdn.size, savePath); // 2. 上传到阿里云OSS MapString, Object result uploadToOSS(savePath); tempWxInfo.setImageUrl((String) result.get(url)); // 3. 清理本地临时文件 File tempFile new File(savePath); if (tempFile.delete()) { System.out.println(文件删除成功: savePath); } break;2.2 信息缓存与持久化2.2.1 内存缓存设计系统使用Constants.WX_INFO_LIST作为消息的内存缓存并配合文件持久化保证数据安全// 内存缓存 public static ListWxInfo WX_INFO_LIST new ArrayList(); // WxInfo数据结构 public class WxInfo { private String id; // 消息唯一ID private String sender; // 发送者 private String sendContent; // 发送内容 private String imageUrl; // 图片URL private String groupName; // 群名称 private long sendTime; // 发送时间 // getters/setters省略 }2.2.2 文件读写锁实现为保障文件操作线程安全采用ReentrantReadWriteLock实现读写分离private static final ReentrantReadWriteLock lock new ReentrantReadWriteLock(); public static void appendToFile(WxInfo wxInfo) { lock.writeLock().lock(); try { ListWxInfo existingList loadFromFile(); existingList.add(wxInfo); writeFullArray(existingList); } finally { lock.writeLock().unlock(); } } public static ListWxInfo loadFromFile() { lock.readLock().lock(); try { // 读取文件逻辑 } finally { lock.readLock().unlock(); } }2.2.3 文件损坏恢复机制为防止文件损坏导致数据丢失实现了自动备份恢复机制private static void backupAndCreateNewFile() { try { File file new File(FILE_PATH); if (file.exists()) { File backupFile new File(wx_info_list_backup_ System.currentTimeMillis() .txt); file.renameTo(backupFile); System.out.println(已备份损坏的文件到: backupFile.getName()); } writeFullArray(new ArrayList()); } catch (IOException e) { System.err.println(备份文件失败: e.getMessage()); } }2.3 消息合并与智能过滤2.3.1 消息合并策略系统实现了基于时间窗口和语义相似度的消息合并机制if (Constants.WX_INFO_LIST.size() 300) { // 获取合并关系列表 ListMergeRelation mergeRelations integrateWxInfosWithRelation( Constants.WX_INFO_LIST ); for (MergeRelation relation : mergeRelations) { WxInfo wxInfo relation.getMergedInfo(); // 处理合并后的信息 } }2.3.2 车源信息判定通过图像识别大模型判定图片是否为汽车或驾驶证String imageModelRes Step6_IsCarOrNotSmart.SmartWork( UUID.randomUUID().toString(), tempImgUrl ); ImageModelResJson imageModelResJson gson.fromJson( imageModelRes, ImageModelResJson.class ); if (imageModelResJson.aCarOrADrivingLicense.equals(是)) { tempTotalUrl.append(tempImgUrl).append(,); }2.3.3 联系方式提取通过正则匹配和AI分析从文本中提取电话号码等联系信息if (Step7_PhoneNumberUtil.containsPhoneNumber(wxInfo.getSendContent()) || Step7_PhoneNumberUtil.containsPhoneNumber(wxInfo.getSender())) { // 构建完整信息并存储 String totalInfo 群名称 wxInfo.getGroupName() 。发送者 wxInfo.getSender() 。\n; totalInfo totalInfo 发送信息如下\n wxInfo.getSendContent() 。imgRul的值为 tempTotalUrl; // 调用信息提炼大模型 String uploadInfo Step8_InfoExtractSmart.SmartWork( UUID.randomUUID().toString(), totalInfo ); }2.4 数据同步与定时任务2.4.1 好友列表同步PostMapping(/update_friend1_list) public Res update_friend1_list(RequestBody ListFriend1 friend1List) { try { ListFriend1 mysqlExistFriend1List friend1Mapper.selectList(null); MapString, Friend1 mysqlMap mysqlExistFriend1List.stream() .collect(Collectors.toMap(Friend1::getUserId, f - f)); // 分离需要更新和新增的数据 MapBoolean, ListFriend1 partitioned friend1List.stream() .collect(Collectors.partitioningBy( friend - mysqlMap.containsKey(friend.getUserId()) )); // 批量更新 ListFriend1 toUpdate partitioned.get(true).stream() .filter(friend - { Friend1 exist mysqlMap.get(friend.getUserId()); return !Objects.equals(friend.getNickName(), exist.getNickName()); }) .peek(friend - friend.setId(mysqlMap.get(friend.getUserId()).getId())) .collect(Collectors.toList()); // 批量插入 ListFriend1 toInsert partitioned.get(false); if (!toUpdate.isEmpty()) { for (Friend1 tempFriend1 : toUpdate) { friend1Mapper.updateById(tempFriend1); } } if (!toInsert.isEmpty()) { sendMapper.insertBatchFriend1(toInsert); } return Res.success(); } catch (Exception e) { e.printStackTrace(); return Res.error(); } }2.4.2 定时任务配置// 群信息同步 - 每12小时执行一次 Scheduled(fixedRate 30 * 720 * 60 * 1000) public void scheduledRefreshGroup() { try { Step3_GroupOnce.doWork(); System.out.println(恭喜刷新信息成功请继续操作); } catch (Exception e) { System.err.println(抱歉刷新信息出现错误请检查...); e.printStackTrace(); } } // 好友信息同步 - 每10分钟执行一次 Scheduled(fixedRate 10 * 60 * 1000) public void scheduledRefresh() { try { Step1_Friend.doWork(); Step2_Friend.doWork(); System.out.println(恭喜刷新信息成功请继续操作); } catch (Exception e) { System.err.println(抱歉刷新信息出现错误请检查...); e.printStackTrace(); } }2.5 大模型智能答复2.5.1 上下文对话管理系统维护每个用户或群的对话历史构建上下文进行智能答复public void modelGiveAnswer(String user_id, Boolean group, String addId) throws Exception { QueryWrapperMsg msgQueryWrapper new QueryWrapper(); String finalQueryId ; if (group) { finalQueryId user_id addId; } else { finalQueryId user_id; } msgQueryWrapper.eq(chat_room_or_user_id, finalQueryId); ListMsg msgList msgMapper.selectList(msgQueryWrapper); // 调用大模型生成答复 String answer Step2_AnswerSmart.SmartWork( 7642293093576425524, // botId finalQueryId, // user_id msgList // 历史消息列表 ); answer answer.replaceAll(\\\\n, \n); // 存储答复消息 Msg tempMsg new Msg(); tempMsg.setChatRoomOrUserId(finalQueryId); tempMsg.setSender(客服人员); tempMsg.setContent(answer); tempMsg.setType(answer); tempMsg.setRole(assistant); tempMsg.setCreateTime(new Date()); msgMapper.insert(tempMsg); }2.5.2 信息提炼模型系统还集成了专门的信息提炼大模型用于从非结构化文本中提取结构化信息String uploadInfo Step8_InfoExtractSmart.SmartWork( UUID.randomUUID().toString(), totalInfo ); Car car new Car(); car.setInfo(JSON.toJSON(uploadInfo).toString()); car.setCreateTime(new Date()); carMapper.insert(car);三、数据库设计与优化3.1 核心表结构设计3.1.1 好友表 (friend1)CREATE TABLE friend1 ( id INT PRIMARY KEY AUTO_INCREMENT, user_id VARCHAR(64) NOT NULL COMMENT 企业微信用户ID, nick_name VARCHAR(255) COMMENT 昵称, remark VARCHAR(255) COMMENT 备注名, conversation_id VARCHAR(64) COMMENT 会话ID, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_user_id (user_id) );3.1.2 群组表 (group3)CREATE TABLE group3 ( id INT PRIMARY KEY AUTO_INCREMENT, chat_room_id VARCHAR(64) NOT NULL COMMENT 群聊ID, nick_name VARCHAR(255) COMMENT 群名称, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_chat_room_id (chat_room_id) );3.1.3 消息表 (msg)CREATE TABLE msg ( id BIGINT PRIMARY KEY AUTO_INCREMENT, chat_room_or_user_id VARCHAR(64) NOT NULL COMMENT 会话ID, sender VARCHAR(255) COMMENT 发送者, content TEXT COMMENT 消息内容, type VARCHAR(50) COMMENT 消息类型, role VARCHAR(50) COMMENT 角色(user/assistant), create_time DATETIME DEFAULT CURRENT_TIMESTAMP );3.1.4 车辆信息表 (car)CREATE TABLE car ( id BIGINT PRIMARY KEY AUTO_INCREMENT, info JSON COMMENT 提炼的车源信息, create_time DATETIME DEFAULT CURRENT_TIMESTAMP );3.2 分页查询优化PostMapping(/select_friend1_list) public Res select_friend1_list(RequestBody Friend1 friend1) { QueryWrapperFriend1 queryWrapper new QueryWrapper(); if (!MyUtils.blankFlag(friend1.getNickName())) { queryWrapper.like(nick_name, friend1.getNickName()); } Integer total Math.toIntExact(friend1Mapper.selectCount(queryWrapper)); MyUtils.selectByPageManage(total, friend1); queryWrapper.last(limit friend1.getStart() , friend1.getEnd()); ListFriend1 friend1List friend1Mapper.selectList(queryWrapper); HashMapObject, Object hashMap new HashMap(); hashMap.put(total, total); hashMap.put(data, friend1List); return Res.success(hashMap); }四、关键技术难点与解决方案4.1 并发安全与数据一致性问题多个线程同时操作共享缓存和文件时可能产生竞态条件。解决方案使用ReentrantReadWriteLock实现读写锁分离缓存操作与文件操作保持原子性消息ID去重机制private static final ReentrantReadWriteLock lock new ReentrantReadWriteLock(); // 写操作加写锁 lock.writeLock().lock(); try { // 业务操作 } finally { lock.writeLock().unlock(); } // 读操作加读锁 lock.readLock().lock(); try { // 业务操作 } finally { lock.readLock().unlock(); }4.2 图片处理性能优化问题图片下载、上传涉及网络IO可能成为系统瓶颈。解决方案使用异步处理或线程池优化图片压缩策略设置合理的超时时间// 线程池配置建议 Bean public ExecutorService imageProcessExecutor() { return new ThreadPoolExecutor( 5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue(100), new ThreadPoolExecutor.CallerRunsPolicy() ); }4.3 大模型调用稳定策略问题大模型API调用可能失败或超时影响用户体验。解决方案实现降级策略请求重试机制本地缓存常用答复public String callModelWithRetry(String botId, String userId, ListMsg history) { int maxRetries 3; int retryCount 0; while (retryCount maxRetries) { try { return Step2_AnswerSmart.SmartWork(botId, userId, history); } catch (Exception e) { retryCount; if (retryCount maxRetries) { return 系统繁忙请稍后再试...; } Thread.sleep(1000 * retryCount); // 指数退避 } } return 系统繁忙请稍后再试...; }五、系统部署与运维5.1 部署架构┌─────────────────────────────────────────────────────────┐ │ 部署架构 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 企业微信服务器 ←→ Python监听服务(ECS) │ │ ↓ │ │ Java SpringBoot应用(ECS) │ │ ↓ │ │ 阿里云OSS(图片存储) │ │ ↓ │ │ 阿里云RDS(MySQL数据库) │ │ │ └─────────────────────────────────────────────────────────┘5.2 配置文件管理yaml复制下载# application.yml 关键配置 spring: datasource: url: jdbc:mysql://localhost:3306/wechat_bigdata username: ${DB_USERNAME} password: ${DB_PASSWORD} driver-class-name: com.mysql.cj.jdbc.Driver # 阿里云OSS配置 aliyun: oss: endpoint: ${OSS_ENDPOINT} access-key-id: ${OSS_ACCESS_KEY_ID} access-key-secret: ${OSS_ACCESS_KEY_SECRET} bucket-name: ${OSS_BUCKET_NAME} # 系统常量 constant: self-id: ${SELF_WECHAT_ID} image-save-path: /tmp/wechat_images/5.3 监控与告警Component public class SystemMonitor { private static final Logger logger LoggerFactory.getLogger(SystemMonitor.class); Scheduled(fixedRate 60000) public void monitorCacheSize() { int cacheSize Constants.WX_INFO_LIST.size(); if (cacheSize 1000) { logger.warn(消息缓存过大当前大小: {}, cacheSize); } if (cacheSize 2000) { logger.error(消息缓存严重过大请立即处理: {}, cacheSize); // 发送告警通知 sendAlert(消息缓存过大当前大小: cacheSize); } } }六、总结与展望6.1 项目亮点实时性毫秒级消息响应不错过任何商机智能化AI驱动的意图识别与信息提炼可扩展模块化设计易于接入新的AI能力安全性完善的并发控制与数据备份机制可观测全链路日志跟踪与监控告警6.2 优化方向引入消息队列使用RabbitMQ/Kafka削峰填谷增加缓存层使用Redis缓存热点数据模型优化训练专属垂直领域模型提升准确率多租户支持支持多个企业微信账号同时接入可视化看板开发数据统计与监控Dashboard6.3 心得体会通过本项目的实践我们深刻体会到架构设计的重要性良好的分层设计使系统易于维护和扩展并发安全的必要性在企业级应用中线程安全是不可忽视的基础AI与传统业务的融合大模型能力与业务场景结合能产生巨大价值异常处理的完善性完善的异常处理是系统稳定运行的保障未来我们将继续深化AI在客户服务领域的应用打造更智能、更高效的汽车销售辅助系统。