首页/新闻资讯/正文详情

【AI大模型应用开发】【项目实战】24.RAG智慧问答项目-(十二)融合MySQL的RAG系统之基于 FastAPI 的 FAQ 与知识库查询接口

发布时间:2026/9/25 16:22:48 来源:云帆数科 栏目:资讯中心
【AI大模型应用开发】【项目实战】24.RAG智慧问答项目-(十二)融合MySQL的RAG系统之基于 FastAPI 的 FAQ 与知识库查询接口
目标:理解如何基于FastAPI构建高效的问答系统 API 接口掌握WebSocket 流式输出和HTTP 接口的实现,优化用户交互体验前后端交互、前端静态文件服务以及日常问候处理的集成一、开发完RAG系统以后,怎么对外提供服务?对外:调用链路: 前端 - 后端 - RAG系统功能:前端和后端是已有的业务系统,比如电商系统增加一个售后机器人:前端和后端改造代码, RAG系统从0到1开发职责划分:前端和后端对应的人员进行维护开发, AI工程师只负责做RAG系统RAG系统专门作为一个单独的系统对外服务,前端、后端从0到1开发,RAG系统也是从0到1职责划分:AI工程师负责做RAG系统, 也有可能兼职做后端(小团队甚至要做前端),后端仍然需要权限验证、登录等功能二、查询流程图app.py是对new_main.py的进一步优化,基于 FastAPI 框架构建了RESTful API和WebSocket 接口,集成了 RAG 系统 和 RAG 系统,支持流式输出、对话历史管理和日常问候处理,同时,通过静态文件服务支持前端页面交互,适用于项目场景下的实时问答系统下面是基于 FastAPI 的问答系统查询流程图,展示从前端请求到后端响应的处理逻辑三、流程说明1.请求接收:前端通过HTTP POST (/api/query)或WebSocket (/api/stream)发送查询请求,包含查询内容 (query)、学科过滤 (source_filter)和会话 ID (session_id)2.日常问候处理:检查查询是否为日常问候(如“你好”),若匹配则返回模板化回复3.BM25 搜索:使用BM25 算法搜索MySQL 知识库,设置相似度阈值 0.854.答案判断:若找到可靠答案(相似度 0.85),通过HTTP 一次性返回或WebSocket 流式返回若无可靠答案且需要 RAG,HTTP 接口提示使用 WebSocket,WebSocket 接口流式返回 RAG 答案若无需 RAG,返回“未找到答案”5.历史更新:将查询和答案存入 MySQL 的conversations表,保留最近 5 轮对话6.响应输出:HTTP 返回 JSON 格式响应,WebSocket 流式发送 JSON 数据(包含start、token、end或error类型)四、代码介绍下面是app.py的完整代码,包含逐行注释,详细解析功能与实现逻辑实现步骤,准备工作创建 FastAPI 应用并配置构建一个FastAPI对象配置跨域初始化RAG系统配置问答模板,定义日常问答模式定义请求和响应的数据结构,给核心query接口使用request: query,source_filter, session_idResponse: answer,is_streaming, session_id ,processing_timeis_streaming代表返回的结果是批式还是流式的,如果是批式的,前端直接获取answer。如果是流式的,需要前端去构建websocket通道,接收流式输出的内容挂载静态文件,重定向: / 到静态文件中的前端页面历史对话操作创建历史对话查询历史消息清除历史消息1.导入必备的工具包# 导入 FastAPI 相关模块,用于构建 API 和 WebSocket from fastapi import FastAPI, WebSocket, HTTPException, Query, Depends # 导入 FastAPI 响应类型,用于流式响应和文件服务 from fastapi.responses import StreamingResponse, FileResponse # 导入 CORS 中间件,支持跨域请求 from fastapi.middleware.cors import CORSMiddleware # 导入静态文件服务模块 # 给前端使用 from fastapi.staticfiles import StaticFiles # 导入 WebSocket 断开异常 from starlette.websockets import WebSocketDisconnect # 导入系统操作模块,用于文件目录管理 import os # 导入 Pydantic 模型,用于请求验证 from pydantic import BaseModel # 导入异步事件循环模块 import asyncio # 导入 JSON 处理模块 import json # 导入 UUID 模块,生成唯一会话 ID import uuid # 导入类型注解模块 from typing import Optional, List, Dict, Any # 导入时间模块,记录处理时间 import time # 导入正则表达式模块,用于匹配日常问候 import re # 导入优化后的问答系统 from new_main import IntegratedQASystem from base.logger import single_logger as logger2.创建 FastAPI 应用并配置创建 FastAPI 实例并配置 CORS和静态文件服务功能:初始化 FastAPI 应用,允许跨域请求,挂载静态文件目录关键点:CORS 配置在生产环境中需限制域名,静态文件服务支持前端页面# 创建 FastAPI 应用实例,设置标题和描述 app = FastAPI(title="问答系统API", description="集成MySQL和RAG的智能问答系统") # 配置 CORS 中间件,允许跨域请求 app.add_middleware( CORSMiddleware, allow_origins=["*"], # 允许所有来源(生产环境需限制) allow_credentials=True, # 允许凭证 allow_methods=["*"], # 允许所有 HTTP 方法 allow_headers=["*"], # 允许所有头部 ) # 创建静态文件目录(如果不存在) os.makedirs("static", exist_ok=True) # 创建全局问答系统实例 qa_system = IntegratedQASystem()3. 定义日常问候模式定义问候语正则匹配模式和回复功能:快速响应常见问候,提升用户体验关键点:使用正则表达式匹配,支持大小写无关匹配# 定义日常问候用语模式和回复 GREETING_PATTERNS = [ { "pattern": r"^(你好|您好|hi|hello)", # 匹配问候语 "response": "你好!我是小爱同学,专注于答疑解惑,很高兴为你服务!" }, { "pattern": r"^(你是谁|您是谁|你叫什么|你的名字|who are you)", # 匹配身份询问 "response": "我是小爱同学,你的智能助手,致力于提供 各方面 内容相关的解答!" }, { "pattern": r"^(在吗|在不在|有人吗)", # 匹配在线确认 "response": "我在!我是小爱同学,随时为你解答问题!" }, { "pattern": r"^(干嘛呢|你在干嘛|做什么)", # 匹配状态询问 "response": "我正在待命,随时为你解答 互联网 相关的问题!有什么我可以帮你的?" } ]4.定义请求和响应模型使用Pydantic定义请求和响应数据结构功能:规范 API 输入和输出格式,确保数据验证关键点:支持可选字段,方便扩展# 定义查询请求模型 # TODO 相当于java中的注解 @RequestBody class QueryRequest(BaseModel): # TODO @Param(param = "query", nullable = false) query: str # 查询内容,必填 # TODO @Param(param = "query", nullable = true) subject_filter: Optional[str] = None # 学科过滤,可选 session_id: Optional[str] = None # 会话 ID,可选 # 定义查询响应模型 # TODO 相当于java中的注解 @ResponseBody class QueryResponse(BaseModel): answer: str # 答案内容 # TODO 这个bool值的意思是告诉前端,将要接受流式输出,需要建立一个websocket通道 is_streaming: bool # 是否流式响应 session_id: str # 会话 ID processing_time: float # 处理时间5.挂载静态文件服务挂载静态文件目录并设置根路径功能:服务前端 HTML 文件,支持交互页面关键点:根路径重定向到index.html# 挂载静态文件目录,服务前端文件 # TODO app.mount("/static" - 127.0.0.1/static app.mount("/static", StaticFiles(directory="static"),) # 根路径重定向到 index.html # TODO 127.0.0.1/static/index.html - 127.0.0.1/ @app.get("/") async def read_root(): return FileResponse("static/index.html")6.创建新会话/api/create_session接口功能:生成新的唯一会话 ID关键点:使用 UUID 确保唯一性# 创建新会话接口 # TODO 类似于java中的@PostMapping @app.post("/api/create_session") async def create_session(): session_id = str(uuid.uuid4()) # 生成唯一会话 ID return {"session_id": session_id} # 返回会话 ID7.查询历史消息/api/history/{session_id}接口功能:获取指定会话的历史记录关键点:异常处理确保接口健壮性# 查询历史消息接口 # TODO restful api 规范 。比如某厂规范:internal-api.xxxx.com/{业务线: driver/passanger}/{二级:运营、打车}/xxxx # TODO 对外的api(openapi) : /api/v1/edu-rag/history/{session_id} @app.get("/api/history/{session_id}") async def get_history(session_id: str): try: # 获取指定会话的历史记录 history = qa_system.get_session_history(session_id) # 返回会话 ID 和历史记录 # TODO 规范操作:{"data": {"session_id": session_id, "history": history} ,"errno":0,"errmsg":报错信息, "log_id":日志编号} return {"session_id": session_id, "history": history} except Exception as e: # 抛出 HTTP 异常,包含错误信息 raise HTTPException(status_code=500, detail=f"获取历史记录失败: {str(e)}")8.清除历史消息/api/history/{session_id}接口功能:删除指定会话的所有历史记录关键点:返回操作状态,异常处理确保健壮性# 清除历史消息接口 @app.delete("/api/history/{session_id}") async def clear_history(session_id: str): # 清除指定会话的历史记录 success = qa_system.clear_session_history(session_id) if success: # 返回成功状态 return {"status": "success", "message": "历史记录已清除"} else: # 抛出 HTTP 异常 raise HTTPException(status_code=500, detail="清除历史记录失败")9.检查日常问候check_greeting函数功能:检查查询是否匹配日常问候,返回模板化回复关键点:正则匹配支持大小写无关,简化交互逻辑# 检查是否为日常问候用语并返回模板回复 def check_greeting(query: str) - Optional[str]: query_text = query.strip() # 去除首尾空格 for pattern_info in GREETING_PATTERNS: # 使用正则匹配,忽略大小写 if re.match(pattern_info["pattern"], query_text, re.IGNORECASE): return pattern_info["response"] # 返回匹配的回复 return None # 无匹配返回 None10.非流式查询接口/api/query接口功能:处理非流式查询,支持 MySQL 答案和日常问候,提示使用 WebSocket 获取 RAG 流式答案关键点:返回 JSON 格式响应,记录处理时间后端代码:# 非流式查询接口 @app.post("/api/query") async def query(request: QueryRequest): """ 用户输入的query,前端先去调用当前接口根据返回值的is_streaming字段决定是否输出答案,还是调用websocket接收流式输出 :param request: :return: """ start_time = time.time() # 记录开始时间 # 使用请求中的 session_id 或生成新 ID session_id = request.session_id or str(uuid.uuid4()) # 检查是否为日常问候 greeting_response = check_greeting(request.query) if greeting_response: # 返回问候回复 return { "answer": greeting_response, "is_streaming": False, "session_id": session_id, "processing_time": time.time() - start_time } # 执行 BM25 搜索 answer, need_rag = qa_system.faq.search(request.query, threshold=0.85) if need_rag: # 需要 RAG,提示使用 WebSocket return { "answer": "请使用WebSocket接口获取流式响应", "is_streaming": True, "session_id": session_id, "processing_time": time.time() - start_time } # 返回 MySQL 答案 return { "answer": answer, "is_streaming": False, "session_id": session_id, "processing_time": time.time() - start_time }前端调用代码:// 接收消息时 socket.onmessage = function(event) { const data = JSON.parse(event.data); switch (data.type) { case 'start': console.log('流式响应开始'); break; case 'token': // 追加 token 到内容 accumulatedContent += data.token; // 使用 marked.js 解析 Markdown 格式 contentElement.innerHTML = marked.parse(accumulatedContent); scrollToBottom(); break; case 'end': console.log('流式响应结束'); socket.close(); resolve(); break; case 'error': console.error('流式响应错误:', data.error);

相关推荐

Arduino Leonardo做的双旋钮+十四键音游控制器,即插即用支持多平台
Arduino Leonardo做的双旋钮+十四键音游控制器,即插即用支持多平台

本文还有配套的精品资源,点击获取 简介:用Arduino Leonardo打造的音乐游戏专用外设,自带两个带按压功能的高精度旋转编码器和十四颗独立按键,所有输入都可自由映射。设备通过标准HID协议通信,Windows/macOS/Linux系… · 2026/9/17 2:29:38

基于SpringBoot的社区优选商城(Java+SpringBoot+MySQL)| 计算机毕业设计 附源码论文PPT
基于SpringBoot的社区优选商城(Java+SpringBoot+MySQL)| 计算机毕业设计 附源码论文PPT

本项目为计算机本科毕业设计,采用 Java Spring Boot 作为后端框架,Vue.js 作为前端框架,数据库使用 MySQL。系统涵盖用户管理、商家管理、商品管理、订单管理、客服聊天管理、论坛管理、商品资讯管理、购物车等八大功能模块。配套材料包括论… · 2026/8/23 9:06:00

Java图书借阅系统源码:含MySQL建库脚本、Bootstrap界面与双角色管理功能
Java图书借阅系统源码:含MySQL建库脚本、Bootstrap界面与双角色管理功能

本文还有配套的精品资源,点击获取 简介:这是一套可直接部署的Java Web图书借阅管理系统,基于JSPServlet开发,集成Spring和Spring MVC框架,使用Maven构建。数据库采用MySQL,配套完整的library.sql脚本&am… · 2026/9/11 6:47:09

Spring AI RAG 全链路观测落地:从 OTel 埋点到观测云排障指南
Spring AI RAG 全链路观测落地:从 OTel 埋点到观测云排障指南

Spring AI 的 RAG 项目做多了以后,你会发现最折磨人的不是模型答得差,而是出了问题根本不知道在哪一环。一次用户提问从进入系统到把答案流式吐出来,链路少说也有五六个环节:文档解析、切片、embedding、向量检索、prompt 拼装、大… · 2026/9/25 16:22:42

Claude桌面端Agent与Cowork升级:从对话到办公自动化的实操指南
Claude桌面端Agent与Cowork升级:从对话到办公自动化的实操指南

1. 从"聊天框"到"工位":这次升级到底改了什么大多数人第一次用 Claude,都是把它当成一个更聪明的搜索框——问一句答一句,复制粘贴来回倒腾。但如果你最近打开过 Claude 的桌面端,会发现它的定位已经悄悄变了… · 2026/9/25 16:22:42

基于SpringBoot的“电掌通”共享充电宝管理系统:技术栈、背景意义与核心代码
基于SpringBoot的“电掌通”共享充电宝管理系统:技术栈、背景意义与核心代码

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 1. 项目背景与意义 随着移动互联网和智能手机的深度普及,移动设备的续航焦虑成为高频痛点。共享充电宝作为“即取即用、异地归还”的便民服务,已… · 2026/9/25 16:22:36

Codex-CLI 下载安装与 Token 配置教程:TaoToken 统一 Key 接入 settings.json 骨架
Codex-CLI 下载安装与 Token 配置教程:TaoToken 统一 Key 接入 settings.json 骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 16:22:36

Atlas 300V 24G推理卡上部署YOLO实战:从模型转换到性能调优
Atlas 300V 24G推理卡上部署YOLO实战:从模型转换到性能调优

1. 先说结论:Atlas 300V 24G 到底是张什么卡这两天后台收到好几个私信都在问同一件事:atlas 部署 YOLO 靠不靠谱,还有人直接问 atlas 300v 24g 是运算加速卡吗。我先给个明确答案:是,它是运算加速卡,但准确… · 2026/9/25 16:22:36

华为Atlas 300V加速卡上YOLO模型推理部署全攻略
华为Atlas 300V加速卡上YOLO模型推理部署全攻略

开头是这么回事:最近手上拿到一块华为的Atlas 300V加速卡,24G显存版本,第一反应和多数人一样,先搞清楚它到底是不是一块“运算加速卡”。答案是肯定的,但又不是传统意义上那种通用GPU。它的定位很明确——面向AI推理场… · 2026/9/25 16:22:29

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码