本项目依托 FastAPI 构建后端服务,通过 LangChain 实现 RAG 全流程编排,结合通义千问 Embedding 与 LLM 能力、PostgreSQL 向量数据库,对外暴露接口完成知识库管理与检索增强问答。
一个基于检索增强生成(Retrieval-Augmented Generation, RAG)技术的智能问答后端服务。使用 FastAPI 构建接口,LangChain 编排流程,通义千问(Qwen)提供 Embedding 和 LLM 能力,PostgreSQL + pgvector 作为向量数据库。
本项目是一个完整的 RAG 后端服务,旨在解决大模型的“知识时效性”和“私有知识库问答”问题。
- 知识库管理:通过
/add接口将文本切分、向量化后存入 PostgreSQL。 - 智能问答:通过
/query接口,基于已添加的私有知识库进行精准检索并生成回答。 - 防幻觉 (Hallucination):通过 Prompt 工程严格约束 LLM 仅使用检索到的上下文回答,未知问题明确告知“未找到相关内容”。
- 毕业设计智能问答系统
- 企业内部文档知识库
- 个人笔记智能助手
- ✅ RESTful API:基于 FastAPI,自动生成交互式文档 (
/docs)。 - ✅ 文本切分 (Chunking):使用
RecursiveCharacterTextSplitter,支持自定义 chunk 大小与重叠。 - ✅ 向量存储:集成 PostgreSQL + pgvector,开源、稳定、可扩展。
- ✅ 检索增强生成:LangChain
RetrievalQA链,实现“检索 -> 组装 Prompt -> LLM 生成”全流程。 - ✅ 配置分离:使用
python-dotenv管理 API Key 等敏感信息。
| 层级 | 技术选型 | 版本 | 作用 |
|---|---|---|---|
| Web 框架 | FastAPI | 0.115.0 | 构建高性能 API 接口,提供自动文档。 |
| ASGI 服务器 | Uvicorn | 0.32.0 | 运行 FastAPI 应用。 |
| RAG 编排框架 | LangChain | 0.3.4 | 串联文本切分、向量化、检索、LLM 调用。 |
| 向量数据库 | PostgreSQL + pgvector | 14 | 存储文本片段及其向量,执行相似度搜索。 |
| 数据库驱动 | psycopg2-binary | 2.9.10 | Python 连接 PostgreSQL 的驱动。 |
| Embedding 模型 | 通义千问 Embedding-v3 | - | 阿里云提供,将文本转化为 1536 维向量。 |
| 大语言模型 | 通义千问 Qwen-Max | - | 阿里云提供,基于上下文生成最终回答。 |
| 配置管理 | python-dotenv | 1.0.1 | 环境变量管理。 |
| 数据校验 | Pydantic | 2.9.2 | API 请求/响应的数据结构定义与校验。 |
graph TD
User[用户/前端] -->|POST /add| FastAPI[FastAPI 接口层]
User -->|POST /query| FastAPI
subgraph "业务逻辑层 (app/services)"
FastAPI -->|文本| Chunk[文本切分<br/>TextSplitter]
FastAPI -->|问题| Retrieve[向量检索<br/>Similarity Search]
Chunk --> Embedding[向量化<br/>Qwen-Embedding]
Retrieve --> Embedding
Retrieve --> Prompt[Prompt 组装<br/>Context + Question]
Prompt --> LLM[大模型生成<br/>Qwen-LLM]
end
subgraph "数据存储层 (PostgreSQL)"
Embedding -->|存储| PG[(langchain_pg_embedding<br/>文本 + 向量)]
Retrieve -->|相似度搜索 <=>| PG
end
- Add (写入):
用户文本->切分 (Chunk)->向量化 (Embedding)->存入 PostgreSQL - Query (查询):
用户问题->向量化->相似度检索 (Top K)->组装上下文->送入 LLM->返回答案
项目采用经典的后端分层架构,实现了接口层、业务逻辑层、数据层的解耦。
fastapi-rag-service/
├── app/
│ ├── __init__.py
│ ├── api/
│ │ ├── __init__.py
│ │ └── routes.py # [接口层] URL 路由定义,仅负责接收和返回
│ ├── core/
│ │ ├── __init__.py
│ │ ├── config.py # [配置中心] 读取 .env,全局单例
│ │ └── database.py # [数据库连接] 初始化 PGVector 和 Embedding
│ ├── schemas/
│ │ ├── __init__.py
│ │ └── schemas.py # [数据模型] Pydantic 模型,定义 API 入参/出参
│ └── services/
│ ├── __init__.py
│ └── rag_service.py # [业务逻辑层] RAG 核心算法实现
├── .env # 环境变量 (需自行创建,不上传 Git)
├── .gitignore
├── requirements.txt # Python 依赖列表
├── main.py # [入口文件] FastAPI 应用初始化
└── README.md # 项目文档 (本文件)
确保你已安装以下环境:
- Python 3.9+
- PostgreSQL 12+ (需安装
pgvector扩展) - Docker (可选,用于快速启动 PostgreSQL)
git clone <your-repo-url>
cd fastapi-rag-service在根目录创建 .env 文件,填入以下内容:
# 阿里云 API Key (获取地址: https://bailian.console.aliyun.com/)
DASHSCOPE_API_KEY=sk-你的APIKey
# PostgreSQL 数据库连接串
# 格式: postgresql://用户名:密码@主机:端口/数据库名
DATABASE_URL=postgresql://postgres:你的密码@localhost:5432/my_vector_db
# 模型配置
EMBEDDING_MODEL=text-embedding-v3
LLM_MODEL=qwen-maxconda create -n py39 python=3.9
conda activate py39
pip install -r requirements.txt如果你使用 Docker 启动 PostgreSQL:
# 拉取并运行带 pgvector 的 PostgreSQL
docker run -d \
--name pgvector-14 \
-e POSTGRES_PASSWORD=你的密码 \
-e POSTGRES_DB=my_vector_db \
-p 5432:5432 \
pgvector/pgvector:pg14
# 进入容器并创建扩展
docker exec -it pgvector-14 psql -U postgres -d my_vector_db
# 在 psql 中执行:
# CREATE EXTENSION IF NOT EXISTS vector;
# \quvicorn main:app --reload打开浏览器访问:http://127.0.0.1:8000/docs
你将看到 FastAPI 自动生成的交互式文档,可以直接在页面上测试 /add 和 /query 接口。
文件位置:app/services/rag_service.py -> add_document_to_kb()
- 文本切分:使用
RecursiveCharacterTextSplitter将长文本切分为固定大小的片段 (Chunks)。- 参数:
chunk_size=500,chunk_overlap=50。 - 目的:解决 Embedding 模型输入长度限制,提高检索精度。
- 参数:
- 向量化与存储:调用
vector_store.add_documents()。- LangChain 自动调用 Qwen-Embedding 将每个 Chunk 转化为向量。
- 将
原文 (Content)+向量 (Vector)+元数据 (Metadata)批量写入 PostgreSQL。
文件位置:app/services/rag_service.py -> query_knowledge_base()
- 初始化 LLM:加载
qwen-max,设置temperature=0.1以保证输出严谨。 - Prompt 工程:
- 核心指令:“仅使用以下上下文回答用户的问题。如果上下文中没有答案,请明确说明‘知识库中未找到相关内容’。”
- 作用:防止 LLM 幻觉 (Hallucination)。
- 构建检索链:使用
RetrievalQA.from_chain_type。search_kwargs={"k": 3}:召回相似度最高的 3 个文本片段。
- 执行逻辑:
- 用户问题向量化。
- 在 PostgreSQL 中执行余弦相似度搜索 (
<=>运算符)。 - 拼接召回片段作为 Context。
- 将 Context + Question 送入 LLM。
- 返回 LLM 生成的答案及参考来源。
- URL:
POST /api/v1/add - Content-Type:
application/json - Request Body:
{
"content": "桂林电子科技大学,简称桂电,坐落于广西桂林市...",
"source": "桂电官方介绍"
}- Response (200):
{
"status": "success",
"message": "成功添加 3 个文本片段"
}- URL:
POST /api/v1/query - Content-Type:
application/json - Request Body:
{
"query": "桂林电子科技大学的计算机学科评估结果是什么?"
}- Response (200):
{
"answer": "桂林电子科技大学的计算机科学与技术学科在第四轮学科评估中获评B-。",
"sources": [
"桂电的计算机科学与技术学科是国家级特色专业,在第四轮学科评估中获评B-...",
"..."
]
}LangChain 会在首次启动时自动创建以下两张表,无需手动执行 SQL。
用于管理不同的知识库集合。
| 字段 | 类型 | 说明 |
|---|---|---|
uuid |
UUID | 主键,集合唯一ID |
name |
VARCHAR | 集合名称 (如: knowledge_base) |
cmetadata |
JSONB | 自定义元数据 |
存储文本片段、向量及元数据。
| 字段 | 类型 | 说明 |
|---|---|---|
uuid |
UUID | 主键,本条数据唯一ID |
collection_id |
UUID | 外键,关联集合表 |
embedding |
vector(1536) |
核心:Qwen-Embedding 生成的向量 |
document |
TEXT | 原文片段 (Chunk) |
cmetadata |
JSONB | 元数据 (如: {"source": "..."}) |
A: 缺少 Python 客户端包。运行 pip install pgvector 即可。
A: LangChain 的 PGVector 类封装了所有底层 SQL 操作(建表、插入、相似度查询)。它会在初始化时自动建表,在调用方法时自动生成并执行 SQL。
A: 在 app/core/database.py 开头添加 SQLAlchemy 日志配置:
import logging
logging.basicConfig()
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)- 迁移到新包:将
langchain_community.vectorstores.PGVector迁移到官方新包langchain-postgres(使用PGVectorStore)。 - 文档解析:支持 PDF、Word 等文件的自动解析与上传 (使用
PyPDF2或 LangChain Document Loaders)。 - 混合检索:结合关键词检索 (BM25) 和向量检索,提升召回率。
- 日志系统:引入
logging模块,记录 Query 全链路日志。 - 前端界面:开发简单的 Web UI (如 Gradio/Streamlit/Vue) 用于演示。
你的项目是一个标准的检索增强生成(Retrieval-Augmented Generation, RAG)系统,采用经典的分层架构设计。
graph TD
User[用户/前端] -->|HTTP请求| FastAPI[FastAPI 接口层]
subgraph "业务逻辑层"
FastAPI -->|add| Chunk[文本切分模块]
FastAPI -->|query| Retrieve[向量检索模块]
Chunk --> Embedding[向量化模块 Qwen-Embedding]
Retrieve --> Embedding
Retrieve --> Prompt[Prompt 组装模块]
Prompt --> LLM[大模型 Qwen-LLM]
end
subgraph "数据存储层"
Embedding -->|存储向量/文本| PG[(PostgreSQL + pgvector)]
Retrieve -->|相似度搜索| PG
end
-
Add(写入)流程:用户文本
$\to$ 切分$\to$ 向量化$\to$ 存入 PostgreSQL -
Query(查询)流程:用户问题
$\to$ 向量化$\to$ 向量检索$\to$ 组装上下文$\to$ 送入 LLM$\to$ 返回答案
我们来逐一分析为什么选这些技术,以及它们在项目中的具体角色:
| 层级 | 技术选型 | 版本 | 核心作用 & 选型理由 |
|---|---|---|---|
| Web框架 | FastAPI | 0.115.0 | 提供 RESTful API 接口。 理由:自动生成交互式文档 ( /docs),非常适合毕设演示和调试;异步支持好;Python 生态完善。 |
| ASGI 服务器 | Uvicorn | 0.32.0 | 运行 FastAPI 应用。 理由:FastAPI 官方推荐,性能优异。 |
| RAG 编排 | LangChain | 0.3.4 | 串联整个 RAG 流程的“胶水”。 理由:内置文本切分器、向量数据库集成、LLM Chain,避免重复造轮子,快速搭建原型。 |
| 向量数据库 | PostgreSQL + pgvector | PG 14 | 存储原文和向量,并执行相似度搜索。 理由:你已熟悉 Docker 部署;开源免费;是目前业界最主流的向量存储方案之一。 |
| 数据库驱动 | psycopg2-binary | 2.9.10 | Python 连接 PostgreSQL 的驱动。 |
| Embedding 模型 | Qwen-Embedding-v3 | - | 将文本转化为向量。 理由:阿里云提供,API 稳定,中文效果好。 |
| LLM 模型 | Qwen-Max | - | 理解上下文并生成最终回答。 理由:能力强,适合作为毕设的生成底座。 |
| 配置管理 | python-dotenv | 1.0.1 | 管理 API Key、数据库密码等敏感信息。 理由:安全(不把密码写死在代码里),符合开发规范。 |
| 数据校验 | Pydantic | 2.9.2 | 定义接口请求/响应的数据结构。 理由:FastAPI 原生集成,自动做数据类型校验。 |
你的项目采用了经典的后端分层架构,职责清晰,耦合度低。
my_rag_project/
├── app/
│ ├── api/
│ │ └── routes.py # [接口层] 定义 URL 路由,只负责接收请求和返回响应,不写业务逻辑
│ ├── core/
│ │ ├── config.py # [配置中心] 读取 .env 文件,全局单例配置
│ │ └── database.py # [数据库连接] 初始化 PGVector 和 Embedding 模型
│ ├── schemas/
│ │ └── schemas.py # [数据模型] 定义 Pydantic 模型(接口入参/出参长什么样)
│ └── services/
│ └── rag_service.py # [业务逻辑层] RAG 的核心算法都在这里
├── .env # 环境变量(不上传 Git)
├── requirements.txt # 依赖包列表
└── main.py # [入口文件] 初始化 FastAPI 应用,注册路由
- 单一职责:每个文件只做一件事。
- 易维护:比如以后想换数据库,只需要改
database.py,不用动routes.py。 - 易测试:可以单独测试
rag_service.py里的函数。
文件位置:app/services/rag_service.py -> add_document_to_kb()
- 接收输入:拿到用户传来的长文本
content。 - 文本切分 (Chunking):
- 工具:
RecursiveCharacterTextSplitter - 参数:
chunk_size=500(每段最多500字符),chunk_overlap=50(段与段之间重叠50字符)。 - 为什么要切分?:LLM 和 Embedding 模型都有输入长度限制;切分后检索更精准。
- 为什么要重叠?:防止语义在切分处被割裂。
- 工具:
- 向量化与存储:
- 调用
vector_store.add_documents(chunks)。 - 内部发生了什么?:
- LangChain 自动遍历每个 Chunk。
- 调用
DashScopeEmbeddings(Qwen) 将文本变成向量(数组)。 - 将 原文 (Content) + 向量 (Vector) + 元数据 (Metadata) 一起写入 PostgreSQL。
- 调用
文件位置:app/services/rag_service.py -> query_knowledge_base()
- 初始化 LLM:
- 模型:
qwen-max temperature=0.1:温度设得很低,让模型输出更严谨、更少发散。
- 模型:
- 构建 Prompt 模板:
- 核心指令:“仅使用以下上下文回答...如果没有请说明...”
- 作用:这是 RAG 的“灵魂”,强制 LLM 只使用检索到的内容,禁止编造(Hallucination)。
- 构建检索链 (RetrievalQA):
chain_type="stuff":最简单的策略,把检索到的文档直接“塞进” Prompt 里。search_kwargs={"k": 3}:召回最相关的 3 个文本片段。
- 执行查询(内部黑箱):
- 问题向量化:把用户的
query发给 Qwen-Embedding,得到问题向量。 - 相似度搜索:拿着问题向量去 PostgreSQL 里算距离(余弦相似度),找出最接近的 3 个文本。
- 组装上下文:把这 3 个文本拼在一起,作为
{context}。 - 调用 LLM:把
{context}和{question}填入 Prompt,发给 Qwen-Max。 - 返回结果:拿到 LLM 的回答,连同参考的原文片段一起返回给用户。
- 问题向量化:把用户的
这是项目的基石,我们在这里初始化了 LangChain 的 PGVector 对象。
- 注意:你现在看到的
PGVector来自langchain_community,虽然有警告,但目前是稳定可用的。 - 它做了什么?:它自动帮你在数据库里创建了两张表(见下文数据库设计),并封装了
add_documents和similarity_search方法。
这里定义了接口的“输入输出格式”。
AddDocumentRequest:规定了加知识必须传content,可选传source。QueryResponse:规定了返回必须包含answer(回答)和sources(参考来源),这在毕设演示中非常重要,能证明你的系统确实是“基于知识库”在回答。
虽然你没写 SQL,但 LangChain 已经在 my_vector_db 里自动建好了表。理解这两张表对后续优化很重要。
| 字段 | 类型 | 说明 |
|---|---|---|
uuid |
UUID | 集合的唯一ID |
name |
VARCHAR | 集合名称,即代码里的 knowledge_base |
cmetadata |
JSON | 自定义元数据 |
这是真正存数据的地方。
| 字段 | 类型 | 说明 |
|---|---|---|
uuid |
UUID | 本条数据的唯一ID |
collection_id |
UUID | 外键,关联到 langchain_pg_collection |
embedding |
vector |
重点:存储 Qwen-Embedding 生成的向量数组 |
document |
VARCHAR | 存储原文片段 (Chunk) |
cmetadata |
JSON | 存储元数据(比如 {"source": "桂电介绍"}) |
目前的项目是一个MVP(最小可行性产品)。为了让毕设更出彩,你可以考虑以下优化方向(按优先级排序):
- 警告内容:
PGVectoris pending deprecation. Please swap tolangchain_postgres. - 解决方案:将
langchain_community.vectorstores.PGVector迁移到新的官方包langchain-postgres。 - 迁移收益:消除警告,使用性能更好的
PGVectorStore,代码更规范。
目前 add 接口只能传纯文本。
- 优化:引入
PyPDF2或LangChain Document Loaders,让接口支持上传 PDF/Word/TXT 文件。 - 效果:用户直接上传毕业论文,系统就能自动解析并回答,演示效果非常好。
- 现状:只有 Uvicorn 的访问日志。
- 优化:引入 Python 标准库
logging,记录每一次 Query 的:- 用户输入的问题
- 检索到了哪些片段
- LLM 最终返回了什么
- 耗时多久
- 收益:方便调试;答辩时可以展示后台运行逻辑。
- 现状:只有 API 文档页面。
- 优化:写一个简单的 HTML 页面(或用 Gradio/Streamlit),有一个输入框和一个对话窗口。
- 收益:答辩时演示非常直观,看起来像一个完整的产品。
你的这个 RAG 项目,麻雀虽小,五脏俱全:
- 技术栈主流:覆盖了 FastAPI、LangChain、向量数据库等当前 AI 后端开发的核心技术。
- 流程完整:从数据摄入到检索生成,形成了闭环。
- 扩展性强:分层架构使得后续加功能(如文件上传、用户管理)很方便。
这作为一个本科毕业设计的基础项目,是完全合格且有亮点的。