大语言模型应用实战:FastAPI与RAG智能文档问答系统构建|附教程文档

0 阅读9分钟

全文链接:tecdat.cn/?p=45100
原文出处:拓端数据部落公众号

封面

关于分析师

在此对Mou Ni对本文所作的贡献表示诚挚感谢,他完成了数据科学专业的硕士学位,专注深度学习与生成式人工智能领域。擅长Python、LangChain、FastAPI、大语言模型应用开发。他曾在多个数据科学项目中担任核心开发角色,专注于将前沿AI技术转化为实际应用,在构建RAG系统、模型微调与部署方面积累了丰富经验。

引言

在企业数字化转型的浪潮中,我们常遇到这样一个痛点:海量的业务文档、研究报告、技术手册堆积如山,当需要从中寻找某个特定答案时,员工往往要花费数小时甚至数天进行翻阅。这不仅是效率的浪费,更是知识资产沉睡的体现。

本文内容改编自过往客户咨询项目的技术沉淀并且已通过实际业务校验,该项目完整代码已分享至交流社群。阅读原文进群获取更多最新AI见解和行业洞察,可与900+行业人士交流成长;还提供人工答疑,拆解核心原理、代码逻辑与业务适配思路,帮大家既懂 怎么做,也懂 为什么这么做;遇代码运行问题,更能享24小时调试支持。

本文将引导您一步步构建一个基于FastAPI的RAG( 检索增强生成 **)系统。我们会先梳理RAG的核心概念与FastAPI的优势,随后深入代码实现,打造一个能够接收PDF或TXT文档、对其内容进行索引、并回答用户问题的API服务。最后,我们还会探讨HTTP状态码的工程意义,并展望系统的优化方向。

理解REST API

REST API 是一种接口,用于在客户端和服务器之间建立通信。REST API 是 Representational State Transfer API 的缩写。客户端可以向特定的 API 端点发送 HTTP 请求,服务器负责处理这些请求。存在不少HTTP方法。其中几项我们会用FastAPI在项目中实现。

HTTP 方法:

检索增强生成与FastAPI:为何是黄金组合?

在我们动手之前,先来理解两个核心概念:RAG和FastAPI,并探讨为什么它们是天作之合。

什么是RAG?

RAG,即检索增强生成,是一种让 大语言模型 **能够利用外部知识库的技术。它就像一个开卷考试的学生:面对问题(查询),他首先快速翻阅参考资料(检索相关文档片段),然后结合资料和自己的理解,组织出一个精准的回答(生成)。

RAG的核心由两部分构成:

  • 检索器:负责根据用户问题,从文档库中快速找到最相关的信息片段。
  • 生成器:大语言模型,将检索到的信息片段作为上下文,结合问题生成最终答案。

这种架构有效解决了大语言模型知识截止、幻觉等问题,是连接通用大模型与私有数据的最佳桥梁。

– 为本项目创建一个虚拟环境(以隔离项目的依赖关系)。

为什么选择FastAPI?

FastAPI是一个现代、高性能的Python Web框架,专为构建API而生。它在本次项目中的优势显而易见:

  • 自动生成交互式文档:只需编写代码,FastAPI就能自动生成Swagger UI,我们可以在浏览器中直接测试API,无需额外开发前端。
  • 基于Python类型提示:利用Pydantic模型,它能自动进行请求体验证和序列化,减少大量模板代码。
  • 异步支持:天然支持异步请求处理,非常适合I/O密集型任务,如文件读取和网络调用。
  • 高性能:得益于Starlette和Pydantic,其性能可与Node.js、Go相媲美。

结合RAG与FastAPI,我们可以快速将一个智能文档 问答 **系统封装成易于集成的API服务。

项目实战:打造文档智能问答API

接下来,我们进入核心环节——代码实现。我们的目标是创建两个API端点:

  • /ingest:接收用户上传的PDF或TXT文档,将其分块、向量化并存入FAISS索引。
  • /query:接收用户问题,检索相关文档块,并调用大语言模型生成答案。

环境准备与依赖安装

首先,确保您已完成以下准备工作:

  1. 获取OpenAI API密钥,并在项目根目录创建.env文件,添加:

    OPENAI_API_KEY=您的密钥
    
  2. 创建并激活Python虚拟环境,安装依赖库。requirements.txt内容如下(版本号已做调整,确保兼容性):

fastapi
uvicorn[standard]
python-multipart
langchain
langchain-community
langchain-openai
faiss-cpu
openai
pypdf
python-dotenv

使用命令 pip install -r requirements.txt 一键安装。

核心模块:rag_pipeline.py

这个脚本封装了RAG的所有核心逻辑,包括文档加载、文本分块、向量存储、检索与生成。我们将代码模块化,便于维护和调用。

# 全局向量存储对象,用于跨请求共享
vector_store: FAISS | None = None
embeddings = OpenAIEmbeddings(model=EMBEDDING_MODEL_NAME)
def _load_vector_store() -> FAISS | None:
    """从本地磁盘加载已存在的FAISS索引。"""
    global vector_store
    if vector_store is None and os.path.exists(VECTOR_STORE_PATH):
        vector_store = FAISS.load_local(
            VECTOR_STORE_PATH,
            embeddings,
            allow_dangerous_deserialization=True
        )
    return vector_store
def process_document(file_path: str, display_filename: str = "") -> int:
    """
    处理上传的文档:加载、分块、向量化并存入FAISS。
    返回被索引的文本块数量。
    """
    global vector_store
    # 1. 根据文件扩展名选择加载器
    if file_path.endswith(".pdf"):
        loader = PyPDFLoader(file_path)
    else:
        loader = TextLoader(file_path)
    documents = loader.load()
    # 为所有文档块添加来源文件名
    source_name = display_filename or os.path.basename(file_path)
    for doc in documents:
        doc.metadata["source"] = source_name
    # 2. 文本分块
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=CHUNK_SIZE,
        chunk_overlap=CHUNK_OVERLAP,
        separators=["\n\n", "\n", ".", " ", ""]
    )
    chunks = splitter.split_documents(documents)
# 代码中省略了部分错误处理和细节优化,完整代码请进群获取。
......

API服务:main.py

现在,我们使用FastAPI将上述功能暴露为RESTful API。这里定义了请求/响应模型和三个端点。

import os
import tempfile
from fastapi import FastAPI, UploadFile, File, HTTPException
from pydantic import BaseModel
from rag_pipeline import process_document, query_rag
app = FastAPI(
    title="文档智能问答API",
    description="上传文档并进行检索增强生成式问答",
    version="1.0.0"
)
# 允许的文件类型
ALLOWED_FILE_TYPES = {
    "application/pdf": ".pdf",
    "text/plain": ".txt",
}
class QueryRequest(BaseModel):
    question: str
    top_k: int = 4
class QueryResponse(BaseModel):
    answer: str
    sources: list[str]
@app.get("/health", tags=["系统状态"])
async def health_check():
    """健康检查端点,用于确认服务是否运行。"""
    return {"status": "running"}
@app.post("/ingest", tags=["文档处理"])
async def ingest_document(file: UploadFile = File(...)):
    """
    上传文档(.txt 或 .pdf),系统将自动进行分块、向量化并存储。
    """
    if file.content_type not in ALLOWED_FILE_TYPES:
# 代码中省略了更复杂的验证逻辑和自定义异常处理,完整代码请进群获取。
......

启动服务只需在终端执行:

uvicorn main:app --reload

访问 http://127.0.0.1:8000/docs,您将看到自动生成的Swagger UI界面,所有API都可以在这里进行测试。


相关文章

DeepSeek、LangGraph和Python融合LSTM、RF、XGBoost、LR多模型预测NFLX股票涨跌|附完整代码数据

原文链接:tecdat.cn/?p=44060


测试与验证

文档上传与索引(/ingest)

在Swagger UI中点击/ingest端点,尝试上传一个PDF文件(例如我们为您准备的一篇关于机器学习应用的文章)。

点击“Execute”后,如果成功,您将看到如下响应,表明文档已被成功分块并索引。

此时,项目目录下会生成faiss_index文件夹,里面保存了向量索引文件,即使服务重启,数据也不会丢失。

智能问答(/query)

接下来,测试/query端点。输入一个问题,例如“机器学习有哪些应用?”,并设置top_k=4

点击Execute后,系统会返回答案以及答案所依据的文档来源。

您可以看到,答案准确地基于上传文档的内容生成,并且指明了来源,增强了可信度。

深入理解HTTP状态码:API的通用语言

在开发API时,合理使用HTTP状态码至关重要,它们用简洁的代码向客户端传达了请求的处理结果。我们的系统也遵循了这一规范。

  • 2xx 成功:如200 OK,表示请求成功。我们的/health/ingest/query在正常处理时都会返回200。

  • 4xx 客户端错误:表示问题出在客户端发送的请求上。例如:

    • 400 Bad Request:当上传了不支持的文件类型,或问题为空时,我们的API会返回此状态码。
    • 422 Unprocessable Entity:当请求体不符合Pydantic模型定义时,FastAPI会自动返回此状态码。
  • 5xx 服务器错误:表示服务器端在处理请求时发生意外。例如,若FAISS或OpenAI调用失败,我们的API会捕获异常并返回500 Internal Server Error

正确使用状态码,能让API更加健壮和易用。

总结与展望

通过本文,我们成功地构建并部署了一个基于FastAPI的RAG系统。该系统能够:

  1. 接收并索引PDF或TXT文档。
  2. 根据用户提问,从文档中检索相关信息。
  3. 利用大语言模型生成精准的答案。

这个项目不仅展示了RAG技术的落地过程,也体现了FastAPI在构建AI服务时的高效与便捷。您可以将此系统应用于企业知识库问答、智能客服、研究报告分析等场景。

展望未来,我们可以从以下几个方面进行优化:

  • 检索策略优化:除了简单的相似度搜索,可以尝试MMR(最大边际相关性)检索,平衡结果的相关性与多样性。
  • 分块策略优化:根据文档类型和语言,调整分块大小和重叠部分,或采用语义分块。
  • 多路召回:结合关键字检索(如BM25)与向量检索,提高召回率。
  • 前端界面:为API开发一个简单的聊天界面,提升用户体验。

我们鼓励您动手实践,并期待您在交流社群中分享您的改进与应用!

封面