实战案例 中级

实战:个人知识库问答机器人

综合运用文档加载、切分、向量检索与对话记忆,端到端实现一个可用的知识库问答应用。

需求与架构

把本地 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 函数的作用是?