《2026 LangChain零基础入门:用AI应用框架快速搭建智能助手》第8课(完结篇):小项目实战 + 部署 —— 构建网页版个人知识库 AI 助手

大家好,我是链上杯子(CSDN:链上杯子)。

失业一年了,天天想着怎么翻身。从第一课安装 LangChain 到现在,我们已经走过 Prompt 模板、Chains、Memory、Agent、Tools、RAG,一路把零散的调用拼成了能干活的小系统。今天最后一课,我们把前面所有内容整合成一个完整的网页版个人知识库 AI 助手:用户上传笔记/文档 → 构建 RAG → 通过网页聊天问答 → 支持多轮记忆 → 部署到免费云平台。第一次在浏览器里问自己笔记里的内容,看到 AI 精准引用原文回答,感觉这几个月没白折腾,终于能给自己造个"私人第二大脑"了。

本课目标

  • 整合前7课知识,构建一个完整的网页版知识库 AI 助手(Streamlit 界面 + RAG + Memory)
  • 学会简单部署到免费平台(Streamlit Community Cloud 或 Railway)
  • 给出后续自学方向和扩展建议,正式收尾本系列

项目整体架构

  • 前端:Streamlit(几行代码做网页聊天界面)
  • 后端:RAG(文档加载 + FAISS 向量库 + RetrievalQA) + ConversationChain(带记忆的多轮对话)
  • 功能
    • 上传 txt/pdf 文件夹或单个文件
    • 自动构建/加载知识库
    • 聊天问答(支持引用来源)
    • 多轮对话记忆
    • 清空/保存知识库

完整项目代码(main.py

把以下代码保存为 main.py,放在项目根目录。

python 复制代码
import streamlit as st
from langchain_openai import ChatOpenAI
from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.chains import RetrievalQA
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
import os
import shutil

# 配置
st.set_page_config(page_title="我的知识库 AI 助手", layout="wide")
st.title("个人知识库 AI 助手")
st.markdown("上传你的笔记/文档 → 聊天问答 → 支持多轮记忆 + 引用来源")

# 初始化大模型
@st.cache_resource
def get_llm():
    return ChatOpenAI(
        openai_api_key=st.secrets.get("DEEPSEEK_API_KEY", ""),  # 或用 st.text_input 让用户输入
        openai_api_base="https://api.deepseek.com/v1",
        model="deepseek-chat",
        temperature=0.3
    )

llm = get_llm()

# 嵌入模型(免费中文支持)
@st.cache_resource
def get_embeddings():
    return HuggingFaceEmbeddings(model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2")

embeddings = get_embeddings()

# 会话状态:向量库 + 记忆
if "vectorstore" not in st.session_state:
    st.session_state.vectorstore = None
if "memory" not in st.session_state:
    st.session_state.memory = ConversationBufferMemory()
if "qa_chain" not in st.session_state:
    st.session_state.qa_chain = None
if "chat_history" not in st.session_state:
    st.session_state.chat_history = []

# 侧边栏:上传文档 & 构建知识库
with st.sidebar:
    st.header("知识库管理")
    uploaded_files = st.file_uploader("上传 txt / pdf 文件(可多选)", type=["txt", "pdf"], accept_multiple_files=True)
    
    if st.button("构建/更新知识库"):
        if uploaded_files:
            os.makedirs("temp_docs", exist_ok=True)
            for file in uploaded_files:
                file_path = os.path.join("temp_docs", file.name)
                with open(file_path, "wb") as f:
                    f.write(file.getbuffer())
            
            # 加载文档
            loader = DirectoryLoader(
                "temp_docs/",
                glob="**/*",
                loader_cls=TextLoader  # pdf 用 PyPDFLoader
            )
            docs = loader.load()
            
            # 切分
            text_splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=100)
            chunks = text_splitter.split_documents(docs)
            
            # 构建向量库
            st.session_state.vectorstore = FAISS.from_documents(chunks, embeddings)
            st.session_state.vectorstore.save_local("my_vector_index")
            st.success(f"知识库构建完成!共 {len(chunks)} 个文档块")
            
            # 清理临时文件
            shutil.rmtree("temp_docs")
        else:
            # 加载已保存的向量库
            if os.path.exists("my_vector_index"):
                st.session_state.vectorstore = FAISS.load_local("my_vector_index", embeddings, allow_dangerous_deserialization=True)
                st.success("已加载本地知识库")
            else:
                st.warning("请先上传文档构建知识库")

# 主界面:聊天
st.header("和你的知识库聊天")

# 显示历史
for message in st.session_state.chat_history:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

# 用户输入
if prompt := st.chat_input("问我笔记/文档里的内容..."):
    st.session_state.chat_history.append({"role": "user", "content": prompt})
    with st.chat_message("user"):
        st.markdown(prompt)
    
    with st.chat_message("assistant"):
        with st.spinner("思考中..."):
            if st.session_state.vectorstore is None:
                st.error("请先构建知识库")
                st.session_state.chat_history.append({"role": "assistant", "content": "请先上传文档构建知识库"})
            else:
                # RAG + Memory 链
                retriever = st.session_state.vectorstore.as_retriever(search_kwargs={"k": 5})
                qa_chain = RetrievalQA.from_chain_type(
                    llm=llm,
                    chain_type="stuff",
                    retriever=retriever,
                    return_source_documents=True
                )
                
                # 带记忆的问答
                full_prompt = f"历史对话:{st.session_state.memory.buffer}\n当前问题:{prompt}"
                result = qa_chain.invoke({"query": full_prompt})
                
                answer = result["result"]
                sources = [doc.page_content[:150] + "..." for doc in result["source_documents"]]
                
                response = f"{answer}\n\n**引用来源**(前3个):\n" + "\n".join([f"- {s}" for s in sources[:3]])
                
                st.markdown(response)
                st.session_state.chat_history.append({"role": "assistant", "content": response})
                
                # 更新记忆
                st.session_state.memory.save_context({"input": prompt}, {"output": answer})

# 侧边栏按钮
with st.sidebar:
    if st.button("清空聊天记录"):
        st.session_state.chat_history = []
        st.session_state.memory.clear()
        st.rerun()
    
    if st.button("清空知识库"):
        if os.path.exists("my_vector_index"):
            shutil.rmtree("my_vector_index")
        st.session_state.vectorstore = None
        st.session_state.qa_chain = None
        st.success("知识库已清空")
        st.rerun()

运行项目

  1. 保存为 main.py

  2. 在 venv 中运行:

    bash 复制代码
    streamlit run main.py
  3. 浏览器打开 localhost:8501

  4. 上传文档 → 构建知识库 → 开始聊天

部署到免费云平台(Streamlit Community Cloud)

  1. 把项目推到 GitHub(新建 repo,上传 main.py + requirements.txt)

    requirements.txt 内容:

    复制代码
    streamlit
    langchain
    langchain-core
    langchain-community
    langchain-openai
    langchain-text-splitters
    langchain-classic
    faiss-cpu
    sentence-transformers
    pypdf
    tiktoken
  2. https://share.streamlit.io/ 登录(GitHub 账号)

  3. New app → 选你的 repo → main.py → Deploy

  4. 在 Advanced settings 添加 Secret:DEEPSEEK_API_KEY = 你的 Key

  5. 部署成功后得到公开链接,随时分享给朋友

注意:免费版有使用限制,适合个人演示;生产级建议 Railway / Vercel + Docker。

本系列完结小结

从第1课安装 LangChain 到现在,我们完成了:

  • Prompt 模板化
  • Chains 多步流程
  • Memory 多轮记忆
  • Agent 自主决策
  • Tools 扩展能力
  • RAG 私有知识问答
  • Streamlit 网页交互 + 部署

你现在已经能独立做出实用级 AI 小工具了!

感谢你一路陪我写完这个系列!

欢迎随时在评论区分享你的知识库助手截图、部署链接,或后续遇到的问题,我会尽量回复建议~

链上杯子(CSDN:链上杯子)

2026年,谢谢陪伴,继续往前走

相关推荐
东方不败之鸭梨的测试笔记2 小时前
AI生成测试用例方案
人工智能·测试用例
笨手笨脚の3 小时前
AI 基础概念
人工智能·大模型·prompt·agent·tool
飞睿科技3 小时前
解析 ESP-AirPuff 泡芙一号的 ESP32-P4 大模型 AI 智能体方案
人工智能
云烟成雨TD3 小时前
Spring AI Alibaba 1.x 系列【4】ReAct 范式与 ReactAgent 核心设计
java·人工智能·spring
乐分启航3 小时前
SliMamba:十余K参数量刷新SOTA!高光谱分类的“降维打击“来了
java·人工智能·深度学习·算法·机器学习·分类·数据挖掘
_codemonster4 小时前
被子植物门 —— 纲、目、科详细梳理 + 分类依据
人工智能·分类·数据挖掘
RoboWizard5 小时前
本地AI主机批量部署 高效存储支撑全场景配置
大数据·人工智能
dingzd955 小时前
产品同质化严重如何用材质升级做出溢价空间
大数据·人工智能·跨境电商·内容营销
@PHARAOH5 小时前
WHAT - AI 时代下的候选人
大数据·前端·人工智能