【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/10/17 13:00:12 阅读更多 →
基于SpringBoot的社区优选商城(Java+SpringBoot+MySQL)| 计算机毕业设计 附源码论文PPT

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

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

2026/10/18 2:35:27 阅读更多 →
皮肤癌良恶性图像二分类数据集:含训练验证划分、类别映射文件与一键可视化脚本

皮肤癌良恶性图像二分类数据集:含训练验证划分、类别映射文件与一键可视化脚本

本文还有配套的精品资源,点击获取 简介:专为皮肤癌二分类任务准备的医学图像数据集,包含2637张训练图和660张测试图,按良性、恶性两类独立存放于train/test子目录中,开箱即用,无需重命名或移动文件。所有…

2026/10/18 2:35:29 阅读更多 →

最新新闻

芯片设计第一课怎么学?从数字电路到Verilog的完整闭环

芯片设计第一课怎么学?从数字电路到Verilog的完整闭环

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

2026/10/18 17:18:12 阅读更多 →
数学分析讲义怎么用?从极限到级数的学习路线与避坑指南

数学分析讲义怎么用?从极限到级数的学习路线与避坑指南

简介:丘成桐先生编写的《数学分析之课程讲义》是面向清华大学丘成桐数学英才班的实验课教材,旨在不改变传统教学根本的前提下,探索更深入、更现代的分析学内容。讲义覆盖数列极限、函数连续性、黎曼积分、子流形理论、抽象测度论等基础&#…

2026/10/18 17:18:12 阅读更多 →
MATLAB光学仿真:F-P腔多光束干涉透射光强曲线复现实战

MATLAB光学仿真:F-P腔多光束干涉透射光强曲线复现实战

简介:光学仿真中,多光束干涉是物理光学教学与研究的重要模型。针对不同反射率下透射光条纹强度分布随参数变化的典型问题,这份 Matlab 资源提供了可直接运行的仿真脚本与配套结果,面向光学、物理光学及光电信息科学与工程方向的学…

2026/10/18 17:18:12 阅读更多 →
C++俄罗斯方块:Win32 GDI工业级学习模板

C++俄罗斯方块:Win32 GDI工业级学习模板

简介:这是一份面向C初学者与图形界面实践者的俄罗斯方块小游戏完整开源项目,聚焦于Windows平台下的MFC框架开发,适用于算法逻辑理解、GUI事件响应及内存绘图(CMyMemDC)等核心技能训练。资源共27个文件,包含…

2026/10/18 17:18:12 阅读更多 →
本地运行AI Agent:从工具调用到闭环执行的工程实践

本地运行AI Agent:从工具调用到闭环执行的工程实践

简介:本资源是一份面向AI开发者与大模型应用实践者的AI Agent原理与工程实现入门资料包,聚焦人工智能代理的核心机制、技术架构与轻量级代码实践。资源包含7个文件(3个HTML页面用于交互式演示与文档说明、1个Python脚本实现基础Agent逻辑、1个…

2026/10/18 17:18:11 阅读更多 →
OpenSpec落地第一步:搞定npm环境才能跑通契约驱动开发

OpenSpec落地第一步:搞定npm环境才能跑通契约驱动开发

1. OpenSpec 是什么:一个被严重低估的 Spec 驱动开发基础设施OpenSpec 不是一个 npm 包名,也不是某个开源项目的代号,更不是某个新出的 AI 编程助手品牌——它是一套可落地、可集成、可验证的接口契约先行(Contract-First&#xf…

2026/10/18 17:17:11 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/18 12:16:16 阅读更多 →