Преглед на файлове

initial for rag [project

linruying преди 2 месеца
родител
ревизия
008f3e68bb

+ 73 - 0
02_rag_build/config.py

@@ -0,0 +1,73 @@
+"""
+统一配置模块:环境变量、数据库连接、LLM 实例。
+
+其他模块直接 `from config import llm, db, engine` 即可,
+无需重复写 load_dotenv 和 db_uri 构造逻辑。
+"""
+
+import os
+from dotenv import load_dotenv
+from langchain_openai import ChatOpenAI
+from langchain_community.utilities import SQLDatabase
+from sqlalchemy import create_engine
+from langchain_community.embeddings import DashScopeEmbeddings
+from langchain_community.chat_models import ChatTongyi
+
+
+# ============================================================
+# 1. 加载 .env(整个项目只调用一次)
+# ============================================================
+load_dotenv(os.path.join(os.path.dirname(__file__), "..", ".env"))
+
+# ============================================================
+# 2. 数据库配置
+# ============================================================
+DB_HOST = os.getenv("DB_HOST", "127.0.0.1")
+DB_PORT = os.getenv("DB_PORT", "3306")
+DB_USER = os.getenv("DB_USER", "root")
+DB_PASSWORD = os.getenv("DB_PASSWORD", "")
+DB_NAME = os.getenv("DB_NAME", "analytics_demo")
+
+DB_URI = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
+
+# SQLAlchemy 引擎(DataFrame 加载用)
+engine = create_engine(DB_URI)
+
+# LangChain SQLDatabase 实例(Agent 工具包用)
+db = SQLDatabase.from_uri(DB_URI)
+
+# ============================================================
+# 3. DEEPSEEK LLM 配置
+# ============================================================
+DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
+DEEPSEEK_BASE_URL = os.getenv("DEEPSEEK_BASE_URL")
+
+llm = ChatOpenAI(
+    model="deepseek-v4-flash",
+    api_key=DEEPSEEK_API_KEY,
+    base_url=DEEPSEEK_BASE_URL,
+    temperature=0,
+)
+
+print("✅ 配置加载完成(LLM + 数据库连接)")
+
+
+
+# ============================================================
+# 4. ALI LLM 配置
+# ============================================================
+# 初始化 Embedding 模型
+# 需要先在 https://dashscope.console.aliyun.com/ 获取 API Key
+DASHSCOPE_API_KEY=os.getenv("DASHSCOPE_API_KEY")
+embedding_model = DashScopeEmbeddings(
+    model="text-embedding-v3",        # 模型名称
+    dashscope_api_key=DASHSCOPE_API_KEY   # 从 .env 读取
+)
+
+# ============================================================
+# 5. ChatTongyi LLM 配置
+# ============================================================
+ChatTongyillm = ChatTongyi(
+    model="qwen-plus", 
+    dashscope_api_key=DASHSCOPE_API_KEY
+    )

BIN
02_rag_build/data/car_info.pdf


BIN
02_rag_build/knowledge_db/bcdc4df2-cfad-4a73-ba4c-df7709c6dd98/data_level0.bin


BIN
02_rag_build/knowledge_db/bcdc4df2-cfad-4a73-ba4c-df7709c6dd98/header.bin


BIN
02_rag_build/knowledge_db/bcdc4df2-cfad-4a73-ba4c-df7709c6dd98/index_metadata.pickle


BIN
02_rag_build/knowledge_db/bcdc4df2-cfad-4a73-ba4c-df7709c6dd98/length.bin


BIN
02_rag_build/knowledge_db/bcdc4df2-cfad-4a73-ba4c-df7709c6dd98/link_lists.bin


BIN
02_rag_build/knowledge_db/chroma.sqlite3


+ 90 - 0
02_rag_build/main.py

@@ -0,0 +1,90 @@
+import os
+from langchain_community.document_loaders import PyMuPDFLoader
+from langchain_text_splitters import RecursiveCharacterTextSplitter
+from utils.dataclean import clean_pdf_text
+from langchain_community.vectorstores import Chroma
+from langchain_core.prompts import ChatPromptTemplate
+from langchain_core.output_parsers import StrOutputParser
+from config import embedding_model, ChatTongyillm
+
+
+# ========== 第一步:加载文档 ==========
+# 获取当前脚本所在目录,构建 PDF 文件的绝对路径
+script_dir = os.path.dirname(os.path.abspath(__file__))
+pdf_path = os.path.join(script_dir, "data", "car_info.pdf")
+
+# 创建加载器实例,传入 PDF 文件路径
+pdf_loader = PyMuPDFLoader(pdf_path)
+
+# 调用 load() 方法,返回一个 Document 列表(每页一个 Document)
+pdf_pages = pdf_loader.load()
+print("加载资料完成")
+
+
+# ========== 第二步:清洗数据(可选,根据文档质量决定)==========
+# 清洗每个 Document 的文本内容
+for page in pdf_pages:
+    page.page_content = clean_pdf_text(page.page_content)
+print("清晰资料完成")    
+
+
+# ========== 第三步:创建递归字符分割器 ==========
+text_splitter = RecursiveCharacterTextSplitter(
+    # 分隔符优先级:段落 → 换行 → 句号 → 空格 → 硬切
+    separators=["\n\n", "\n", "。", "!", "?", " ", ""],
+    
+    # 每个块最大 50 字符
+    chunk_size=50,
+    
+    # 相邻块重叠 10 字符(chunk_size 的 20%)
+    chunk_overlap=10,
+    
+    # 长度计算函数
+    length_function=len
+)
+
+# 对整个文档切分
+split_docs = text_splitter.split_documents(pdf_pages)
+print("切割资料完成") 
+
+# ========== 第四步:向量化 + 存入向量库 ==========
+vectorstore = Chroma.from_documents(
+    documents=split_docs,
+    embedding=embedding_model,
+    persist_directory="./knowledge_db"
+)
+print("存储向量资料完成") 
+
+# ========== 第五步:创建检索器 ==========
+retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
+
+# ========== 第六步:提问 ==========
+query = "什么汽车比较经济实惠"
+relevant_docs = retriever.invoke(query)
+
+# ========== 第七步:生成回答 ==========
+context = "\n\n---\n\n".join([d.page_content for d in relevant_docs])
+
+prompt = ChatPromptTemplate.from_template("""
+你是一个专业的知识库助手。请根据以下上下文回答问题。
+
+**规则:**
+- 只基于提供的上下文回答,不要编造
+- 如果上下文中没有相关信息,直接说「根据现有资料,我找不到这个问题的答案」
+- 回答要简洁直接,引用原文时用引号
+
+**上下文:**
+{context}
+
+**问题:**
+{question}
+""")
+
+
+chain = prompt | ChatTongyillm | StrOutputParser()
+
+
+if __name__ == "__main__":
+
+    answer = chain.invoke({"context": context, "question": query})
+    print(answer)

+ 15 - 0
02_rag_build/utils/dataclean.py

@@ -0,0 +1,15 @@
+def clean_pdf_text(text: str) -> str:
+    """清洗 PDF 解析出的文本,去除常见噪声"""
+    import re
+    
+    # 删除非中文字符之间的换行符
+    text = re.sub(r'[^一](\n)[^一]', 
+                  lambda m: m.group(0).replace('\n', ''), text)
+    
+    # 删除项目符号和多余空格
+    text = text.replace('•', '').replace('  ', ' ')
+    
+    # 删除连续的换行符(保留一个)
+    text = re.sub(r'\n{2,}', '\n', text)
+    
+    return text.strip()