前言:为什么你一定要学 LangChain?
相信很多刚接触大模型应用开发的同学,都有过这样的困惑:
原生的大模型API只能做简单的单轮对话,想做一个能读取自己PDF/文档的专属问答机器人、能联网查数据的智能助手、能自动完成复杂任务的AI Agent,却不知道从何下手?
网上的教程要么过于零散,只讲单个功能,不成体系;要么跳步严重,刚入门就被一堆陌生概念搞懵;还有大量教程用的是早已过时的语法,复制代码全是报错,入门直接从入门到放弃。
别担心,这篇《零基础从入门到精通 LangChain》保姆级超详细教程,就是为你量身打造的。
我会从零开始,带着你一步一步拆解LangChain的核心逻辑,每一个概念都讲透,每一行代码都加注释,每一个步骤都不跳步,哪怕你只有一点点Python基础,也能跟着教程完整跑通所有案例。
本系列教程完整规划
- 上篇(本文):核心概念、环境搭建、大模型API接入、提示词模板、链的基础使用、文档加载与拆分
- 下篇:RAG 核心实现、Agent 开发、记忆模块、工具调用、LangGraph 工作流、生产级工程化
- 附加篇:LangChain 面试八股文全集(含高频考点+标准答案)
你能从本文收获什么?
- 彻底搞懂LangChain的核心设计理念,不再被一堆概念绕晕
- 从零搭建可直接用于生产的LangChain开发环境,避开90%新手会踩的环境坑
- 熟练掌握国内外主流大模型的接入方式,实现同步、流式、批量全场景调用
- 精通提示词工程的标准化实现,用模板实现提示词复用、结构化输出
- 掌握LangChain核心的LCEL表达式,灵活构建可复用的业务链
- 学会上百种格式文档的加载与最优拆分方案,为下篇RAG检索增强生成做好全流程铺垫
话不多说,我们直接开始!
一、LangChain 核心概念:先搞懂“是什么”,再学“怎么用”
很多新手入门LangChain的第一个误区,就是一上来就复制代码跑,结果连每个组件是干嘛的都不知道,出一点问题就卡壳。
所以我们先花10分钟,把LangChain的核心定位和基础概念彻底讲透,用最通俗的类比,让你过目不忘。
1.1 LangChain 到底是什么?
LangChain是一个开源的大语言模型(LLM)应用开发框架,你可以把它理解为「大模型应用开发的乐高套装」。
原生的大模型,就像一个只有大脑的“天才”,它有超强的语言理解和生成能力,但它有天生的短板:
- 无法直接读取你的本地文档、PDF、Excel、网页内容
- 无法实时联网获取最新信息(比如今天的股市、最新的新闻)
- 无法调用外部工具(比如计算器、数据库、邮件、API接口)
- 无法记住多轮对话的上下文,无法完成复杂的多步骤任务
- 无法标准化、工程化地复用提示词和业务逻辑
而LangChain,就是给这个“天才”装上了手脚、眼睛、耳朵和记忆,把大模型的原生能力,和各种外部组件、数据、工具、逻辑无缝衔接起来,帮你省去了大量重复的“胶水代码”,让你用最少的代码,快速搭建出复杂、稳定、可落地的大模型应用。
1.2 LangChain 核心设计理念:组件化+可组合
LangChain的灵魂,就是组件化、可组合。
它把大模型应用开发的所有环节,都拆成了一个个独立的、可复用的“乐高积木”,你可以根据自己的业务需求,自由地把这些积木拼接起来,形成完整的工作流。
哪怕是最复杂的AI Agent,本质上也是这些基础积木的合理组合。
1.3 本文必须掌握的7个核心基础概念
这里我们只讲上篇会用到的核心概念,下篇的Agent、LangGraph等内容,我们放到下篇再详细拆解,避免信息过载。
| 核心概念 | 通俗解释 | 核心作用 |
|---|---|---|
| LLM/Chat Model | 大语言模型,也就是我们常说的GPT、通义千问、文心一言、豆包等 | 整个应用的“大脑”,负责语言理解、生成、逻辑推理 |
| Prompt Template | 提示词模板 | 把固定的提示词规则和动态的用户输入分离开,实现提示词的标准化、复用,避免重复写代码 |
| Output Parser | 输出解析器 | 把大模型生成的自由文本,转换成Python能直接处理的结构化数据(比如字符串、JSON、列表、字典) |
| Chain(链) | 把多个组件按业务逻辑拼接起来的可执行单元 | 把“提示词模板→大模型→输出解析器→后续逻辑”串成完整的工作流,是LangChain的核心载体 |
| Document Loader | 文档加载器 | 把各种格式的文件(PDF、TXT、Markdown、Word、网页等),转换成LangChain能统一处理的Document对象 |
| Document | 文档对象 | LangChain统一的文档格式,包含page_content(文本内容)和metadata(元数据,比如文件名、页码、来源)两个核心属性 |
| Text Splitter | 文本拆分器 | 把长文档拆分成符合大模型上下文窗口限制、同时保留语义完整性的文本块 |
记住这7个概念,后面的所有代码,都是围绕这些组件展开的,你再也不会看不懂代码在干嘛了。
二、环境搭建:从零开始,一步到位,避开所有新手坑
这一部分,我会带着你从零搭建LangChain的开发环境,每一步都有详细的操作和代码,哪怕你是第一次用Python,也能跟着完成。
2.1 前置环境准备
1. Python 版本要求
LangChain要求Python版本必须是 3.9及以上,推荐使用3.10/3.11版本,稳定性最好,兼容性最强。
如果你还没安装Python,可以去Python官方网站下载对应系统的版本,安装时记得勾选「Add Python to PATH」,避免环境变量配置问题。
2. 开发工具推荐
新手推荐使用 VS Code 或者 PyCharm Community版,都是免费的,对新手非常友好,自带代码补全、终端、调试功能,跟着教程写代码会非常顺畅。
2.2 虚拟环境搭建(必做!)
很多新手会直接在全局Python环境里安装依赖,结果后面不同项目的依赖版本冲突,出现各种莫名其妙的报错。
所以我们第一步,先创建独立的虚拟环境,把本项目的依赖和全局环境隔离开,一劳永逸解决版本冲突问题。
这里给大家提供两种最常用的方式,二选一即可:
方式一:使用Python原生venv(无需额外安装,推荐新手)
- 打开终端/命令提示符,进入你想存放项目的文件夹,执行以下命令创建虚拟环境:
# 创建名为langchain_env的虚拟环境
python -m venv langchain_env
- 激活虚拟环境:
- Windows系统(cmd终端):
langchain_env\Scripts\activate
- Windows系统(PowerShell终端):
.\langchain_env\Scripts\Activate.ps1
- Mac/Linux系统:
source langchain_env/bin/activate
激活成功后,你会看到终端的命令行前面,出现了(langchain_env)的标识,说明你已经进入了虚拟环境,后面所有的操作,都在这个虚拟环境里执行。
方式二:使用Anaconda/Miniconda(适合有conda基础的同学)
如果你已经安装了Anaconda/Miniconda,可以用以下命令创建并激活虚拟环境:
# 创建Python3.11的虚拟环境,名为langchain_env
conda create -n langchain_env python=3.11 -y
# 激活虚拟环境
conda activate langchain_env
2.3 安装核心依赖包
激活虚拟环境后,我们一次性安装好上篇所有内容需要的依赖包,直接在终端执行以下命令:
# 安装LangChain核心包
pip install langchain
# 安装OpenAI模型集成包(LangChain官方拆分的独立包,必装)
pip install langchain-openai
# 安装社区贡献的组件包(包含文档加载器、国内大模型集成等,必装)
pip install langchain-community
# 安装文本拆分器独立包
pip install langchain-text-splitters
# 安装核心运行时接口包(所有组件的基础接口,必装)
pip install langchain-core
# 安装环境变量管理工具(必装,避免API密钥泄露)
pip install python-dotenv
# 安装PDF文档加载依赖
pip install pypdf
# 安装网页加载依赖
pip install beautifulsoup4
# 安装token计数工具(精准控制文本拆分)
pip install tiktoken
执行完成后,我们可以执行以下命令,验证LangChain是否安装成功:
python -c "import langchain; print(f'LangChain版本:{langchain.__version__}')"
如果终端输出了LangChain的版本号,说明安装成功,我们的环境就搭建完成了!
2.4 API密钥安全配置(重中之重!新手必看)
这是90%新手都会踩的致命坑:千万不要把你的API密钥直接写在代码里!
一旦你不小心把代码上传到GitHub、或者发给别人,你的密钥就会泄露,轻则被人盗刷产生巨额账单,重则账号被封。
所以我们用.env文件来管理所有的API密钥,用python-dotenv来加载,既安全又方便。
操作步骤:
- 在你的项目根目录下,创建一个名为
.env的文件(注意前面有个点,是隐藏文件) - 打开
.env文件,填入你的大模型API密钥,这里我们先以OpenAI为例,后面会补充国内大模型的配置:
# .env 文件内容
OPENAI_API_KEY=你的OpenAI API密钥
# 如果你有代理地址,需要加上这一行
OPENAI_BASE_URL=你的API代理地址(比如https://api.openai.com/v1)
- (必做!)在项目根目录下,创建一个
.gitignore文件,把.env文件加进去,避免不小心提交到Git仓库:
# .gitignore 文件内容
.env
langchain_env/
__pycache__/
*.pyc
完成这一步,我们的环境就彻底准备好了,接下来就可以正式进入开发环节了!
三、大模型 API 接入:打通LangChain的“大脑”
LangChain本身不提供大模型,它是一个框架,需要对接具体的大模型API来实现核心的推理能力。
这一部分,我们会先以最通用的OpenAI GPT系列为例,讲透大模型的接入和全场景调用,然后补充国内主流大模型的接入方式,照顾到所有国内的同学。
3.1 核心前置知识:Chat Model 与 消息类型
现在主流的大模型,都是对话式模型(Chat Model),比如GPT-3.5/4、通义千问、文心一言等,它们的交互方式,是通过「消息列表」来实现的,而不是传统的单文本输入。
LangChain里定义了3种最核心的消息类型,你必须牢牢记住:
- SystemMessage:系统消息,给大模型设定的人设、规则、约束,只会在对话开头生效,告诉大模型“你应该扮演什么角色,遵守什么规则”
- HumanMessage:用户消息,也就是用户输入的问题、指令
- AIMessage:AI消息,也就是大模型返回的回复内容
所有的对话,都是由这三种消息组成的列表,大模型会根据整个消息列表的上下文,生成对应的回复。
3.2 OpenAI 大模型接入(完整可运行代码)
我们先写一个最简单的代码,实现大模型的调用,每一行都加了详细的注释,你可以直接复制到你的Python文件里运行。
3.2.1 基础同步调用
# 1. 导入所需的包
from dotenv import load_dotenv # 用于加载.env文件里的环境变量
from langchain_openai import ChatOpenAI # OpenAI对话模型封装
from langchain_core.messages import SystemMessage, HumanMessage # 消息类型
# 2. 加载.env文件里的API密钥,这一行必须写,不然会找不到密钥
load_dotenv()
# 3. 实例化大模型,配置核心参数
model = ChatOpenAI(
model="gpt-3.5-turbo", # 要使用的模型名称,也可以用gpt-4o等
temperature=0, # 温度参数,0=最确定,无随机性,适合翻译、分类等任务;1=最随机,适合创作
max_tokens=1024, # 大模型生成的最大token数
timeout=30, # 请求超时时间,单位秒
max_retries=2, # 请求失败后的最大重试次数
)
# 4. 构建消息列表
messages = [
SystemMessage(content="你是一个专业的AI技术科普博主,语言通俗易懂,讲解清晰,只讲干货,不啰嗦。"),
HumanMessage(content="用一句话给零基础的人讲清楚什么是LangChain")
]
# 5. 调用大模型,获取回复
response = model.invoke(messages)
# 6. 打印结果
print("AI回复内容:")
print(response.content)
运行这段代码,你就会看到大模型返回的回复,恭喜你!你已经成功用LangChain完成了第一次大模型调用!
3.2.2 流式输出(打字机效果)
我们平时用ChatGPT的时候,都是一个字一个字蹦出来的打字机效果,而不是等全部生成完才显示,这个就是流式输出,在做前端界面的时候,是刚需。
LangChain里实现流式输出非常简单,只需要把invoke方法换成stream方法即可,代码如下:
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
load_dotenv()
# 实例化模型
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)
# 构建消息列表
messages = [
SystemMessage(content="你是一个专业的AI技术科普博主,语言通俗易懂,讲解清晰。"),
HumanMessage(content="给零基础的人讲一下LangChain的核心优势,不超过300字")
]
# 流式调用大模型
print("AI回复内容:")
for chunk in model.stream(messages):
# 逐token打印,不换行,实现打字机效果
print(chunk.content, end="", flush=True)
运行这段代码,你就会看到终端里出现打字机一样的流式输出效果,就是这么简单!
3.2.3 批量调用
如果你有多个问题需要批量处理,不需要循环调用,直接用batch方法即可,效率更高,代码如下:
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
load_dotenv()
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 构建多个消息列表,批量处理3个翻译任务
batch_messages = [
[
SystemMessage(content="你是一个专业的中英翻译官,只返回译文,不添加额外内容。"),
HumanMessage(content="LangChain是一个强大的大语言模型应用开发框架")
],
[
SystemMessage(content="你是一个专业的中英翻译官,只返回译文,不添加额外内容。"),
HumanMessage(content="提示词工程是大模型应用开发的核心技能")
],
[
SystemMessage(content="你是一个专业的中英翻译官,只返回译文,不添加额外内容。"),
HumanMessage(content="RAG检索增强生成可以解决大模型幻觉问题")
]
]
# 批量调用
responses = model.batch(batch_messages)
# 遍历打印结果
for i, response in enumerate(responses):
print(f"第{i+1}个翻译结果:{response.content}")
3.3 国内主流大模型接入
很多国内的同学无法使用OpenAI,没关系,LangChain已经完美适配了国内所有主流大模型,而且接口完全统一,你只需要修改模型的实例化代码,前面的invoke、stream、batch方法完全不用改,这就是LangChain的核心优势之一!
这里给大家提供2个最常用的国内大模型接入示例,其他模型的接入方式大同小异。
3.3.1 阿里通义千问接入
- 首先去阿里云百炼官网,开通通义千问API,获取你的API密钥(DASHSCOPE_API_KEY)
- 在
.env文件里添加你的密钥:
DASHSCOPE_API_KEY=你的通义千问API密钥
- 安装对应的依赖包:
pip install dashscope langchain-community
- 完整调用代码:
from dotenv import load_dotenv
from langchain_community.chat_models import ChatTongyi
from langchain_core.messages import SystemMessage, HumanMessage
load_dotenv()
# 实例化通义千问模型
model = ChatTongyi(
model="qwen-turbo", # 模型名称,也可以用qwen-plus、qwen-max等
temperature=0,
api_key=os.getenv("DASHSCOPE_API_KEY")
)
# 后续的调用方式和OpenAI完全一致!
messages = [
SystemMessage(content="你是一个专业的AI技术科普博主,语言通俗易懂。"),
HumanMessage(content="用一句话讲清楚什么是LangChain")
]
response = model.invoke(messages)
print(response.content)
3.3.2 字节跳动豆包大模型接入
- 去字节跳动火山引擎官网,开通豆包大模型API,获取你的API密钥
- 在
.env文件里添加密钥,然后用LangChain的ChatOpenAI类即可直接接入(豆包API完全兼容OpenAI接口规范):
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage
import os
load_dotenv()
# 实例化豆包模型
model = ChatOpenAI(
model="doubao-pro-32k", # 豆包模型名称
api_key=os.getenv("DOUBAO_API_KEY"),
base_url="https://ark.cn-beijing.volces.com/api/v3", # 豆包API地址
temperature=0
)
# 调用方式完全一致
messages = [
SystemMessage(content="你是一个专业的AI技术科普博主,语言通俗易懂。"),
HumanMessage(content="用一句话讲清楚什么是LangChain")
]
response = model.invoke(messages)
print(response.content)
3.4 关键知识点总结
- LangChain对所有大模型做了统一的接口封装,换模型只需要修改实例化代码,业务逻辑完全不用改,这是用LangChain对接大模型的核心优势
- 核心调用方法有3个:
invoke(同步调用,一次性返回结果)、stream(流式调用,打字机效果)、batch(批量调用,处理多个任务) temperature参数是核心,确定性任务(翻译、分类、提取)设为0,创作类任务设为0.7-1,不要乱设
四、提示词模板:标准化你的提示词工程
很多新手写提示词,都是每次调用大模型的时候,手动拼接字符串,不仅代码冗余,还容易出错,而且无法复用。
LangChain的Prompt Template(提示词模板),就是专门解决这个问题的,它把提示词里固定的规则、人设、约束和动态的用户输入、变量分离开,实现提示词的标准化、复用、可维护。
4.1 基础提示词模板 PromptTemplate
PromptTemplate是最基础的模板,用于单文本输入的场景,我们先从最简单的例子开始。
4.1.1 基础用法:翻译模板
我们做一个通用的翻译模板,支持动态传入源语言、目标语言、要翻译的文本,代码如下:
from dotenv import load_dotenv
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
load_dotenv()
# 1. 定义提示词模板
# 用{变量名}作为占位符,后续可以动态传入参数
translate_template = """
你是一个专业的{source_lang}到{target_lang}翻译官,翻译必须准确、地道、简洁,符合目标语言的母语者表达习惯。
要求:
1. 只返回翻译后的结果,不要添加任何额外的解释、说明、备注
2. 严格保留原文的格式和语气
3. 禁止篡改原文的意思
需要翻译的文本:
{text}
"""
# 2. 从模板创建PromptTemplate对象
prompt = PromptTemplate(
template=translate_template,
input_variables=["source_lang", "target_lang", "text"] # 模板里的变量名,必须一一对应
)
# 3. 实例化模型和输出解析器
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
parser = StrOutputParser() # 把大模型的输出转成纯字符串,去掉多余的内容
# 4. 用format方法,传入参数,生成完整的提示词
# 这一步可以用来调试,看看生成的提示词是否符合预期
formatted_prompt = prompt.format(
source_lang="中文",
target_lang="英文",
text="LangChain是一个强大的大语言模型应用开发框架,让零基础的人也能快速搭建复杂的AI应用。"
)
print("生成的完整提示词:")
print(formatted_prompt)
print("-"*50)
# 5. 调用大模型
response = model.invoke(formatted_prompt)
result = parser.invoke(response)
print("翻译结果:")
print(result)
运行这段代码,你会看到,模板会自动把我们传入的参数,填充到对应的占位符里,生成完整的提示词,然后传给大模型,得到翻译结果。
以后你需要翻译其他内容,只需要调用prompt.format()传入新的参数即可,不用再重复写整个提示词,非常方便。
4.2 聊天提示词模板 ChatPromptTemplate
前面我们讲过,现在主流的大模型都是Chat Model,用消息列表的方式交互,所以对应的,我们用ChatPromptTemplate来构建聊天场景的提示词模板,这是我们日常开发中最常用的。
4.2.1 最简用法:from_messages 方法
ChatPromptTemplate.from_messages()是最简洁、最推荐的用法,我们可以用元组的方式,快速定义不同角色的消息模板,代码如下:
from dotenv import load_dotenv
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
load_dotenv()
# 1. 定义聊天提示词模板
# 元组格式:(角色, 模板内容),角色可以是system、human、ai
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个专业的{profession}领域专家,有10年以上的从业经验,回答问题专业、准确、通俗易懂,只讲干货,不啰嗦。"),
("human", "请用不超过{word_count}个字,给零基础的人解释一下{question}")
])
# 2. 实例化模型和解析器
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
parser = StrOutputParser()
# 3. 传入参数,生成消息列表
formatted_messages = prompt.format_messages(
profession="AI应用开发",
word_count=100,
question="什么是LangChain"
)
print("生成的消息列表:")
print(formatted_messages)
print("-"*50)
# 4. 调用大模型
response = model.invoke(formatted_messages)
result = parser.invoke(response)
print("AI回复:")
print(result)
这个用法非常灵活,你可以任意添加system、human、ai的消息模板,构建多轮对话的提示词,完全贴合Chat Model的交互逻辑。
4.3 进阶:少样本提示词模板 FewShotPromptTemplate
少样本提示(Few-Shot Learning)是提示词工程里非常核心的技巧,就是给大模型几个示例,让大模型学习示例里的格式、逻辑、风格,然后按照相同的规则处理新的输入,比单纯的文字描述效果好10倍。
LangChain的FewShotPromptTemplate,专门用来标准化实现少样本提示,我们以情感分类任务为例,看一下具体用法:
from dotenv import load_dotenv
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
load_dotenv()
# 1. 准备少样本示例
examples = [
{
"text": "这个产品的质量太好了,用了半年一点问题都没有,非常推荐!",
"sentiment": "正面"
},
{
"text": "什么垃圾东西,刚收到就坏了,客服还不理人,避雷!",
"sentiment": "负面"
},
{
"text": "这个东西还行,不算特别好,也不算差,中规中矩吧。",
"sentiment": "中性"
}
]
# 2. 定义每个示例的模板
example_template = """
用户评论:{text}
情感分类:{sentiment}
"""
example_prompt = PromptTemplate(
template=example_template,
input_variables=["text", "sentiment"]
)
# 3. 创建少样本提示词模板
few_shot_prompt = FewShotPromptTemplate(
examples=examples, # 少样本示例
example_prompt=example_prompt, # 每个示例的模板
prefix="你是一个专业的电商评论情感分类专家,根据用户的评论内容,判断情感倾向,只返回「正面」「负面」「中性」三个结果中的一个,不要添加任何额外内容。以下是示例:", # 示例前的前缀
suffix="用户评论:{input_text}\n情感分类:", # 示例后的后缀,也就是用户的输入
input_variables=["input_text"], # 动态输入的变量
example_separator="\n\n" # 示例之间的分隔符
)
# 4. 实例化模型和解析器
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
parser = StrOutputParser()
# 5. 生成完整提示词,调用大模型
formatted_prompt = few_shot_prompt.format(input_text="物流很快,产品和描述的一样,用着还不错,下次还会买。")
response = model.invoke(formatted_prompt)
result = parser.invoke(response)
print("情感分类结果:", result)
运行这段代码,你会发现,哪怕你没有给大模型复杂的规则,只给了3个示例,大模型也能精准地完成情感分类任务,这就是少样本提示的威力。
4.4 输出解析器:实现结构化输出
很多时候,我们需要大模型返回结构化的数据,比如JSON、字典、列表,而不是自由文本,不然代码里很难处理。
比如你做一个翻译工具,需要大模型返回原文、译文、词性、例句四个字段,这时候就需要用到Output Parser(输出解析器)。
LangChain提供了很多种输出解析器,这里我们讲两个最常用、最核心的。
4.4.1 StrOutputParser:字符串解析器
这个是最简单、最常用的解析器,它的作用就是把大模型返回的AIMessage对象,转换成纯字符串,去掉所有多余的内容,我们前面的代码里已经多次用到了,这里就不再重复。
4.4.2 JsonOutputParser:JSON解析器(核心!)
这个是日常开发中最实用的解析器,它可以把大模型的输出,直接转换成Python能直接处理的字典/JSON对象,而且可以配合Pydantic定义数据结构,让大模型严格按照你定义的格式输出,避免JSON格式错误的问题。
完整可运行代码如下:
from dotenv import load_dotenv
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import JsonOutputParser
from pydantic import BaseModel, Field # 用于定义数据结构
from typing import List
load_dotenv()
# 1. 用Pydantic定义输出的数据结构,告诉大模型要输出什么格式
class TranslationResult(BaseModel):
source_text: str = Field(description="用户输入的原始文本")
target_text: str = Field(description="翻译后的目标文本")
word_explanation: List[dict] = Field(description="重点词汇解析,每个词汇是一个字典,包含word(词汇)和explanation(解释)两个字段")
example_sentence: str = Field(description="用翻译后的词汇造一个地道的例句,附带中文翻译")
# 2. 创建JSON解析器
parser = JsonOutputParser(pydantic_object=TranslationResult)
# 3. 定义提示词模板,把解析器的格式指令放进去
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个专业的中英翻译官,翻译准确、地道,严格按照用户要求的格式返回结果,不要添加任何额外内容。\n{format_instructions}"),
("human", "请翻译以下文本:{text}")
])
# 4. 给模板传入解析器的格式指令,让大模型知道要按什么格式输出
prompt = prompt.partial(format_instructions=parser.get_format_instructions())
# 5. 实例化模型
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 6. 调用大模型,解析结果
chain = prompt | model | parser
result = chain.invoke({"text": "LangChain是一个强大的大语言模型应用开发框架"})
# 7. 打印结果,这里的result已经是Python字典,可以直接取值
print("解析后的结果:")
print(result)
print("-"*50)
print("翻译结果:", result["target_text"])
print("重点词汇解析:", result["word_explanation"])
运行这段代码,你会发现,大模型严格按照我们定义的结构,返回了JSON格式的内容,解析器直接把它转换成了Python字典,你可以直接用result["key"]的方式取值,再也不用自己写正则去匹配大模型的输出了,完美解决了大模型输出格式不稳定的问题!
五、链的基础使用:用LCEL构建你的第一个工作流
前面我们学习了提示词模板、大模型、输出解析器这三个核心组件,现在,我们要学习LangChain的核心——Chain(链),把这些组件串起来,形成完整的可复用的工作流。
5.1 先搞懂:什么是LCEL?
LCEL的全称是 LangChain Expression Language(LangChain表达式语言),是LangChain官方现在主推的、全新的链构建方式,替代了旧的LLMChain、SequentialChain等类,语法更简洁、可读性更强、功能更强大、调试更方便。
LCEL的核心语法,就是用 | 运算符,把多个实现了Runnable接口的组件串起来,就像Linux的管道符一样,前一个组件的输出,会作为后一个组件的输入。
比如,最基础的链,就是:
提示词模板 | 大模型 | 输出解析器
就是这么简单!一行代码,就能构建一个完整的工作流,而且支持同步、流式、批量、重试、错误处理、追踪等所有功能,开箱即用。
5.2 第一个基础链:翻译链
我们用LCEL,把前面的翻译功能,构建成一个完整的链,代码如下:
from dotenv import load_dotenv
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
load_dotenv()
# 1. 定义提示词模板
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个专业的{source_lang}到{target_lang}的翻译官,翻译准确、地道、简洁,只返回译文,不添加任何额外内容。"),
("human", "{text}")
])
# 2. 实例化模型和解析器
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
parser = StrOutputParser()
# 3. 用LCEL构建链,一行代码搞定!
chain = prompt | model | parser
# 4. 调用链,只需要传入模板里的变量字典即可
result = chain.invoke({
"source_lang": "中文",
"target_lang": "日文",
"text": "LangChain是一个强大的大语言模型应用开发框架,零基础也能快速上手。"
})
print("翻译结果:", result)
就是这么简洁!我们再也不用手动调用prompt.format()生成提示词,再调用model.invoke(),再调用parser.invoke(),链会自动按顺序执行,前一个组件的输出,自动传给后一个组件。
5.3 链的全场景调用
和大模型一样,LCEL构建的链,天生支持invoke、stream、batch三种调用方式,完全统一的接口,不用写额外的代码。
5.3.1 流式调用(打字机效果)
# 沿用上面构建好的chain,直接用stream方法即可
print("翻译结果:")
for chunk in chain.stream({
"source_lang": "中文",
"target_lang": "英文",
"text": "LangChain的LCEL表达式语言,让构建大模型工作流变得非常简单。"
}):
print(chunk, end="", flush=True)
5.3.2 批量调用
# 批量传入多个参数,一次性处理多个翻译任务
batch_inputs = [
{"source_lang": "中文", "target_lang": "英文", "text": "提示词工程是大模型应用开发的核心技能"},
{"source_lang": "中文", "target_lang": "英文", "text": "RAG检索增强生成可以解决大模型幻觉问题"},
{"source_lang": "中文", "target_lang": "英文", "text": "AI Agent是大模型应用的未来方向"}
]
# 批量调用
results = chain.batch(batch_inputs)
# 遍历打印结果
for i, result in enumerate(results):
print(f"第{i+1}个翻译结果:{result}")
5.4 进阶:多链组合与参数传递
实际开发中,我们的业务逻辑往往不是单链,而是需要把多个链组合起来,比如先翻译,再润色,再提取重点词汇,这时候就需要用到LCEL的参数传递能力。
5.4.1 多链组合示例:翻译+润色
我们构建两个链,第一个链负责翻译,第二个链负责把翻译结果润色得更地道,然后把两个链组合起来,形成一个完整的工作流。
from dotenv import load_dotenv
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
load_dotenv()
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
parser = StrOutputParser()
# 1. 第一个链:翻译链
translate_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个专业的中文到英文的翻译官,翻译准确、字面意思完整,只返回译文,不添加额外内容。"),
("human", "{text}")
])
translate_chain = translate_prompt | model | parser
# 2. 第二个链:润色链
polish_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个专业的英文文案润色专家,把给定的英文文本润色得更地道、更流畅,符合科技领域的母语者表达习惯,只返回润色后的文本,不添加额外内容。"),
("human", "{translation_result}")
])
polish_chain = polish_prompt | model | parser
# 3. 组合两个链:前一个链的输出,作为后一个链的输入
# 用字典的方式,定义参数传递:key是后一个链的变量名,value是前一个链
full_chain = {"translation_result": translate_chain} | polish_chain
# 4. 调用完整的链
result = full_chain.invoke({"text": "LangChain是一个强大的大语言模型应用开发框架,让零基础的开发者也能快速搭建复杂的AI应用。"})
print("润色后的翻译结果:", result)
5.4.2 RunnablePassthrough:传递原始参数
上面的例子里,润色链只能拿到翻译链的输出,如果我们想让润色链同时拿到用户输入的原始文本,怎么办?
这时候就需要用到RunnablePassthrough,它的作用就是把原始的输入参数,原封不动地传递下去,代码如下:
# 沿用上面的链,修改组合链,用RunnablePassthrough传递原始文本
full_chain = {
"translation_result": translate_chain, # 翻译链的输出
"original_text": RunnablePassthrough() # 原始输入的text参数,原封不动传递
} | polish_prompt | model | parser
# 这时候,我们的润色模板里,就可以用{original_text}变量了
# 我们修改一下润色模板,让它对比原始文本,保证润色不偏离原意
polish_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个专业的英文文案润色专家,结合原始中文文本,把给定的英文译文润色得更地道、更流畅,符合科技领域的母语者表达习惯,保证不偏离原文的意思,只返回润色后的文本,不添加额外内容。"),
("human", "原始中文文本:{original_text}\n英文译文:{translation_result}")
])
# 重新调用
result = full_chain.invoke({"text": "LangChain是一个强大的大语言模型应用开发框架,让零基础的开发者也能快速搭建复杂的AI应用。"})
print("润色后的翻译结果:", result)
RunnablePassthrough是LCEL里非常常用的组件,尤其是在复杂的链和RAG场景里,我们会经常用到它来传递参数。
5.5 LCEL的核心优势总结
- 语法极简,可读性极强:一行代码就能构建复杂的工作流,代码就是逻辑,一眼就能看懂
- 统一的接口:所有用LCEL构建的链,都支持
invoke、stream、batch方法,不用写额外的代码 - 内置强大功能:天生支持重试、超时、错误处理、日志、追踪,无缝对接LangSmith调试工具
- 极致的灵活性:可以任意组合多个链、分支、条件判断,实现任何复杂的业务逻辑
六、文档加载与拆分:给大模型装上“阅读能力”
前面我们学习的内容,都是让大模型处理用户输入的文本,但是实际开发中,我们经常需要让大模型读取我们自己的文档,比如PDF、TXT、Markdown、Word、网页等,这就是RAG检索增强生成的第一步,也是下篇内容的核心基础。
这一部分,我们就彻底讲透:如何用LangChain加载各种格式的文档,以及如何把长文档拆分成符合大模型要求的、保留语义完整性的文本块。
6.1 先搞懂:为什么要做文档加载与拆分?
大模型有两个天生的限制,决定了我们必须做文档加载和拆分:
- 上下文窗口限制:任何大模型的上下文窗口都是有限的,比如GPT-3.5-turbo是16K token,GPT-4o是128K token,哪怕是最大的模型,也装不下一本几百页的书、一个几十万字的文档。
- 成本与效率限制:上下文窗口越大,调用大模型的成本越高,而且长文本会降低大模型的检索精度和推理速度,很容易出现“读了后面忘了前面”的问题。
所以,我们的解决方案是:
- 文档加载:用Document Loader,把各种格式的外部文档,转换成LangChain统一的Document对象,让大模型能“读得到”
- 文本拆分:用Text Splitter,把长文档拆分成合适大小的、保留语义完整性的文本块,让大模型能“装得下、读得懂”
6.2 核心前置知识:Document 对象
LangChain里,所有加载进来的文档,都会被转换成Document对象,它有两个核心属性,你必须记住:
- page_content:字符串类型,文档的文本内容,也就是我们要给大模型看的内容
- metadata:字典类型,文档的元数据,比如文件名、页码、作者、来源、创建时间等,用来标识文档的来源,后续检索的时候可以用来过滤
6.3 文档加载:支持上百种格式,全覆盖
LangChain提供了上百种文档加载器,支持几乎所有你能想到的文档格式,这里我们讲最常用的几种,每一种都有完整的可运行代码。
6.3.1 纯文本文件(.txt)加载
这是最基础的加载器,用来加载.txt格式的纯文本文件,代码如下:
from langchain_community.document_loaders import TextLoader
# 1. 实例化加载器,传入txt文件的路径
loader = TextLoader("./test.txt", encoding="utf-8")
# 2. 加载文档,返回Document对象的列表
documents = loader.load()
# 3. 查看加载结果
print(f"加载的文档数量:{len(documents)}")
print(f"文档内容预览:{documents[0].page_content[:200]}...")
print(f"文档元数据:{documents[0].metadata}")
6.3.2 PDF 文件加载(最常用!)
这是日常开发中最常用的加载器,用来加载.pdf格式的文件,我们用PyPDFLoader,它会把PDF的每一页,转换成一个Document对象,metadata里会自动带上页码,非常方便。
注意:前面环境搭建的时候,我们已经安装了pypdf依赖,如果没安装,先执行pip install pypdf。
from langchain_community.document_loaders import PyPDFLoader
# 1. 实例化加载器,传入PDF文件的路径
loader = PyPDFLoader("./test.pdf")
# 2. 加载文档,每一页生成一个Document对象
documents = loader.load()
# 3. 查看加载结果
print(f"PDF总页数:{len(documents)}")
print(f"第1页内容预览:{documents[0].page_content[:200]}...")
print(f"第1页元数据:{documents[0].metadata}") # 会自动带上页码、文件名等信息
6.3.3 Markdown 文件加载
用来加载.md格式的Markdown文件,会保留Markdown的标题、列表、代码块等格式信息,代码如下:
from langchain_community.document_loaders import UnstructuredMarkdownLoader
# 安装依赖:pip install unstructured
loader = UnstructuredMarkdownLoader("./test.md", mode="elements", encoding="utf-8")
documents = loader.load()
print(f"加载的文档块数量:{len(documents)}")
print(f"内容预览:{documents[0].page_content[:200]}...")
print(f"元数据:{documents[0].metadata}")
6.3.4 网页内容加载
用来加载网页的HTML内容,转换成纯文本,代码如下:
from langchain_community.document_loaders import WebBaseLoader
# 安装依赖:pip install beautifulsoup4
# 传入要加载的网页URL
loader = WebBaseLoader("https://python.langchain.com/docs/introduction/")
# 加载网页内容
documents = loader.load()
print(f"网页内容预览:{documents[0].page_content[:300]}...")
print(f"网页元数据:{documents[0].metadata}")
6.3.5 更多加载器
LangChain支持的加载器远不止这些,还包括Word、Excel、PPT、CSV、JSON、Notion、GitHub、Confluence、微信公众号、知乎等上百种格式,你可以去LangChain官方文档查看所有可用的加载器,用法和上面的示例完全一致,非常简单。
6.4 文本拆分:把长文档拆成最优的文本块
加载完文档之后,我们得到的是完整的文档内容,比如一页PDF可能有几千字,还是超过了大模型和嵌入模型的上下文窗口,而且粒度太粗,后续检索的时候找不到精准的内容,所以我们需要把文档拆分成合适大小的文本块。
6.4.1 文本拆分的3个核心原则
这是文本拆分的灵魂,很多新手拆分的效果不好,就是因为没遵守这3个原则:
- 保持语义完整性:优先按段落、句子拆分,绝对不要把一个完整的句子、一个完整的概念,拆到两个不同的块里,不然会丢失语义,后续检索的时候找不到正确的内容。
- 控制块的大小:根据嵌入模型的上下文窗口,常用的块大小是500-1000个字符,或者100-300个token,不要太大,也不要太小。太大了检索不精准,太小了丢失上下文语义。
- 块之间必须有重叠:也就是
chunk_overlap,一般设置为块大小的10%-20%,比如块大小是500字符,重叠就是50-100字符。重叠的作用,是避免语义被截断,保证一个完整的句子、概念,至少能完整地出现在一个块里。
6.4.2 官方推荐:递归字符拆分器 RecursiveCharacterTextSplitter
LangChain官方最推荐、日常开发中最常用的拆分器,就是RecursiveCharacterTextSplitter(递归字符拆分器)。
它的核心逻辑是:按你设置的分隔符优先级,递归地拆分文本。先按最粗的分隔符(比如段落)拆分,如果拆分后的块还是超过了chunk_size,就按下一个优先级的分隔符(比如换行)拆分,以此类推,直到所有块都符合大小要求。
这种方式,能最大程度地保留文本的语义完整性,是所有拆分器里效果最好的。
中文优化版拆分器(完整可运行代码)
中文和英文的分隔符不一样,英文用空格分隔单词,中文用句号、感叹号、问号分隔句子,所以我们需要针对中文优化分隔符的优先级,代码如下:
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyPDFLoader
# 1. 先加载PDF文档
loader = PyPDFLoader("./test.pdf")
documents = loader.load()
print(f"原始文档页数:{len(documents)}")
# 2. 初始化中文优化的递归字符拆分器
text_splitter = RecursiveCharacterTextSplitter(
# 中文场景的分隔符优先级:段落→换行→句号→感叹号→问号→空格→单个字符
separators=["\n\n", "\n", "。", "!", "?", " ", ""],
chunk_size=500, # 每个块的最大字符数
chunk_overlap=100, # 块之间的重叠字符数,块大小的20%
length_function=len, # 计算长度的函数,这里按字符数计算
is_separator_regex=False, # 分隔符是否用正则表达式
)
# 3. 拆分文档
split_docs = text_splitter.split_documents(documents)
# 4. 查看拆分结果
print(f"拆分后的文本块数量:{len(split_docs)}")
print("-"*50)
# 遍历前3个块,查看详情
for i, doc in enumerate(split_docs[:3]):
print(f"第{i+1}个块,字符长度:{len(doc.page_content)}")
print(f"内容预览:{doc.page_content[:200]}...")
print(f"元数据:{doc.metadata}")
print("-"*50)
运行这段代码,你就会看到,文档被拆分成了一个个500字符左右的块,块之间有100字符的重叠,而且优先按句子、段落拆分,完美保留了语义完整性。
6.4.3 进阶:按Token拆分,更贴合大模型逻辑
前面的拆分是按字符数计算的,但是大模型和嵌入模型,都是按token来计算上下文窗口的,中文字符和token的换算比例大概是1.5:1,也就是1个token≈1.5个中文字符,按字符数拆分,可能会出现块大小不准确的问题。
所以我们可以用tiktoken来计算token数,按token来拆分,更贴合大模型的处理逻辑,拆分的大小更精准,代码如下:
import tiktoken
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyPDFLoader
# 1. 定义token长度计算函数,用OpenAI的tiktoken
def tiktoken_len(text):
# 用GPT-3.5/4/4o通用的cl100k_base编码
tokenizer = tiktoken.get_encoding("cl100k_base")
tokens = tokenizer.encode(text, disallowed_special=())
return len(tokens)
# 2. 加载文档
loader = PyPDFLoader("./test.pdf")
documents = loader.load()
# 3. 初始化按token拆分的拆分器
text_splitter = RecursiveCharacterTextSplitter(
separators=["\n\n", "\n", "。", "!", "?", " ", ""],
chunk_size=200, # 每个块的最大token数
chunk_overlap=40, # 20%的重叠token数
length_function=tiktoken_len, # 用我们定义的token长度函数
is_separator_regex=False,
)
# 4. 拆分文档
split_docs = text_splitter.split_documents(documents)
# 5. 查看每个块的token数
print(f"拆分后的块数量:{len(split_docs)}")
for i, doc in enumerate(split_docs[:3]):
print(f"第{i+1}个块,token数:{tiktoken_len(doc.page_content)}")
print(f"内容预览:{doc.page_content[:200]}...")
print("-"*50)
6.4.4 其他常用拆分器
除了递归字符拆分器,LangChain还有一些针对特定场景的拆分器,这里简单提一下,大家可以根据自己的需求选择:
- MarkdownHeaderTextSplitter:按Markdown的标题(#、##、###)拆分,自动保留标题层级,非常适合Markdown文档
- HTMLHeaderTextSplitter:按HTML的标题标签(h1、h2、h3)拆分,适合网页内容
- RecursiveJsonSplitter:专门用来拆分JSON数据,保留JSON的结构完整性
- CodeSplitter:专门用来拆分代码,支持Python、Java、JavaScript等多种编程语言,保留代码的语法结构
上篇总结 & 下篇预告
恭喜你!坚持看到这里,你已经完成了LangChain零基础入门的全部核心内容,彻底打通了大模型应用开发的基础环节。
上篇我们学到了什么?
- 彻底搞懂了LangChain的核心定位、设计理念和7个基础核心概念,再也不会被陌生名词绕晕
- 从零搭建了可用于生产的LangChain开发环境,学会了安全管理API密钥,避开了90%新手会踩的环境坑
- 熟练掌握了国内外主流大模型的接入,实现了同步、流式、批量全场景调用,打通了LangChain的“大脑”
- 精通了提示词模板的标准化实现,从基础模板到少样本提示,再到结构化输出解析器,彻底掌握了提示词工程的核心
- 学会了用LCEL表达式构建基础链,掌握了链的全场景调用和多链组合,能灵活构建可复用的业务工作流
- 掌握了上百种格式文档的加载方法,以及官方推荐的递归文本拆分技巧,为下篇的RAG检索增强生成做好了100%的铺垫
下篇预告
在下篇里,我们会正式进入LangChain的进阶核心内容,从零实现生产级的RAG检索增强生成系统、AI Agent智能体、记忆模块、工具调用、LangGraph复杂工作流,以及生产级工程化最佳实践,带你从入门直接进阶到精通,做出能真正落地的大模型应用。
互动环节
如果大家在学习过程中遇到任何问题,都可以在评论区留言,我会一一解答!
也可以在评论区说说你最想用LangChain做什么应用,下篇我会针对大家的需求,补充更多对应的实战案例和代码!
如果这篇教程对你有帮助,欢迎点赞、收藏、关注,后续会持续更新LangChain系列的全部内容,带你从零到一精通大模型应用开发!
转载自CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/2502_92311356/article/details/160228609



