RAG系统运行¶
学习目标:¶
- 1.掌握如何通过命令行参数和增强的错误处理运行EduRAG系统。
- 2.了解整合核心的RAG逻辑。
main.py是EduRAG系统的运行模块,涵盖错误处理、参数灵活性和日志记录等功能。main.py作为命令行入口,支持数据处理和交互式查询,适合开发和调试;该模块整合了前几章的核心逻辑,为用户提供了健壮的交互方式。
7.1 系统运行入口¶
功能概述¶
main.py是EduRAG系统的运行入口,提供两种运行模式:
- 数据处理模式:加载并向量化文档,构建向量数据库,支持多学科目录处理。
- 查询模式:通过命令行交互式回答用户查询,支持学科过滤。
- 完整代码
import os
import sys
from base import Config, logger
from core.document_loader import process_documents # 导入处理文档的函数
from core.vector_store import VectorStore
from core.rag_system import RAGSystem
from openai import OpenAI # 使用 OpenAI 接口
conf = Config()
def main(query_mode=True, directory_path="data"):
# 初始化 DashScope API 客户端 (通过 OpenAI 接口)
# 确保环境变量 DASHSCOPE_API_KEY 和 DASHSCOPE_BASE_URL 已设置
try:
client = OpenAI(api_key=conf.DASHSCOPE_API_KEY,
base_url=conf.DASHSCOPE_BASE_URL)
except Exception as e:
logger.error(f"初始化 OpenAI 客户端失败 (请检查 API Key 和 Base URL): {e}")
# 如果客户端初始化失败,可能无法继续,取决于模式
if query_mode: # 查询模式下必须要有 LLM
print("错误:无法初始化语言模型客户端,无法进入查询模式。")
return
# 数据处理模式可能不需要 LLM,可以继续,但最好记录错误
client = None # 标记客户端不可用
# 定义 LLM 调用函数 (仅在需要时定义和使用)
def call_dashscope(prompt):
if not client: # 检查客户端是否可用
logger.error("LLM 客户端未初始化,无法调用 call_dashscope")
return f"错误: LLM客户端不可用"
try:
completion = client.chat.completions.create(
model=conf.LLM_MODEL,
messages=[
{"role": "system", "content": "你是一个有用的助手."},
{"role": "user", "content": prompt},
]
# 可以添加 temperature 等参数
)
if completion.choices and completion.choices[0].message:
return completion.choices[0].message.content
else:
logger.error("LLM API 调用返回无效响应或空消息")
return "错误: LLM返回无效响应"
except Exception as e:
logger.error(f"LLM API (call_dashscope) 调用失败: {e}")
return f"错误: 调用LLM失败 - {e}"
# 初始化 VectorStore
try:
vector_store = VectorStore(
collection_name=conf.MILVUS_COLLECTION_NAME,
host=conf.MILVUS_HOST,
port=conf.MILVUS_PORT,
database=conf.MILVUS_DATABASE_NAME,
)
except Exception as e:
logger.error(f"初始化 VectorStore 失败 (请检查 Milvus 连接配置): {e}")
print("错误:无法连接到向量数据库,程序无法继续。")
return
# 根据模式执行不同操作
if not query_mode:
# --- 数据处理模式 ---
logger.info("进入数据处理模式...")
total_chunks_added = 0
for source_dir in conf.VALID_SOURCES:
dir_path = os.path.join(directory_path, f"{source_dir}_data")
if os.path.exists(dir_path):
logger.info(f"开始处理目录: {dir_path}")
try:
chunks = process_documents(
dir_path,
conf.PARENT_CHUNK_SIZE,
conf.CHILD_CHUNK_SIZE,
conf.CHUNK_OVERLAP,
)
if chunks:
vector_store.add_documents(chunks)
total_chunks_added += len(chunks)
logger.info(f"成功处理目录 {dir_path},添加了 {len(chunks)} 个文档块")
else:
logger.info(f"目录 {dir_path} 未发现有效文档或处理结果为空")
except Exception as e:
logger.error(f"处理目录 {dir_path} 时出错: {e}")
else:
logger.warning(f"目录 {dir_path} 不存在,跳过处理")
logger.info(f"数据处理完成,共添加了 {total_chunks_added} 个文档块到向量存储")
else:
# --- 交互式查询模式 ---
if not client: # 再次检查 LLM 客户端是否必须且可用
print("错误:查询模式需要语言模型客户端,但初始化失败。")
return
logger.info("进入交互式查询模式...")
try:
rag_system = RAGSystem(vector_store, call_dashscope)
except Exception as e:
logger.error(f"初始化 RAGSystem 失败: {e}")
print("错误:无法初始化 RAG 系统,无法进入查询模式。")
return
valid_sources = conf.VALID_SOURCES
print("\n欢迎使用 EduRAG 交互式查询系统!")
print(f"支持的学科类别:{valid_sources}")
print("输入您的问题,或输入 'exit' 退出。")
while True:
query = input("\n请输入您的问题:")
if query.lower() == "exit":
logger.info("用户退出查询模式")
print("再见!")
break
source_filter_input = input(f"请输入学科类别 ({'/'.join(valid_sources)}) (直接回车默认不过滤):").strip()
source_filter = None # 默认不过滤
if source_filter_input:
if source_filter_input in valid_sources:
source_filter = source_filter_input
logger.info(f"用户选择了学科过滤: {source_filter}")
else:
logger.warning(
f"无效的学科类别 '{source_filter_input}',将不过滤"
)
print(f"提示:输入的学科 '{source_filter_input}' 无效,将不过滤。")
try:
print("正在生成答案,请稍候...")
answer = rag_system.generate_answer(query, source_filter=source_filter)
print("-" * 30)
print(f"问题: {query}")
print(f"回答: {answer}")
print("-" * 30)
except Exception as e:
logger.error(f"处理查询 '{query}' 时失败: {str(e)}")
print(f"抱歉,处理您的问题时遇到了错误,请稍后重试或联系管理员。\n")
if __name__ == "__main__":
# 默认进入查询模式
# 若要执行数据处理,可以修改调用方式,例如:
# main(query_mode=False)
# 或者通过命令行参数控制
import argparse
parser = argparse.ArgumentParser(description="EduRAG System Main Entry Point")
parser.add_argument('--data-processing', action='store_true', help='Run in data processing mode instead of query mode.')
parser.add_argument('--data-dir', type=str, default='./data', help='Path to the data directory.')
args = parser.parse_args()
main(query_mode=(not args.data_processing), directory_path=args.data_dir)
实现细节¶
- 环境变量加载:
- 使用
Config文件,确保API密钥等配置从环境变量读取。
- 使用
- LLM客户端初始化:
- 增强错误处理,若初始化失败,在查询模式下退出,数据处理模式可继续。
- 定义
call_dashscope函数,封装DashScope API调用,包含详细异常处理。
- VectorStore初始化:
- 使用显式参数初始化,确保配置可控,若失败则终止程序。
- 数据处理模式:
- 遍历
VALID_SOURCES,处理每个学科目录,记录处理的文档块数量。 - 支持自定义分块参数(如
PARENT_CHUNK_SIZE)。
- 遍历
- 查询模式:
- 显示支持的学科类别,提供输入提示。
- 校验
source_filter,若无效则提示并忽略。 - 输出格式化答案,增强用户体验。
- 命令行参数:
- 使用
argparse支持--data-processing和--data-dir,提高灵活性。
- 使用
6.2 RAG系统运行¶
运行方式¶
- 命令行运行(main.py):
- 数据处理:
python main.py --data-processing --data-dir ./data - 查询模式:
示例输出:
python main.py欢迎使用 EduRAG 交互式查询系统! 支持的学科类别:['ai', 'java', 'test', 'ops', 'bigdata'] 输入您的问题,或输入 'exit' 退出。 请输入您的问题:AI学科学费是多少? 请输入学科类别 (ai/java/test/ops/bigdata) (直接回车默认不过滤):ai 正在生成答案,请稍候... ------------------------------ 问题: AI学科学费是多少? 回答: ... ------------------------------
- 数据处理:
章节总结¶
本章节详细介绍了RAG系统运行的main.py:
main.py:命令行入口,支持数据处理和交互式查询。