跳转至

融合 FAQ 和知识库查询

学习目标:

  • 理解智能问答系统的端到端工作流程。
  • 掌握 MySQL FAQ 和 RAG 系统的集成与协调。
  • 学习如何通过日志记录和错误处理提升系统健壮性。

old_main.py 是一个融合 MySQL FAQ 和 RAG 系统的交互式问答程序,专注于快速、精准的答案生成。它通过 MySQL 提供结构化数据的高效查询,通过 RAG 系统处理复杂问题,同时配备日志记录和用户友好的命令行界面,适合教育场景的实时问答需求。

1 查询流程图

以下是智能问答系统的查询流程图,展示从用户输入到答案输出的完整逻辑。

2 流程说明

  1. 输入处理:用户提供查询 (query) 和可选的学科过滤 (source_filter)。
  2. BM25 搜索:使用 BM25 算法在 MySQL 知识库中搜索,设置相似度阈值 0.85。
  3. 答案判断
    • 若找到可靠答案(相似度 > 0.85),直接返回。
    • 若无可靠答案且需要 RAG,调用 RAG 系统生成答案。
    • 若无需 RAG,返回“未找到答案”。
  4. 日志记录:记录查询内容、答案和处理时间,便于调试和性能分析。
  5. 输出:将答案返回给用户。

3 代码介绍

以下是 old_main.py 的完整代码,包含详细注释,逐行解析功能与实现逻辑。

3.1 导入必备的工具包

# 导入 MySQL 系统组件,用于数据库操作和搜索
from mysql_qa import MySQLClient, RedisClient, BM25Search
# 导入 RAG 系统组件,用于知识库检索和答案生成
from rag_qa import VectorStore, RAGSystem
# 导入配置和日志工具,用于系统配置和日志记录
from base import logger, Config
# 导入 OpenAI 客户端,用于调用 DashScope API
from openai import OpenAI
# 导入时间库,用于记录处理时间
import time

3.2 系统初始化

  • (__init__) 初始化方法
  • 功能:初始化日志、配置、数据库客户端、搜索模块、向量存储和 RAG 系统。
  • 关键点:通过 Config 管理 API 密钥和模型参数,异常处理确保 OpenAI 客户端初始化成功。
class IntegratedQASystem:
    def __init__(self):
        # 初始化日志工具,用于记录系统运行信息
        self.logger = logger
        # 初始化配置对象,加载系统参数
        self.config = Config()
        # 初始化 MySQL 客户端,用于数据库操作
        self.mysql_client = MySQLClient()
        # 初始化 Redis 客户端,用于缓存管理
        self.redis_client = RedisClient()
        # 初始化 BM25 搜索模块,结合 MySQL 和 Redis
        self.bm25_search = BM25Search(self.redis_client, self.mysql_client)
        try:
            # 初始化 OpenAI 客户端,连接 DashScope API
            self.client = OpenAI(api_key=self.config.DASHSCOPE_API_KEY, base_url=self.config.DASHSCOPE_BASE_URL)
        except Exception as e:
            # 记录 OpenAI 初始化失败的错误日志
            self.logger.error(f"OpenAI 客户端初始化失败: {e}")
            # 抛出异常,终止初始化
            raise
        # 初始化向量存储,用于 RAG 系统的知识库管理
        self.vector_store = VectorStore()
        # 初始化 RAG 系统,传入向量存储和 DashScope API 调用函数
        self.rag_system = RAGSystem(self.vector_store, self.call_dashscope)

3.3 调用 DashScope API

  • (call_dashscope) 方法
  • 功能:通过 OpenAI 客户端调用 DashScope API,基于用户提示生成答案。
  • 关键点:设置系统提示为“你是一个有用的助手”,异常处理捕获 API 调用失败,返回错误信息。
    def call_dashscope(self, prompt):
        # 定义调用 DashScope API 的方法,生成自然语言答案
        try:
            # 创建聊天完成请求,调用 DashScope API
            completion = self.client.chat.completions.create(
                model=self.config.LLM_MODEL,  # 使用配置中的语言模型
                messages=[
                    {"role": "system", "content": "你是一个有用的助手。"},  # 系统提示
                    {"role": "user", "content": prompt},  # 用户输入的提示
                ]
            )
            # 检查响应是否有效,返回答案内容
            return completion.choices[0].message.content if completion.choices else "错误:无效的 LLM 响应"
        except Exception as e:
            # 记录 API 调用失败的错误日志
            self.logger.error(f"LLM 调用失败: {e}")
            # 返回错误信息,便于调试
            return f"错误:LLM 调用失败 - {e}"

3.4 查询处理

  • (query) 方法
  • 功能:处理用户查询,优先通过 BM25 搜索 MySQL,若无可靠答案则回退到 RAG 系统。
  • 关键点:设置 BM25 相似度阈值 0.85,记录查询和处理时间,支持学科过滤。
    def query(self, query, source_filter=None):
        # 定义查询方法,处理用户输入的查询
        start_time = time.time()  # 记录查询开始时间
        # 记录查询信息到日志
        self.logger.info(f"处理查询: '{query}'")
        # 执行 BM25 搜索,获取答案和是否需要 RAG 的标志
        answer, need_rag = self.bm25_search.search(query, threshold=0.85)
        if answer:
            # 如果找到可靠答案,记录答案到日志
            self.logger.info(f"MySQL 答案: {answer}")
            # 计算处理时间
            processing_time = time.time() - start_time
            # 记录处理时间到日志
            self.logger.info(f"查询处理耗时 {processing_time:.2f}秒")
            # 返回 MySQL 答案
            return answer
        elif need_rag:
            # 如果需要 RAG,记录回退信息到日志
            self.logger.info("无可靠 MySQL 答案,回退到 RAG")
            # 调用 RAG 系统生成答案,支持学科过滤
            answer = self.rag_system.generate_answer(query, source_filter=source_filter)
            # 记录 RAG 答案到日志
            self.logger.info(f"RAG 答案: {answer}")
            # 计算处理时间
            processing_time = time.time() - start_time
            # 记录处理时间到日志
            self.logger.info(f"查询处理耗时 {processing_time:.2f}秒")
            # 返回 RAG 答案
            return answer
        else:
            # 如果无答案,记录信息到日志
            self.logger.info("未找到答案")
            # 计算处理时间
            processing_time = time.time() - start_time
            # 记录处理时间到日志
            self.logger.info(f"查询处理耗时 {processing_time:.2f}秒")
            # 返回默认答案
            return "未找到答案"

3.5 命令行交互

  • (main) 函数
  • 功能:提供交互式命令行界面,接受用户查询和学科过滤,显示答案。
  • 关键点:验证学科过滤的有效性,异常处理和资源清理确保系统健壮。
def main():
    # 定义主函数,提供命令行交互界面
    qa_system = IntegratedQASystem()  # 初始化问答系统
    try:
        # 打印欢迎信息
        print("\n欢迎使用集成问答系统!")
        # 打印支持的学科类别
        print(f"支持的来源: {qa_system.config.VALID_SOURCES}")
        # 提示用户输入查询或退出
        print("输入查询进行问答,输入 'exit' 退出。")
        while True:
            # 获取用户输入的查询
            query = input("\n输入查询: ").strip()
            if query.lower() == "exit":
                # 如果用户输入 exit,记录退出日志
                logger.info("退出系统")
                # 打印退出信息
                print("再见!")
                # 退出循环
                break
            # 获取用户输入的学科过滤
            source_filter = input(f"输入来源过滤 ({'/'.join(qa_system.config.VALID_SOURCES)}) (按 Enter 跳过): ").strip()
            if source_filter and source_filter not in qa_system.config.VALID_SOURCES:
                # 如果学科过滤无效,记录警告日志
                logger.warning(f"无效来源 '{source_filter}',忽略过滤")
                # 打印无效信息,忽略过滤
                print(f"无效来源 '{source_filter}',继续无过滤。")
                source_filter = None
            # 执行查询,获取答案
            answer = qa_system.query(query, source_filter)
            # 打印答案
            print(f"\n答案: {answer}")
    except Exception as e:
        # 记录系统错误日志
        logger.error(f"系统错误: {e}")
        # 打印错误信息
        print(f"发生错误: {e}")
    finally:
        # 无论是否发生错误,关闭 MySQL 连接
        qa_system.mysql_client.close()

if __name__ == "__main__":
    # 如果脚本作为主程序运行,调用 main 函数
    main()

章节总结

本章展示了如何通过 old_main.py 构建一个融合 MySQL FAQ 和 RAG 的智能问答系统。系统利用 BM25 算法快速匹配结构化数据,RAG 系统处理复杂查询,配备日志记录和错误处理,适合教育场景下的实时问答需求。