LangChain实现简易版-----PDF 文档问答机器人

文档加载器 + 文本分割器 + PromptTemplate + LLM

原理(极简版,不学向量也能懂)

  1. 加载 PDF 全部文本
  2. 分割成多个语义完整文本块
  3. 用户提问 → 简单匹配最相关的文本块
  4. 把「相关文档片段 + 用户问题」塞进提示词
  5. 强制 LLM 只能看给的文档片段回答,不准瞎编

第一步 安装依赖

复制代码
pip install -U langchain langchain-openai langchain-community pypdf python-dotenv

第二步 完整可运行代码(纯基础知识点,无 RAG 无向量库)

复制代码
# 文档问答机器人
import os
from dotenv import load_dotenv
from langchain_core import documents

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter


# 加载环境变量
load_dotenv()

# ====================== 1. 配置 =================================
PDF_PATH = "Dubbo面试.pdf"
CHUNK_SIZE = 1200 # 单个块最大的字符数(推荐1000 - 2000)
CHUNK_OVERLAP = 200 # 相邻块的重叠字符数(推荐200 - 400) 保留上下文

# 初始化大模型 LLM
llm = ChatOpenAI(
    api_key=os.getenv("QWEN_API_KEY"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    model='qwen3-max', # 必须用 pro模型,支持工具调用
    temperature=0
)

# ======================2, 加载PDF =================================
def load_PDF(pdf_path: str):
    """
    加载本地 PDF 文档
    :param pdf_path: PDF 文件路径
    :return: Document 对象列表(每个元素是 PDF 的一页)
    """
    print(f'📄 正在加载,PDF:{PDF_PATH}...')

    # 初始化PDF加载器
    loader = PyPDFLoader(pdf_path)

    #加载PDF 每个元素 对应pdf一页
    documents = loader.load()
    print(f'✅️PDF文档加载完成!共{len(documents)}页 \n')

    return documents

# ======================= 3. 文本语义分割 ===============================
def split_documents(documents):
    """
    用 RecursiveCharacterTextSplitter 进行语义完整的文本分割
    :param documents: 加载后的 Document 对象列表
    :return: 分割后的文本块列表
    """
    print("✂️  正在进行语义完整的文本分割...")

    # ✅️ 核心:初始化 RecursiveCharacterTextSplitter (最推荐的分割器)
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=CHUNK_SIZE,
        chunk_overlap=CHUNK_OVERLAP,
        # 分割优先级(按顺序,优先保留段落、句子)
        separators=["\n\n", "\n", "。", "!", "?", " ", ""],
    )

    # 执行分割
    split_chunks = text_splitter.split_documents(documents)
    print(f"✅ 文本分割完成!共生成 {len(split_chunks)} 个文本块\n")
    return split_chunks


# ====================== 4. 简单的文本匹配 ==========================
def get_relevant_chunk(question, chunks):
    """
    简易关键词匹配:找出和问题最相关的文档块
    不用向量,纯字符串包含匹配
    """
    # 提取问题关键词 (简单按空格拆分)
    q_words = set(question.replace(",", " ").replace("。", " ").split())
    print(f'q_words: {q_words}')
    best_chunk = None
    max_score = 0

    for chunk in chunks:
        content = chunk.page_content

        # 统计命中关键词数量
        hit = sum(1 for word in q_words if word in content)
        if hit > max_score:
            max_score = hit
            best_chunk = content

    # 没有任何匹配 返回空
    if max_score == 0:
        return None
    return best_chunk


# ============================ # 5,构建问答prompt + 普通chain ==============================
# 强约束 只能用文档内容 不能编造
prompt = ChatPromptTemplate.from_template("""
你是文档专属问答助手,**严格遵守以下规则**:
1. 只能依据【文档内容】回答用户问题
2. 文档里没有相关信息,直接回复:文档中没有相关内容
3. 绝对不能自己编造、不能使用外部知识
4. 回答简洁准确
【文档内容】
{context}
【用户问题】
{question}
""")
# 普通链式组装
chain = prompt | llm | StrOutputParser()

# ===================== 6. 对话主循环 ==========================================
def main():
    print("===== 📚 简易PDF文档问答机器人(无向量库、无RAG)=====")
    print("正在加载并处理文档...\n")

    # 加载+分割
    documents = load_PDF(PDF_PATH)
    chunks = split_documents(documents)

    print("🤖 文档加载完毕,可以开始提问,输入 q 退出\n")
    while True:
        question = input("你:").strip()
        if question.lower() == "q":
            print("🤖 再见!")
            break
        if not question:
            continue

        # 匹配相关文档片段
        context = get_relevant_chunk(question, chunks)

        if not context:
            print("🤖:文档中没有相关内容\n")
            continue

        # 传入文档片段+问题,让LLM回答
        ans = chain.invoke({
            "context": context,
            "question": question
        })
        print(f"🤖:{ans}\n")

if __name__ == "__main__":
    main()

第三步 .env 文件配置

复制代码
DOUBAO_API_KEY=你的豆包密钥

四、用到的知识点(全是你学过的)

  1. PyPDFLoader 文档加载器
  2. RecursiveCharacterTextSplitter 语义文本分割器
  3. ChatPromptTemplate 提示词模板
  4. ChatOpenAI 大模型调用
  5. LCEL 链式调用 |
  6. StrOutputParser 输出解析器

五、运行效果

  • 问文档里有的内容 → 精准基于文档回答

  • 问文档里没有的 → 自动回复:文档中没有相关内容

  • 不会瞎编、不会扯外面知识

    ===== 📚 简易PDF文档问答机器人(无向量库、无RAG)=====
    正在加载并处理文档...

    📄 正在加载,PDF:Dubbo面试.pdf...
    ✅️PDF文档加载完成!共15页

    ✂️ 正在进行语义完整的文本分割...
    ✅ 文本分割完成!共生成 16 个文本块

    🤖 文档加载完毕,可以开始提问,输入 q 退出

    你:Dubbo 支持哪些协议,每种协议的应用场景,优缺点
    q_words: {'支持哪些协议,每种协议的应用场景,优缺点', 'Dubbo'}
    🤖:Dubbo 支持以下协议,每种协议的应用场景和优缺点如下:

    • dubbo:单一长连接和 NIO 异步通讯,适合大并发小数据量的服务调用,以及消费者远大于提供者。传输协议 TCP,异步,Hessian 序列化。

    • rmi:采用 JDK 标准的 rmi 协议实现,传输参数和返回参数对象需实现 Serializable 接口,使用 java 标准序列化机制,使用阻塞式短连接,传输数据包大小混合,消费者和提供者个数差不多,可传文件,传输协议 TCP。多个短连接,TCP 协议传输,同步传输,适用常规的远程服务调用和 rmi 互操作。在依赖低版本的 Common-Collections 包时,java 序列化存在安全漏洞。

    • webservice:基于 WebService 的远程调用协议,集成 CXF 实现,提供和原生 WebService 的互操作。多个短连接,基于 HTTP 传输,同步传输,适用系统集成和跨语言调用。

    • http:基于 Http 表单提交的远程调用协议,使用 Spring 的 HttpInvoke 实现。多个短连接,传输协议 HTTP,传入参数大小混合,提供者个数多于消费者,需要给应用程序和浏览器 JS 调用。

    • hessian:集成 Hessian 服务,基于 HTTP 通讯,采用 Servlet 暴露服务,Dubbo 内嵌 Jetty 作为服务器时默认实现,提供与 Hessian 服务互操作。多个短连接,同步 HTTP 传输,Hessian 序列化,传入参数较大,提供者大于消费者,提供者压力较大,可传文件。

    • memcache:基于 memcached 实现的 RPC 协议。

    • redis:基于 redis 实现的 RPC 协议。

    你:q
    🤖 再见!

🔴 先预判一下你的问题

这个报错 ValueError: Invalid input type <class 'dict'> 是 LangChain 里最经典的链结构错误,大概率是这 3 种情况之一:

  1. 直接把字典传给了大模型 你可能写了 llm.invoke({"question": "xxx"}),但大模型只接受字符串或消息列表。

  2. 链的顺序写错了 你可能写了 {...} | llm,但正确的应该是 prompt | llm

  3. PromptTemplate 后面没接 llm,或者接错了你可能在链里混用了不同类型的 Runnable,导致输出格式不对。

相关推荐
一水鉴天3 小时前
从“AI内在机制探询”到“三重三九格人本主权智能体架构”的演进 之2 20260503 (腾讯元宝)
人工智能·架构
guslegend3 小时前
第4节:应用架构与代码组织
人工智能·大模型·ai编程
一水鉴天3 小时前
现今/现在/现代——系统设计“现”层架构 20260503 (腾讯元宝)
人工智能·架构
格林威3 小时前
工业视觉检测:两大主流异常检测开源框架深度对比(PatchCore vs SPADE)
开发语言·人工智能·深度学习·数码相机·计算机视觉·视觉检测·工业相机
天诚智能门锁3 小时前
天诚cat.1人脸公租房智能锁及管控平台助力三门县公租房管理
大数据·人工智能·物联网·智慧城市·公租房
threelab3 小时前
Three.js 3D 饼图效果 | 三维可视化 / AI 提示词
javascript·人工智能·3d
小何code3 小时前
人工智能【第11篇】K近邻算法KNN:简单有效的分类方法(长文+代码实现)
人工智能·机器学习·knn
测试员周周3 小时前
【AI测试系统】第5篇:AI 编码工具抛硬币?我们用 LangGraph 做了个“确定性+AI”的测试系统(附自愈架构)
人工智能·python·功能测试·测试工具·架构·langchain·单元测试
初学大模型3 小时前
与机器心智的对话:论人机交互中提问的精确性与描述的详尽性
人工智能