RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合了信息检索和生成式AI的技术框架,常用于问答系统、智能分析、知识驱动对话等应用场景。
传统的大语言模型(LLM)如 ChatGPT,知识固定在训练数据中,一旦训练完成,其知识不能实时更新。RAG 技术通过在推理时引入外部知识库,解决了这一问题。RAG 是一种结合了文档检索与语言生成的 AI 技术,通过先检索(Retrieve)相关内容,再由生成模型(Generate)基于这些内容进行回答或生成。
RAG的流程结构如下:
+----------------+
| 用户输入问题 |
+----------------+
|
v
+--------------------------+
| 向量化问题,语义检索相关文档 |
+--------------------------+
|
v
+----------------------+
| 提取的文档上下文片段 |
+----------------------+
|
v
+---------------------------+
| LLM 读取问题 + 上下文生成答案 |
+---------------------------+
在RAG中有几个关键技术:
- Embedding 模型:将文本转为向量以支持相似度检索。
- 向量数据库:如 FAISS、Chroma、Weaviate,用于存储文档向量。
- 检索逻辑:根据用户问题找到最相关的文档片段。
- 生成模型(LLM):输入“问题 + 检索结果”生成最终输出。
假设我们有如下文档数据:
documents = [
"Python 是一种解释型编程语言,广泛用于 Web、数据分析和人工智能。",
"FAISS 是 Facebook 开发的高效相似度搜索库,常用于向量检索。",
"LangChain 是一个支持构建 LLM 应用的框架,广泛应用于 RAG 和 Agent 场景。"
]
首先我们需要对文档切片并构建向量数据库(FAISS),这里的 CharacterTextSplitter
是用于将长文本拆封成块的工具,chunk_size=100
表示每个文本块(chunk)的最大长度是 100 个字符,chunk_overlap=10
表示相邻两个 chunk 之间会有 10 个字符的重叠部分:
# 创建文档对象
doc_objs = [Document(page_content=text) for text in documents]
# 切片:可选,但推荐
splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=10)
docs = splitter.split_documents(doc_objs)
# 创建向量数据库(使用 OpenAI embedding)
embedding = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(docs, embedding)
接着用户提问并搜索上下文,这里的 query
会被作为向量搜索的输入,vectorstore.similarity_search(query, k=2)
会把我们上面定义的问题转化为向量,在 FAISS 向量库中查找与该向量“最接近”的文本块,然后返回与 query
最相似的前 k = 2
条文档记录:
query = "什么是 FAISS?"
retrieved_docs = vectorstore.similarity_search(query, k=2)
for i, doc in enumerate(retrieved_docs):
print(f"[{i+1}] {doc.page_content}")
最后使用 LLM 进行上下文增强生成(RAG),这里的content也就是我们上面获得的相关文档,让llm在已经获得相关信息的前提下回答问题,这样自然正确率要高得多:
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.3)
context = "\n".join([doc.page_content for doc in retrieved_docs])
prompt = f"""
基于以下资料,回答问题:“{query}”
资料:
{context}
请用简洁的中文回答。
"""
response = llm.invoke(prompt)
print(response.content)
完整代码如下:
from langchain_community.vectorstores import FAISS
from langchain.text_splitter import CharacterTextSplitter
from langchain.schema import Document
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
# 一些原始知识内容
documents = [
"Python 是一种解释型编程语言,广泛用于 Web、数据分析和人工智能。",
"FAISS 是 Facebook 开发的高效相似度搜索库,常用于向量检索。",
"LangChain 是一个支持构建 LLM 应用的框架,广泛应用于 RAG 和 Agent 场景。",
]
# 1. 文本转为 LangChain 文档对象
doc_objs = [Document(page_content=text) for text in documents]
# 2. 文本切片
splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=10)
docs = splitter.split_documents(doc_objs)
# 3. 构建向量数据库(使用 OpenAI embeddings)
embedding = OpenAIEmbeddings(
model="text-embedding-ada-002",
api_key="xxx",
base_url="https://o3.fan/v1",
)
vectorstore = FAISS.from_documents(docs, embedding)
# 4. 用户查询
query = "什么是 FAISS?"
retrieved_docs = vectorstore.similarity_search(query, k=2)
# 5. 打印检索结果
print("🔍 检索到的文档:\n")
for i, doc in enumerate(retrieved_docs):
print(f"[{i+1}] {doc.page_content}\n")
# 6. 组织上下文 + 问题作为 Prompt 输入 LLM
context = "\n".join([doc.page_content for doc in retrieved_docs])
prompt = f"""
你是一个专业助手,以下是相关背景信息,请根据资料回答用户的问题:
资料:
{context}
问题:{query}
请用简洁的中文回答。
"""
# 7. 使用 LLM(ChatGPT)生成答案
llm = ChatOpenAI(
model="deepseek-coder",
temperature=0.3,
api_key="xxx",
base_url="xxx",
)
response = llm.invoke(prompt)
print("💡 回答:")
print(response.content)
可以发现在输出中有两条被查询到的文档,这就是与 query
最相似的两条查询结果,接着llm就会基于这个给出的查询到的文档回答问题。
太强了大师傅👍