星云API www.xingyapi.com 的底层重构笔记。最近有个做财税 SaaS 的兄弟吐槽,他们给客户群配的答疑机器人毫无上下文连贯性------客户问完"高企所得税",追问"普通商贸公司呢",机器人直接宕机听不懂。
他为了给机器人加"记忆",收到消息就去实时查群详情和数据库历史,结果早高峰直接把企微的 45009 频控打穿,数据库连接池耗尽。
企微推给机器人的消息是高度碎片化且无状态的。要在工业级架构中让大模型拥有"专家记忆",必须在内存中极速缝合静态群资料、动态上下文和瞬时消息。今天不废话,直接上手撕代码。
一、斩断实时查询:构建群画像影子库
机器人的 Webhook 报文里只有干巴巴的 ChatId 和 UserId。
工业级防线:坚决不主动查接口。 你需要仔细查阅 开发文档,利用自建应用的 change_external_chat 回调,把群名、状态等静态资料实时更新到 Redis。机器人收到消息时,直接 O(1) 提取:
Java
public GroupProfile getGroupProfile(String chatId) {
// 缓存击穿时返回默认占位符,绝不在此阻塞调企微 API
String profile = redisTemplate.opsForValue().get("WeCom:Group:" + chatId);
return profile != null ? JSON.parseObject(profile, GroupProfile.class) : GroupProfile.defaultProfile();
}
二、滑动会话窗口:Redis 托管动态上下文
关系型 DB 扛不住群聊的高频读写,记忆必须放内存。我们用 Redis List 构建定长滑动窗口,以 ChatId:UserId 为联合 Key,只保留最近 10 条高优上下文喂给大模型。
Java
public List<ChatMessage> appendContext(String chatId, String userId, ChatMessage msg) {
String key = "WeCom:Session:" + chatId + ":" + userId;
// 1. 新消息入列
redisTemplate.opsForList().rightPush(key, JSON.toJSONString(msg));
// 2. 裁剪窗口,防 Token 溢出
redisTemplate.opsForList().trim(key, -10, -1);
// 3. 30分钟不说话清空记忆
redisTemplate.expire(key, 30, TimeUnit.MINUTES);
return redisTemplate.opsForList().range(key, 0, -1).stream()
.map(str -> JSON.parseObject(str, ChatMessage.class))
.collect(Collectors.toList());
}
三、内存组装器(Assembler):终极缝合
在 MQ 的消费端,把雷达数据和会话记忆拧成一股绳,完成最终的 Data Assembler:
Java
@RabbitListener(queues = "queue_robot_msg")
public void process(String jsonMsg) {
RobotMsgDTO msg = JSON.parseObject(jsonMsg, RobotMsgDTO.class);
// 1. 提取静态画像
GroupProfile group = getGroupProfile(msg.getChatId());
if (!group.isActive()) return;
// 2. 拉取动态记忆
ChatMessage newChat = new ChatMessage("user", msg.getText().getContent());
List<ChatMessage> history = appendContext(msg.getChatId(), msg.getFrom().getUserId(), newChat);
// 3. 缝合 Prompt 并调大模型
EnrichedPrompt prompt = new EnrichedPrompt("你是财税顾问,所在群:" + group.getGroupName(), history);
String answer = llmService.chat(prompt);
// 4. 将机器人的回复也加入历史记忆闭环
appendContext(msg.getChatId(), msg.getFrom().getUserId(), new ChatMessage("assistant", answer));
// 5. 走 WebhookUrl 零权限专用通道下发...
}
机器人能"记事观局",核心不在 Prompt,而是底层的异构数据组装能力。这套体系跑通后,你们遇到带图片的复杂提问,是把图片扔进 Redis List 给视觉大模型,还是在网关直接 OCR 降维成文本?
