当前位置: 首页 > news >正文

5、对话接口与前端交互文档

1. 接口概览

项目说明
路径POST /chat/send
Content-Typeapplication/x-www-form-urlencoded
响应类型text/event-stream(SSE 事件流)
入口[ChatController.java:L141](file:///Users/yangguojun01/IdeaProjects/InfoHelper/src/main/java/com/yang/llm/infohelper/chat/controller/ChatController.java#L141)
核心逻辑[ChatApplicationService.chat()](file:///Users/yangguojun01/IdeaProjects/InfoHelper/src/main/java/com/yang/llm/infohelper/chat/service/ChatApplicationService.java#L316)
前端页面[chat.html](file:///Users/yangguojun01/IdeaProjects/InfoHelper/src/main/resources/static/chat.html)

2. 请求参数

参数类型必填说明
userIdString用户唯一标识,如"test_user_001"
contentString用户问题文本,如"ods库的user_info表有哪些字段?"
conversationIdString会话ID,不传则自动创建新会话;传入则继续保持多轮对话

请求示例

# 新会话 POST /chat/send?userId=test_user_001&content=ods库的user_info表有哪些字段? # 继续对话 POST /chat/send?userId=test_user_001&content=那这个表有哪些字段类型?&conversationId=abc123-def456

3. SSE 响应事件类型

后端返回的是一个Flux<String>,被 Spring WebFlux 自动序列化为 SSE 格式(每行data:xxx,以空行分隔)。前端解析出 5 类事件:

3.1 进度通知[PROGRESS]:xxx

消息内容触发时机说明
正在识别您的意图...意图识别开始调用 LLM 判断是否数据治理领域
正在优化您的问题...QueryTransformer 开始将用户问题改写为更精确的检索查询
正在路由您的问题...QueryRouter 开始决定走哪些检索器
正在检索知识库内容...每个 ContentRetriever 开始4路检索器(ES KNN / ES BM25 / SQL / Neo4j)可多次触发
正在排序筛选结果...ContentAggregator 开始融合排序多路检索结果
正在生成回答...LLM 流式生成开始进入最终回答生成阶段

3.2 引用资料[REFERENCE]:json

[{"documentTitle":"数据标准规范_v2.0","url":"https://...","similarityScore":0.95,"chunkContent":"..."}]

前端渲染为"参考来源"卡片,每条引用包含:

  • 文档标题(可点击跳转)
  • 相似度分数
  • 去重处理(按documentTitle + url去重)

3.3 警告消息[WARN]:xxx

[WARN]:未找到相关参考信息,以下回答基于通用知识生成。

前端渲染为带 ⚠️ 图标的黄色警告条。

3.4 流式内容 Token

data:您好,ods库的 data:user_info表包含以下字段: data: data:1. **user_id** (VARCHAR) - 用户ID data:2. **user_name** (VARCHAR) - 用户姓名

LLM 逐 token 输出的文本内容,前端累积拼接后实时按 Markdown 渲染。

3.5 结束标记[DONE]:conversationId

data:[DONE]:abc123-def456test_user_001
  • 前端收到后更新currentConversationId,下次请求自动带上实现多轮对话
  • 刷新左侧会话列表
  • 停止 loading 状态

4. 前端交互流程

4.1 整体流程

用户输入问题 │ ├── 1. 前端渲染用户消息气泡(👤 头像) ├── 2. 创建空的 AI 消息气泡(🤖 头像 + 打字动画) ├── 3. 发送 fetch POST 请求到 /chat/send ├── 4. 读取 response.body (ReadableStream) ├── 5. 按 SSE 双空行分隔事件 ├── 6. 逐事件解析并渲染 │ ├── [PROGRESS]:xxx → 渲染进度步骤列表(✓ / spinner) │ ├── [REFERENCE]:json → 渲染参考来源卡片 │ ├── [WARN]:xxx → 渲染警告条 │ ├── 普通文本 → 累积拼接 + Markdown 实时渲染 │ └── [DONE]:xxx → 更新会话ID,刷新列表 └── 7. finally:移除打字动画,恢复按钮状态

4.2 关键代码片段

// 发送消息asyncfunctionsendMessage(){constparams=newURLSearchParams();params.append('userId',currentUserId);params.append('content',content);if(currentConversationId){params.append('conversationId',currentConversationId);}constresponse=awaitfetch(`/chat/send?${params.toString()}`,{method:'POST'});constreader=response.body.getReader();constdecoder=newTextDecoder();letbuffer='';while(true){const{done,value}=awaitreader.read();if(done)break;buffer+=decoder.decode(value,{stream:true});// SSE 事件以空行分隔consteventSep=/\r?\n\r?\n/g;letm,lastIndex=0;while((m=eventSep.exec(buffer))!==null){processEvent(buffer.substring(lastIndex,m.index));lastIndex=m.index+m[0].length;}buffer=buffer.substring(lastIndex);}}

4.3 事件解析

constprocessEvent=(eventBlock)=>{// 提取 data: 行,多条用 \n 拼接constdata=dataLines.join('\n');if(data.startsWith('[DONE]:')){/* 更新会话ID */}if(data.startsWith('[PROGRESS]:')){/* 更新进度列表 */}if(data.startsWith('[REFERENCE]:')){/* 解析JSON + 渲染参考来源 */}if(data.startsWith('[WARN]:')){/* 渲染警告消息 */}// 否则 → 普通文本,累积 + Markdown 渲染};

5. 进度步骤渲染

5.1 状态管理

前端维护一个progressSteps数组,每个步骤有两种状态:

状态图标说明
active🔵 spinner 动画当前正在执行的步骤
done✓ 绿色勾已完成的步骤

5.2 渲染逻辑

收到 [PROGRESS]:正在优化您的问题... → 上一步标记为 done ✓ → 新步骤添加为 active(spinner) 收到首个内容 token → 最后一步标记为 done ✓ → 进度列表保持在消息正文上方

5.3 渲染位置

进度列表始终插入在.message-text(正文)之前,保证:

┌─ AI 消息气泡 ─────────────────┐ │ ✓ 正在识别您的意图... │ │ ✓ 正在优化您的问题... │ │ ✓ 正在路由您的问题... │ │ ✓ 正在检索知识库内容... │ │ ✓ 正在排序筛选结果... │ │ ✓ 正在生成回答... │ │ ────────────────────────────── │ │ 您好,ods库的user_info表包含... │ ← 正文在进度下方 │ 1. user_id (VARCHAR) ... │ │ 2. user_name (VARCHAR) ... │ │ ────────────────────────────── │ │ 📎 参考来源: │ │ [1] 数据标准规范_v2.0 │ │ [2] 数据资产目录 │ └────────────────────────────────┘

6. 参考来源渲染

functionbuildReferencesHtml(references){// 1. 按 documentTitle + url 去重// 2. 渲染为链接列表return`<div class="message-references"> <div class="references-label">参考来源:</div>${references.map((ref,idx)=>`<a href="${ref.url}" target="_blank" class="reference-item"> <span class="reference-index">[${idx+1}]</span> <span class="reference-title">${ref.documentTitle}</span> </a>`)}</div>`;}

字段说明:

字段类型说明
documentTitleString文档标题
urlString文档链接
similarityScoreNumber向量相似度(0-1)
chunkContentString匹配到的文档片段文本

7. Markdown 渲染与安全

前端使用三层库处理 AI 回答的 Markdown 内容:

作用
marked将 Markdown 解析为 HTML
DOMPurify过滤 XSS 攻击,白名单式净化 HTML
highlight.js代码块语法高亮
functionrenderMarkdown(text){constrawHtml=marked.parse(text||'');returnDOMPurify.sanitize(rawHtml,{ALLOWED_TAGS:['p','br','strong','em','code','pre','h1','h2','h3','h4','h5','h6','ul','ol','li','a','img','table','thead','tbody','tr','th','td','blockquote','hr','span','div'],ALLOWED_ATTR:['href','src','alt','class','target','rel']});}

8. 多轮对话支持

第一轮: POST /chat/send?userId=u1&content=ods库有哪些表? → SSE: ... [DONE]:abc123-u1 第二轮(前端自动带上): POST /chat/send?userId=u1&content=user_info表有哪些字段?&conversationId=abc123-u1 → SSE: ... [DONE]:abc123-u1
  • conversationId由后端首次创建,通过[DONE]:xxx返回给前端
  • 前端存储在currentConversationId变量中,后续请求自动附带
  • 后端通过conversationId关联 Redis 中的对话记忆,实现上下文感知

9. 错误处理

9.1 后端异常

// 全局异常兜底:SSE 响应中无法返回 JSON 错误体,转为文本消息.onErrorResume(e->{log.error("流式对话异常: conversationId={}",finalConversationId,e);returnMono.just("系统处理您的问题时遇到异常,请稍后重试。");})

9.2 前端异常

}catch(error){console.error('发送消息失败:',error);updateMessageContent(aiMessageElement,'发送失败: '+error.message);}finally{isStreaming=false;sendBtn.disabled=false;removeTypingIndicator(aiMessageElement);}

9.3 防护措施

  • 按钮防抖isStreaming = true时禁用发送按钮
  • 空内容保护:未收到流式内容时显示"对话已创建,请继续输入您的问题。"
  • 非 SSE 兜底:兼容直接返回的裸文本(如[DONE]:xxx不带data:前缀)

10. 完整 SSE 数据流示例

输入:userId=test_user_001, content="ods库的user_info表有哪些字段?" data:[PROGRESS]:正在识别您的意图... data:[PROGRESS]:正在优化您的问题... data:[PROGRESS]:正在路由您的问题... data:[PROGRESS]:正在检索知识库内容... data:[PROGRESS]:正在排序筛选结果... data:[PROGRESS]:正在生成回答... data:您好,ods库的 data:user_info表包含以下字段: data: data:1. **user_id** (VARCHAR) - 用户ID,主键 data:2. **user_name** (VARCHAR) - 用户姓名 data:3. **email** (VARCHAR) - 邮箱地址 data:4. **create_time** (DATETIME) - 创建时间 data: data:如需了解更多字段详情,请参考相关文档。 data:[REFERENCE]:[{"documentTitle":"数据标准规范_v2.0","url":"https://...","similarityScore":0.95}] data:[DONE]:abc123-def456test_user_001
http://www.jsqmd.com/news/1247981/

相关文章:

  • 基于CNN的车牌识别系统设计与工程实践
  • AI行业人才争夺战:静默招聘与复合型人才需求
  • WAIC 2026 产业观察:具身智能落地提速,国产实时操作系统筑牢机器人底层底座
  • 机械设计中实体分割的核心技术与实践应用
  • 精密激光焊接设备怎么选?先给你的焊缝分类
  • 小安派工:售楼部弱电工程施工,隐蔽工程处理技巧
  • C++网络编程实战:从Socket封装到事件驱动模型的设计与实现
  • 别光看跑分!用Iperf实测OpenWrt、pfSense、iKuai、RouterOS四大软路由,谁才是家庭网络的真·王者?
  • 微软用户反馈机制解析:从封闭开发到开放共创
  • Transformer架构解析:编码器与解码器工作原理
  • 数据工程中的标记化指令解析与静默任务调度实践
  • 市面上质量比较好的铝镁锰板支架厂家推荐:兰陵县铭达金属配件 - 大风02
  • Tiva TM4C123x ROM API实战:ADC、比较器与AES加密应用详解
  • Oracle数据库连接与查询优化实战指南
  • 2026年手机切膜机口碑推荐:门店经营者与创业者选购指南 - 资讯报道
  • 没技术背景,怎么转 AI 产品经理
  • HarmonyOS开发实战:小分享-从零到一回顾——小分享 App 架构演进与最佳实践总结
  • AI系统安全与伦理:构建健壮可靠的技术框架
  • UE5蓝图实现GPU Instancing:动态海量物体渲染与性能优化指南
  • DOSBox-X配置指南:完美运行经典Windows游戏
  • AI在软件项目风险管理中的应用与实践
  • 音乐MV制作全流程解析:从音频处理到视频合成的技术实践
  • Python毕设项目:基于 Python 的影视大数据分析推荐系统 电影收藏评分与个性化推送系统 (源码+文档,讲解、调试运行,定制等)
  • Vertex AI与LLM集成开发实战指南
  • 聚焦规模化创作,热门的AI漫剧创作工具测评,适配短剧出海与批量创作 - 资讯报道
  • 2026 年小程序生态新趋势下,开发公司选型的 6 个核心标准
  • 深入解析ARM Cortex-M4核心外设:SysTick、NVIC、MPU与FPU实战指南
  • 云原生一体化数仓:架构革新与实战优化
  • 测试文章 001634 - 请忽略
  • 安阳北关区甲醛检测治理怎么选靠谱机构?实地对比多家后优选森家环保 - 专注室内空气检测治理