AI应用开发实战:RAG知识库助手实战-附带前后端和完整可运行服务

RAG 知识库问答系统 - 从零开始的完整指南
基于 Milvus 向量数据库 + LangChain + DashScope 的本地知识库问答解决方案
直接可以运行的代码已经整理好了,需要的话找老师拿

什么是 RAG?
1.1 RAG 的定义
RAG(Retrieval-Augmented Generation,检索增强生成) 是一种将信息检索与大语言模型(LLM)生成相结合的技术。
用一个简单的比喻来理解:
想象你在参加一场开卷考试。RAG 就像是:
- 📚 你的参考书(知识库)
- 🔍 快速翻书找答案的能力(检索系统)
- 🧠 理解并组织答案的大脑(大语言模型)
1.2 为什么需要 RAG?

传统大语言模型存在几个问题:
| 问题 |
说明 |
RAG 如何解决 |
| 知识过时 |
模型训练后不再更新 |
可以随时更新知识库 |
| 幻觉问题 |
模型可能”编造”答案 |
基于真实文档生成回答 |
| 领域限制 |
缺乏专业/私有知识 |
可导入任意专业文档 |
| 不可追溯 |
无法知道答案来源 |
可以引用原始文档 |
1.3 RAG 的工作流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ┌─────────────────────────────────────────────────────────────┐ │ RAG 完整工作流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 【索引阶段 - 离线处理】 │ │ │ │ 文档 → 加载 → 切分 → 向量化 → 存入向量数据库 │ │ │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 【检索阶段 - 在线查询】 │ │ │ │ 问题 → 向量化 → 相似度搜索 → 获取相关文档 → LLM生成答案 │ │ │ └─────────────────────────────────────────────────────────────┘
|
什么是 Milvus?
2.1 向量数据库简介
在理解 Milvus 之前,我们需要先了解什么是向量:
向量(Vector) 是一组数字,用来表示文本、图片等数据的”语义特征”。
例如:
1 2 3
| "猫" → [0.23, -0.45, 0.78, ..., 0.12] (1536维向量) "狗" → [0.21, -0.42, 0.75, ..., 0.15] (相似度高!) "汽车" → [0.89, 0.23, -0.56, ..., 0.67] (相似度低)
|
向量数据库 就是专门用来存储和快速搜索这些向量的数据库。
2.2 Milvus 是什么?
Milvus 是一个开源的向量数据库,专门为 AI 应用设计:
- 🚀 高性能:支持亿级向量的毫秒级搜索
- 📊 可扩展:支持分布式部署
- 🔧 易集成:提供 Python、Java、Go 等多种 SDK
- 💾 持久化:数据可靠存储,支持备份恢复
2.3 Milvus 的核心概念
| 概念 |
类比 |
说明 |
| Collection |
数据库表 |
存储向量数据的容器 |
| Entity |
表中的行 |
一条向量数据记录 |
| Field |
表中的列 |
向量字段、标量字段等 |
| Index |
索引 |
加速搜索的数据结构 |
2.4 本项目中的 Milvus 配置
1 2 3 4 5 6 7 8 9 10 11
| MILVUS_HOST = "localhost" MILVUS_PORT = "19530"
fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True), FieldSchema(name="name", dtype=DataType.VARCHAR, max_length=255), FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=5000), FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1536) ]
|
项目架构概览
3.1 整体架构图
本项目的架构可以分为两大流程:
📥 文档索引流程(Indexing Pipeline)
1 2
| 本地文档 → DocumentLoader → TextSplitter → Embedding Model → Milvus ① ② ③ ④ ⑤
|
🔍 检索问答流程(Retrieval Pipeline)
1 2
| 用户提问 → Query Embedding → Vector Search → Top-K Results → LLM → 答案 ⑥ ⑦ ⑧ ⑨ ⑩ ⑪
|
3.2 技术栈
| 组件 |
技术选型 |
用途 |
| 向量数据库 |
Milvus |
存储和检索向量 |
| 应用框架 |
LangChain |
构建 RAG 流水线 |
| 嵌入模型 |
DashScope text-embedding-v1 |
文本向量化 |
| 大语言模型 |
Qwen-Plus |
生成回答 |
| Web 框架 |
Flask |
提供 REST API |
| 文档处理 |
PyPDF、Docx2txt 等 |
解析各类文档 |
核心概念详解

4.1 文本切分(Text Splitting)
为什么需要切分文本?
- 嵌入模型有长度限制:大多数模型最多处理 512-8192 个 token
- 检索精度:较短的文本块更容易精确匹配
- 上下文控制:LLM 的上下文窗口有限
本项目使用 RecursiveCharacterTextSplitter:
1 2 3 4 5
| self.text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""] )
|
4.2 向量嵌入(Embedding)
嵌入是将文本转换为数值向量的过程:
1 2 3 4 5
| "Milvus是一个向量数据库" ↓ Embedding Model ↓ [0.023, -0.156, 0.892, ..., 0.445] # 1536维向量
|
本项目使用阿里云 DashScope 的 text-embedding-v1 模型,输出 1536 维向量。
4.3 相似度搜索(Similarity Search)
向量相似度通常使用以下方法计算:
| 方法 |
公式 |
特点 |
| L2 距离 |
√Σ(aᵢ-bᵢ)² |
值越小越相似 |
| 余弦相似度 |
cos(θ) |
值越大越相似 |
| 内积 |
Σ(aᵢ×bᵢ) |
值越大越相似 |
本项目使用 L2 距离(欧氏距离)。
项目文件结构
1 2 3 4 5 6 7 8 9
| project/ ├── vector_db_manager.py # 核心:向量数据库管理器 ├── document_loader.py # 文档加载器(支持多格式) ├── vector_retriever.py # 向量检索器 + 问答 ├── query_system.py # 独立查询系统(命令行) ├── upload_document.py # 独立上传脚本(命令行) ├── api_integration.py # Flask API 蓝图 ├── server.py # Flask 服务器入口 └── .env # 环境变量配置
|
文件职责说明
关键代码讲解
6.1 向量数据库管理器 (vector_db_manager.py)
这是项目的核心模块,负责整个 RAG 的”写入”流程。
初始化连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class VectorDatabaseManager: def __init__(self, milvus_host, milvus_port, ...): self.milvus_host = milvus_host or os.getenv("MILVUS_HOST", "127.0.0.1") self.milvus_port = str(milvus_port or os.getenv("MILVUS_PORT", "19530")) self._init_embeddings() self.text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""] ) self._connect_to_milvus()
|
文档处理流水线
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| def process_file(self, file_path: str, collection_name: str = None) -> bool: """处理单个文件:加载 → 切分 → 存储""" documents = self.load_document(file_path) split_docs = self.split_documents(documents) self.add_documents_to_db(split_docs, collection_name) return True
|
向量存储逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| def add_documents_to_db(self, documents: List[Document], collection_name: str = None): """将文档添加到 Milvus""" target_collection = collection_name or self.collection_name collection_exists = utility.has_collection(target_collection) if collection_exists: self.vectorstore = Milvus( embedding_function=self.embeddings, collection_name=target_collection, connection_args={"host": self.milvus_host, "port": self.milvus_port} ) self.vectorstore.add_documents(documents) else: self.vectorstore = Milvus.from_documents( documents=documents, embedding=self.embeddings, collection_name=target_collection, connection_args={"host": self.milvus_host, "port": self.milvus_port} )
|
6.2 向量检索器 (vector_retriever.py)
这个模块负责 RAG 的”读取”流程。
相似度搜索
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def search_similar_content(self, query: str, collection_name: str, k: int = None): """搜索相似内容""" search_results = self.db_manager.search( query=query, k=k, collection_name=collection_name ) results = [] for doc, score in search_results: if score >= self.similarity_threshold: results.append((doc, score)) return results
|
问答生成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| def answer_question(self, question: str, collection_name: str, k: int = 5): """回答问题 - RAG 的核心逻辑""" relevant_docs = self.search_similar_content( query=question, collection_name=collection_name, k=k ) context_parts = [] for i, (doc, score) in enumerate(relevant_docs): context_parts.append(f"参考资料{i+1}: {doc.page_content}") context = "\n\n".join(context_parts) answer = self._generate_answer_with_llm(question, context) return AnswerResult( answer=answer, source_documents=source_documents, scores=scores )
|
LLM 调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| def _generate_answer_with_llm(self, question: str, context: str) -> str: """使用 LLM 生成回答""" client = OpenAI( api_key=os.environ.get("DASHSCOPE_API_KEY"), base_url="https://dashscope.aliyuncs.com/compatible-mode/v1" ) system_prompt = """你是一个智能助手。请基于提供的【参考资料】回答用户的问题。 如果参考资料为空或与问题无关,请利用你的通用知识进行回答...""" response = client.chat.completions.create( model="qwen-plus", messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": f"问题:{question}\n\n【参考资料】:\n{context}"} ] ) return response.choices[0].message.content
|
6.3 API 接口 (api_integration.py)
提供 REST API 供外部调用。
上传文档端点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @vector_bp.route('/upload_document', methods=['POST']) def upload_document(): """POST /api/vector/upload_document""" data = request.get_json() file_path = data['file_path'] collection_name = data['collection_name'] success = vector_manager.process_file(file_path, collection_name) if success: return jsonify({ 'success': True, 'message': f'文档处理成功: {file_path}', 'database_info': vector_manager.get_database_info(collection_name) })
|
查询端点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @vector_bp.route('/query', methods=['POST']) def query_documents(): """POST /api/vector/query""" data = request.get_json() question = data['question'] collection_name = data['collection_name'] k = data.get('k', 5) result = vector_retriever.answer_question( question, k=k, collection_name=collection_name ) return jsonify({ 'success': True, 'question': question, 'answer': result.answer, 'confidence': result.confidence, 'sources': [...] })
|
快速上手指南
7.1 环境准备
- 启动 Milvus(使用 Docker)
- 安装 Python 依赖
1 2 3 4
| pip install langchain langchain-community langchain-milvus pip install pymilvus dashscope openai pip install flask flask-cors python-dotenv pip install pypdf docx2txt pandas openpyxl
|
- 配置环境变量
创建 .env 文件:
1 2 3 4 5 6
| MILVUS_HOST=localhost MILVUS_PORT=19530 COLLECTION_NAME=agent_rag DASHSCOPE_API_KEY=your_api_key_here EMBEDDING_MODEL=text-embedding-v1 LLM_MODEL=qwen-plus
|
7.2 命令行使用
上传文档:
1 2
| python upload_document.py
|
查询问答:
7.3 API 使用
启动服务:
上传文档:
1 2 3
| curl -X POST http://localhost:5000/api/vector/upload_document \ -H "Content-Type: application/json" \ -d '{"file_path": "/path/to/doc.pdf", "collection_name": "my_docs"}'
|
提问:
1 2 3
| curl -X POST http://localhost:5000/api/vector/query \ -H "Content-Type: application/json" \ -d '{"question": "什么是RAG?", "collection_name": "my_docs", "k": 5}'
|
API 接口说明
| 端点 |
方法 |
描述 |
| /api/vector/upload_document |
POST |
上传并处理文档(路径方式) |
| /api/vector/upload_file |
POST |
上传文件流 |
| /api/vector/query |
POST |
RAG 问答 |
| /api/vector/search |
POST |
纯相似度搜索 |
| /api/vector/collection_info |
GET |
获取集合信息 |
| /api/vector/clear_collection |
POST |
清空集合 |