RAG(Retrieval-Augmented Generation) 是一种结合检索(Retrieval)和生成(Generation)技术的人工智能模型架构,特别适用于处理需要广泛背景知识的自然语言处理任务。RAG模型通过动态从大型文档集合中检索相关信息来增强其生成文本的能力,从而提供更准确、更丰富的输出。
序言
从GPT诞生之初到最近爆火的deepSeek,生成式人工智能取得的突破性进展,已经不得不让我们感到惊叹,它们在文本生成、对话交互、代码编写等场景中展现出强大的能力,已经快速进入我们的日常工作。然而,这类模型也存在明显的局限性:知识固化 (依赖模型最初训练时的静态数据,但是现在模型可以使用基于联网能力,在网络上搜索最新内容)、幻觉问题 (生成看似合理但不符合事实的内容-一本正经的胡说八道)。为了解决以及优化这些问题,检索增强生成(Retrieval-Augmented Generation, RAG)应运而生。
它通过在生成答案时动态引入外部知识库,显著提升模型的准确性。目前的常见应用:
- 智能客服:基于企业文档生成精准回答
- 问答平台(结合行业资料如医疗、法律领域的内容生成)
是大模型在业务上落地的一个重要方向,本文将介绍如何利用开源工具链,快速搭建一个基于场景的智能问答RAG应用。
搭建应用
1. 准备工作
AI相关开发主要使用python
作为开发语言,需要提前准备好开发环境以及相关IDE。
推荐版本python3
以上,使用vscode
开发。
接下来需要准备一些的业务数据,因为我们目前的大模型主要以通用为主,所以它的主要对于通识类的内容,可以给出有价值的内容,但是对于一些特定领域的内容,它没有经过针对性训练的话,是无法产出有效内容的,也就容易出现幻觉问题,所以我们就需要根据我们具体的场景,来准备一些专业性比较强的内容。
例如:一个erp系统,如何创建出入库单据的具体步骤等。数据的格式可以是word、pdf、cvs甚至是一些音、视频。
但是需要保证数据的质量,否则无法给出有价值的内容。
2. 构建知识库
接下来需要搭建知识库,也就是模型回答所依赖的知识。这里我们需要引入一些开源库,来帮助我们搭建应用。
LangChain
: 是一个用于开发由语言模型驱动的应用程序的框架。JinaEmbeddings
: 多语言文本嵌入模型。Milvus
: 是一个为 GenAI 应用程序构建的开源向量数据库。使用pip
安装,执行高速搜索,并在性能损失最小的情况下扩展到数十亿个向量。
在这里我们要说明,在人工智能的相关开发中,数据都是以向量(高维空间中的数字坐标,用于量化表示各种实体)的形式,进行操作或计算。
我们之前准备的数据,都是文本形式的数据,所以我们需要将它们向量化,也叫做文本嵌入。这个操作也是通过嵌入模型来完成,目前有大量的开源或闭源的嵌入模型,这里我们使用JinaEmbeddings
。
模型的token是有限的,也就是它单次的数据处理量是有限的,所以我们在进行文本嵌入之前,需要先对数据进行一次整理,优化我们的数据源,对于文本类的数据常见的方式有:文本分块、文本分段、语义分割、拼写纠正、同一大小写、移除等,主要思路:1.减少单次处理文本数据的量;2. 减少数据噪声。
python
# 加载示例数据
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("example_text.pdf")
documents = loader.load()
# 文本分块
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 根据内容调整
chunk_overlap=50,
length_function=len
)
docs = text_splitter.split_documents(documents)
# 生成文本嵌入
from langchain_community.embeddings.jina import JinaEmbeddings
embeddings = JinaEmbeddings(
model_name="jina-embeddings-v2-small-en"
)
完成文本嵌入后,我们需要持久化,否则我们每次进行问答时,都要重新处理数据,非常影响性能,也无法有效共建我们的知识库。这里我们使用开源的向量数据库Milvus
。
python
# 存储至Milvus
from langchain.vectorstores import Milvus
vector_store = Milvus.from_documents(
docs,
embeddings,
connection_args={"host": "localhost", "port": "19530"}
)
3. 语义检索
使用langchain
的能力,就可以实现向量的检索,检索简单来说就是计算输入的向量和我们知识库中向量的距离,距离越近我们就认为它的相似度越高,然后再进行排序,输出相似度最高的数据。
python
from langchain_core.runnables import RunnablePassthrough
retriever = vector_store.as_retriever()(search_kwargs={"k": 2}) # 返回Top2结果
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
# 组装检索链
retrieval_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
)
4. 大模型接入
终于可以使用我们熟悉的大模型了,这里可以根据我们的实际情况选择大语言模型,当然参数量更高、模型性能更好的大模型,可以明显提升应用的使用体验,例如GPT4o、deepSeekV3、qwen2.5等。这里我们使用智谱的GLM-4-Flash
,因为它是智谱推出的免费大语言模型,对于搭建一个示例应用,没有使用压力,而且它的api与openAi的api基本一致,可以很容易切换成目前市面各种主流大模型api。
同时我们要利用prompt工程,来优化问答能力,例如:如果它没有检索到合适内容,应该回答"不好意思,我现在还不知道这个问题的答案,我会持续学习",通过这种方式减少大模型幻觉的产生。
python
from langchain_core.runnables import RunnableBranch
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
llm = ChatOpenAI(
temperature=0.95,
model="glm-4-flash",
openai_api_key="your zhipuai api key",
openai_api_base="https://open.bigmodel.cn/api/paas/v4/"
)
def check_retrieved_docs(input_dict):
"""检查是否检索到有效内容"""
# input_dict["context"] 是检索到的Document列表
return len(input_dict["context"]) > 0 # 判断是否有结果
# 定义提示模板
normal_prompt = ChatPromptTemplate.from_template("""
根据以下上下文回答问题:
{context}
问题:{question}
答案:""")
empty_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个严谨的助手,当没有相关信息时,必须且只能回复:"),
("human", "{fallback_response}")
])
# 构建处理链
chain = (
retrieval_chain
| RunnableBranch(
(check_retrieved_docs, normal_prompt), # 有结果时走正常流程
empty_prompt.partial(fallback_response="不好意思,我现在还不知道这个问题的答案,我会持续学习") # 无结果时固定回复
)
| llm
)
至此一个简单的问答RAG服务就搭建完成了,后续在搭建一个IM的问答前端页面,就可以部署上线了。
结尾
但是这个应用要达到企业级,还是有多的优化空间:
- 如何设计增量式向量库更新机制,例如CDC技术,增量更新数据库,减少知识库全量更新的损耗;
- 通过分布式搭建大型的知识库,适应大规模的知识库并提高系统的可用性;
- 如何更好的清晰和整理数据,保证输出的可靠性;
- 如何监控和评估应用的指标,例如:回答的准确率、效应速率;
- 如何将图像、视频等非结构化数据纳入检索体系,增加多模态的能力。
这些都是RAG应用可以探索和优化的方向,通过本文希望和大家一起探索和讨论人工从通用能力向行业深度解决方案演进。