目录

第 1 章:LangChain 简介

1.1 什么是 LangChain

1.2 LangChain 能做什么(简单场景:问答、摘要、智能体)

1.3 环境搭建(安装 langchain、配置 API Key)

第 2 章:核心概念速览

2.1 模型 I/O(LLM、提示词、输出解析)

2.2 链(Chain)—— 把多个组件串起来

2.3 智能体(Agent)—— 让 LLM 自己选择工具

2.4 记忆(Memory)—— 让对话有上下文

第 3 章:向量数据库 —— 让 LLM 拥有长期记忆

3.1 为什么需要向量数据库(LLM 的局限性:无长期记忆、无法检索外部知识)

3.2 向量数据库原理简介

3.3 常用向量数据库对比(Chroma、FAISS、Pinecone 等,侧重轻量级)

3.4 代码示例:使用 Chroma 存储与检索向量

第 4 章:RAG(检索增强生成)原理与实践

4.1 什么是 RAG —— 检索 + 生成,让 LLM 基于外部知识回答

4.2 RAG 工作流程详解

4.3 RAG 的核心组件

4.4 完整代码示例:用 LangChain 构建一个 RAG 问答系统(10-20 行代码)

4.5 RAG 的优缺点与常见优化(简单提及:重排序、HyDE 等)

第 5 章:快速实战 —— 从零搭建一个文档问答机器人

5.1 准备文档(PDF、网页或文本文件)

5.2 使用 LangChain + Chroma + OpenAI 实现完整流程

5.3 增加记忆功能(支持多轮对话)

5.4 测试与调试

第 6 章:总结与下一步学习建议

6.1 回顾核心概念

6.2 进阶方向推荐(LangGraph、LangSmith、生产部署)

6.3 资源链接(官方文档、社区、示例项目)


第 1 章:LangChain 简介

1.1 什么是 LangChain

LangChain is an open source framework with a pre-built agent architecture and integrations for any model or tool, so you can build agents that adapt as fast as the ecosystem evolves.

LangChain 是一个用于开发由大语言模型(LLM,Large Language Model)驱动的应用程序的开源框架。它把调用 LLM 所需的通用组件(提示词模板、记忆、工具、数据加载等)封装成标准化的接口,让开发者可以像搭积木一样组合出复杂的智能应用。

简单来说,如果没有 LangChain,你需要自己处理:

  • 不同 LLM 厂商的 API 差异

  • 对话历史的存储与截断

  • 从 PDF、网页等来源读取并分割文本

  • 将外部知识检索后塞进提示词

而 LangChain 为你提供了这些能力的统一接口,大幅降低了开发门槛。

1.2 LangChain 能做什么(简单场景:问答、摘要、智能体)

LangChain 可以用于构建:

  • 文档问答系统:上传一份 PDF,让 AI 回答其中的问题(RAG 的经典应用)。

  • 聊天机器人:带有长期记忆和工具调用能力的客服、个人助理。

  • 数据分析和代码生成:让 AI 连接数据库、执行代码、分析结果。

  • 智能体(Agent):让 LLM 自己决定调用哪些工具(搜索、计算、API 调用)来完成复杂任务。

1.3 环境搭建(安装 langchain、配置 API Key)

安装 LangChain 及相关依赖

建议使用 Python 3.9 以上版本,创建一个虚拟环境后执行:

pip install langchain langchain-openai langchain-chroma chromadb

如果你希望使用其他模型(如 DeepSeek、通义千问)或向量数据库,只需替换对应的集成包。

配置 API 密钥

本教程以 OpenAI 为例。你需要注册 OpenAI 账号并获取 API Key。然后在 Python 脚本或 Jupyter Notebook 中设置环境变量:

import osos.environ["OPENAI_API_KEY"] = "your-api-key-here"

如果使用其他模型,请参考相应文档配置。

第 2 章:核心概念速览

在深入向量数据库和 RAG 之前,我们先快速了解 LangChain 的四个核心抽象。

2.1 模型 I/O(LLM、提示词、输出解析)

模型 I/O 负责与 LLM 的交互,包含三部分:

  • 模型(Model):统一接口封装了 OpenAI、Anthropic、HuggingFace 等模型。例如 ChatOpenAI

  • 提示词模板(Prompt Template):将用户输入和固定指令组合成完整的提示词。

  • 输出解析器(Output Parser):将模型返回的文本解析成结构化数据(如 JSON、Pydantic 对象)。

示例:

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

model = ChatOpenAI(model="gpt-3.5-turbo")
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个乐于助人的助手。"),
    ("user", "{input}")
])
output_parser = StrOutputParser()

chain = prompt | model | output_parser
result = chain.invoke({"input": "什么是 LangChain?"})
print(result)

2.2 链(Chain)—— 把多个组件串起来

链将一个或多个组件串联成一个可执行的任务流。上面代码中的 prompt | model | output_parser 就是 LangChain 表达式语言(LCEL)定义的链。你可以用 | 管道符组合任意 Runnable 对象。

2.3 智能体(Agent)—— 让 LLM 自己选择工具

智能体让 LLM 自己决定下一步做什么——是直接回答,还是调用某个工具(如搜索、计算器、数据库查询)。它会反复推理,直到完成任务。对于简单场景,链更轻量;对于需要多步决策的复杂任务,智能体更合适。

2.4 记忆(Memory)—— 让对话有上下文

记忆组件负责在多次调用之间保存和加载上下文。最简单的 ConversationBufferMemory 会把所有对话历史存下来,每次调用时都塞给模型。更高级的记忆类型包括摘要记忆(定期压缩历史)、向量存储记忆(长期保存)等。

第 3 章:向量数据库 —— 让 LLM 拥有长期记忆

3.1 为什么需要向量数据库(LLM 的局限性:无长期记忆、无法检索外部知识)

大语言模型有一个致命弱点:它只知道自己训练时见过的知识,无法实时获取你私有的文档或最新的信息。例如,你问 GPT-3.5 “我们公司的最新报销政策是什么?”,它肯定不知道。

解决方法是:把私有文档提前存起来,当用户提问时,先找到相关的文档片段,再把片段和问题一起交给 LLM 回答。这就需要一种能够高效检索相似文本的数据库——向量数据库。

3.2 向量数据库原理简介

  • 文本 → 向量(嵌入模型)

  • 相似性搜索(余弦相似度、欧氏距离)

  • 索引与检索

  向量数据库的核心思想是:将文本转换为一串数字(向量),然后通过计算向量之间的相似度来找到相关内容。

  步骤 1:文本 → 向量

  使用“嵌入模型”(Embedding Model,如 OpenAI 的 text-embedding-3-small)将一段文本映射为固定长度的浮点数数组。语义相似的文本,其向量在空间中的距离也更近。

  例如:

  • “猫咪真可爱” → [0.12, -0.34, 0.56, ...]

  • “小狗很萌” → [0.11, -0.33, 0.57, ...] (距离很近)

  • “今天天气不错” → [0.89, 0.12, -0.45, ...](距离较远)

文本是怎么分块的?按照什么依据来分段?

文本分块(Chunking)的目的是将长文档切成适合后续处理(嵌入、检索)的小段落。分块的核心依据是:保持语义完整性,同时控制块的大小。

常用的分块依据(策略)

  1. 按固定字符长度切分

    • 例如每 500 个字符切一块,不管内容。

    • 缺点:可能切断句子或段落,破坏语义。

  2. 按递归分隔符切分(推荐)

    • 优先按段落 \n\n 切;如果段落太长,再按句子 。!? 切;如果句子还太长,按逗号、空格等依次切。

    • 常见工具:RecursiveCharacterTextSplitter

  3. 按语义边界切分

    • 使用 NLP 模型(如句子分割器、段落检测)或 Markdown 标题结构。

    • 例如:每个 ## 二级标题下的内容作为一个块。

  4. 按 Token 数量切分

    • 用模型的 tokenizer 计算 token 数(如 OpenAI 的 tiktoken),保证每块不超过模型限制(如 512 tokens)。

实际例子

原文本:

第一章 总则
第一条 本制度适用于全体员工。
年假政策:员工每年享有15天带薪年假。
第二条 年假需提前3个工作日申请。

使用 RecursiveCharacterTextSplitter(chunk_size=100, chunk_overlap=20) 可能会切成:

  • 块1:第一章 总则\n第一条 本制度适用于全体员工。\n年假政策:员工每

  • 块2:工每年享有15天带薪年假。\n第二条 年假需提前3个工作日申请。

注意块1末尾被截断,但 overlap 可以保留一些上下文。

实际开发中,通常需要针对你的文档类型(代码、法律文书、对话记录)调整分块大小和分隔符。

  

步骤 2:相似性搜索

  用户提问时,同样将问题转为向量,然后到数据库中寻找最相似的 K 个文档向量。常用的相似度度量包括余弦相似度、欧氏距离等。数据库通过建立索引(如 HNSW、IVF)来加速搜索,即使上亿条数据也能毫秒级返回。

如何计算文本向量之间的空间距离?

有了向量,就可以计算两个文本的“语义相似度”。常用方法:

1. 余弦相似度(最常用)

公式:

similarity=\tfrac{A\cdot B}{\left | \left | A \right |\left | B \right | \right |}

结果范围 [-1, 1]:1 表示完全相同方向(语义相同),0 表示无关,-1 表示相反。

直观理解:两个向量的夹角越小,语义越接近。

例子:

  • A = [0.9, 0.1, 0.2](猫)

  • B = [0.85, 0.12, 0.18](猫科动物)

  • 计算点积和模长 → 余弦相似度 ≈ 0.99(非常接近)

2. 欧氏距离

计算两点之间的直线距离。值越小越相似。

distance=\sqrt{\sum (A_{i}-B_{i})^{2}}

实际中

向量数据库会使用近似最近邻(ANN)算法(如 HNSW、IVF)来快速找到与查询向量最相似的 K 个向量,而不是逐一计算所有距离(虽然原理上还是基于这些距离公式)。

什么是向量,维度,固定维度的向量

1. 什么是向量?

在数学和编程中,向量就是一个有序的数字列表
例如:[0.5, -1.2, 3.8] 是一个 3 维向量。

向量可以表示空间中的一个点一个方向。在文本处理中,我们用一个向量来代表一段文本的“语义坐标”

2. 什么是维度?

维度就是向量中数字的个数

  • [2, 3] 是 2 维(可以想象成平面上的 x, y 坐标)。

  • [0.1, -0.5, 0.8, 0.2, -0.3] 是 5 维。

  • 嵌入模型的维度通常很高:384、768、1536 等。

高维度的意义:每个维度可以捕捉文本的一种“语义特征”(比如 1 号维度表示“是否涉及时间”,2 号维度表示“情绪积极程度”……但这些特征不是人可解释的,是模型自己学出来的)。

3. 什么是“固定维度的向量”?

意思是:同一个嵌入模型对任何输入文本,输出的向量长度都一样

  • 无论你输入“你好”还是整部《三体》小说,模型都输出例如 1536 个浮点数。

  • 这就保证了所有文本都可以放在同一个向量空间里进行比较。

  步骤 3:返回原文

  找到相似向量后,返回对应的原始文本片段,供后续 LLM 使用。

3.3 常用向量数据库对比(Chroma、FAISS、Pinecone 等,侧重轻量级)

名称 特点 适用场景
Chroma 轻量级、嵌入式、开源,支持内存/磁盘持久化 开发测试、小型项目
FAISS Meta 出品,纯本地、高性能,不支持分布式 对性能要求高的本地应用
Pinecone 全托管云服务,自动索引和扩展 生产环境、不想运维
Qdrant 开源、支持 Docker 和云,功能丰富 需要控制部署的中大型项目
PGVector PostgreSQL 扩展,与关系数据共存 已有 PG 基础设施的场景

入门阶段推荐使用 Chroma,无需单独部署,安装后即可使用。

3.4 代码示例:使用 Chroma 存储与检索向量

from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
from langchain_core.documents import Document

# 准备一些文档片段
documents = [
    Document(page_content="LangChain 是一个开发 LLM 应用的框架", metadata={"source": "doc1"}),
    Document(page_content="向量数据库可以存储文本的向量表示", metadata={"source": "doc2"}),
    Document(page_content="RAG 结合了检索和生成,能回答私有知识的问题", metadata={"source": "doc3"})
]

# 创建嵌入模型
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

# 创建 Chroma 向量数据库(自动计算并存储向量)
vector_store = Chroma.from_documents(documents, embeddings)

# 执行相似性检索
query = "什么是 RAG?"
results = vector_store.similarity_search(query, k=1)

print(f"最相关的文档片段:{results[0].page_content}")

输出示例:

最相关的文档片段:RAG 结合了检索和生成,能回答私有知识的问题

第 4 章:RAG(检索增强生成)原理与实践

4.1 什么是 RAG —— 检索 + 生成,让 LLM 基于外部知识回答

RAG(Retrieval-Augmented Generation,检索增强生成)是一种让 LLM 先检索外部知识,再基于检索结果生成回答的技术模式。它的核心价值在于:

  • 知识外挂:无需重新训练模型,即可让 LLM 掌握私有或最新信息。

  • 减少幻觉:提供相关事实作为依据,模型编造内容的概率大大降低。

  • 可溯源:可以告诉用户答案来自哪份文档。

4.2 RAG 工作流程详解

  • 文档加载 → 切分 → 向量化 → 存储

  • 用户提问 → 向量检索 → 召回相关片段 → 拼接提示词 → LLM 生成回答

  一个典型的 RAG 流程包含两个阶段:

  索引阶段(离线)

  1. 加载文档:从 PDF、网页、Markdown 等源读取文本。

  2. 分割文本:将长文档切分成适当大小的块(chunk),一般几百到上千字符。

  3. 向量化并存储:对每个块调用嵌入模型得到向量,存入向量数据库。

  查询阶段(在线)

  1. 用户提问:接收用户输入。

  2. 检索相关块:将问题向量化,在数据库中搜索最相似的 K 个块。

  3. 构造提示词:将检索到的块作为上下文,与用户问题一起填入提示词模板。

  4. 生成回答:调用 LLM 生成最终答案。

  下图直观展示了这个流程:

[用户提问] --> 向量检索 --> 召回相关块 --> 拼接提示词 --> LLM --> 答案
                ↑                           ↑
            [向量数据库]              [系统指令 + 上下文]

4.3 RAG 的核心组件

  文档加载器(Document Loader)

  文本分割器(Text Splitter)

  嵌入模型(Embedding Model)

  向量数据库(Vector Store)

  检索器(Retriever)

  生成链(Generation Chain)

  在 LangChain 中,构建一个 RAG 系统需要用到以下组件:

  • DocumentLoader:加载原始文档,例如 PyPDFLoaderWebBaseLoader

  • TextSplitter:将文档分割成块,例如 RecursiveCharacterTextSplitter

  • Embeddings:嵌入模型,将文本转为向量。

  • VectorStore:向量数据库,存储和检索向量。

  • Retriever:检索器,封装了向量数据库的查询逻辑,通常用 vector_store.as_retriever() 创建。

  • Chain:将检索器和 LLM 组合起来,例如使用 create_retrieval_chain

4.4 完整代码示例:用 LangChain 构建一个 RAG 问答系统(10-20 行代码)

# 1. 导入所需模块
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_chroma import Chroma
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate

# 2. 加载文档(假设有一个 policy.txt 文件)
loader = TextLoader("policy.txt", encoding="utf-8")
docs = loader.load()

# 3. 分割文本
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(docs)

# 4. 创建向量数据库
embeddings = OpenAIEmbeddings()
vector_store = Chroma.from_documents(chunks, embeddings)
retriever = vector_store.as_retriever(search_kwargs={"k": 3})

# 5. 定义提示词模板
system_prompt = (
    "你是一个公司政策助手。请根据以下上下文回答用户的问题。"
    "如果上下文里没有相关信息,就说你不知道,不要编造答案。\n\n"
    "上下文:\n{context}\n"
)
prompt = ChatPromptTemplate.from_messages([
    ("system", system_prompt),
    ("human", "{input}")
])

# 6. 创建链
llm = ChatOpenAI(model="gpt-3.5-turbo")
combine_docs_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, combine_docs_chain)

# 7. 提问
response = rag_chain.invoke({"input": "年假最多可以累积多少天?"})
print(response["answer"])

假设 policy.txt 内容包含:“员工每年有 10 天年假,最多可累积至 20 天。” 那么程序会检索到相关段落并给出准确回答。

4.5 RAG 的优缺点与常见优化(简单提及:重排序、HyDE 等)

优点:

  • 可以利用私有知识,无需微调模型。

  • 答案有据可循,方便用户核对。

  • 知识库可以随时更新,只需重新索引。

缺点与挑战:

  • 检索质量直接影响最终答案。如果检索到不相关的内容,LLM 可能被误导。

  • 长上下文会增加 token 消耗和延迟。

  • 对于多跳推理(需要结合多个分散信息)效果较差。

常见优化方法:

  • 重排序(Re-ranking):先检索较多候选,再用一个更精准的模型重新排序。

  • HyDE(Hypothetical Document Embeddings):让 LLM 先针对问题生成一个假想答案,用假想答案去检索。

  • 多向量检索:将文档分成句子、摘要等不同粒度,结合使用。

  • 上下文压缩:提取检索结果中最相关的句子,而不是返回整个块。

第 5 章:快速实战 —— 从零搭建一个文档问答机器人

本章将综合前面所学,搭建一个可交互的文档问答机器人,并支持多轮对话记忆。

5.1 准备文档(PDF、网页或文本文件)

你可以使用任何文本文件(.txt)、PDF 或网页。这里我们准备一份名为 company_rules.txt 的示例文件:

公司考勤制度:
1. 上班时间为 9:00-18:00,午休 1 小时。
2. 迟到超过 30 分钟算半天旷工。
3. 请假需提前一天在系统中提交申请。

福利政策:
- 每年一次免费体检。
- 每月 500 元交通补贴。
- 入职满一年后享有 5 天额外福利假。

5.2 使用 LangChain + Chroma + OpenAI 实现完整流程

import os
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_chroma import Chroma
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate

# 设置 API Key(建议用环境变量)
os.environ["OPENAI_API_KEY"] = "your-key"

# 加载并分割文档
loader = TextLoader("company_rules.txt", encoding="utf-8")
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=30)
chunks = splitter.split_documents(docs)

# 创建向量存储和检索器
embeddings = OpenAIEmbeddings()
vector_store = Chroma.from_documents(chunks, embeddings)
retriever = vector_store.as_retriever(search_kwargs={"k": 2})

# 提示词模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个公司内部助手。根据以下上下文回答问题。如果不知道就说不知道。\n上下文:{context}"),
    ("human", "{input}")
])

# 创建 RAG 链
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
combine_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, combine_chain)

# 交互循环
print("问答机器人已启动(输入 'exit' 退出)")
while True:
    question = input("\n你: ")
    if question.lower() == "exit":
        break
    response = rag_chain.invoke({"input": question})
    print(f"机器人: {response['answer']}")

运行结果:

你: 上班时间是几点?
机器人: 上班时间为 9:00-18:00,午休 1 小时。
你: 迟到怎么办?
机器人: 迟到超过 30 分钟算半天旷工。

5.3 增加记忆功能(支持多轮对话)

目前机器人每次回答都是独立的,无法记住上一轮对话。为了支持多轮对话(例如用户追问“那交通补贴呢?”),我们需要加入对话记忆。

from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain

# 使用 ConversationalRetrievalChain 替代之前的链
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

conversation_chain = ConversationalRetrievalChain.from_llm(
    llm=llm,
    retriever=retriever,
    memory=memory,
    combine_docs_chain_kwargs={"prompt": prompt}  # 复用之前的提示词
)

# 交互
while True:
    question = input("\n你: ")
    if question.lower() == "exit":
        break
    result = conversation_chain.invoke({"question": question})
    print(f"机器人: {result['answer']}")

5.4 测试与调试

  • 测试检索质量:可以打印出每次检索到的文档块,确认是否相关。

result = rag_chain.invoke({"input": "福利假"})
for doc in result["context"]:
    print(doc.page_content)
  • 调整 chunk 大小:如果答案不完整,尝试增大 chunk_size;如果包含太多无关信息,减小它。

  • 更换嵌入模型:中文文档建议使用支持多语言的模型,例如 text-embedding-3-small 或智源的 BAAI/bge-large-zh

  • 检查 API 成本:每次检索+生成会消耗 tokens,可以使用 LangSmith 或自行统计。

第 6 章:总结与下一步学习建议

6.1 回顾核心概念

  • LangChain:一个框架,用标准化的组件快速构建 LLM 应用。

  • 向量数据库:存储文本的向量表示,通过相似性搜索快速找到相关内容。

  • RAG:检索 + 生成,让 LLM 回答私有知识问题,减少幻觉。

  • 核心流程:文档加载 → 分割 → 向量化 → 存储 → 检索 → 生成。

6.2 进阶方向推荐(LangGraph、LangSmith、生产部署)

当你掌握了入门知识后,可以继续探索:

  • LangGraph:用于构建有状态、多步骤、可中断的复杂智能体(比普通的 AgentExecutor 更强大)。

  • LangSmith:生产级的追踪、评估和调试工具。

  • 生产部署:使用 FastAPI 包装 RAG 链,配合缓存、异步、限流等。

  • 高级 RAG 技术:重排序、HyDE、Self-RAG、CRAG。

  • 多模态 RAG:支持图像、表格、音频等。

6.3 资源链接(官方文档、社区、示例项目)

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐