现在位置: 首页 > LangChain 教程 > 正文

LangChain 个人知识库问答系统

本篇构建一个能加载 Markdown 文件、PDF 文档,并基于这些内容进行问答的个人知识库系统。


系统设计

  • 文档加载:支持 Markdown、TXT、PDF 多种格式
  • 向量检索:Chroma 持久化存储,支持增量更新
  • 引用来源:回答中附带来源文档和片段位置
  • 流式输出:逐 Token 显示回答

完整代码

实例

# 文件路径:knowledge_qa.py
# pip install langchain langchain-deepseek langchain-chroma chromadb pypdf
from dotenv import load_dotenv
load_dotenv()

import os
from pathlib import Path
from langchain.tools import tool
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import TextLoader


class KnowledgeBase:
    """个人知识库管理器"""

    def __init__(self, persist_dir: str = "./my_knowledge_db"):
        self.persist_dir = persist_dir
        self.embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
        self.text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=500, chunk_overlap=50,
            separators=["\n\n", "\n", "。", "!", "?", ". ", "! ", "? ", " "],
        )
        self.vector_store = None
        self._load_or_create()

    def _load_or_create(self):
        """加载已有向量库或创建新的"""
        if os.path.exists(self.persist_dir) and os.listdir(self.persist_dir):
            self.vector_store = Chroma(
                persist_directory=self.persist_dir,
                embedding_function=self.embeddings,
            )
            print(f"已加载向量库:{self.vector_store._collection.count()} 个文档块")
        else:
            self.vector_store = Chroma(
                embedding_function=self.embeddings,
                persist_directory=self.persist_dir,
            )
            print("已创建新的向量库")

    def add_file(self, file_path: str) -> int:
        """添加文件到知识库,返回添加的文档块数"""
        loader = TextLoader(file_path, encoding="utf-8")
        docs = loader.load()

        # 添加文件来源元数据
        for doc in docs:
            doc.metadata["source"] = Path(file_path).name

        chunks = self.text_splitter.split_documents(docs)
        self.vector_store.add_documents(chunks)
        print(f"已添加 {Path(file_path).name}:{len(chunks)} 个文档块")
        return len(chunks)

    def add_text(self, text: str, source: str = "手动添加") -> int:
        """直接添加文本到知识库"""
        chunks = self.text_splitter.create_documents(
            [text], metadatas=[{"source": source}]
        )
        self.vector_store.add_documents(chunks)
        return len(chunks)

    def search(self, query: str, k: int = 3) -> list:
        """搜索知识库"""
        return self.vector_store.similarity_search(query, k=k)

    def get_retriever(self):
        """获取检索器"""
        return self.vector_store.as_retriever(search_kwargs={"k": 3})

继续 Agent 部分:

实例

# ========== 创建知识库并添加示例数据 ==========

kb = KnowledgeBase("./my_knowledge_db")

# 添加一些示例知识
kb.add_text(
    "菜鸟教程 RUNOOB 的 Python3 基础教程包含以下章节:"
    "1. Python 简介与环境搭建 2. 基本数据类型 3. 运算符与表达式 "
    "4. 条件判断 if-else 5. 循环 for/while 6. 函数定义与调用 "
    "7. 模块与包 8. 文件操作 9. 异常处理 10. 面向对象编程",
    source="Python3 教程大纲"
)

kb.add_text(
    "要成为一名优秀的 Python 开发者,建议按以下路线学习:"
    "第一步,掌握 Python 基础语法(1-2 周);"
    "第二步,学习数据结构和算法基础(2-3 周);"
    "第三步,选择一个方向深入学习(Web 开发/数据分析/AI);"
    "第四步,做 2-3 个实战项目巩固知识。",
    source="Python 学习路线"
)

kb.add_text(
    "菜鸟教程的在线编程环境支持 Python、JavaScript、Java、C++ 等多种语言。"
    "用户无需安装任何软件,打开浏览器即可编写和运行代码。"
    "在线环境还支持代码高亮、自动补全和错误提示功能。",
    source="在线编程环境说明"
)


# ========== 创建 RAG Agent ==========

@tool
def search_knowledge(query: str) -> str:
    """在个人知识库中搜索相关信息。搜索时使用完整的问题或关键短语。

    Args:
        query: 搜索问题或关键短语
    """

    docs = kb.search(query, k=3)
    if not docs:
        return "知识库中未找到相关信息。"

    results = []
    for i, doc in enumerate(docs, 1):
        source = doc.metadata.get("source", "未知来源")
        content = doc.page_content[:200]
        results.append(f"[{i}] 来源:{source}\n{content}")

    return "\n\n---\n\n".join(results)


model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
    model=model,
    tools=[search_knowledge],
    system_prompt="""你是个人知识库助手。

## 规则
1. 所有问题必须先用 search_knowledge 工具检索知识库
2. 回答时注明信息来源(文档名称)
3. 如果知识库中没有相关内容,如实告知
4. 回答要结构化,使用数字列表或分段"""
,
)


# ========== 测试 ==========

def ask(question: str):
    """提问并流式显示回答"""
    print(f"\n{'='*60}")
    print(f"Q: {question}")
    print(f"{'='*60}")

    result = agent.invoke({
        "messages": [HumanMessage(content=question)]
    })

    # 显示检索到的内容
    for msg in result["messages"]:
        if msg.type == "tool":
            print(f"\n[检索到的内容]")
            print(msg.content[:300])

    print(f"\n[回答]")
    print(result["messages"][-1].content)


ask("Python3 基础教程包含哪些章节?")
ask("如何规划 Python 学习路线?")
ask("菜鸟教程的在线编程环境支持哪些功能?")

运行结果:

============================================================
Q: Python3 基础教程包含哪些章节?
============================================================

[检索到的内容]
[1] 来源:Python3 教程大纲
菜鸟教程 RUNOOB 的 Python3 基础教程包含以下章节:...

[回答]
Python3 基础教程包含以下章节(来源:Python3 教程大纲):
1. Python 简介与环境搭建
2. 基本数据类型
3. 运算符与表达式
...

============================================================
Q: 如何规划 Python 学习路线?
============================================================

[回答]
根据知识库中的 Python 学习路线建议(来源:Python 学习路线):
第一步:掌握基础语法(1-2 周)
第二步:学习数据结构和算法(2-3 周)
第三步:选择方向深入学习(Web/数据分析/AI)
第四步:做 2-3 个实战项目巩固