一个普遍的困境
你有没有遇到过这样的情况:把一份内部文档丢给ChatGPT,让它帮你总结,结果它要么说"我没有访问这份文件的权限",要么一本正经地编造内容?
这是因为大语言模型是在一个固定时间点的公开数据上训练的,它天然不知道你公司的内部资料、你收集的私有文献,或者任何训练截止日期之后发生的事情。
RAG(Retrieval-Augmented Generation,检索增强生成)就是为解决这个问题而生的。
RAG 是什么
RAG 的核心思路很简单:与其让模型死记硬背所有知识,不如在回答时实时查资料。
类比一下:你参加一场开卷考试,可以随时翻阅手边的资料,而不是靠死记硬背。RAG 让 AI 也拥有了这种"开卷"能力。
工作流程分三步:
- 检索(Retrieve):收到用户提问后,先去知识库里搜索与问题最相关的文段。
- 增强(Augment):把检索到的相关内容拼接到 Prompt 里,一起送给大模型。
- 生成(Generate):模型根据这些"参考资料"来生成最终回答。
RAG 不是在"训练"模型,而是在推理阶段动态注入知识。这意味着你随时可以更新知识库,不需要重新训练模型,成本极低。
向量数据库:RAG 的关键组件
RAG 的检索步骤不是关键词匹配,而是语义搜索——理解意思的相似度,而不是字面重叠。这依赖于"向量嵌入(Embedding)"技术。
简单解释:把每段文字转换为一个高维数字向量,语义相近的文字,其向量在空间中的距离也更近。
# 使用 OpenAI Embedding API 将文本转为向量
import openai
def get_embedding(text):
response = openai.embeddings.create(
model="text-embedding-3-small",
input=text
)
return response.data[0].embedding
# 例:将文档分块并向量化存储
chunks = [
"公司2024年Q3营收为3.2亿元,同比增长18%",
"研发投入占营收比例达到12%,较上年提升2个百分点",
"新产品线在华南地区的市场占有率达到23%"
]
embeddings = [get_embedding(chunk) for chunk in chunks]
# 这些向量存入 Chroma、Pinecone、Milvus 等向量数据库
搭建一个简单的 RAG 系统
第一步:安装依赖
pip install openai chromadb langchain pypdf2
第二步:文档分块与向量化
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
# 加载 PDF 文档
loader = PyPDFLoader("my_document.pdf")
documents = loader.load()
# 按段落切分(每块 500 字,重叠 50 字保持上下文)
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50
)
chunks = splitter.split_documents(documents)
# 向量化并存入本地数据库
embedding_model = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embedding_model,
persist_directory="./chroma_db"
)
print(f"已处理 {len(chunks)} 个文本块")
第三步:检索 + 生成
from openai import OpenAI
client = OpenAI()
def rag_query(question: str) -> str:
# 1. 检索:找最相关的 3 段内容
relevant_docs = vectorstore.similarity_search(question, k=3)
context = "\n\n".join([doc.page_content for doc in relevant_docs])
# 2. 构建带上下文的 Prompt
prompt = f"""请根据以下参考资料回答问题。
如果参考资料中没有相关信息,请明确说明"根据现有资料无法回答"。
【参考资料】
{context}
【问题】
{question}
请给出准确、简洁的回答:"""
# 3. 调用大模型生成回答
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
temperature=0.2, # 降低随机性,让回答更严谨
)
return response.choices[0].message.content
# 测试
answer = rag_query("2024年Q3的研发投入占比是多少?")
print(answer)
实践中的关键细节
分块策略很重要
分块太小:丢失上下文,模型看到的信息碎片化;分块太大:引入噪声,消耗更多Token。通常以段落为单位,500-800字一块,并保持适当重叠,是较好的起点。
检索后重排序
单纯向量搜索有时会漏掉关键信息。可以加入交叉编码器(Cross-Encoder)重排序,先粗检索20条,再精排选出最优3条,显著提升检索质量。
让模型标注来源
# 在 Prompt 中要求标注来源
prompt += "\n回答时请在末尾注明参考了哪段资料(用[资料1][资料2]等形式)。"
适合 RAG 的场景
- 企业内部知识库问答(规章制度、产品手册)
- 个人读书笔记/研究文献的智能检索
- 客服机器人接入产品FAQ
- 合同/法律文档的条款查询
- 代码库问答(让AI"读懂"你的项目)
小结
RAG 是目前让 AI 处理私有知识最实用、成本最低的方案。它不需要微调模型,不需要大量GPU资源,只需要一个向量数据库和基础的 Python 代码就能跑起来。
如果你有一批文档想让AI帮你处理,RAG 是最值得先试的路径。