前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >手把手教你从0到1集成混元AI问答客服系统

手把手教你从0到1集成混元AI问答客服系统

原创
作者头像
fanstuck
修改2024-10-23 10:25:39
3964
修改2024-10-23 10:25:39
举报
文章被收录于专栏:大模型快速上手实践

前言

之前写过一篇《如何优雅的在页面上嵌入AI-Agent人工智能》,本篇文章很多基础架构都是集成于上篇文章,也是对上篇文章继续深化挖掘,从更基础的开始搭建,做到从设计到实现再到代码层业务层的实践运用。本篇文章集成演示系统设置为网页端,对于交互界面本篇文章UI前端也有设计,很多灵活设计的内容不必严格按照本篇文章代码效果编写,按照生产规则设计即可。如果本篇文章有帮助请不吝支持!

项目顶层架构

我将项目模块设计为四块,涉及了AI通信、用户请求的全流程和系统反馈模块的功能。旨在通过自然语言处理与外部数据集成,自动高效地回答用户的查询,同时根据用户反馈不断优化自身,以提供准确、智能和个性化的客户服务体验。

1. 用户信息交互模块

  • 用户请求处理:
    • 负责接受用户的输入信息(如文本或语音请求),如果语音开发难度大可以采用第三方API来解析,成本不大。
    • 包括输入的格式化和预处理,比如拼写检查、自然语言理解(NLU)等步骤,以确保数据可以被AI模型有效处理,不过现在很多AI自带有拼写改正,依据使用的模型来调整是否使用该功能。
  • 消息处理:
    • 分析用户请求的内容,确定用户的意图(如查询信息、请求帮助、反馈问题)。
    • 使用意图识别模型来分辨用户的实际需求。
    • 消息处理还包括通过知识库(如常见问题解答或历史聊天记录)获取相关信息,确保响应的一致性。
  • 渲染与反馈:
    • 生成面向用户的最终回复,确保响应符合预期,包含必要的上下文信息。
    • 渲染可以包括格式化文本、表格、图片等,以便用户更容易理解。
    • 系统可向用户提供反馈的选项,确认他们是否满意以调整交互策略。

2. AI通信交互模块

  • AI响应生成:
    • 使用AI模型API(例如阿里通义,暗面,文心或者元宝)对用户请求进行分析并生成自然语言回复。
    • 响应生成涉及模型推理阶段,可能还包括上下文维护,以保证多轮对话的一致性。
    • 若需要复杂回答(如技术问题或多方面内容),还可能需要调用多个模型或组合模型。
  • API接口集成:
    • 与外部系统集成,以从其他数据源(如CRM系统、数据库等)获取信息,用于丰富AI响应。
    • 通过API对接和调用外部的服务(如天气、物流状态等),为用户提供实时更新的数据。

3. 信息传输模块

  • 整合响应:
    • 将AI生成的响应与从其他系统获取的信息进行整合,使得最终的回复对用户更具参考性和实际价值。
    • 整合过程中,需要对信息进行合理的编排和逻辑连接,以确保最终输出自然流畅。
    • 此模块还可能包含某种业务逻辑,用于决定如何组合数据或优先提供哪些信息。
  • 信息传输:
    • 将整合好的信息通过相应的渠道传送给用户(如Web前端、APP、微信等)。
    • 该模块还需要负责传输状态的确认,确保信息成功送达,且在失败时提供重传机制。
    • 支持多通道交互(文本、图片、表格),适配不同的用户设备和界面要求。

4. 反馈机制模块

  • 用户满意度反馈:
    • 向用户询问他们是否对生成的响应感到满意,以便收集有价值的用户反馈。
  • 模型优化和系统调整:
    • 收集到的用户反馈可以进一步用于模型优化,例如,通过标注满意和不满意的回答以继续训练和改进AI模型。
    • 系统可以根据反馈内容调整问答策略和优化对话流程,例如识别常见用户问题,提前准备更多答案模板。
  • 异常处理和升级机制:
    • 针对用户的负面反馈,启动人工干预流程,或将请求升级到人工客服,保证用户问题得到及时解决。
    • 系统可以根据历史数据分析出需要人工干预的场景,优化工作流,以减少重复性问题并提高自动回复率。

技术选型

前端我们采用VUE3来搭建对话界面,快捷方便。后端采用Spring Boot:作为项目的核心框架,MyBatis-Plus用于数据库持久化操作,简化了 MyBatis 的使用,并提供了基本的 CRUD 方法。MySQL: 作为数据库,用于存储 AI 会话数据。我这里调用的是阿里通义千问的模型,当然每个厂商的AI SDK都大差不差,调用规则基本都是一致的,通过查阅SDK的返回参数就能很轻松的调用。

设计时序图

客户点击智能窗口开始会话,前端记录窗口会话ID,与客户提问Prompt一并返回后端,后端请求阿里通义接口获取回答和问答ID,后端再将获取到的text和本次会话request_id一并返回给前端,若用户对给出的回答点赞,则返回单次回答的request_id和evaluate状态,如果满意则evaluate返回1,不满意evaluate返回2。

前端UI设计

前端UI可借鉴的模板有很多,比如ChatGPT、文心一言等,或者走比较简约的客服弹窗:

比如类似微信界面的对话框,是最容易让客户明白使用的。

前端实现

实现一个简单的对话页面:

代码语言:javascript
复制
<template>
  <div class="chat-window">
    <div class="chat-header">Fanstuck</div> 
    <div class="messages">
      <div v-if="isLoading" class="load">
        <hr/><hr/><hr/><hr/>
      </div>
      <div v-for="(message, index) in messages" :key="index" class="message" :class="{ 'user': message.sender === 'user', 'bot': message.sender === 'bot' }">
        <div class="avatar">
          <img v-if="message.sender === 'user'" :src="userAvatar" alt="User">
          <img v-else :src="botAvatar" alt="Bot">
        </div>
        <div v-if="message.sender === 'bot' && message.isTyping" class="typing" :ref="'typeitContainer' + index"></div>
        <div v-else class="message-content">{{ message.content }}</div>
      </div>
    </div>
    <div class="input-area">
      <input v-model="newMessage" @keyup.enter="sendMessage" placeholder="Type a message..." class="input-field" :disabled="isSending"/>
      <button @click="sendMessage" class="send-button" :disabled="isSending || !newMessage.trim()">发送</button>
    </div>
  </div>
</template>
​

聊天窗口结构

  • 消息展示区域:循环遍历messages 数组,显示每条消息。
    • 加载动画:当isLoadingtrue时,显示加载动画。
    • 消息内容:
      • 根据message.sender区分用户和机器人消息,应用不同的样式。
      • 显示对应的头像(userAvatarbotAvatar)。
      • 如果机器人正在输入(isTypingtrue),显示打字动画容器,否则显示消息内容。
  • 输入区域:包含输入框和发送按钮。
    • 输入框绑定newMessage,在按下回车键时调用sendMessage方法,禁用状态取决于isSending
    • 发送按钮在点击时调用sendMessage方法,禁用条件为isSendingnewMessage为空。

我们需要和后端进行通信还需要实现打字机效果展示,可以通过引入的库

  • TypeIt:用于实现打字机效果。
  • axios:用于处理HTTP请求。

方法

  • startChat():向后端发送请求,启动新的聊天会话。
    • 成功后保存chatCode
    • 如果失败,向messages添加一条错误信息。
  • sendMessage():处理发送消息的逻辑。
    • 检查newMessage是否为空。
    • 更新isSendingisLoading状态。
    • 将用户消息添加到messages
    • 如果chatCode为空,调用startChat()获取。
    • 发送用户输入到后端,获取机器人回复。
    • 将机器人回复添加到messages,并设置isTypingtrue
    • 使用TypeIt在指定的容器中显示打字机效果。
    • 处理请求失败的情况。
代码语言:javascript
复制
methods: {
    async startChat(){
      try{
        const response = await axios.post('http://localhost:8080/api/chats/start');
        this.chatCode = response.data; // 将后端返回的 chatCode 保存在前端
        console.log('Chat started with code:', this.chatCode);
      } catch (error) {
        console.error('Failed to start chat:', error);
        this.messages.push({ sender: 'bot', content: '无法启动对话。请稍后再试。' });
      }
    },
​
    async sendMessage() {
      if (!this.newMessage.trim()) return; // 确保不发送空消息
      this.isSending = true; // 开始发送,禁用发送按钮
      this.isLoading = true;
​
      // 添加用户消息到对话
      this.messages.push({ sender: 'user', content: this.newMessage, isTyping: false });
      
      // 如果 chatCode 为空,先调用 startChat 获取
      if (!this.chatCode) {
              await this.startChat();
              if (!this.chatCode) {
                this.isSending = false;
                this.isLoading = false;
                return; // 如果获取 chatCode 失败,停止发送
              }
            }
​
      try {
      // 模拟异步获取机器人回复
      setTimeout(async () => {
        // 向Spring Boot后端发送POST请求
        const response = await axios.post(`http://localhost:8080/api/chats/${this.chatCode}/ask`, {
          prompt: this.newMessage // 使用POST请求并传递JSON格式的数据
        });
​
        const botMessageContent = response.data.reply; // 根据后端响应的结构获取消息内容
        
        this.messages.push({ sender: 'bot', content: botMessageContent, isTyping: true });
​
        setTimeout(() => {
          const botMessageIndex = this.messages.length -1 ;
          const container = this.$refs[`typeitContainer${botMessageIndex}`];
          if (container) {
            new TypeIt(container[0], {
              strings: [botMessageContent],
              speed: 50,
              afterComplete: (instance) => {
                this.messages[botMessageIndex].isTyping = false;
                instance.destroy(); // 强制更新以显示完整消息
              }
            }).go();
          }
        },0);
​
        this.isLoading = false;
        // 清空输入框
        this.newMessage = '';
        this.isSending = false; // 结束发送,允许再次发送
      }, 1000); // 假设1秒后收到回复
    } catch (error) {
      console.error('获取回复失败:', error);
      // 处理错误情况,例如添加一条错误消息到对话
      this.messages.push({ sender: 'bot', content: '抱歉,无法获取回复。' });
    }

后端实现

后端在本人的上一篇博文有比较详细的模块划分和讲解,系统的后端设计可以划分为两个主要模块,分别处理Web端数据和AI交互:

Web数据处理模块

  • 负责处理来自前端的用户输入数据,包含敏感词检测、不符合对话逻辑的过滤等业务逻辑。
  • 将处理后的干净数据传递给AI交互模块。
  • 还需要实现数据落库,记录每次用户对话的交互数据,偏重业务信息,不必存储AI的技术细节,如tokens或内部状态,仅需记录用户交互的表层数据,如对返回文本的点赞、评分等。

AI数据交互模块

  • 处理与AI模型的交互,将Web数据处理模块传递的数据提交给AI SDK接口,获取生成的响应数据。
  • 这部分的交互数据需要记录下来,以便后续对不同AI的反馈效果进行比较,或者实现多模态大模型的应用。
  • 尽可能地保持模块低耦合,划分清晰的层级,以便于后续维护和扩展。
  • 同时,这个模块还需记录有助于调优AI性能的数据,如每次请求的tokens数量、响应时间等指标。

这里我们用混元大模型设计API接口,首先打开腾讯云混元创建对应应用:

发布之后我们可以得到对应的APIKey

访问密钥管理创建密钥,和API组合一起访问就可以进行后端AI通信了。

API实现通信调用模版可以参考:

代码语言:javascript
复制
Slf4j
@Service
public class TencentyiServicelmpl implements TencentiService{
    @Resource
    private TencentProperties aliyunProperties;
    @Autowired
    private AiChatTencentRespRepository aiChatTencentRespRepository;
    @Override
    public TencentChatRespDto chat(TencentChatReqDto dto) {
        try {
            // 构建API调用参数
            ApplicationParam param = ApplicationParam.builder()
                    .apiKey(TencentProperties.getTongyi().getApiKey())
                    .appId(TencentProperties.getTongyi().getChatAppId())
                    .prompt(dto.getPrompt())
                    .build();
            Application application = new Application();
            ApplicationResult result = application.call(param);
            // 创建返回对象
            AiResponse response = new AiResponse(result.getRequestId(), dto.getPrompt(), result.getOutput().getText(), result.getOutput().getFinishReason(), result.getUsage());
            // 将 AiResponse 转换为实体类 AiChatTongyiRespPo
            AiChatTencentRespPo po = AiResponseToPoConverter.convert(response);
            aiChatTencentRespRepository.saveAiResponse(po);
            return new TencentChatRespDto().setReply(result.getOutput().getText());
​
        }catch (Exception e){
            log.error("调用大模型未知错误", e);
            throw new RuntimeException("调用失败", e);
        }
    }
}

同时返回的数据信息需要我们建表保存,用于后续的大模型召回统计测试:

其中request_id对应的是一条回复通信的唯一识别,tokens对应的是输入和输出的字节数,帮助我们优化模型和prompt节省经费。后端的RESTful API可以设计三个:

开始对话 (/start)

  • POST /start 路由用于开始一个新的聊天会话,调用 askService.startChat() 启动一个新的对话并返回一个聊天编号,方便后续的提问和互动。

提问 (/{chatCode}/ask)

  • POST /{chatCode}/ask 路由允许用户在特定的聊天会话中向AI提问。
  • 该方法接收聊天编号和用户提交的表单数据 (AiChatForm),调用 askService.ask(chatCode, form.getPrompt()) 生成AI的回答,并通过 assemble() 方法将 AiChatAsk 对象转换为返回给用户的 AskReplyVo 视图对象。

评价 (/{chatCode}/asks/{askCode}/evaluate)

  • PUT /{chatCode}/asks/{askCode}/evaluate 路由用于对AI的回答进行评价。
  • 通过聊天编号和问答编号定位到特定的对话,调用 askService.evaluate() 方法将用户的评价(如满意度)记录下来。
  • 如果找不到对应的问答数据,则抛出异常 ServiceException("问答不存在")

同时新建一张表保留全部对话数据,用于后续业务模型的调优:

需要注意设计的点是chat_code记录的是同一对话框编号,可以标记为同一客户标识,就可以追溯上下文问题关联。后续客户对评论的点赞是后触发操作,通过前端返回ask_code和evaluate,更新这张mysql表,起到对评论的点赞记录。

代码语言:javascript
复制
public class AiChatAskServiceImpl implements AiChatAskService {
    @Resource
    private AiChatAskRepository askRepository;
    @Resource
    private AiyunTongyiService tongyiService;
​
    @Override
    public String startChat() {
        return IdUtil.fastSimpleUUID();
    }
​
    @Override
    public AiChatAsk ask(String chatCode, String prompt) {
        AiChatAsk ask = new AiChatAsk(new AiChatAskInfo(chatCode, prompt));
        ask.start();
​
        TongyiChatRespDto resp = tongyiService.chat(new TongyiChatReqDto()
                .setAskCode(ask.getAskInfo().getAskCode())
                .setPrompt(prompt));
        ask.reply(resp.getReply());
​
        askRepository.save(ask);
        return ask;
    }
    @Override
    public void evaluate(AiChatAsk ask, Integer evaluate) {
        ask.evaluate(evaluate);
        askRepository.saveOnEvaluate(ask);
    }
​
}

参照以上功能设计实现即可,接口涵盖了AI聊天会话的基本功能:启动会话、向AI提问、以及对AI回答的满意度评价,同时设计了一个测试接口用于验证系统是否正常运行。源代码将上传至Github有需要的同学可以直接看源码浏览,代码逻辑简单基本上没有什么很复杂的设计,后续可以集成多模态多功能作为基底使用。

总结

通过本篇文章,我们从基础架构的设计到前后端的具体实现,系统性地展示了如何集成一个AI问答客服系统。从最初的项目顶层架构和技术选型,到详细的设计时序图,再到具体的前端UI设计和实现,以及后端的逻辑和代码演示,逐步完成了一个功能齐全、模块清晰的AI问答客服系统。

在项目构建的过程中,强调了系统的低耦合性和模块化设计,以便于后续的维护和扩展。前端和后端各自承担相应的职责,前端注重用户体验和交互设计,后端则注重业务逻辑的处理和与AI的高效交互,确保系统既能为用户提供流畅的使用体验,也能快速处理用户的请求并返回有价值的回答。希望这篇文章能够帮助大家了解AI问答客服系统的构建流程,并为实际开发提供有效的参考。感谢阅读和支持,期待你的反馈和进一步的交流。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 项目顶层架构
    • 1. 用户信息交互模块
      • 2. AI通信交互模块
        • 3. 信息传输模块
          • 4. 反馈机制模块
          • 技术选型
          • 设计时序图
          • 前端UI设计
          • 前端实现
          • 后端实现
          • 总结
          相关产品与服务
          媒体 AI 处理
          媒体 AI 处理(Media Artificial Intelligence processing)基于腾讯云点播产品提供智能化的媒体内容审核、分析、识别能力,包含违禁检测,画面识别、语音转文字等功能。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档