小白的Langchain实践__附RAG问答助手源码

流程

  1. 环境配置

  2. 知识文本转向量后存入知识向量库(embeding.py):

    获取文本内容 → 文本分割 → 创建嵌入模型 → 创建向量数据库并保存到本地

  3. RAG问答助手编写(main.py):

    用户问题 → 知识向量库检索 → 知识内容+用户问题给到模型 →模型返回结果

一、项目初始化 + 环境配置

  1. 下载uv(包管理工具)
pip install uv # 使用pip下载
powershell -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows下载
curl -LsSf https://astral.sh/uv/install.sh | sh # Linux下载

uv --version # 下载完后进行验证
  1. 创建项目
uv init AIAssistant # AIAssistant是项目的名称
  1. 创建虚拟环境并激活
uv venv # 创建虚拟环境,在项目目录下生成.venv文件夹
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser # 将powershell设置执行策略为RemoteSigned
.\.venv\Scripts\activate # 激活环境

4.环境搭建

uv add langchain langchain-core langchain-community # langchain三件套
uv add langchain-openai # 问答模型相关
uv add DashScopeEmbeddings # 千问embeding

3.项目结构
在这里插入图片描述

main.py:通过RAG和大模型进行简单问题的回答

embeding.py:将文档转成向量并进行存储

.env:环境配置,不要提交到 Git,添加到 .gitignore

BASE_URL=https://api.deepseek.com   #deepseek api地址
MODEL=deepseek-chat                 #deepseek模型名称
OPENAI_API_KEY="your_api_key"       #deepseek 问答模型
DASHSCOPE_API_KEY="your_api_key"    #千问 embeding模型

knowledge.txt:知识内容

.venv:虚拟环境中的各类包

.gitignore:出现在.gitignore中的文件将不会被提交到Git上

二、embeding.py

1. 文档+环境变量加载

#加载环境变量(确保DASHSCOPE_API_KEY已设置)
load_dotenv()
#文档加载
loader = TextLoader("knowledge.txt", encoding="utf-8")
documents = loader.load()

load_dotenv():从 .env 文件中加载环境变量到系统环境中。

TextLoader(**file_path,encoding**)

输入参数:

file_path:文本文件的路径

encoding:文件编码格式,如 "utf-8""latin-1"

常用方法:

load(): 同步加载整个文件为一个 Document

load_and_split(text_splitter): 加载并分割文档(配合文本分割器使用)

aload(): 异步加载文档

2. 文本分割

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=200,
    chunk_overlap=50,
    length_function=len
)
texts = text_splitter.split_documents(documents)

RecursiveCharacterTextSplitter()

输入参数

separators: 分隔符列表,默认 ["\n\n", "\n", " ", ""](按段落→行→空格→字符递归分割)

chunk_size: 每个块的最大字符数,默认 100

chunk_overlap:块间重叠字符数,默认 20

length_function:计算长度的函数,默认 len

is_separator_regex:是否将分隔符视为正则表达式,默认 False

add_start_index: 是否在元数据中添加起始索引,默认 False

常用方法

split_text(text):将文本分割为字符串列表

create_documents([texts]): 将文本列表转换为Document对象

from_language(language): 创建特定编程语言的分割器

python_splitter = RecursiveCharacterTextSplitter.from_language(language=Language.PYTHON, chunk_size=50)

3. Embdeing模型将文档向量化并存储到本地

# 使用DashScope创建嵌入模型(自动从环境变量读取API Key)
embeddings = DashScopeEmbeddings(model="text-embedding-v4")

# 创建向量数据库并保存到本地
vectorstore = FAISS.from_documents(texts, embeddings)
vectorstore.save_local("vectorstore")  # 保存到当前目录的vectorstore文件夹

使用千问text-embedding-v4作为Embeding模型
具体使用方法参考官方文档https://bailian.console.aliyun.com/cn-beijing/?utm_content=se_1021227934&tab=doc#/doc/?type=model&url=2842587

FAISS.from_documents(texts, embeddings)(返回一个Faiss对象):
输入参数:
texts:文档列表(List[Document]),每个Document包含page_content(文本内容)和metadata(元数据)
embeddings: 嵌入模型对象(如HuggingFaceEmbeddings),用于将文本转换为向量
常用方法:
.save_local("vectorstore"):将Faiss对象存储到vectorstore文件夹中

三、main.py

1. 初始化

知识向量库加载

vectorstore = FAISS.load_local(
    "vectorstore", 
    embeddings=DashScopeEmbeddings(model="text-embedding-v4",),
    allow_dangerous_deserialization=True
) 

.load_local(folder_path,embeddings,allow_dangerous_deserialization)加载向量数据库:

folder_pathstr保存向量存储的本地目录路径
embeddingsEmbeddings与创建时相同的嵌入模型
allow_dangerous_deserializationbool是否允许反序列化(安全风险)

创建检索器

retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 3}
)

vectorstore.as_retriever()用于从向量数据库中检索相关文档:

参数说明示例
search_type检索类型,常用值:
  • "similarity":基于相似度的检索(默认)
  • "mmr":最大边际相关性(平衡相关性与多样性)
  • "similarity_score_threshold":基于相似度阈值的检索|search_type="similarity"|
    |search_kwargs|检索配置参数字典:
  • "k":返回的文档数量(默认5)
  • "score_threshold":相似度阈值(0-1之间)
  • "filter":元数据过滤条件|search_kwargs={"k": 3}|

初始化Chat模型

llm = ChatOpenAI(
    api_key=os.getenv("OPENAI_API_KEY"),
    base_url="https://api.deepseek.com",
    model="deepseek-chat",
    temperature=0.3
)

提示词模板预填装

custom_prompt = PromptTemplate.from_template(
    """
    你是一个日志分析专家。请根据以下 知识内容 回答 问题。如果你不知道答案,请说“我不知道”。
    知识内容:{context}
    问题:{question}
    """
)

文档格式化

def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

格式化的意义:

LLM需要结构化、清晰的输入

\n\n分隔不同文档内容,使LLM能明确区分不同来源的信息

2. chain(链)的构建

qa_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | custom_prompt
    | llm
    | StrOutputParser()
)

RunnablePassthrough:直接传递原始输入(用户问题)不作处理

管道符|:将上一个操作的内容作为下一个操作的输入

在这里插入图片描述

3. 主循环(问答主题)

def ask_question(question):
    answer = qa_chain.invoke(question)
    print(f"\n问题: {question}")
    print(f"回答: {answer}")
    print("\n参考来源:")
    for i, doc in enumerate(retriever.invoke(question)):
        print(f"来源 {i+1}: {doc.page_content[:150]}...")

四、源码

main.py
from langchain_community.vectorstores import FAISS
from langchain_openai import ChatOpenAI
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_community.embeddings import DashScopeEmbeddings 
import os
from dotenv import load_dotenv
load_dotenv()
# 1. 加载向量数据库(从第一部分保存的文件)
vectorstore = FAISS.load_local(
    "vectorstore", 
    embeddings=DashScopeEmbeddings(model="text-embedding-v4",),
    allow_dangerous_deserialization=True
)
# 2. 创建检索器
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 3}
)

# 3. 初始化DeepSeek LLM(兼容OpenAI接口)
llm = ChatOpenAI(
    api_key=os.getenv("OPENAI_API_KEY"),
    base_url="https://api.deepseek.com",
    model="deepseek-chat", 
    temperature=0.3
)
# 4. RAG提示模板
custom_prompt = PromptTemplate.from_template(
    """
    你是一个日志分析专家。请根据以下 知识内容 回答 问题。如果你不知道答案,请说“我不知道”。
    知识内容:{context}
    问题:{question}
    """
)

# 5. 文档格式化
def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

# 6. 构建RAG链
qa_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | custom_prompt
    | llm
    | StrOutputParser()
)

# 7. 问答函数
def ask_question(question):
    answer = qa_chain.invoke(question)
    print(f"\n问题: {question}")
    print(f"回答: {answer}")
    print("\n参考来源:")
    for i, doc in enumerate(retriever.invoke(question)):
        print(f"来源 {i+1}: {doc.page_content[:150]}...")

if __name__ == "__main__":
    ask_question("日志的特点")
embeding.py
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_community.vectorstores import FAISS
import os
from dotenv import load_dotenv

# 1. 加载环境变量(确保DASHSCOPE_API_KEY已设置)
load_dotenv()

# 2. 文档加载
loader = TextLoader("knowledge.txt", encoding="utf-8")
documents = loader.load()

# 3. 文本分割
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=200,
    chunk_overlap=50,
    length_function=len
)
texts = text_splitter.split_documents(documents)

# 4. 使用DashScope创建嵌入模型(自动从环境变量读取API Key)
embeddings = DashScopeEmbeddings(model="text-embedding-v4")

# 5. 创建向量数据库并保存到本地
vectorstore = FAISS.from_documents(texts, embeddings)
vectorstore.save_local("vectorstore")  # 保存到当前目录的vectorstore文件夹

print("向量数据库已创建并保存到 vectorstore 目录")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值