大语言模型实战:FastAPI+RAG智能问答系统构建

2026-06-11阅读 0热度 0
语言模型

文档智能问答已成为大模型落地实施中的高频场景。无论是搭建企业知识库、解析产品手册,还是从研究报告里快速定位答案,传统的关键词搜索在精度和效率上都难以满足需求。RAG(检索增强生成)因此成为业界公认的主流方案。

实践中,许多团队卡在“如何将RAG封装成可调用的API”这一环节。一个能跑的原型演示与一套可集成上线的服务之间,藏着大量工程细节。本文完整梳理如何借助FastAPI构建RAG系统——从核心原理到代码实现,再到HTTP状态码在工程中的实际意义,一次性讲透。

理解REST API

先对齐一个基础概念。REST API是客户端与服务器之间通信的接口标准,全称Representational State Transfer API。客户端向特定API端点发起HTTP请求,服务器处理后返回结果。本文后续会用到几种核心HTTP方法。

检索增强生成与FastAPI:为何是最佳搭档?

动手前,有必要把两个核心组件拆开来看。

什么是RAG?

RAG的本质是为大语言模型配备“开卷考试”的能力。面对问题,模型先快速翻查资料(检索相关文档片段),再结合资料与自身理解,整合出精准回答。

RAG的核心架构只有两部分:

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

这套方案有效解决了大模型知识截止、容易产生幻觉等痛点,是当前连接通用大模型与私有数据的最优路径。

为何选FastAPI?

FastAPI是近两年Python Web框架中的黑马,专为构建API而生。它在RAG项目中的优势只需几条:

  • 自动生成交互式文档:代码写完,Swagger UI自动生成,浏览器中可直接测试接口,省去额外前端开发。
  • 基于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=你的密钥
  1. 创建并激活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=["nn", "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股票涨跌|附完整代码数据

原文链接:https://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系统。它能够接收并索引PDF或TXT文档,根据用户提问从文档中检索相关信息,再利用大语言模型生成精准答案。

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

如果继续往下走,有几个优化方向值得关注:

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

鼓励动手实践,也期待在实际应用中看到更多的改进与落地。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策