大模型很强,但如果你只是调用 API 聊两句,那充其量只是个“玩具”。真正的工程问题是:怎么让 AI 基于你自己的文档回答?怎么让 AI 记住聊到哪了?怎么组织多步推理?

这篇文章就手把手带你解决这些问题。我们会用到 LangChain 这个 LLM 应用开发框架,和 DeepSeek 这个高性价比的中文模型,从零开始,一步步搭建一个能真正“干活”的智能问答机器人。


第一部分:先弄明白,LangChain 到底是什么?

简单说,LangChain 是给大模型配的一个“操作系统”。它自己不是模型,但它帮你把各种零件拼装起来,让模型能干活。它解决的核心问题是:如何将复杂的 AI 任务组织成一个可控、可扩展的工程系统

你可以把它想象成一套“乐高积木”:

  • 模型积木:用统一的接口调用 DeepSeek、Kimi、OpenAI 等各种模型。

  • 数据积木:加载你的 PDF、Word、网页文档,并进行切割。

  • 记忆积木:让 AI 记住你上一句说了什么,实现连贯对话。

  • 编排积木:用简洁的 LCEL 语法(| 管道符)把上面的积木串成一条流水线。

我们这次的目标,就是搭建一条 RAG(检索增强生成) 流水线。它就像一个“开卷考试”的流程:用户提问 → 从你的知识库中检索相关段落 → 把问题和检索到的资料一起发给大模型 → 大模型基于资料生成答案。这能极大减少模型“胡说八道”的幻觉问题。

第二部分:开工!搭建你的专属问答机器人

第一步:环境准备

我们使用 DeepSeek,因为它兼容 OpenAI 的接口,而且目前来看性价比和中文能力都很不错。

  1. 安装依赖包

    bash

    pip install langchain langchain-openai chromadb python-dotenv pypdf
    • langchain-openai:因为 DeepSeek 接口和 OpenAI 兼容,所以用这个包来调用。

    • chromadb:轻量级向量数据库,用来存你的文档。

    • pypdf:用来读 PDF 文档。

  2. 配置环境变量
    在项目根目录创建 .env 文件,填上你的 DeepSeek 信息:

    env

    DEEPSEEK_API_KEY=你的真实API密钥
    DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
    MODEL_NAME=deepseek-chat

第二步:搭一个最简单的“聊天机器人”

我们先测试一下模型是否能调通,这是最基础的“大脑”。

python

import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI

# 加载环境变量
load_dotenv()

# 初始化 DeepSeek 模型
llm = ChatOpenAI(
    model=os.getenv("MODEL_NAME"),
    openai_api_key=os.getenv("DEEPSEEK_API_KEY"),
    openai_api_base=os.getenv("DEEPSEEK_BASE_URL"),
    temperature=0.7
)

# 简单的测试
response = llm.invoke("你好,请介绍一下你自己。")
print(response.content)

如果运行后能正常返回内容,说明“大脑”已经就位,可以进行下一步了。

第三步:实现核心——RAG 知识库问答

这才是让机器人区别于普通聊天框的关键:让它“读”你的文档。

1. 加载文档并切割
我们用一个 PDF 作为知识库。DirectoryLoader 负责加载,RecursiveCharacterTextSplitter 负责把长文档切成合适大小的小块,方便检索和喂给模型。

python

from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 1. 加载 PDF 文档
loader = PyPDFLoader("path/to/your/knowledge.pdf") # 替换成你的文件路径
documents = loader.load()

# 2. 切割文档
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,      # 每块大小
    chunk_overlap=50,    # 块之间重叠部分,防止丢失上下文
    separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""] # 按中文语义切割
)
chunks = text_splitter.split_documents(documents)
print(f"文档被切割为 {len(chunks)} 个片段")

2. 向量化并存储
把文字转换成向量(一系列数字),让计算机能理解语义。然后把这些向量存入向量数据库,方便后续检索。

python

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma

# 1. 初始化嵌入模型(DeepSeek 兼容 OpenAI Embedding)
embeddings = OpenAIEmbeddings(
    model="text-embedding-ada-002", # 可替换为其他嵌入模型
    openai_api_key=os.getenv("DEEPSEEK_API_KEY"),
    openai_api_base=os.getenv("DEEPSEEK_BASE_URL"),
)

# 2. 将切割好的文档块存入 Chroma 向量库
vector_store = Chroma.from_documents(
    documents=chunks, 
    embedding=embeddings,
    persist_directory="./chroma_db" # 持久化目录
)

# 3. 创建检索器
retriever = vector_store.as_retriever(search_kwargs={"k": 3}) # 每次检索返回最相关的3个片段

3. 组装 RAG 问答链
现在把提示词模板、大模型、检索器串成一条链。这是 LangChain 最核心的“积木拼接”环节。

python

from langchain.chains import RetrievalQA
from langchain_core.prompts import ChatPromptTemplate

# 1. 设计提示词模板
prompt = ChatPromptTemplate.from_messages([
    ("system", """你是一个专业的智能问答助手。请根据以下参考资料回答用户的问题。
    如果参考资料中没有相关信息,请明确告知用户。
    参考资料:
    {context}
    """),
    ("human", "{question}")
])

# 2. 构建 RAG 链 (使用 LCEL 语法)
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

rag_chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser() # 解析输出为字符串
)

# 3. 运行测试
question = "请解释一下文档里提到的核心概念是什么?"
response = rag_chain.invoke(question)
print(response)

至此,一个能基于你的文档进行问答的机器人就搭建完成了!整个过程清晰地展示了 LangChain 如何将数据加载、向量化、检索和模型调用串联成一个完整的工作流。

第四步:添加“记忆”功能,实现连贯对话

目前的机器人是“失忆”的。要让对话更自然,需要加入记忆组件。

我们使用 RunnableWithMessageHistory 和 ChatMessageHistory,这是 LangChain 中更推荐的记忆管理方式。

python

from langchain.memory import ChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

# 1. 创建一个存储会话历史的字典
store = {}

def get_session_history(session_id: str):
    """根据 session_id 获取或创建对话历史"""
    if session_id not in store:
        store[session_id] = ChatMessageHistory()
    return store[session_id]

# 2. 构建一个带记忆的 RAG 链
# 这一步假设你已经有了上面的 rag_chain 和 retriever
# 但为了记忆功能,最好用更细粒度的方式构建链,以便插入消息占位符
from langchain_core.prompts import MessagesPlaceholder

prompt_with_history = ChatPromptTemplate.from_messages([
    ("system", "你是一个智能问答助手,请基于参考资料回答问题:\n{context}"),
    MessagesPlaceholder(variable_name="history"), # 关键:对话历史占位符
    ("human", "{question}")
])

# 重新构建链 (为了简洁,省略部分重复代码)
chain_with_history = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt_with_history
    | llm
    | StrOutputParser()
)

# 3. 封装为可记忆的链
conversational_rag_chain = RunnableWithMessageHistory(
    chain_with_history,
    get_session_history,  # 获取历史的函数
    input_messages_key="question",
    history_messages_key="history",
)

# 4. 使用测试
response1 = conversational_rag_chain.invoke(
    {"question": "我的第一个问题"},
    config={"configurable": {"session_id": "user_123"}}
)
print(response1)

response2 = conversational_rag_chain.invoke(
    {"question": "那我刚才问的是什么?"}, # AI 能结合历史回答
    config={"configurable": {"session_id": "user_123"}}
)
print(response2)

这样,机器人就能通过 session_id 区分不同用户,记住每个人的对话上下文了。

第三部分:总结与进阶思路

到这里,你已经亲手搭建了一个具备私有知识库问答多轮对话记忆能力的智能机器人。它不再是一个简单的 API 调用,而是一个有结构的、可扩展的系统。

回顾一下这个流水线:
文档加载与切割 → 向量化存储 → 语义检索 → 提示词增强 → 模型生成 → 记忆管理

这个框架可以衍生出很多实用的应用,比如:

  • 企业智能客服:上传产品手册和 FAQ,让 AI 解答客户问题,可以显著降低人力成本。

  • 个人知识库助手:把你的笔记、收藏的文章、电子书丢进去,随时用自然语言查询。

  • 内部研读机器人:帮助团队快速查阅和分析大量内部文档。

如果你想更进一步,可以探索这些方向:

  • Agent(智能体):让 AI 自己决定调用什么工具(如查天气、算数、调用企业 API),实现更复杂的自主任务。

  • 优化检索效果:尝试不同的分块策略,或引入“重排序”等高级检索技术,提高找对资料的概率。

  • 流式输出:使用 stream 方法让答案一个字一个字地显示,提升用户体验。

真正的工程能力,不在于你把 Prompt 写得有多花哨,而在于你如何将这些组件稳定、优雅地组合起来,解决实际问题。希望这篇文章能成为你探索 LangChain 世界的一个起点。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐