大模型RAG检索增强生成是当前解决模型幻觉与知识过期问题的主流技术路线。RAG把外部知识库检索与大模型生成结合,让模型在回答前先读取相关资料,回答内容有据可依。本文以 Python 生态为例,给出从文档加载、切块、向量化到检索生成的完整实现,覆盖工程落地中常见的坑点。
RAG为什么能解决大模型幻觉问题
大模型的参数知识存在截止时间,训练语料里没有的新内容、企业内部私有文档,模型都无法准确回答。RAG 的思路是:回答问题前先检索相关知识片段,把片段拼进提示词,让模型基于给定材料作答。检索到的内容限定了模型的回答范围,事实性错误明显减少,回答也更容易追溯到原始出处。
RAG 与微调相比有两点优势:一是知识更新成本低,替换向量库里的文档即可生效,不需要重训模型;二是可解释性强,回答附带的引用片段可以直接溯源。生产环境里,RAG 是性价比最高的私有知识问答方案。
RAG 系统架构与组件选型
一个完整的 RAG 流水线由四部分组成:文档加载与切块、文本向量化、向量检索、大模型生成。选型上,向量化与检索环节用开源框架可以快速搭建,常用组合是 LangChain 或 LlamaIndex 配合 FAISS 或 Chroma。
- 文档加载:支持 PDF、Markdown、Word、HTML 等格式,按文件类型选择对应 loader
- 切块策略:按字符数或语义边界切块,块大小一般取 300-800 个 token
- 向量化模型:可选 bge-large-zh、text-embedding-3-small 等,中文场景优先选中文训练过的模型
- 向量库:FAISS 适合单机,Milvus、Qdrant 适合生产集群
文档加载与切块策略
切块质量直接决定检索效果。切块过小,片段缺少上下文;切块过大,向量相似度被无关内容稀释。常用做法是固定窗口切块加重叠,保证相邻片段语义连续。
from langchain_text_splitters import RecursiveCharacterTextSplitter
text = open("knowledge.txt", encoding="utf-8").read()
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=100,
separators=["\n\n", "\n", "。", "!", "?", ";", ",", " "],
)
chunks = splitter.split_text(text)
print(f"切块数量: {len(chunks)}")
separators 的优先级决定文本从哪里断。中文场景把句号、逗号放进分隔符列表,比纯按字符数硬切效果好。
向量化与向量检索实现
文档切块后逐块做 embedding 并写入向量库,查询时对用户问题做同样的 embedding,计算余弦相似度取 top-k。
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-large-zh-v1.5",
encode_kwargs={"normalize_embeddings": True},
)
vectorstore = FAISS.from_texts(chunks, embeddings)
vectorstore.save_local("faiss_index")
store = FAISS.load_local("faiss_index", embeddings, allow_dangerous_deserialization=True)
docs = store.similarity_search_with_score("什么是 RAG", k=5)
for doc, score in docs:
print(f"score={score:.4f} {doc.page_content[:50]}")
检索分数低于阈值时,模型应回答”知识库中没有相关内容”,而不是强行生成。阈值按真实数据分布调,一般通过验证集人工评估确定。
提示词组装与生成
检索到的片段按资料来源拼接进提示词。提示词要明确要求模型只依据给定资料回答,资料中没有的信息直接说明,不要编造。上下文超长时,只保留得分最高的片段。
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1")
def rag_answer(question, docs):
context = "\n\n".join(f"[片段{i+1}] {d.page_content}" for i, d in enumerate(docs))
prompt = f"""请仅根据以下资料回答用户问题。
资料:
{context}
问题:{question}
回答要求:只使用资料中的信息,资料没有提到就明确说不知道。"""
resp = client.chat.completions.create(
model="qwen2.5-14b-instruct",
messages=[{"role": "user", "content": prompt}],
temperature=0.2,
)
return resp.choices[0].message.content
温度值调到 0.2 以下,生成更保守,减少自由发挥。线上系统还需要把命中的片段 ID 与回答一起返回,方便审计。
生产环境部署要点
生产环境 RAG 要考虑三个问题:数据更新、检索质量监控、成本控制。
- 数据更新:定时任务重新加载源文件,增量写入向量库,删除过期片段
- 检索质量:记录检索命中率与回答引用率,低召回时优先调整切块策略与 embedding 模型
- 成本控制:高频问题做缓存,命中缓存直接返回,减少大模型调用
RAG 不是一步到位的方案,落地时先跑通最小闭环,再用真实问答数据持续调切块参数与检索阈值,效果才会稳步提升。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/da-mo-xing-rag-jian-suo-zeng-qiang-shi-zhan-jie-jue-huan/