如果你用过纯大模型处理公司内部问题,可能会发现两个令人头疼的现象:
这两个问题指向同一个根源:大模型的"知识"在训练完成时就已固化。它无法访问你的内部数据,也无法记住最新的信息。
知识库(RAG,检索增强生成),就是为解决这个问题而生。
RAG的全称是Retrieval-Augmented Generation,即检索增强生成。它的核心理念非常朴素:
与其让模型"硬答"它不知道的问题,不如先帮它找到相关的参考资料,再让它基于资料来回答。
这就好比:你有一个非常聪明的助理(大模型),但他不可能知道所有事情。你要做的是在他回答之前,先递给他一叠相关文件,告诉他:"你的答案要从这里面找。"
RAG的流程可以概括为三个阶段:
问题输入 → 检索(从知识库中找相关内容)→ 增强(将检索结果与问题组合)→ 生成(大模型基于资料作答)RAG中最核心的技术是向量嵌入(Embedding)。计算机不懂"意思",但它能算数学。向量嵌入就是将文本转换为数字向量,让语义相似的文本在数学空间中"靠得更近"。
"苹果很好吃" → [0.12, -0.34, 0.56, ...] (一个高维向量)
"香蕉很甜" → [0.11, -0.33, 0.57, ...] (与上面距离很近)
"今天天气不错" → [0.89, -0.12, -0.23, ...] (与上面距离很远)相似度通过余弦相似度来计算——用向量夹角的余弦值衡量两个向量在语义上的接近程度。1表示完全同向(语义完全相同),0表示正交(语义无关),-1表示完全相反。
# 向量余弦相似度的计算思想
import numpy as np
def cosine_similarity(vec_a, vec_b):
# 点积 / (模长乘积)
# 值越接近1,语义越相似
return np.dot(vec_a, vec_b) / (np.linalg.norm(vec_a) * np.linalg.norm(vec_b))正是基于这种数学原理,我们才能在数十万条文档中快速检索出语义最相关的内容。
这是"建库"的过程,一次性完成,后续定期更新:
1. 文档切分:将长文档拆分成有语义完整性的文本块(chunk)
2. 向量化:将每个文本块通过嵌入模型转换为向量
3. 存储索引:将向量存入向量数据库,并建立索引切分策略很关键:太大会影响检索精度(内容太杂),太小会丢失上下文关联。常见的做法是按段落切分,并保留一定的重叠内容。
当用户提问时,系统启动检索流程:
1. 将用户问题转换为向量
2. 在向量数据库中搜索最相似的K个向量
3. 返回这K个向量对应的原始文本块这一步决定了RAG的"资料质量"。如果检索到的内容与问题无关,后续生成必然跑偏。检索是RAG的上限,生成只是逼近这个上限。
1. 组合提示词:系统指令 + 检索到的资料 + 用户问题
2. 发送给大模型生成答案
3. 返回结果一个典型的RAG提示词结构:
你是一个基于知识库回答问题的助手。
请仅根据以下参考资料回答用户问题,如果资料中没有相关信息,请明确告知。
参考资料:
[检索到的文本块1]
[检索到的文本块2]
[检索到的文本块3]
用户问题:[用户输入的问题]
你的回答:很多人在"RAG"和"微调"之间纠结。它们的区别本质上是:
RAG(检索增强) | 微调(Fine-tuning) | |
|---|---|---|
本质 | 给模型"递小抄" | 让模型"重新学习" |
成本 | 低,只需搭建检索系统 | 高,需要GPU训练 |
数据更新 | 即时生效 | 需要重新训练 |
适用场景 | 知识频繁更新、个性化数据 | 风格调整、专业能力培养 |
效果确定性 | 高,答案可追溯到资料 | 低,模型可能"自由发挥" |
一般建议是:优先尝试RAG,解决不了再用微调。 RAG像给员工发参考资料,微调像送员工去进修——前者更快更灵活,后者更根本但成本更高。
向量数据库是专门为存储和检索高维向量而设计的数据库。与传统数据库不同,它支持相似性搜索——不是找"完全相等"的记录,而是找"最相似"的向量。
主流向量数据库对比:
数据库 | 特点 | 适用场景 |
|---|---|---|
Chroma | 轻量级,开箱即用 | 开发原型、小规模应用 |
Pinecone | 云原生,托管服务 | 生产环境,不想运维 |
Milvus | 分布式,高可用 | 大规模企业级部署 |
Qdrant | 高可用,性能优秀 | 中大规模应用 |
pgvector | PostgreSQL扩展 | 已有PG生态,不想引入新组件 |
基础的RAG可以快速搭建,但生产级的RAG需要解决诸多工程问题:
多路召回:不只依赖语义检索,结合关键词检索(BM25)等多种方式,提高召回率。
重排序(Rerank):向量检索出的top-K结果中,前几个不一定最相关。用精细的重排序模型对结果重新打分,确保最相关的内容排在前面。
父文档溯源:只返回文本块可能割裂上下文。通过记录每个块属于哪个父文档,在回答时附带来源链接。
缓存机制:高频问题直接缓存答案,避免重复检索和生成,降低成本。
以下是一个使用主流技术栈搭建的极简RAG示例:
# 使用LangChain + Chroma构建RAG
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import OpenAIEmbeddings
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
# 1. 加载文档
loader = TextLoader("knowledge.txt")
documents = loader.load()
# 2. 切分文档
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块500字
chunk_overlap=50, # 块之间重叠50字
)
chunks = text_splitter.split_documents(documents)
# 3. 向量化并存储到Chroma
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=OpenAIEmbeddings()
)
# 4. 构建检索器(找到最相关的3个文本块)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# 5. 构建RAG问答链
qa_chain = RetrievalQA.from_chain_type(
llm=ChatOpenAI(model="gpt-3.5-turbo"),
retriever=retriever,
return_source_documents=True
)
# 6. 提问!
response = qa_chain.invoke("知识库里关于XXX的内容是什么?")
print(response['result'])这段代码只有20多行,却完成了一个完整RAG流程的搭建。今天构建知识库的门槛,已经低到了个人开发者也能在几小时内完成。 重点是理解每一步的意图,而不是机械地复制代码。
陷阱一:文档切分不合理 切分不当会导致语义割裂。例如在"知识"和"库"之间切开,一句话被拆成两半。解法:基于段落或语义边界切分,而非机械地按字符数。
陷阱二:检索质量差 向量检索返回的内容与问题不相关。解法:结合关键词检索、调整chunk_size、优化Embedding模型。
陷阱三:上下文窗口过载 检索出的内容太多或太长,超出模型的上下文限制。解法:增加重排序环节,只取最精华的top-K。
陷阱四:时效性问题 新数据无法及时纳入知识库。解法:建立定时更新机制,或实现增量索引。
RAG正在快速进化。未来的方向不仅仅是"问-答",而是:
知识库将不再是被动的"资料库",而是AI主动使用、不断更新的"活的大脑"。
RAG的出现,让人工智能从"通用知识问答"走向了"专属知识应用"。任何一个组织——无论是企业、学校还是政府部门——都可以将自己的数据转化为可交互的知识资产。
RAG的本质是让AI学会"临时学习"——它不需要重新训练就能理解新的知识。这种能力,正是AI从"娱乐工具"走向"生产力工具"的关键一跃。
而你的数据,就是RAG最宝贵的燃料。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。