快速搭建RAG应用,节省开发时间,显著提升工作效率
核心内容:
- RAG技术栈的通用性与关键作用
- 构建RAG应用的基础技术选型与实施步骤
- 快速启动RAG应用的具体操作指南与实战部署

RAG让大语言模型真正发挥价值。毫不夸张地说:在检索增强生成技术出现之前,LLM的功能十分有限,只能做简单的情感分类等琐碎任务,难以支撑实际应用。根本原因在于LLM无法实时学习——任何需要动态信息的场景,它都无法胜任。
但RAG的出现彻底改变了这一局面。它使我们能够利用实时数据构建应用,也能围绕私有数据打造智能系统。
然而,如果你去问任何一位正在搭建RAG的工程师,他们的技术栈是什么,得到的回答几乎千篇一律——就像循环播放的老磁带一样缺乏新意。所有RAG管线的前几个阶段高度相似,核心技术几乎没有替代方案。
一个典型的入门应用通常包含:Langchain(LlamaIndex是唯一的可比替代品)、ChromaDB,以及用于LLM和嵌入的OpenAI。开发环境则大多选择Docker,因为结果易于复现,跨机器共享也不成问题。
打包方面,使用最广泛的是Streamlit或Gradio。Django虽然也是一个出色的Web框架,但对于全职数据科学家来说,Streamlit或Gradio能省去大量繁琐工作。
正是因为我每次做项目都离不开这套组合,索性搭建了一个项目模板——每当有新想法时,就不必在重复性的基础工作上浪费时间。今天就把这个模板分享出来,或许你也能用它节省时间。
如何在几分钟内启动一个RAG应用程序
在深入细节之前,我们先让基础RAG应用运行起来。
前提是:你的机器上必须安装好Docker和Git,并且手头有一个有效的OpenAI API密钥。
先克隆下面的仓库:
git clone git@github.com:thuwarakeshm/ragbasics.git
cd ragbasics
在项目目录里创建一个.env文件,将OpenAI API密钥填入其中。
OPENAI_API_KEY=sk-proj-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
一切就绪后,就可以构建并运行Docker实例了。它会启动一个完整的RAG应用:
docker build -t ragbasics .
docker run -p 8000:7860 --env-file .env --name ragbasics-001 ragbasics
首次构建镜像会稍慢一些,但等服务器就绪后,打开浏览器访问https://localhost:8000,即可看到应用界面。
RAG入门模板 — 作者提供的图片。
你可以上传任意PDF文档并提交。提交后,应用会对文档进行分块,并创建向量存储。随后,你就可以针对文档提问,应用会自动给出答案。
运行中的RAG入门模板 — 作者提供的图片。
你可以立即更改什么?
这个应用远非完美,但它包含了大多数RAG应用的共同元素。
此外,有几样东西是经常需要调整的。其中最重要的是RAG的提示词(prompt)。最终的响应通过一次LLM调用生成,而检索到的信息则作为上下文。这个提示模板直接决定了响应质量。
模板里使用的只是一个基础版本——要求LLM根据上下文回答问题。但如果你想要更高质量的回复,或者想避免某些特定查询被响应,那就需要对它进行修改。
因为它太常见了,所以已经将它从pyproject.toml文件中提取出来。你无需深入代码库,直接在配置文件里就能指定提示词。
另一个经常调整的是分块策略。
分块,就是把大文档切成小块(理想情况下每块只有一个完整的概念)。递归字符分割和Markdown分割是两种最主流的做法。
递归字符分割把所有内容都当作文本处理,创建一个移动的块窗口。比如块大小设为1000、重叠设为200,那么移动窗口就会把前1000个字符放进去,接下来是第201到第1200个字符,依此类推。使用这种策略时,通常需要调整块大小和重叠度,这些都能在pyproject.toml里直接修改。
如果文档本身已经是Markdown格式,那就更好了——你可以利用Markdown的结构信息,创建出更有信息量的相关块。同样,这也是通过配置文件完成的。下面是一个示例:
[chunking]
strategy = "recursive_character_text_splitter"
chunk_size = 1000
chunk_overlap = 200
## strategy = "markdown_splitter"
## headers_to_split_on = ["##", "###", "####", "#####", "######"]
## return_each_line = true
## strip_headers = false
[rag_prompt]
prompt_template = """
Answer the question in the below context:
{context}
Question: {question}
"""
如果想给应用添加新的分块技术,实现起来也很简单——实现ChunkingStrategy抽象类,再在Chunker类里注册它即可:
## Create a chunking strategy
## chunking/your_chunking_stragey.py
from typing import List
from chunking.chunking import ChunkingStrategy
from langchain.docstore.document import Document
class YourChunkingStrategy(ChunkingStrategy):
def chunk(self, documents: List[Document]) -> List[Document]:
# implement your own chunking technique here
pass
## Register the new chunking strategy
## chunking/__init__.py
from chunking.your_chunking_stragey import YourChunkingStrategy
class Chunker:
def __init__(self):
...
elif config["chunking"]["strategy"] == "your_chunking_strategy":
self.chunking_strategy = YourChunkingStrategy()
else:
raise ValueError(f"Invalid chunking strategy: {config['chunking']['strategy']}")
许多工程师在分块上花费了大量时间,但说实话,没有哪种方法绝对优于其他。我之前已经记录过一些关于分块的体会——这本质上是一个需要调整许多超参数的实验过程。
有了这样一个模板,就能更快地完成实验,也能更轻松地和他人沟通整个流程。
部署到Huggingface
应用搭建好之后,下一步就是部署。
选项很多,但Huggingface Spaces对数据科学家来说既简单又流行,所以这里就用它来完成部署。
为什么选择Docker?
主要使用Docker封装器来构建应用,原因有几个。
第一,方便共享。与同事分享后,应用几乎总能在他们的机器上以完全一致的方式运行。
第二,扩展灵活。例如,如果想使用Neo4J而不是向量存储来创建知识图谱,只需创建一个docker-compose,往里添加一个Neo4J容器即可。
第三,Docker与Huggingface的兼容性良好。你可以快速将Docker容器部署到HF Spaces。示例中的Gradio本身就和HF Spaces兼容,但Docker用起来更灵活。
转到HF Spaces,创建一个新的Space。如果按照本例操作,免费的CPU选项就足够使用。对于更复杂的应用,则需要更多资源。
创建HF空间 — 作者的截图。
确保为空间SDK选择Docker,并选一个空白模板。
创建完成后,你会看到关于克隆和更新空间仓库的说明。将其克隆到本地,将项目文件复制进去,再推回空间。
注意:不要直接将.env文件推送到HF Spaces。
cd
git clone hfspace
cp -r app.py Dockerfile pyproject.toml requirements.txt chunking hfspace
git add .
git commit -m "Deploying basic RAG app"
git push
推送之后,HF空间会构建并部署你的Docker容器。
HF空间构建和部署Docker容器 — 作者的图片
但应用目前还不可用——还记得刚才推送时跳过了.env文件吗?必须通过HF Space的设置来安全地提供环境变量。
在HF空间的“设置”选项卡中的“变量和密钥”部分,单击“新建密钥”,输入OPENAI_API_KEY变量。
在HF Space中添加环境变量 — 作者的截图。
密钥保存后,应用会自动重启。现在就可以访问空间,看到应用实时运行了。
部署到Huggingface空间的基本RAG — 作者的截图。
最后的想法
检索增强型应用无疑是LLM的主要用例之一。但大多数RAG应用都共用同一套技术栈,导致工程师们反复在基础工作上耗费精力。
正因如此,我才创建了这个模板项目——每次想启动RAG应用时,它都能派上用场。这篇文章就是关于这个模板的。你可以直接拿来用,快速构建并部署RAG应用至Spaces;当然,也完全可以仿照它创建一个类似的模板,从此再也不必为样板文件发愁。
