基于MySQL数据库实现问答系统与BM25算法详解
基于MySQL数据库实现问答系统与BM25算法详解学习目标通过本章学习,你将掌握:FQA(常见问题解答)系统的整体架构与工作流程基于MySQL数据库存储问答知识库的实现方案Redis缓存加速问答系统响应的设计思路BM25文本检索算法的原理与代码实现Softmax归一化在相似度判断中的应用完整的Python项目模块化设计与实现一、FQA系统概述1 系统流程FQA(Frequently Asked Questions)系统是一种基于知识库的智能问答系统,核心是通过文本检索技术从预存的问答库中找到与用户问题最匹配的答案。2 项目结构本项目采用模块化设计,将不同功能封装为独立模块,便于维护和扩展。1 系统流程FQA系统的完整工作流程如下:用户提问:用户输入自然语言问题文本预处理:对用户问题进行分词、清洗等预处理操作BM25检索:使用BM25算法计算用户问题与知识库中所有问题的相似度得分Softmax归一化:将BM25原始得分转换为0-1之间的概率值,便于阈值判断缓存判断:若最高相似度得分超过阈值(如0.85),且Redis中存在缓存答案,直接返回缓存结果数据库查询:若未命中缓存但得分达标,从MySQL数据库中查询对应答案结果回写:将高置信度的问答对写入Redis缓存,提升后续查询速度兜底处理:若得分未达标,可转向RAG大模型生成答案或返回"未找到相关答案"核心设计思想:通过Redis缓存高频问答对,减少数据库查询和BM25计算开销,实现冷热数据分离,大幅提升系统响应速度和并发能力。2 项目结构项目采用标准的Python模块化设计,目录结构如下:fqa_system/ ├── config/ │ └── config.ini # 配置文件 ├── src/ │ ├── __init__.py │ ├── config_manager.py # 配置管理模块 │ ├── logger.py # 日志记录模块 │ ├── mysql_db.py # MySQL数据库操作模块 │ ├── redis_cache.py # Redis缓存操作模块 │ ├── text_preprocess.py # 文本预处理模块 │ └── bm25_search.py # BM25检索模块 ├── data/ │ └── qa_dataset.csv # 问答数据集 ├── logs/ │ └── app.log # 日志文件 ├── main.py # 主程序入口 └── requirements.txt # 依赖文件各模块职责清晰,遵循单一职责原则,便于单元测试和维护。三、代码实现1 配置文件 (config.ini)使用INI格式的配置文件统一管理系统配置,将数据库连接、缓存参数、日志配置等与代码分离,便于不同环境切换。[mysql] host = 127.0.0.1 port = 3306 user = root password = 123456 database = fqa_db charset = utf8mb4 [redis] host = 127.0.0.1 port = 6379 password = db = 0 decode_responses = True [log] log_file = logs/app.log level = INFO format = %(asctime)s | %(levelname)s | %(message)s [bm25] k1 = 1.5 b = 0.75 threshold = 0.85 [system] top_k = 5配置说明:配置文件按功能划分为多个section(区块),分别管理MySQL、Redis、日志、BM25算法等不同模块的参数,实现配置解耦。2 配置管理2.1 功能配置管理模块负责读取和解析INI配置文件,提供统一的配置访问接口,避免各模块直接读取文件,实现配置集中管理。支持按section分组读取配置自动类型转换(字符串、整数、布尔值)单例模式,全局唯一配置实例配置项缺失时给出明确错误提示2.2 代码实现importconfigparserimportosclassConfigManager:"""配置管理类,单例模式"""_instance=Nonedef__new__(cls,config_path=None):ifcls._instanceisNone:cls._instance=super().__new__(cls)cls._instance._init_config(config_path)returncls._instancedef_init_config(self,config_path=None):"""初始化配置"""ifconfig_pathisNone:# 默认配置文件路径config_path=os.path.join(os.path.dirname(os.path.dirname(__file__)),"config","config.ini")ifnotos.path.exists(config_path):raiseFileNotFoundError(f"配置文件不存在:{config_path}")self.config=configparser.ConfigParser()self.config.read(config_path,encoding="utf-8")defget(self,section,key,fallback=None):"""获取字符串类型配置"""returnself.config.get(section,key,fallback=fallback)defgetint(self,section,key,fallback=None):"""获取整数类型配置"""returnself.config.getint(section,key,fallback=fallback)defgetfloat(self,section,key,fallback=None):"""获取浮点数类型配置"""returnself.config.getfloat(section,key,fallback=fallback)defgetboolean(self,section,key,fallback=None):"""获取布尔类型配置"""returnself.config.getboolean(section,key,fallback=fallback)defget_section(self,section):"""获取整个section的配置字典"""ifsectionnotinself.config:return{}returndict(self.config[section])# 全局配置实例defget_config():returnConfigManager()2.3 说明单例模式:确保整个应用只有一个配置实例,避免重复读取文件,节省资源类型安全:提供getint、getfloat、getboolean等方法,自动进行类型转换容错处理:支持fallback参数,配置项缺失时返回默认值使用方式:通过get_config()获取全局配置实例,如get_config().get("mysql", "host")3 日志记录3.1 功能日志记录模块封装Python标准logging库,提供统一的日志记录接口,支持控制台和文件双输出,便于开发调试和线上问题排查。支持控制台和文件双渠道输出日志分级(DEBUG/INFO/WARNING/ERROR/CRITICAL)标准化日志格式,包含时间、级别、内容自动创建日志目录全局单例日志器3.2 代码实现importloggingimportosfromlogging.handlersimportRotatingFileHandlerfromconfig_managerimportget_configclassLogger:"""日志管理类,单例模式"""_instance=Nonedef__new__(cls):ifcls._instanceisNone:cls._instance=super().__new__(cls)cls._instance._init_logger()returncls._instancedef_init_logger(self):"""初始化日志器"""config=get_config()# 创建日志器self.logger=logging.getLogger("fqa_system")self.logger.setLevel(getattr(logging,config.get("log","level","INFO")))self.logger.propagate=False# 日志格式log_format=config.get("log","format","%(asctime)s | %(levelname)s | %(message)s")formatter=logging.Formatter(log_format)# 控制台处理器console_handler=logging.StreamHandler()console_handler.setLevel(logging.INFO)console_handler.setFormatter(formatter)self.logger.addHandler(console_handler)# 文件处理器log_file=config.get("log","log_file","logs/app.log")log_dir=os.path.dirname(log_file)iflog_dirandnotos.path.exists(log_dir):os.makedirs(log_dir,exist_ok=True)# 使用滚动文件处理器,避免单文件过大file_handler=RotatingFileHandler(log_file,maxBytes=10*1024*1024,# 10MBbackupCount=5,encoding="utf-8")file_handler.setLevel(logging.DEBUG)file_handler.setFormatter(formatter)self.logger.addHandler(file_handler)defdebug(self,message):self.logger.debug(message)definfo(self,message):self.logger.info(message)defwarning(self,message):self.logger.warning(message)deferror(self,message,exc_info=False):self.logger.error(message,exc_info=exc_info)defcritical(self,message,exc_info=False):self.logger.critical(message,exc_info=exc_info)# 全局日志实例defget_logger():returnLogger()3.3 说明双输出渠道:控制台输出便于开发调试,文件输出用于线上问题排查日志滚动:使用RotatingFileHandler实现日志文件滚动,单个文件最大10MB,保留5个备份分级过滤:控制台输出INFO及以上级别,文件记录DEBUG及以上级别,兼顾性能与排错需求使用方式:通过get_logger()获取全局日志实例,如get_logger().info("系统启动成功")线上规范:生产环境建议将日志级别设置为INFO,屏蔽DEBUG调试信息,减少磁盘占用;数据库操作、缓存操作、检索计算等关键环节必须打印INFO日志记录入参和耗时。4 MySQL操作模块4.1 功能MySQL操作模块封装数据库的增删改查操作,负责问答知识库的持久化存储,是系统的底层数据源。问答知识库的CRUD操作批量导入问答数据连接池管理,自动重连机制参数化查询,防止SQL注入统一的异常处理和日志记录4.2 代码实现importpymysqlfrompymysql.cursorsimportDictCursorfromdbutils.pooled_dbimportPooledDBfromconfig_managerimportget_configfromloggerimportget_loggerclassMySQLDB:"""MySQL数据库操作类"""_instance=Nonedef__new__(cls):ifcls._instanceisNone:cls._instance=super().__new__(cls)cls._instance._init_pool()returncls._instancedef_init_pool(self):"""初始化数据库连接池"""config=get_config()self.logger=get_logger()try:self.pool=PooledDB(creator=pymysql,maxconnections=10,mincached=2,maxcached=5,host=config.get("mysql","host"),port=config.getint("mysql","port"),user=config.get("mysql","user"),password=config.get("mysql","password"),database=config.get("mysql","database"),charset=config.get("mysql","charset","utf8mb4"),cursorclass=DictCursor,ping=4,# 连接前自动ping,断连自动重连)self.logger.info("MySQL连接池初始化成功")exceptExceptionase:self.logger.error(f"MySQL连接池初始化失败:{e}",exc_info=True)raisedefget_connection(self):"""从连接池获取连接"""returnself.pool.connection()defget_all_questions(self):"""获取所有问题,用于BM25索引构建"""conn=Nonetry:conn=self.get_connection()withconn.cursor()ascursor:sql="SELECT id, question, answer FROM qa_table"cursor.execute(sql)results=cursor.fetchall()self.logger.info(f"从MySQL获取了{len(results)}条问答数据")returnresultsexceptExceptionase:self.logger.error(f"获取所有问题失败:{e}",exc_info=True)return[]finally:ifconn:conn.close()defget_answer_by_question(self,question):"""根据问题查询答案"""conn=Nonetry:conn=self.get_connection()withconn.cursor()ascursor:sql="SELECT answer FROM qa_table WHERE question = %s"cursor.execute(sql,(question,))result=cursor.fetchone()returnresult["answer"]ifresultelseNoneexceptExceptionase:self.logger.error(f"根据问题查询答案失败:{e}",exc_info=True)returnNonefinally:

相关新闻

BurpSuite被动扫描插件组合实战:构建分层感知体系提升漏洞挖掘效率

BurpSuite被动扫描插件组合实战:构建分层感知体系提升漏洞挖掘效率

1. 项目概述:为什么被动扫描插件组合是效率翻倍的关键在渗透测试和漏洞挖掘的日常里,BurpSuite 就像是我们手里的瑞士军刀,功能强大但有时候也略显笨重。尤其是主动扫描,动静大、耗时长,还容易触发目标系统的防护机制。…

2026/6/26 19:48:15阅读更多 →
【Springboot毕设全套源码+文档】基于SpringBoot的招聘系统的设计与实现(丰富项目+远程调试+讲解+定制)

【Springboot毕设全套源码+文档】基于SpringBoot的招聘系统的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/6/26 19:43:13阅读更多 →
AMD Ryzen调试工具SMUDebugTool:解决处理器性能问题的完整指南

AMD Ryzen调试工具SMUDebugTool:解决处理器性能问题的完整指南

AMD Ryzen调试工具SMUDebugTool:解决处理器性能问题的完整指南 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: ht…

2026/6/26 19:43:13阅读更多 →
车间粉尘治理:避免清扫扬尘的清洁方案

车间粉尘治理:避免清扫扬尘的清洁方案

福建不少生产车间在作业过程中会持续产生金属粉尘、铁屑以及各类固体颗粒物。使用普通扫帚清扫时极易扬起灰尘,造成车间环境二次污染。大功率工业吸尘器具备较强负压,支持干湿工况作业,能够快速清理固体碎屑与污水,适用于机械厂、…

2026/6/26 20:53:27阅读更多 →
HarmonyOS7 从 6 升 7 怎么最稳?迁移流程、坑点和发布一次过

HarmonyOS7 从 6 升 7 怎么最稳?迁移流程、坑点和发布一次过

文章目录前言升级前的准备DevEco Studio 升级Breaking Changes 与 API 替换1. 网络模块变更2. 分布式能力变更3. 权限声明格式4. 通知 API 变更5. Preferences 变更批量替换策略迁移前后对比发布配置APMS 故障监控接入踩坑总结发布检查清单写在最后前言 写了一大圈新特性&…

2026/6/26 20:53:27阅读更多 →
Agentic AI:从概念到可交付结果

Agentic AI:从概念到可交付结果

聊《Agentic AI:从概念到可交付结果》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。摘要这篇面向关注 AI 产品化和自动化系统的开发者,但不会把“Agentic AI:从概念到可交付结果…

2026/6/26 20:53:27阅读更多 →
4G与Lora混合组网的紫外线监测系统设计与优化

4G与Lora混合组网的紫外线监测系统设计与优化

1. 项目背景与核心价值 这个4G_Lora远程紫外线监测器项目解决了一个非常实际的痛点问题——户外紫外线强度的实时监测与数据上报。在农业大棚、建筑工地、户外作业等场景中,紫外线指数直接影响作业安全与作物生长,传统人工记录方式效率低下且无法实现预警…

2026/6/26 20:53:27阅读更多 →
2026年模型网关演进观察:五大API聚合架构的生产力实测与工程边界

2026年模型网关演进观察:五大API聚合架构的生产力实测与工程边界

# 2026年模型网关演进观察:五大API聚合架构的生产力实测与工程边界步入2026年,AI基础设施的演进路径已发生质变。在开发者与企业技术决策者的视野中,API聚合平台(中转站)的功能边界正在重塑:它不再仅仅是多…

2026/6/26 20:53:27阅读更多 →
【Springboot毕设全套源码+文档】基于Java+springboot小型哺乳类宠物诊所管理系统的设计与实现(丰富项目+远程调试+讲解+定制)

【Springboot毕设全套源码+文档】基于Java+springboot小型哺乳类宠物诊所管理系统的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/6/26 20:48:27阅读更多 →
【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体 一文搞定到底什么是智能体【人工智能】一文搞定到底什么是智能体一. LM,WorkFlow,Agent分别有什么么不同二. Agent的思考过程是怎样的三. Agent的五个核心部分1)LLM2)Prompt3)Me…

2026/6/26 11:03:22阅读更多 →
嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

1. 嵌入式GUI控件:从原理到实战的深度解析在嵌入式系统开发中,图形用户界面(GUI)的设计与实现往往是项目从“能用”到“好用”的关键一跃。不同于资源充沛的PC或移动平台,嵌入式设备的GUI需要在有限的CPU性能、内存空间…

2026/6/26 4:15:25阅读更多 →
Google AI Studio 300美元额度的真相与实战指南

Google AI Studio 300美元额度的真相与实战指南

1. 这300美金不是“送钱”,而是Google埋下的第一道技术门槛 你看到标题里那个醒目的“$300美金”时,第一反应可能是:又一个免费额度?领完就完事?我亲手试过——这300美金根本不是红包,而是一张入场券&…

2026/6/26 9:29:01阅读更多 →
HPE (慧与) 服务器专用 ESXi 9 全套官方定制资源详解 + 完整部署升级教程

HPE (慧与) 服务器专用 ESXi 9 全套官方定制资源详解 + 完整部署升级教程

一、前言:企业运维痛点与资源价值自博通收购 VMware 之后,原 VMware 公开免费下载渠道全面关闭,企业运维人员想要获取适配 HPE 慧与服务器的 ESXi 9 原厂镜像,必须注册博通账号、绑定有效授权才能下载,无授权账号无法获…

2026/6/26 0:02:15阅读更多 →
Kotlin的@JvmStatic与@JvmField:与Java互操作的注解

Kotlin的@JvmStatic与@JvmField:与Java互操作的注解

Kotlin作为一门现代编程语言,与Java的互操作性一直是其核心优势之一。为了让Kotlin代码能够无缝对接Java,Kotlin提供了多种注解来优化互操作体验,其中JvmStatic和JvmField是两个关键注解。它们分别用于解决静态成员和字段在Java中的访问问题&…

2026/6/26 0:02:15阅读更多 →
深入解析musl libc中的mmap实现源码

深入解析musl libc中的mmap实现源码

最近在阅读musl libc源码时,发现其mmap的实现非常精妙,特分享给大家。 一、代码整体结构 这段代码实现了__mmap函数,并通过weak_alias导出为mmap。这是典型的musl libc风格——提供弱符号以便用户可以重写。 weak_alias(__mmap, mmap); 二…

2026/6/26 0:02:15阅读更多 →