实战:个人知识库问答机器人
综合运用文档加载、切分、向量检索与对话记忆,端到端实现一个可用的知识库问答应用。
需求与架构
把本地 Markdown 笔记/PDF 变成可问答的知识库:
离线:load → split → embed → 存向量库(persist)
在线:用户问题 → 检索 Top-3 → Prompt(资料+问题) → LLM → 带引用的回答
关键代码骨架
# build_kb.py —— 离线建库
loader = DirectoryLoader("./notes", glob="**/*.md")
chunks = RecursiveCharacterTextSplitter(
chunk_size=400, chunk_overlap=60).split_documents(loader.load())
Chroma.from_documents(chunks, embeddings,
persist_directory="./kb").persist()
# app.py —— 在线问答
kb = Chroma(persist_directory="./kb", embedding_function=embeddings)
retriever = kb.as_retriever(search_kwargs={"k": 3})
prompt = ChatPromptTemplate.from_messages([
("system", "根据资料回答,并注明引用了哪些文件名:\n{context}"),
MessagesPlaceholder("history"),
("human", "{question}"),
])
chain = (RunnablePassthrough.assign(
context=(lambda x: x["question"]) | retriever | format_docs))
| prompt | llm | StrOutputParser()
chain_with_history = RunnableWithMessageHistory(
chain, get_session_history,
input_messages_key="question", history_messages_key="history")
上线前的三个检查
- 准备 10 个真实问题跑评测,Hit Rate < 80% 先回去调切分;
- 回答必须带文件名引用,方便用户核对来源;
- 资料更新流程:删除旧向量 → 重新入库(向量库按 source metadata 过滤删除)。
📝 课后练习
quiz-1 RAG 链中 format_docs 函数的作用是?