聊天助手模块是派聪明系统的核心组件之一,承载了用户与系统之间的主要交互能力。
模块通过 WebSocket 协议实现双向通信,支持大语言模型(接入了 DeepSeek)输出内容的流式返回;为支持多轮连续对话,该模块集成了 Redis 用于存储和维护用户会话上下文,确保大模型在生成回答时能够“记住”前文内容,维持语义连贯性。
同时,模块深度集成了 Elasticsearch,可以为用户提供结构化文本的全文索引和关键词匹配,通过这套混合检索机制,派聪明能在海量本地知识中快速定位与用户问题相关的信息片段。

为了更好地引导大语言模型生成高质量回答,系统特别强化了 Prompt 构建与模板管理能力:
- 根据检索结果动态生成 Prompt;
- 支持多种 Prompt 模板配置与调优;
- 确保内容组织清晰、有重点,引导模型围绕核心信息生成响应。
这一机制是实现 RAG 的关键保障,确保模型回答既有语义逻辑,又有知识依据。
一、功能需求

二、技术选型
| 功能模块 | 技术选型 | 备注 |
|---|---|---|
| 实时通信 | WebSocket(基于Spring WebSocket) | 支持STOMP子协议 |
| 对话上下文存储 | Redis(使用Spring Data Redis) | 高性能缓存,支持TTL |
| 本地知识库(当前) | Elasticsearch | 支持混合检索 |
| 本地知识库(规划) | Faiss | 提升向量检索性能 |
| 语言模型调用 | DeepSeek API | 通过WebClient调用 |
| Prompt管理 | 自研模板引擎 | 支持动态模板和变量替换 |
| 异步处理 | Spring WebFlux | 支持响应式编程 |
| 安全认证 | JWT | 确保WebSocket连接安全 |
三、关键流程
01、用户发起对话流程
当用户在页面上开始一次对话时,系统的第一步是由客户端主动发起一个 WebSocket 连接请求,这个请求里会带上用户的 JWT 身份认证信息。
服务端收到请求后,会先验证用户的身份和权限,确认无误后,就会和客户端建立一个稳定的 WebSocket 长连接,用于后续的实时对话。

连接建立之后,用户可以开始提问了。客户端会把用户输入的问题通过 WebSocket 发给服务端。服务端这边接收到消息后,会先解析内容,然后根据情况获取一个当前的会话 ID,如果是新的对话,就创建一个。
接着系统会启动知识库检索流程。它会调用内部的 /api/search/hybrid 接口,执行一轮“混合检索”,也就是结合关键词匹配和语义匹配的方式,快速从本地知识库中找出和用户问题最相关的文档。这些结果还会再经过筛选、排序,并提取出关键内容和出处信息,为后面生成回答做准备。
在拿到检索结果后,系统会开始构建 Prompt,也就是发送给大模型的提问模板。它会根据问题类型选择一个合适的 Prompt 模板,然后把刚刚检索到的内容填进去,同时还会加上一些系统级的指令或限制条件。这个过程中还会管理好上下文的长度,保证多轮对话的连贯性,最终生成一份结构化的 Prompt。
准备好 Prompt 之后,系统会把它发送给大语言模型的 API(比如 DeepSeek)。大模型会开始生成回答,系统这边则以流式的方式逐段接收内容。为了保证体验,还会处理模型返回中的异常或错误,比如超时、内容为空等问题。
生成内容后,系统会把这些文本切分成一段一段,再通过 WebSocket 实时地推送给客户端。这样用户就能一边看到内容一边继续等待剩下的生成,体验上就像在“实时对话”一样流畅。客户端也会一段段渲染这些返回的内容,提升整体交互体验。
最后,为了支持后续的上下文对话,系统会把当前这轮的用户提问和模型回答完整地存进 Redis 中,更新对话历史记录。同时也会设置或刷新这个会话的过期时间,以便未来再次使用或者进行归档。
02、新建会话流程
当用户打开对话页面,准备开始一次新的交流时,客户端会先通过一个 REST 接口向服务端发送“创建会话”的请求。这时候,服务端首先会对用户的身份进行校验,确保这是一个合法登录的用户。
验证通过后,系统会为这次新对话生成一个全局唯一的 conversationId,用作这轮会话的身份标识。同时,会为这次对话准备一份空的历史记录结构,方便后续存储每轮提问和回答内容。

接下来,系统会在 Redis 里建立用户和这个会话 ID 之间的映射关系,也就是说:这个会话是属于哪个用户的。为了防止会话无限制增长,系统还会给这个会话设置一个过期时间,比如 24 小时或 7 天,超时后自动清理。
最后,系统会把新生成的 conversationId 返回给客户端,表示这轮对话已经正式创建成功,用户可以开始提问啦。
03、查询历史对话流程
当用户想要查看之前的聊天记录时,客户端会向服务端发送一个查询历史记录的 REST 请求。服务端收到请求后,第一步还是先对用户的身份进行校验,确认用户是合法且有权限访问对应数据的。
接着,系统会去 Redis 中查找当前用户对应的 conversationId,也就是这位用户当前正在使用的那一轮对话的标识。如果 Redis 中没有查到,或者这条会话已经过期失效,系统会及时返回提示信息,避免出现无效请求。
private List<Map<String, String>> getConversationHistory(String conversationId) {
String key = "conversation:" + conversationId;
String json = redisTemplate.opsForValue().get(key);
try {
if (json == null) {
logger.debug("会话 {} 没有历史记录", conversationId);
return new ArrayList<>();
}
List<Map<String, String>> history = objectMapper.readValue(json, new TypeReference<List<Map<String, String>>>() {});
logger.debug("读取到会话 {} 的 {} 条历史记录", conversationId, history.size());
return history;
} catch (JsonProcessingException e) {
logger.error("解析对话历史出错: {}, 会话ID: {}", e.getMessage(), conversationId, e);
return new ArrayList<>();
}
}
如果会话是有效的,那系统就会继续从 Redis 中读取这个会话对应的聊天历史记录,包括之前用户问过什么、系统是怎么回答的。这些内容会经过一轮格式化处理,比如按时间顺序排列、结构整理清晰,最后统一打包成接口返回数据发回给客户端,方便前端展示成对话列表,帮助用户快速回顾之前的交流内容。
四、Redis 结构设计
01、用户到会话的映射
- Key:
user:{userId}:current_conversation - Value: 当前用户的 conversationId
- TTL: 7 天
- 用途: 快速查找某个用户的当前会话 ID
- 示例:
Key: user:12345:current_conversation
Value: abcdef123456
02、对话历史记录:
- Key:
conversation:{conversationId} - Value: JSON 格式的对话历史记录数组,每个元素包含 role、content、timestamp 字段
- TTL: 7 天
- 用途: 存储用户的对话上下文,支持多轮对话,限制最多保存 20 条消息
- 示例:
{
"messages": [
{"role": "user", "content": "人工智能是什么?"},
{"role": "assistant", "content": "人工智能是模拟人类智能的技术。"}
]
}
03、历史会话列表:
- Key:
user:{userId}:conversations - Value: 用户的所有 conversationId 列表(JSON 格式)
- TTL: 7 天
- 用途: 支持用户查看历史会话记录
04、Prompt 模板缓存:
- Key:
prompt_templates:{templateName} - Value: 模板内容
- TTL: 无(或较长时间)
- 用途: 存储系统定义的 Prompt 模板
- 示例:
{
"name": "knowledge_qa",
"template": "你是派聪明,一个基于本地知识库的智能助手。\n\n当回答问题时,请遵循以下规则:\n1. 优先基于提供的参考信息回答\n2. 如果参考信息不足,清楚地表明\n3. 回答要简洁、准确、客观\n4. 引用来源时使用[文档X]格式\n\n参考信息:\n{{context}}\n\n对话历史:\n{{history}}\n\n用户问题:{{query}}\n\n请用中文回答。",
"variables": ["context", "history", "query"],
"max_tokens": 4000
}
五、接口设计
01、WebSocket 接口
- URL:
/chat/{token} - 协议: WebSocket
- 功能: 用户通过 WebSocket 发送消息,服务端逐段返回回答内容
客户端发送消息格式:
①、普通聊天消息,**格式**为纯文本字符串,比如:”沉默王二是沙雕吗?”
②、停止响应指令,格式为 JSON 对象(需要先获取停止令牌)示例:
{
"type": "stop",
"_internal_cmd_token": "WSS_STOP_CMD_123456"
}
服务端返回格式:
①、AI 响应内容块(流式),示例:
{"chunk": "沉默王二是"}
{"chunk": "一名帅气的"}
{"chunk": "技术博主。"}
②、响应完成通知,格式: JSON对象,示例:
{
"type": "completion",
"status": "finished",
"message": "响应已完成",
"timestamp": 1703123456789,
"date": "2025-05-26T09:04:16.789Z"
}
③、停止确认通知,格式: JSON对象,示例:
{
"type": "stop",
"message": "响应已停止",
"timestamp": 1703123456789,
"date": "2025-05-26T09:04:16.789Z"
}
④、错误消息,格式: JSON 对象,示例:
{
"error": "AI服务暂时不可用,请稍后重试"
}
02、获取中止回答 Token
- URL:
/api/chat/websocket-token - Method: GET
- 请求头:
Authorization: Bearer {JWT_TOKEN}
Content-Type: application/json
- Response:
{
"code": 200,
"message": "获取WebSocket停止指令Token成功",
"data": {
"cmdToken": "WSS_STOP_CMD_123456"
}
}
03、获取对话历史
- URL:
/api/v1/users/conversation - Method: GET
- 请求头:
Authorization: Bearer {JWT_TOKEN}
Content-Type: application/json
- 查询参数(可选):
start_date (string, 可选): 开始日期时间,格式支持:
● 2023-01-01T12:00:00 (完整格式)
● 2023-01-01T12:00 (不带秒)
● 2023-01-01T12 (不带分钟和秒)
● 2023-01-01 (仅日期)
end_date (string, 可选): 结束日期时间,格式同上
- Response:
{
"code": 200,
"message": "获取对话历史成功",
"data": [
{
"role": "user",
"content": "沉默王二是沙雕吗?",
"timestamp": "2025-01-26T10:30:15"
},
{
"role": "assistant",
"content": "沉默王二是一名帅气的技术博主...",
"timestamp": "2025-01-26T10:30:15"
}
]
}
- 说明: 根据用户的userId获取其当前会话的对话历史
04、获取对话历史(admin)
- URL:
/api/v1/admin/conversation - Method: GET
- 请求头:
Authorization: Bearer {JWT_TOKEN}
Content-Type: application/json
- 查询参数(可选):
userid: string (可选) - 目标用户ID(数字),不填则获取所有用户的对话历史
start_date: string (可选) - 开始日期时间,多种格式支持
end_date: string (可选) - 结束日期时间,多种格式支持
yyyy-MM-dd 例: 2025-01-26
yyyy-MM-ddTHH:mm 例: 2025-01-26T10:30
yyyy-MM-ddTHH:mm:ss 例: 2025-01-26T10:30:15
- Response:
{
"code": 200,
"message": "获取对话历史成功",
"data": [
{
"role": "user",
"content": "沉默王二是沙雕吗?",
"timestamp": "2025-01-26T10:30:15",
"username": "test"
},
{
"role": "assistant",
"content": "沉默王二是一名帅气的技术博主,编程星球已有 5 个实战项目:编程喵、技术派、mydb、PmHub 和派聪明。",
"timestamp": "2025-01-26T10:30:15",
"username": "test"
},
{
"role": "user",
"content": "沉默王二有什么特殊癖好吗?",
"timestamp": "2025-01-26T11:15:30",
"username": "admin"
},
{
"role": "assistant",
"content": "沉默王二喜欢美女,喜欢篮球、喜欢足球、喜欢技术、喜欢撒野。",
"timestamp": "2025-01-26T11:15:30",
"username": "admin"
}
]
}
六、Prompt构建与管理设计
七、小结
聊天助手模块是派聪明系统中最关键的交互中枢,它整合了 WebSocket 实时通信、Redis 对话存储、本地知识库检索以及大语言模型(如 DeepSeek)的强大能力,为用户提供了一种基于知识库的智能问答体验。
这个模块的最大特点在于,它不仅能“回答问题”,更能结合知识库内容,生成有依据、有深度的回答。这背后,得益于我们对 Prompt 构建与管理机制 的深度设计——系统内置了一整套结构化的 Prompt 模板体系,能够智能拼接检索结果、对话上下文和系统指令,从而构建出更适合语言模型理解和输出的 Prompt。
这一整套机制的存在,使得派聪明真正具备了 RAG 的完整能力:
- 回答更精准、相关性更强:通过把知识库中最相关的信息“喂”给大模型,回答内容更聚焦、更靠谱。
- 合理引用知识内容,增强可信度:回答中会引用具体文档或段落,让用户清楚回答来源,提升可信度和专业性。
- 支持多轮连续对话,理解上下文:借助 Redis 保存历史记录,系统可以持续理解用户上下文,做到“前后呼应”。
- 适配多种问题类型与场景:无论是专业知识问答、业务流程咨询,还是日常闲聊,Prompt 模板都能灵活适配。








