从零搭建 AI 智能 PDF 问答工具:Streamlit+LangChain + 千问大模型实战

在日常工作与学习中,我们经常需要处理大量 PDF 文档 ------ 学术论文、行业报告、书籍资料、企业手册等。传统阅读方式效率低下,尤其是面对数百页的长文档时,快速定位关键信息、精准解答疑问变得十分困难。

随着大语言模型(LLM)与检索增强生成(RAG)技术的快速发展,智能 PDF 问答工具应运而生。它能让 AI "读懂" PDF 内容,支持自然语言提问并给出精准答案,大幅提升信息获取效率。本文将基于 Streamlit、LangChain 与阿里千问大模型,手把手带你从零搭建一款功能完整的 AI 智能 PDF 问答工具,全程实战,代码可直接复用。

一、技术选型:核心框架与工具解析

在动手开发前,先明确技术栈选型,确保工具适配性与开发效率。本项目核心技术组合为 Streamlit + LangChain + 阿里千问大模型 + FAISS 向量库,各组件作用如下:

1.1 Streamlit:快速搭建 Web 交互界面

Streamlit 是一款轻量级 Python Web 框架,专为数据科学与 AI 应用设计,无需前端基础,几行代码即可搭建美观的 Web 界面。相比 Flask、Django,它开发效率极高,支持实时交互、文件上传、会话状态管理等功能,完美适配本项目的 "文件上传 - 提问 - 回答" 交互流程。

1.2 LangChain:大模型应用开发核心框架

LangChain 是连接大语言模型与外部数据的核心框架,提供文档加载、文本分割、向量存储、检索问答、对话记忆等模块化组件,能快速构建 RAG 系统。它的核心价值是让大模型 "学会使用外部知识",避免回答幻觉,同时支持对话历史记忆,实现连续问答。

1.3 阿里千问大模型:高性能中文 LLM

本项目选用阿里千问(qwen3.5-plus)作为核心大模型,通过 DashScope(阿里灵积)API 调用。千问模型在中文理解、文本生成、逻辑推理方面表现优异,支持长文本上下文,且 API 调用稳定、性价比高,适合中文场景下的 PDF 问答需求。

1.4 FAISS:轻量级高效向量数据库

FAISS 是 Meta 开源的向量数据库,专为高维向量检索优化,支持快速存储与查询文本向量。本项目用它存储 PDF 文本块的向量数据,用户提问时,先检索与问题最相关的文本片段,再交给大模型生成答案,确保回答基于 PDF 原文,准确可靠。

二、项目整体架构:从 PDF 到答案的全流程

在编写代码前,先梳理项目整体架构,明确数据流转与核心模块分工,避免开发过程中逻辑混乱。本项目架构可分为5 大核心模块,流程清晰、层层递进:

  1. Web 交互层(Streamlit):负责用户交互,包括 API 密钥输入、PDF 文件上传、问题输入、答案展示、历史对话记录管理,是用户与系统的直接接口。
  2. 会话状态管理层:基于 Streamlit 的 session_state,存储对话记忆(ConversationBufferMemory)与聊天历史,确保多轮问答时上下文连贯,不会丢失对话信息。
  3. 文档处理模块(LangChain) :接收上传的 PDF 文件,完成加载→文本分割→向量生成→向量存储全流程,将非结构化 PDF 转化为可检索的向量数据。
  4. 检索问答模块(LangChain):用户提问后,先通过 FAISS 检索相关文本片段,再将 "问题 + 相关上下文 + 对话历史" 传入千问大模型,生成精准答案。
  5. 大模型调用层(DashScope):封装千问大模型与嵌入模型的 API 调用,负责与阿里灵积平台通信,处理请求与响应,确保模型调用稳定。

简单来说,整个流程就是:用户上传 PDF→系统解析并向量化→用户提问→系统检索相关内容→大模型生成答案→展示结果并记忆对话。下面进入实战开发环节,分步实现各模块功能。

三、环境准备与依赖安装

3.1 环境要求

  • Python 3.9+(建议 3.10,兼容性最佳)
  • 操作系统:Windows/macOS/Linux 均可
  • 网络:可访问阿里灵积 DashScope API(需注册账号获取 API 密钥)

3.2 安装核心依赖包

创建项目文件夹,在终端执行以下命令,安装项目所需依赖:

bash 复制代码
pip install streamlit langchain langchain-openai langchain-community langchain-text-splitters pypdf faiss-cpu python-dotenv

依赖包说明:

  • streamlit:Web 界面框架
  • langchain:核心 RAG 框架
  • langchain-openai:适配 OpenAI 接口(千问兼容此接口)
  • langchain-community:社区组件(PDF 加载、向量库等)
  • langchain-text-splitters:文本分割工具
  • pypdf:PDF 文件解析
  • faiss-cpu:CPU 版 FAISS 向量库
  • python-dotenv:环境变量管理

3.3 获取阿里灵积 API 密钥

  1. 访问阿里灵积控制台:https://bailian.console.aliyun.com/
  2. 注册 / 登录账号,进入 "API-KEY 管理"
  3. 创建 API 密钥,保存备用(后续代码需使用)

四、分步实现核心功能(代码实战)

项目共包含 2 个核心代码文件:main.py(Web 界面与交互逻辑)、scripts.py(PDF 处理与问答核心逻辑),以及 1 个测试用 PDF 文件(卢浮宫.pdf)。下面分步编写代码,详解关键逻辑。

4.1 编写 scripts.py:核心问答逻辑封装

scripts.py是项目的 "大脑",负责 PDF 加载、文本分割、向量生成、检索问答与大模型调用。代码如下:

python 复制代码
import os
from langchain.chains import ConversationalRetrievalChain
from langchain_community.document_loaders import PyPDFLoader
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.embeddings import DashScopeEmbeddings

def qa_agent(openai_api_key, memory, uploaded_file, question):
    # 1. 初始化千问大模型(兼容OpenAI接口)
    model = ChatOpenAI(
        model="qwen3.5-plus",  # 千问3.5增强版
        openai_api_key=os.getenv("DASHSCOPE_API_KEY"),  # DashScope API密钥
        openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1"  # 千问API地址
    )

    # 2. 保存上传的PDF为临时文件
    file_content = uploaded_file.read()
    temp_file_path = "temp.pdf"  # 临时PDF路径
    with open(temp_file_path, "wb") as temp_file:
        temp_file.write(file_content)

    # 3. 加载PDF并分割文本
    loader = PyPDFLoader(temp_file_path)  # PDF加载器
    docs = loader.load()  # 加载PDF所有页面
    # 文本分割器:按中文语义分割,块大小500,重叠50(保证上下文连贯)
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,
        chunk_overlap=50,
        separators=["\n", "。", "!", "?", ",", "、", ""]  # 中文分隔符
    )
    texts = text_splitter.split_documents(docs)  # 分割后的文本块

    # 4. 初始化嵌入模型(千问文本嵌入模型)
    embeddings_model = DashScopeEmbeddings(
        model="text-embedding-v2",  # 文本嵌入模型
        dashscope_api_key="替换为你的API密钥"
    )

    # 5. 生成向量并存储到FAISS
    db = FAISS.from_documents(texts, embeddings_model)  # 向量库
    retriever = db.as_retriever()  # 检索器

    # 6. 创建检索问答链(支持对话记忆)
    qa = ConversationalRetrievalChain.from_llm(
        llm=model,
        retriever=retriever,
        memory=memory  # 绑定对话记忆
    )

    # 7. 执行问答并返回结果
    response = qa.invoke({"chat_history": memory, "question": question})
    return response
关键逻辑详解:
  • 大模型初始化 :千问模型兼容 OpenAI 接口,通过openai_api_base指定千问 API 地址,无需额外适配,降低开发成本。
  • PDF 临时存储:Streamlit 上传的文件是字节流,需保存为临时 PDF 文件,供 PyPDFLoader 加载。
  • 中文文本分割 :使用RecursiveCharacterTextSplitter,设置中文分隔符(句号、逗号等),确保分割后的文本块语义完整,避免断句混乱。
  • 嵌入模型选择 :选用千问text-embedding-v2嵌入模型,与大模型同源,中文向量匹配度更高,检索结果更精准。
  • 对话记忆绑定 :通过ConversationalRetrievalChain绑定memory,自动记录对话历史,支持多轮连续问答。

4.2 编写 main.py:Web 界面与交互逻辑

main.py是项目的 "脸面",基于 Streamlit 搭建 Web 界面,处理用户输入、文件上传、结果展示与历史对话管理。代码如下:

python 复制代码
import streamlit as st
from langchain.memory import ConversationBufferMemory
from scripts import qa_agent

# 1. 初始化会话状态(对话记忆+聊天历史)
if "memory" not in st.session_state:
    st.session_state["memory"] = ConversationBufferMemory(
        return_messages=True,
        memory_key="chat_history",
        output_key="answer"
    )
if "chat_history" not in st.session_state:
    st.session_state["chat_history"] = []

# 2. 页面配置(标题、图标、布局)
st.set_page_config(
    page_title="AI智能PDF问答工具",
    page_icon="📑",
    layout="centered"
)

# 3. 主标题
st.title("📑 AI智能PDF问答工具")

# 4. API密钥输入区域
st.subheader("🔑 API设置")
api_col1, api_col2 = st.columns([3, 1])
with api_col1:
    openai_api_key = st.text_input(
        "请输入OpenAI API密钥",
        type="password",
        placeholder="sk-..."
    )
with api_col2:
    st.markdown("[获取API密钥](阿里云百炼的api_key的网址)")
st.divider()

# 5. 文件上传区域
st.subheader("📁 文件上传")
uploaded_file = st.file_uploader(
    "点击或拖拽PDF文件到此处",
    type="pdf",
    help="支持PDF格式文件"
)

# 6. 问题输入区域
st.subheader("❓ 提问")
question = st.text_input(
    "请输入您的问题...",
    disabled=not uploaded_file,  # 未上传PDF时禁用输入
    placeholder="例如:请总结PDF的主要内容..."
)

# 7. 核心处理逻辑(上传文件+输入问题后触发)
if uploaded_file and question:
    if not openai_api_key:
        st.warning("⚠️ 请先输入OpenAI API密钥")
    else:
        with st.spinner("🤖 AI正在思考中,请稍等..."):
            try:
                # 调用scripts.py中的问答函数
                response = qa_agent(
                    openai_api_key,
                    st.session_state["memory"],
                    uploaded_file,
                    question
                )
                # 展示答案
                st.subheader("📝 答案")
                st.write(response["answer"])
                # 更新会话历史
                st.session_state["chat_history"] = response["chat_history"]
            except Exception as e:
                st.error(f"❌ 处理过程中发生错误: {str(e)}")

# 8. 历史对话记录展示
if st.session_state["chat_history"]:
    st.divider()
    with st.expander("🗣️ 历史对话记录", expanded=False):
        st.write("---")
        # 遍历对话历史(用户问题+AI答案成对展示)
        for i in range(0, len(st.session_state["chat_history"]), 2):
            if i + 1 < len(st.session_state["chat_history"]):
                human_msg = st.session_state["chat_history"][i]
                ai_msg = st.session_state["chat_history"][i + 1]
                st.markdown(f"**👤 你**: {human_msg.content}")
                st.markdown(f"**🤖 AI**: {ai_msg.content}")
                if i < len(st.session_state["chat_history"]) - 2:
                    st.write("---")
        # 清空对话历史按钮
        if st.button("🔄 清空对话历史"):
            st.session_state["memory"] = ConversationBufferMemory(
                return_messages=True,
                memory_key="chat_history",
                output_key="answer"
            )
            st.session_state["chat_history"] = []
            st.success("✅ 对话历史已清空")
            st.experimental_rerun()

# 9. 使用说明
st.divider()
st.subheader("ℹ️ 使用说明")
st.write("1. 输入OpenAI API密钥")
st.write("2. 上传PDF文件")
st.write("3. 输入您的问题")
st.write("4. 查看AI的回答")
关键逻辑详解:
  • 会话状态初始化 :Streamlit 的session_state用于跨交互保存数据,初始化memory(对话记忆对象)与chat_history(对话历史列表),确保页面刷新后对话不丢失。
  • 交互体验优化 :未上传 PDF 时禁用问题输入框,避免无效操作;添加加载动画(st.spinner),提升等待体验;错误时展示具体异常信息,便于排查问题。
  • 历史对话管理 :用expander折叠历史对话,界面更简洁;支持一键清空对话历史,重置记忆对象,满足多文档问答需求。

4.3 测试用 PDF 文件:卢浮宫.pdf

为方便测试,准备一份简单的 PDF 文档(卢浮宫介绍),内容包含卢浮宫的历史、位置、开放时间等信息。上传后可提问:"卢浮宫的开放时间是什么?""卢浮宫的建筑始建于哪一年?" 等,验证问答准确性。

五、项目运行与功能测试

5.1 启动项目

在终端进入项目文件夹,执行以下命令启动 Streamlit 应用:

bash 复制代码
streamlit run main.py

启动成功后,浏览器会自动打开 Web 界面(默认地址:http://localhost:8501)。

5.2 功能测试步骤

  1. 输入 API 密钥 :在 "API 设置" 区域输入你的 DashScope API 密钥(注意:密钥以sk-开头)。
  2. 上传 PDF 文件:点击 "文件上传" 区域,选择 "卢浮宫.pdf" 上传,上传成功后可看到文件名。
  3. 输入问题并提问 :在 "提问" 区域输入问题,例如:
    • 问题 1:卢浮宫的建筑始建于哪一年?
    • 问题 2:卢浮宫现在的开放时间是怎样的?
    • 问题 3:请总结卢浮宫的主要信息。
  4. 查看答案:等待几秒后,AI 会基于 PDF 内容生成精准答案,展示在 "答案" 区域。
  5. 多轮对话测试:继续输入关联问题,例如:"卢浮宫的参观费用是什么时候开始收取的?",验证对话记忆是否生效,上下文是否连贯。
  6. 历史对话查看与清空:展开 "历史对话记录",可查看所有问答记录;点击 "清空对话历史",可重置对话,重新开始。

5.3 测试结果示例

以 "卢浮宫的开放时间是什么?" 为例,AI 生成的答案如下:

卢浮宫除周二公休和特殊假日外,通常向游客全面开放参观。在 1855 年至 1922 年期间,除周一外全天向公众免费开放;1922 年开始收费。1824 年起,公众可在星期日和节假日参观,其他日子仅对艺术家和外国游客开放。

答案完全基于 PDF 原文,准确无误,无幻觉信息,验证了系统的可靠性。

六、核心技术深度解析:RAG 如何让 AI 读懂 PDF?

本项目的核心是检索增强生成(RAG)技术,它解决了大模型 "知识过时""幻觉回答""无法处理长文档" 三大痛点。下面深度解析 RAG 的核心原理,帮助你理解系统背后的逻辑。

6.1 RAG 的核心流程:分 "离线处理" 与 "在线问答" 两阶段

阶段 1:离线文档处理(上传 PDF 时执行)
  1. 文档加载:用 PyPDFLoader 读取 PDF 内容,提取所有文本。
  2. 文本分割:将长文本分割为 500 字左右的短文本块(Chunk),避免超出大模型上下文限制,同时保证语义完整。
  3. 向量生成 :用嵌入模型(text-embedding-v2)将每个文本块转化为高维向量(1024 维),向量能精准表征文本语义,语义相似的文本向量距离更近。
  4. 向量存储:将所有文本块的向量与原文存储到 FAISS 向量库,建立索引,便于快速检索。
阶段 2:在线问答(用户提问时执行)
  1. 问题向量化:用户提问后,用同样的嵌入模型将问题转化为向量。
  2. 相似向量检索 :在 FAISS 向量库中,检索与问题向量距离最近的 Top-k 文本块(默认 k=3),这些文本块就是与问题最相关的上下文。
  3. Prompt 构建:将 "用户问题 + 检索到的相关上下文 + 对话历史" 拼接成 Prompt,传入大模型。
  4. 答案生成:大模型基于 Prompt 中的上下文,生成精准、可靠的答案,确保答案完全基于 PDF 原文,避免幻觉。

6.2 对话记忆原理:如何实现多轮连贯问答?

本项目使用 LangChain 的ConversationBufferMemory实现对话记忆,其核心原理是:自动记录每一轮的 "用户问题 + AI 答案",并在后续问答时,将历史对话自动拼接到 Prompt 中,让大模型能理解上下文,实现连贯问答。

例如:

  • 第一轮问题:卢浮宫始建于哪一年?
  • 第一轮答案:1190 年左右。
  • 第二轮问题:现在的开放时间呢?
  • Prompt 会自动拼接:"历史对话:用户:卢浮宫始建于哪一年?AI:1190 年左右。用户:现在的开放时间呢?",大模型据此生成答案。

七、总结与感悟

本文基于 Streamlit、LangChain 与阿里千问大模型,从零搭建了一款功能完整的 AI 智能 PDF 问答工具,实现了 PDF 上传、文本解析、向量检索、智能问答、对话记忆等核心功能。整个开发过程无需复杂的前端与算法基础,基于模块化框架快速落地,充分体现了大模型时代 "低代码开发 AI 应用" 的优势。

通过本项目,我们不仅掌握了 Streamlit Web 开发、LangChain RAG 系统搭建、大模型 API 调用等核心技能,更深入理解了检索增强生成(RAG)技术的核心原理 ------让 AI 学会使用外部知识,是解决大模型痛点的关键

在实际应用中,这款工具可广泛用于学术研究(论文精读)、职场办公(报告分析)、学习备考(资料梳理)等场景,大幅提升信息获取效率。同时,项目的优化与扩展方向也为后续迭代提供了清晰思路,可根据实际需求持续升级,打造更强大、更易用的智能文档问答工具。

最后,随着大模型技术的不断发展,AI 应用的开发门槛会持续降低,未来会有更多基于 RAG 技术的智能工具落地,赋能各行各业,让信息获取更高效、更智能。

相关推荐
莱歌数字1 小时前
汽车外流场仿真+深度学习预测:风阻优化的“秒级革命”
人工智能·科技·汽车·电脑·制造·散热
LaughingZhu1 小时前
Product Hunt 每日热榜 | 2026-05-12
大数据·人工智能·经验分享·神经网络·产品运营
Resistance丶未来1 小时前
从零构建大语言模型:核心原理与实战落地
人工智能·ai·语言模型·自然语言处理·nlp·多模态大模型·ai工具
Allnadyy1 小时前
【LangChain&LangGraph】LangChain快速上手
langchain
eastyuxiao1 小时前
数字孪生(Digital Twin)从入门到实战教程
大数据·人工智能·数字孪生
皮皮学姐分享-ppx1 小时前
上市公司数字技术风险暴露数据(2010-2024)|《经济研究》同款大模型测算
大数据·网络·数据库·人工智能·chatgpt·制造
Jay-r2 小时前
ChatGPT 官网入口(2026 年最新版)——简明指南
人工智能·语言模型·chatgpt·ai助手·chatgpt5.5
小星AI2 小时前
LangGraph 超详细教程,附源码
人工智能·agent
JavaAgent架构师2 小时前
前端AI工程化(一):AI通信协议深度解析
前端·人工智能