RAG 入门:三小时做一个「会读文档」的 AI 问答机器人
大模型不知道你公司的内部文档,也记不住上周的会议纪要——RAG(检索增强生成)就是解决这个问题的标准方案。这篇教程用最小代码把它讲透,看完你能自己搭一个「上传 PDF 就能提问」的机器人。
RAG 在解决什么问题
直接把文档塞进提示词有三个死穴:上下文装不下、成本随长度爆炸、长文本中间部分注意力衰减(lost in the middle)。
RAG 的思路很朴素:先检索出相关片段,只把相关内容给模型。整个流程四步:
文档 → 切分 → 向量化 → 存入向量库
↓
提问 → 检索 Top-K 片段 → 拼进提示词 → 生成回答
最小可运行实现
依赖只要三个包(向量库用最轻的 Chroma):
pip install openai chromadb pypdf
第一步:读文档并切分
from pypdf import PdfReader
text = "\n".join(p.extract_text() for p in PdfReader("手册.pdf").pages)
chunks = []
size, overlap = 500, 50 # 每块 500 字,相邻重叠 50 字
for i in range(0, len(text), size - overlap):
chunks.append(text[i:i + size])
切块是 RAG 效果的第一决定因素:太大则检索不精准且浪费上下文,太小则语义破碎。经验起点 300-800 字符 + 10% 重叠,之后按效果调。
第二步:向量化入库
import chromadb
client = chromadb.PersistentClient(path="./db")
col = client.get_or_create_collection("docs")
col.add(
ids=[str(i) for i in range(len(chunks))],
documents=chunks
# 不指定 embedding 函数时 Chroma 用内置模型,零配置可用
)
第三步:检索 + 生成
from openai import OpenAI
llm = OpenAI() # 也可指向 Ollama 本地模型
def ask(question, k=4):
hits = col.query(query_texts=[question], n_results=k)
context = "\n---\n".join(hits["documents"][0])
resp = llm.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "仅根据以下资料回答,找不到就说不知道,注明依据片段编号。"},
{"role": "user", "content": f"资料:\n{context}\n\n问题:{question}"}
]
)
return resp.choices[0].message.content
print(ask("报销流程是什么?"))
不到 40 行,一个能读 PDF 的问答机器人就跑起来了。
三个立竿见影的优化
1. 提示词里强制「说不知道」
上面 system 提示里的「找不到就说不知道」是防幻觉的第一道闸。不加这句,模型即使检索不到也会硬编。
2. 加重排(Rerank)
向量检索召回的 Top-K 里常有「相似但不相关」的噪音。用重排模型(如 bge-reranker)对 Top-20 粗筛结果精排,取前 3-5 块再生成,命中率显著提升。
3. 要求引用标注
让模型回答时注明「依据片段 2」,前端把片段号做成悬浮卡片。这既提升可信度,也让你能快速定位检索哪里出了问题——是 RAG 调试的利器。
什么时候 RAG 不够用
- 问题需要跨多篇文档综合(谁和谁什么关系)→ 看 GraphRAG
- 文档是扫描件/复杂表格 → 用 RAGFlow 这类强解析方案
- 知识需要高频更新且体量小 → 直接微调可能更简单
相关资源:LlamaIndex、LangChain、RAGFlow、GraphRAG 的详细上手步骤见本站资源详情页。中文视频教程推荐 Datawhale《动手学大模型应用开发》。