大家好,我是链上杯子(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()
运行项目
-
保存为
main.py -
在 venv 中运行:
bashstreamlit run main.py -
浏览器打开 localhost:8501
-
上传文档 → 构建知识库 → 开始聊天
部署到免费云平台(Streamlit Community Cloud)
-
把项目推到 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 -
去 https://share.streamlit.io/ 登录(GitHub 账号)
-
New app → 选你的 repo → main.py → Deploy
-
在 Advanced settings 添加 Secret:DEEPSEEK_API_KEY = 你的 Key
-
部署成功后得到公开链接,随时分享给朋友
注意:免费版有使用限制,适合个人演示;生产级建议 Railway / Vercel + Docker。
本系列完结小结
从第1课安装 LangChain 到现在,我们完成了:
- Prompt 模板化
- Chains 多步流程
- Memory 多轮记忆
- Agent 自主决策
- Tools 扩展能力
- RAG 私有知识问答
- Streamlit 网页交互 + 部署
你现在已经能独立做出实用级 AI 小工具了!
感谢你一路陪我写完这个系列!
欢迎随时在评论区分享你的知识库助手截图、部署链接,或后续遇到的问题,我会尽量回复建议~
链上杯子(CSDN:链上杯子)
2026年,谢谢陪伴,继续往前走