打造沉浸式智能AI问答助手:Vue3 + UniApp 全端实战(支持 Markdown/公式/多模态交互)

打造沉浸式智能AI问答助手:Vue3 + UniApp 全端实战(支持 Markdown/公式/多模态交互)

在移动互联网时代,用户期待的不再是一个简单的关键词匹配机器人,而是一个能理解上下文、支持富文本展示、甚至能解答数学难题的智能对话助手

本文将基于真实的 Vue3 + UniApp 项目代码,深入剖析如何构建一个企业级智能问答 H5/小程序应用。我们将重点讲解会话状态管理Markdown 与 LaTeX 公式渲染多模式推荐算法 以及附件预览下载等核心功能的实现细节。


🎯 系统核心亮点

本系统不仅是一个聊天界面,它解决的是复杂知识表达流畅交互体验的痛点:

  1. 双模式智能应答:支持"模型优化模式"(直接回答)与"知识匹配模式"(推荐相关问题),灵活适配不同业务场景。
  2. 专业内容渲染 :集成 markdown-itkatex,完美支持富文本、代码高亮及复杂的数学公式渲染。
  3. 会话生命周期管理:自动检测会话超时,支持本地缓存恢复断点续聊,确保用户体验不中断。
  4. 多模态交互:支持图文混排、附件在线预览/下载、一键复制、满意度评价(已解决/未解决)等丰富操作。

🏗️ 核心模块深度解析

1. 沉浸式对话流与状态机

对话列表采用经典的"左问右答"布局,通过时间轴串联整个会话过程。系统内置严谨的状态机,处理新建会话、追加提问、超时结束等逻辑。

💾 会话持久化与断点续聊

利用 uni.setStorageSync 缓存 sessionId,用户刷新页面或重新进入时,自动恢复上次会话上下文。

typescript 复制代码
const CACHE_KEY = 'intelligent_qa_session_id';
const CACHE_EXPIRE_TIME = 60 * 60 * 1000; // 1 小时过期

// 从本地缓存获取 sessionId
const getSessionFromCache = (): number | null => {
  try {
    const cacheData = uni.getStorageSync(CACHE_KEY);
    if (!cacheData) return null;
    const parsed = JSON.parse(cacheData);
    // 检查缓存是否过期
    if (Date.now() - parsed.timestamp > CACHE_EXPIRE_TIME) {
      uni.removeStorageSync(CACHE_KEY);
      return null;
    }
    return parsed.sessionId;
  } catch (error) {
    return null;
  }
};

// 发送消息时自动创建或复用会话
const handleSend = async () => {
  if (data.sessionId) {
    // 复用现有会话
    await AddSessionQARecord({ question: data.message, sessionId: data.sessionId });
  } else {
    // 创建新会话
    const res = await AddSessionInfo({ question: data.message });
    data.sessionId = res.data.sessionId;
    saveSessionToCache(res.data.sessionId); // 缓存 ID
    
    // 启动定时器轮询会话状态(判断是否超时)
    addSessionTimer = setInterval(findSessionDetailById, 30000);
  }
  await findSessionQARecordList(); // 刷新列表并滚动到底部
};

⏳ 超时自动结束

后端返回 endTime 后,前端停止轮询并显示"会话已结束"提示,禁止继续发送消息。

vue 复制代码
<template>
  <div v-if="data.sessionEndTime" class="question-answer-end-list">
    <div class="question-answer-end-list-title">
      客户会话超时,本次会话已经结束 {{ moment(data.sessionEndTime).calendar() }}
    </div>
  </div>
  
  <!-- 发送前校验 -->
  <div @click="handleRecommendClick(answer)">
    <!-- 若已超时,点击推荐问题也无效 -->
    <script>
    if(data.sessionEndTime){
        message.warning('客户会话超时,本次会话已经结束');
        return;
    }
    </script>
  </div>
</template>

2. 强大的内容渲染引擎 (Markdown + LaTeX)

针对教育、科研等场景,系统必须支持复杂的数学公式和富文本。我们使用 markdown-it 配合 markdown-it-katex 插件实现。

typescript 复制代码
import MarkdownIt from 'markdown-it';
import markdownItKatex from 'markdown-it-katex';

// 初始化渲染器
const md = new MarkdownIt();
md.use(markdownItKatex); // 启用 LaTeX 支持

// 渲染函数
const renderedMarkdown = (item: any) => {
  const content = item.answer; 
  // 移除模型模式下的特殊标记(可选)
  const cleanContent = data.systemSessionModel === '1' ? content.replace(/<[^>]+>/g, '') : content;
  return md.render(cleanContent);
};

UI 展示

  • 通过 v-html 将渲染后的 HTML 插入页面。
  • 引入 katex.min.css 确保公式样式正确。
  • 支持行内公式 $E=mc^2$ 和块级公式 $$...$$
vue 复制代码
<div class="question-answer-content-item-content-text">
  <!-- 模型优化模式:直接渲染 answer -->
  <span v-if="data.systemSessionModel==='1'" v-html="renderedMarkdown(item)"></span>
  
  <!-- 知识匹配模式:渲染第一个匹配知识的答案 -->
  <span v-else-if="item?.answerList?.length===1" v-html="renderedMarkdownHtml(item.answerList[0])"></span>
</div>

3. 多模式智能应答策略

系统支持两种核心应答模式,通过后端配置动态切换:

模式一:模型优化模式 (Direct Answer)

AI 直接生成最终答案,适合通用问答。

  • 逻辑 :直接渲染 item.answer 字段。
  • 特点:响应快,无需用户二次选择。

🔍 模式二:知识匹配模式 (Recommendation)

当问题模糊或存在多个相关知识时,系统返回候选列表,引导用户精准提问。

vue 复制代码
<!-- 推荐列表展示 -->
<div class="question-answer-recommend-section" v-if="data.systemSessionModel==='2' && item.answerList.length > 1">
  <div class="question-answer-recommend-title">您是否要咨询以下问题呢:</div>
  <div class="question-answer-recommend-list">
    <div 
      v-for="(answer, idx) in item.answerList" 
      :key="answer.knowledgeId" 
      class="question-answer-recommend-item" 
      @click="handleRecommendClick(answer)"
    >
      {{ answer.question }}
    </div>
  </div>
</div>

<!-- 无匹配结果兜底 -->
<div v-else-if="data.systemSessionModel==='2' && item.answerList.length === 0">
  <div class="question-answer-recommend-title">
    很抱歉,目前我没有这个问题的相关答案...
  </div>
</div>

交互逻辑

点击推荐问题后,自动将该问题填入输入框并模拟发送 (simulateAddSessionQARecord),形成闭环。


4. 附件管理与多媒体交互

支持在答案中携带附件(PDF、Word、图片等),提供预览和下载功能。

vue 复制代码
<div class="question-answer-attachment-section" v-if="item.answerList[0]?.annexList?.length > 0">
  <div class="question-answer-attachment-header">
    <span>附件</span><span class="question-answer-attachment-line"></span>
  </div>
  <div class="question-answer-attachment-list">
    <div v-for="annex in item.answerList[0].annexList" :key="annex.id" class="question-answer-attachment-item">
      <img src="@/static/images/common-type-file.svg" />
      <!-- 文件名截断显示 -->
      <span class="question-answer-attachment-name" @click="handlePreview(annex)">
        {{ annex.name.length > 40 ? annex.name.substring(0, 40) + '...' : annex.name }}
      </span>
      <!-- 下载按钮 -->
      <img src="@/static/images/Download.svg" @click.stop="handleDownload(annex)" />
    </div>
  </div>
</div>

核心方法

  • 预览 :拼接 onlinePreviewPath + Base64 编码的文件路径,在新窗口打开。
  • 下载 :使用 file-saver 库,通过 fetch 获取 Blob 流并触发浏览器下载。
typescript 复制代码
const handleDownload = async (item: any) => {
  const prefixPath = data.prefixPath || '';
  try {
    const response = await fetch(`${prefixPath}${item.path}`);
    const blob = await response.blob();
    saveAs(blob, item.name); // 触发下载
  } catch (error) {
    // 降级处理:直接跳转链接
    window.open(`${prefixPath}${item.path}`);
  }
};

5. 用户反馈与辅助功能

  • 满意度评价:每条回答下方提供"已解决"/"未解决"按钮,实时上报反馈数据,用于优化知识库。
  • 一键复制:支持复制纯文本答案,方便用户留存。
  • 消息提醒:顶部导航栏集成 Badge 红点,提示有待处理的留言回复,点击直达留言页。
typescript 复制代码
// 评价逻辑
const handleResolve = async (item: any) => {
  item.evaluate = item.evaluate === 1 ? null : 1; // 切换状态
  await EvaluateSessionQARecord({
    sessionId: data.sessionId,
    qaRecordId: item.id,
    evaluate: item.evaluate,
  });
  message.success('感谢您的反馈!');
};

💡 最佳实践与细节优化

  1. 平滑滚动 :每次新消息加载后,使用 scrollIntoView({ behavior: 'smooth' }) 自动滚动到底部,提升阅读体验。
  2. 防抖与加载态 :发送消息时显示 uni.showLoading,防止重复提交;输入框限制 500 字并实时提示。
  3. 响应式布局 :适配 H5 全屏模式与弹窗模式 (isFullScreen / isModal),动态计算容器高度。
  4. 安全过滤:在渲染 Markdown 前,根据模式选择性过滤 HTML 标签,防止 XSS 攻击(视具体需求而定)。
  5. 视觉分层
    • 用户消息:蓝色气泡,右对齐。
    • 系统消息:灰色背景,左对齐,带圆角。
    • 推荐问题:可点击链接样式,引导性强。

📊 效果总结

  • ** 智能灵活**:双模式切换,既能直接作答又能引导探索,适应不同复杂度场景。
  • 📐 专业呈现:完美支持 LaTeX 公式与富文本,满足学术、技术类问答需求。
  • 🔄 体验连贯:会话缓存、超时控制、自动滚动,打造如原生 App 般的流畅体验。
  • 📎 功能完备:附件预览下载、满意度评价、消息通知,覆盖用户全链路需求。

✅ 结语

这套智能问答系统不仅实现了基础的对话功能,更在内容渲染能力交互逻辑严密性用户反馈闭环 上做了深度打磨。它适用于高校教务咨询、企业技术支持、图书馆参考咨询等多种场景,是构建现代化智能客服体系的优秀范本。

💡 未来展望:后续可引入语音输入/输出、多轮对话上下文记忆、以及基于用户画像的个性化推荐,让助手更加"懂你"。

技术栈 :Vue3 | UniApp | TypeScript | Markdown-it | Katex | File-saver
适用场景:智能客服 | 教育问答 | 技术支持 | 知识库检索

如果你觉得这篇文章对你有帮助,欢迎点赞、收藏!有任何关于 Markdown 渲染优化或会话状态管理的问题,欢迎在评论区交流~