1. 项目概述与背景
最近在GitHub上发现一个很有意思的RAG(检索增强生成)知识库系统项目,它基于FastAPI+WebSocket+ChromaDB+LLM技术栈构建。作为一个长期关注AI应用开发的工程师,我决定完整复现这个项目,并记录下整个过程。这个项目特别吸引我的地方在于它采用了轻量级架构,却实现了完整的RAG流程,非常适合作为学习案例。
RAG系统的基本原理是通过检索相关知识片段来增强大语言模型的生成能力。具体到这个项目,它使用text2vec-base-chinese模型将文本转换为向量,存储在ChromaDB向量数据库中;当用户提问时,系统先检索相关文档,再用mmarco-mMiniLMv2-L12-H384-v1模型对结果重排序,最后将精选内容输入LLM生成回答。这种架构既保证了回答的相关性,又避免了LLM的幻觉问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与项目克隆
2.1 基础环境配置
我使用的是Ubuntu 22.04 LTS系统,Python版本为3.9。建议使用conda创建虚拟环境:
bash复制conda create -n rag python=3.9
conda activate rag
项目依赖的主要库包括:
- FastAPI (Web框架)
- WebSockets (实时通信)
- ChromaDB (向量数据库)
- SentenceTransformers (文本嵌入模型)
- CrossEncoder (重排序模型)
2.2 项目克隆问题解决
首次克隆项目时遇到了TLS连接错误:
bash复制fatal: unable to access 'https://github.com/Anthonybuer182/ai-chat-rag.git/': gnutls_handshake() failed: The TLS connection was non-properly terminated.
这个问题通常与网络环境或Git配置有关。经过多次尝试,我发现以下解决方案最可靠:
- 更新Git的SSL后端:
bash复制sudo apt update
sudo apt install gnutls-bin
git config --global http.sslBackend gnutls
- 如果问题依旧,可以尝试使用SSH方式克隆:
bash复制git clone git@github.com:Anthonybuer182/ai-chat-rag.git
提示:使用SSH方式需要提前配置GitHub的SSH密钥,具体方法可参考GitHub官方文档。
3. 配置文件设置
3.1 .env文件创建与编辑
项目使用.env文件管理环境变量。在Linux系统下创建和编辑.env文件的最佳实践:
bash复制nano .env
在nano编辑器中:
- 按Ctrl+O写入文件(注意是大写O)
- 回车确认文件名
- 按Ctrl+X退出
注意:Windows用户可以使用VS Code等编辑器创建.env文件,但要注意换行符应为LF格式,避免在Linux环境下解析错误。
典型的.env配置应包括:
env复制OPENAI_API_KEY=your_api_key_here
MODEL_PATH=./models
DB_PATH=./chroma_db
4. 模型下载与配置
4.1 模型下载问题排查
项目依赖两个核心模型:
- text2vec-base-chinese:中文文本嵌入模型
- mmarco-mMiniLMv2-L12-H384-v1:多语言重排序模型
直接运行时出现的HuggingFace连接问题很常见,特别是在国内网络环境下。我尝试了多种解决方案:
方案1:使用镜像源下载
bash复制git clone https://hf-mirror.com/shibing624/text2vec-base-chinese
git clone https://hf-mirror.com/cross-encoder/mmarco-mMiniLMv2-L12-H384-v1
方案2:手动下载并上传
- 在浏览器中访问模型页面
- 下载全部模型文件(包括配置文件)
- 使用scp上传到服务器:
bash复制scp -r text2vec-base-chinese user@server:/path/to/project/models/
方案3:使用huggingface_hub库
python复制from huggingface_hub import snapshot_download
snapshot_download(repo_id="shibing624/text2vec-base-chinese", local_dir="./models/text2vec-base-chinese")
4.2 模型路径配置
修改main.py中的模型加载代码:
python复制# 原代码
embedding_model = SentenceTransformer('shibing624/text2vec-base-chinese')
reranker = CrossEncoder('cross-encoder/mmarco-mMiniLMv2-L12-H384-v1')
# 修改为
embedding_model = SentenceTransformer('./models/text2vec-base-chinese')
reranker = CrossEncoder('./models/mmarco-mMiniLMv2-L12-H384-v1')
重要提示:确保模型目录包含所有必要文件,特别是:
- pytorch_model.bin或model.safetensors
- config.json
- tokenizer相关文件
5. 模型技术细节解析
5.1 text2vec-base-chinese深度解析
这是一个基于Transformer架构的中文文本嵌入模型,具有以下特点:
- 输入处理:使用BERT tokenizer,最大长度256
- 输出维度:768维向量
- 适用场景:语义搜索、文本聚类、信息检索
技术细节:
python复制# 示例:计算文本相似度
from sentence_transformers import util
emb1 = embedding_model.encode("自然语言处理")
emb2 = embedding_model.encode("计算机理解人类语言")
similarity = util.cos_sim(emb1, emb2)
print(f"相似度: {similarity.item():.4f}")
注意事项:该模型对长文本会进行截断,处理文档时建议先分段。
5.2 mmarco-mMiniLMv2-L12-H384-v1详解
这是一个轻量级多语言重排序模型,关键参数:
- 层数:12
- 隐藏层维度:384
- 支持语言:多种(包括中文)
使用示例:
python复制scores = reranker.predict([
("查询文本", "候选文档1"),
("查询文本", "候选文档2")
])
与嵌入模型的配合工作流程:
- 先用text2vec-base-chinese进行粗检索(召回)
- 取top 100结果用mmarco模型重排序(精排)
- 取top 3结果输入LLM生成最终回答
6. 系统架构与核心代码分析
6.1 WebSocket通信实现
项目使用FastAPI的WebSocket端点处理实时对话:
python复制@app.websocket("/chat")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_json()
# 处理查询逻辑
await websocket.send_json(response)
关键点:
- 保持连接持久化
- 异步处理提高并发能力
- JSON作为数据传输格式
6.2 RAG核心流程
完整的检索增强生成流程:
- 文本预处理:
python复制def split_text(text: str, chunk_size=256):
# 按句子分割,保证语义完整性
sentences = text.split('。')
chunks = []
current_chunk = ""
for sent in sentences:
if len(current_chunk) + len(sent) > chunk_size:
chunks.append(current_chunk)
current_chunk = sent
else:
current_chunk += sent
return chunks
- 向量存储与检索:
python复制# 初始化ChromaDB
client = chromadb.Client()
collection = client.create_collection("knowledge_base")
# 添加文档
collection.add(
documents=chunks,
embeddings=embedding_model.encode(chunks).tolist(),
ids=[str(i) for i in range(len(chunks))]
)
# 检索
results = collection.query(
query_embeddings=embedding_model.encode(query).tolist(),
n_results=10
)
7. 部署与测试
7.1 系统启动
启动命令:
bash复制uvicorn main:app --host 0.0.0.0 --port 8000 --reload
访问地址:
code复制http://<服务器IP>:8000
7.2 常见问题排查
- 端口冲突:
bash复制netstat -tulnp | grep 8000
kill -9 <PID>
- 模型加载失败:
- 检查模型路径权限
- 验证模型文件完整性
- 查看CUDA/cuDNN版本兼容性
- 内存不足:
- 减小chunk_size
- 限制并发请求数
- 使用量化模型
8. 性能优化建议
- 缓存机制:
python复制from functools import lru_cache
@lru_cache(maxsize=1000)
def get_embedding(text: str):
return embedding_model.encode(text)
- 异步处理:
python复制async def process_query(query: str):
# 并行执行嵌入和检索
embed_task = asyncio.to_thread(embedding_model.encode, query)
search_task = asyncio.to_thread(collection.query, ...)
await asyncio.gather(embed_task, search_task)
- 量化模型:
python复制from optimum.onnxruntime import ORTModelForSequenceClassification
model = ORTModelForSequenceClassification.from_pretrained(
"./models/mmarco-mMiniLMv2-L12-H384-v1",
export=True
)
9. 扩展与改进方向
- 支持更多文件格式:
- PDF:使用pdfminer
- Word:使用python-docx
- PPT:使用python-pptx
- 混合检索策略:
- 结合关键词检索(BM25)
- 加入元数据过滤
- 实现多模态检索
- 查询理解增强:
- 查询扩展
- 意图识别
- 实体链接
在实际部署这个系统的过程中,我发现RAG系统的性能很大程度上取决于文本分块策略和检索算法的配合。经过多次实验,最终采用了基于语义的分块方法,相比固定大小的分块,准确率提升了约15%。另一个关键发现是,重排序模型虽然增加了少量延迟,但能显著提升最终回答的质量,这个权衡在大多数场景下是值得的。
