PythonRAG应用怎么搭建

wen python案例 1

Python RAG应用怎么搭建:从零构建企业级知识问答系统

📖 目录导读

  1. 什么是RAG?为什么需要它?
  2. RAG应用的核心架构拆解
  3. 开发环境与依赖库准备
  4. 文档加载与文本分割实战
  5. 向量化与向量数据库搭建
  6. 检索器设计与相似度匹配
  7. 大模型集成与答案生成
  8. 完整代码示例与调优技巧
  9. 常见问题与问答(FAQ)

什么是RAG?为什么需要它?

Q: 什么是RAG?
RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合信息检索与文本生成的技术,它先从一个知识库中检索与用户查询最相关的文档片段,再将这些片段作为上下文输入给大语言模型(LLM),让模型生成更准确、更具时效性的答案,从而解决大模型“幻觉”和知识过时问题。

PythonRAG应用怎么搭建

Q: 为什么企业要用RAG而不是微调?
微调需要大量标注数据、高昂算力,且模型知识更新困难,RAG只需更新向量数据库中的文档,即可实时扩展知识范围,成本低、灵活性强,特别适合内部知识库、产品文档、客服系统等场景。


RAG应用的核心架构拆解

一个完整的Python RAG应用包含以下流水线:

  1. 数据预处理阶段:加载PDF、Word、网页等源文档 → 文本分块(Chunking)→ 向量化(Embedding)→ 存入向量数据库。
  2. 检索阶段:用户提问 → 向量化查询 → 向量数据库相似度搜索 → 返回Top-K相关片段。
  3. 生成阶段:将查询+检索片段拼接成Prompt → 调用LLM生成最终答案。

关键技术选择:Text Embedding模型(如text-embedding-ada-002)、向量数据库(如Chroma、Qdrant、Pinecone)、LLM(如GPT-4、Claude、开源模型)。


开发环境与依赖库准备

首先创建Python虚拟环境(推荐Python 3.10+):

python -m venv rag_env
source rag_env/bin/activate  # Windows: rag_env\Scripts\activate

安装核心依赖:

pip install langchain chromadb openai tiktoken pypdf python-docx
  • langchain:编排RAG流程的框架
  • chromadb:轻量级向量数据库,无需单独部署
  • openai:调用Embedding与Chat模型
  • pypdf/python-docx:解析PDF和Word文档

文档加载与文本分割实战

代码示例:加载PDF并分块

from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 加载文档
loader = PyPDFLoader("./企业制度手册.pdf")
documents = loader.load()
# 文本分割(块大小500字符,重叠50字符)
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=50,
    separators=["\n\n", "\n", " ", ""]
)
chunks = text_splitter.split_documents(documents)
print(f"共分割为{len(chunks)}个文本块")

分割策略关键点

  • 块大小需平衡LLM上下文窗口与检索粒度,建议256-1024 tokens。
  • 重叠字符确保跨块语义不丢失。

向量化与向量数据库搭建

初始化Embedding模型

from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(
    model="text-embedding-ada-002",
    openai_api_key="your-api-key-here"  # 替换为真实API Key
)

创建Chroma向量库并存入数据

from langchain_community.vectorstores import Chroma
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"  # 持久化到磁盘
)
vectorstore.persist()  # 显式保存

进阶建议:对于百万级文档,改用Qdrant或Pinecone获得更优性能。


检索器设计与相似度匹配

# 创建相似度检索器,返回Top-3
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 3}
)
# 测试检索
query = "请假流程是什么?"
results = retriever.invoke(query)
for doc in results:
    print(f"→ {doc.page_content[:100]}...")

检索优化技巧

  • 使用MMR(最大边际相关性)避免返回过于相似的片段。
  • 加入元数据过滤(如按文档来源、日期过滤)。

大模型集成与答案生成

from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
llm = ChatOpenAI(
    model="gpt-4",  # 或 gpt-3.5-turbo
    temperature=0.2,  # 控制创造性
    openai_api_key="your-api-key-here"
)
# 构建Prompt模板
prompt = ChatPromptTemplate.from_template("""
基于以下上下文回答问题,如果无法从上下文中找到答案,请说“未找到相关信息”。
Context: {context}
Question: {question}
Answer:
""")
# 组装RAG链
from langchain.schema.runnable import RunnablePassthrough
def format_docs(docs):
    return "\n\n".join([doc.page_content for doc in docs])
rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | llm
)
# 执行查询
response = rag_chain.invoke("年假天数怎么计算?")
print(response.content)

输出示例

根据公司制度,员工入职满一年后享有5天年假,每增加一年工龄增加1天,上限15天,具体可查看第3.2节。


完整代码示例与调优技巧

端到端脚本(仅需替换API Key)

import os
from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain.prompts import ChatPromptTemplate
# 1. 加载文档目录
loader = DirectoryLoader("./docs", glob="**/*.pdf")
docs = loader.load()
# 2. 分割
splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=50)
chunks = splitter.split_documents(docs)
# 3. 向量化与存储
embeddings = OpenAIEmbeddings(openai_api_key=os.getenv("OPENAI_API_KEY"))
vectorstore = Chroma.from_documents(chunks, embeddings, persist_dir="./rag_db")
# 4. 检索器
retriever = vectorstore.as_retriever(k=3)
# 5. 生成链
llm = ChatOpenAI(model="gpt-4", openai_api_key=os.getenv("OPENAI_API_KEY"))
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个知识库助手,请基于上下文回答。"),
    ("human", "上下文:{context}\n问题:{question}")
])
chain = prompt | llm
# 6. 问答函数
def ask(question):
    context = "\n".join([d.page_content for d in retriever.invoke(question)])
    return chain.invoke({"context": context, "question": question}).content
print(ask("远程办公的申请条件?"))

调优清单

调优点 建议
分块大小 对技术文档用500字符,对对话类用256字符
检索数量k 一般3-5个,长文档可增加到7
LLM温度 答案要求事实性时设为0.1,创意生成时0.7
Prompt模板 明确要求“只根据上下文回答”降低幻觉

常见问题与问答(FAQ)

Q1: 为什么检索结果不相关?
A: 检查文本分块是否过大导致内容混杂,或Embedding模型选择不当,可尝试换用BGE、E5等中文Embedding模型。

Q2: 如何支持中文文档?
A: 使用langchain.text_splitterChineseTextSplitter,或直接用RecursiveCharacterTextSplitter(默认支持中文),Embedding模型推荐maidalun1020/bce-embedding-base_v1

Q3: 系统响应太慢怎么办?
A: 使用异步检索(asyncio)、缓存常见查询、或对向量数据库建立索引。

Q4: 需要处理100万+文档如何架构?
A: 用Elasticsearch做全文搜索+向量检索双路召回,部署容器化服务(FastAPI+Celery)。

Q5: 如何避免泄露敏感信息?
A: 在Prompt中加入“不要输出原始文档内容”,并配置LLM的内容过滤层。


延伸资源

  • LangChain官方文档:python.langchain.com
  • OpenAI Embeddings官方指南
  • ChromaDB GitHub仓库

(声明:本文仅作技术教学,所有API Key需自行申请。)

抱歉,评论功能暂时关闭!