RuoYi-Ai源码解析:AI 对话接口的技术实现与设计理念

在企业级系统智能化转型的趋势下,RuoYi-AI 开源项目以其成熟的技术架构和工程化实践,成为基于 RuoYi 生态集成 AI 对话能力的典范。本文将结合代码实现流程图,从技术底层到业务流程,全方位拆解其 AI 对话接口的设计逻辑与落地价值。

一、技术入口:SSE 流式响应的技术选型

RuoYi-AI 选择 Server-Sent Events(SSE) 作为 AI 对话的通信协议,核心在于其 “服务端单向流式推送”的特性,完美契合大语言模型 “边生成边返回” 的交互体验。

在代码中,通过 Spring 提供的 SseEmitter 类实现长连接:

@PostMapping("/send")
@ResponseBody
public SseEmitter sseChat(@RequestBody @Valid ChatRequest chatRequest, HttpServletRequest request) {
    return sseService.sseChat(chatRequest, request);
}

@Override
public SseEmitter sseChat(ChatRequest chatRequest, HttpServletRequest request) {
    // 超时时间设为0,实现长连接不中断
    SseEmitter sseEmitter = new SseEmitter(0L);
    // 业务逻辑执行...
    return sseEmitter;
}

这种设计让前端可以通过 EventSource API 实时监听 AI 生成的内容,无需轮询或等待完整响应,极大提升了对话的实时性与流畅度。

二、核心流程拆解:从请求到 AI 响应的全链路

结合流程图与代码,RuoYi-AI 对话接口的执行流程可分为“会话管理、知识库增强、模型调度、服务执行”四大核心阶段。

1. 会话与消息管理:对话上下文的持久化

对于登录用户,系统会自动创建会话(ChatSession)并持久化消息(ChatMessage),为多轮对话提供上下文支撑:

if (LoginHelper.isLogin()) {
    // 自动生成会话ID
    if (chatRequest.getSessionId() == null) {
        ChatSessionBo chatSessionBo = new ChatSessionBo();
        chatSessionBo.setUserId(LoginHelper.getUserId());
        chatSessionBo.setSessionTitle(getFirst10Characters(chatRequest.getPrompt()));
        chatSessionService.insertByBo(chatSessionBo);
        chatRequest.setSessionId(chatSessionBo.getId());
    }
    // 保存用户消息
    chatCostService.saveMessage(chatRequest);
}

对应流程图中“记录会话信息”“保存用户消息”等节点,这一步确保了对话的连续性,让 AI 能够基于历史上下文理解用户意图。

2. 知识库增强:让 AI 具备行业认知

当请求携带知识库ID(kid)时,系统会触发向量检索流程,将领域知识注入对话上下文:

private String processKnowledgeBase(ChatRequest chatRequest, List<Message> messages) {
    // 省略参数校验逻辑...
    // 查询知识库与向量模型
    KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(chatRequest.getKid()));
    ChatModelVo chatModel = chatModelService.selectModelByName(knowledgeInfoVo.getEmbeddingModelName());
    // 构建向量查询参数并检索
    List<String> nearestList = vectorStoreService.getQueryVector(queryVectorBo);
    // 将知识库内容注入对话上下文
    addKnowledgeMessages(messages, nearestList);
    return getKnowledgeSystemPrompt(knowledgeInfoVo);
}

private void addKnowledgeMessages(List<Message> messages, List<String> nearestList) {
    for (String prompt : nearestList) {
        Message userMessage = Message.builder()
                .content(prompt)
                .role(Message.Role.USER)
                .build();
        messages.add(userMessage);
    }
}

这一流程对应流程图中 “知识库处理分支”,通过 “向量生成→相似性检索→知识注入” 三步,让 AI 从 “通用助手” 升级为 “行业专家”,可应用于企业文档问答、业务规则咨询等场景。

3. 模型智能调度:多模型兼容与故障重试

为应对不同场景(如普通对话、图片生成)和模型故障,系统设计了动态模型选择 + 自动重试机制:

    /**
     * 处理知识库相关逻辑
     */
    private String processKnowledgeBase(ChatRequest chatRequest, List<Message> messages) {
        if (StringUtils.isEmpty(chatRequest.getKid())) {
            return getPromptTemplatePrompt(promptTemplateEnum.VECTOR.getDesc());
        }

        try {
            // 查询知识库信息
            KnowledgeInfoVo knowledgeInfoVo = knowledgeInfoService.queryById(Long.valueOf(chatRequest.getKid()));
            if (knowledgeInfoVo == null) {
                log.warn("知识库信息不存在,kid: {}", chatRequest.getKid());
                return getPromptTemplatePrompt(promptTemplateEnum.VECTOR.getDesc());
            }

            // 查询向量模型配置信息
            ChatModelVo chatModel = chatModelService.selectModelByName(knowledgeInfoVo.getEmbeddingModelName());
            if (chatModel == null) {
                log.warn("向量模型配置不存在,模型名称: {}", knowledgeInfoVo.getEmbeddingModelName());
                return getPromptTemplatePrompt(promptTemplateEnum.VECTOR.getDesc());
            }

            // 构建向量查询参数
            QueryVectorBo queryVectorBo = buildQueryVectorBo(chatRequest, knowledgeInfoVo, chatModel);

            // 获取向量查询结果
            List<String> nearestList = vectorStoreService.getQueryVector(queryVectorBo);

            // 添加知识库消息到上下文
            addKnowledgeMessages(messages, nearestList);

            // 返回知识库系统提示词
            return getKnowledgeSystemPrompt(knowledgeInfoVo);

        } catch (Exception e) {
            log.error("处理知识库信息失败: {}", e.getMessage(), e);
            return getPromptTemplatePrompt(promptTemplateEnum.VECTOR.getDesc());
        }
    }

对应流程图中“模型选择”“重试判断”等节点,这一设计让系统能在主模型故障时自动切换到备用模型,同时支持 “聊天、图像生成” 等多场景的模型异构集成,兼顾可用性与扩展性。

4. 计费代理设计:无侵入式的成本管控

为实现对话计费,项目采用代理模式对模型服务进行包装:

public IChatService getChatService(String category) {
    IChatService originalService = chatServiceMap.get(category);
    // 自动包装为计费代理,实现“调用后自动计费”
    return new BillingChatServiceProxy(originalService, chatCostService);
}

三、流程图与代码的映射:可视化执行路径

将流程图与代码逐节点对应,可更直观理解整体逻辑:

流程图节点代码实现关联
请求 → SseEmitterSseEmitter sseEmitter = new SseEmitter(0L) 初始化长连接
记录会话信息ChatSessionService.insertByBo(chatSessionBo) 创建会话
保存用户消息chatCostService.saveMessage(chatRequest) 持久化用户输入
知识库处理分支processKnowledgeBase 方法中向量检索与知识注入
模型选择autoSelectModelAndGetService 方法中按类别 / 名称选择模型
重试判断ChatRetryHelper.executeWithRetry 实现多模型故障切换
服务调用IChatService.chat(chatRequest, sseEmitter) 触发 AI 模型推理
返回 SseEmitter方法最终返回 sseEmitter,完成流式响应闭环

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值