后端转AI第一课:RAG是面试重中之重,也是第一个简历项目的核心。
RAG是什么
RAG = 给模型查资料再答。模型不记得你的文档,那就先检索相关片段,拼进提示词,再让模型回答——答案有依据、能溯源、不胡说。
8步全链路
① 文档解析 → ② 切片分块 → ③ Embedding → ④ 向量库存储
→ ⑤ 语义检索 → ⑥ 召回重排 → ⑦ Prompt拼接 → ⑧ 大模型生成
① 文档解析(PDF/Word→文本)
from langchain_community.document_loaders import PyPDFLoader
documents.extend(PyPDFLoader(path).load())
documents.extend(Docx2txtLoader(path).load())
documents.extend(TextLoader(path, encoding="utf-8").load())
# 坑:表格/图片里的字读不出,需要OCR或多模态
② 切片分块(200-500字+重叠)
from langchain_huggingface import HuggingFaceEmbeddings
splitter = RecursiveCharacterTextSplitter(
chunk_size=300, # 块大小
chunk_overlap=50, # 重叠防切断语义
separators=["\n\n", "\n", "。", "!", "?", " ", ""]
)
chunks = splitter.split_documents(documents)
# 坑:块太大召回糙,太小丢上下文
③ Embedding(中文用bge)
from langchain_community.embeddings import HuggingFaceBgeEmbeddings
embeddings = HuggingFaceEmbeddings(
model_name=embed_model_name,
model_kwargs={"device": "cpu"}, # 无显卡固定cpu
encode_kwargs={"normalize_embeddings": True} # BGE模型强制归一化向量
)
# 中文场景用bge/m3e,比通用英文模型准
④ 向量库存储(Chroma最轻)
from langchain_chroma import Chroma
vectorstore = Chroma(
persist_directory="./chroma_db",
embedding_function=embeddings
)
⑤⑥ 语义检索 + 重排
retriever = vectorstore.as_retriever(
search_kwargs={"k": 5} # 初召回K块
)
# 重排(Rerank):用交叉编码器挑最相关Top-N
from langchain_community.cross_encoders import HuggingFaceCrossEncoder
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CrossEncoderReranker
reranker = CrossEncoderReranker(
model=HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-base"),
top_n=3
)
compression_retriever = ContextualCompressionRetriever(
base_compressor=reranker, base_retriever=retriever
)
⑦⑧ Prompt拼接 + 生成
from langchain_community.document_loaders import (
PyPDFLoader,
TextLoader,
Docx2txtLoader,
)
prompt = ChatPromptTemplate.from_messages([
("system", """你是一个知识库问答助手。
只根据提供的资料回答,资料里没有的,明确说"不知道"。
回答末尾标注引用来源。"""),
("user", "资料:\n{context}\n\n问题:{question}")
])
llm = ChatOpenAI(model="qwen-max", temperature=0.2)
def ask(question: str):
docs = compression_retriever.invoke(question)
context = "\n".join(f"[{i+1}] {d.page_content}" for i, d in enumerate(docs))
chain = prompt | llm
return chain.invoke({"context": context, "question": question})
完整示例
question = "什么是RAG?"
answer = ask(question)
print(answer.content)
关键认知:RAG的"稳"靠检索质量,不是模型多强。召回差,模型再强也胡说。
过关清单
☐ 上传PDF能解析出文本
☐ 分块有重叠,参数可配置
☐ 中文Embedding(bge)检索语义相关
☐ 回答带引用来源
☐ 知识库无答案时明确说"不知道"
📌 配套Demo代码:(Star支持🔥)backend-to-ai-guide/rag-demo/README.md at main · cxy-ai-gongfang/backend-to-ai-guide · GitHub
下一篇:RAG优化实战——去幻觉/提召回/成本控制。
欢迎关注专栏,持续更新。