本系列教程完整规划
- 上篇(本文):核心概念、环境搭建、大模型API接入、提示词模板、链的基础使用、文档加载与拆分
- 下篇:RAG 核心实现、Agent 开发、记忆模块、工具调用、LangGraph 工作流、生产级工程化
- 附加篇:LangChain 面试八股文全集(含高频考点+标准答案)
你能从本文收获什么?
- 彻底搞懂LangChain的核心设计理念,不再被一堆概念绕晕
- 从零搭建可直接用于生产的LangChain开发环境,避开90%新手会踩的环境坑
- 熟练掌握国内外主流大模型的接入方式,实现同步、流式、批量全场景调用
- 精通提示词工程的标准化实现,用模板实现提示词复用、结构化输出
- 掌握LangChain核心的LCEL表达式,灵活构建可复用的业务链
- 学会上百种格式文档的加载与最优拆分方案,为下篇RAG检索增强生成做好全流程铺垫
话不多说,我们直接开始!
1.1 LangChain 到底是什么?
LangChain是一个开源的大语言模型(LLM)应用开发框架,你可以把它理解为「大模型应用开发的乐高套装」。
原生的大模型,就像一个只有大脑的“天才”,它有超强的语言理解和生成能力,但它有天生的短板:
- 无法直接读取你的本地文档、PDF、Excel、网页内容
- 无法实时联网获取最新信息(比如今天的股市、最新的新闻)
- 无法调用外部工具(比如计算器、数据库、邮件、API接口)
- 无法记住多轮对话的上下文,无法完成复杂的多步骤任务
- 无法标准化、工程化地复用提示词和业务逻辑
而LangChain,就是给这个“天才”装上了手脚、眼睛、耳朵和记忆,把大模型的原生能力,和各种外部组件、数据、工具、逻辑无缝衔接起来,帮你省去了大量重复的“胶水代码”,让你用最少的代码,快速搭建出复杂、稳定、可落地的大模型应用。
1.2 LangChain 核心设计理念:组件化+可组合
LangChain的灵魂,就是组件化、可组合。
它把大模型应用开发的所有环节,都拆成了一个个独立的、可复用的“乐高积木”,你可以根据自己的业务需求,自由地把这些积木拼接起来,形成完整的工作流。
哪怕是最复杂的AI Agent,本质上也是这些基础积木的合理组合。
1.3 本文必须掌握的7个核心基础概念
这里我们只讲上篇会用到的核心概念,下篇的Agent、LangGraph等内容,我们放到下篇再详细拆解,避免信息过载。
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原生venv(无需额外安装,推荐新手)
- 打开终端/命令提示符,进入你想存放项目的文件夹,执行以下命令创建虚拟环境:
# 创建名为langchain_env的虚拟环境 python -m venv langchain_env
- 激活虚拟环境:
- Windows系统(cmd终端):
langchain_envScriptsactivate
- Windows系统(PowerShell终端):
.langchain_envScriptsActivate.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
完成这一步,我们的环境就彻底准备好了,接下来就可以正式进入开发环节了!
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 流式输出(打字机效果)
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,不要乱设
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}到翻译官,翻译必须准确、地道、简洁,符合目标语言的母语者表达习惯。 要求:
- 只返回翻译后的结果,不要添加任何额外的解释、说明、备注
- 严格保留原文的格式和语气
- 禁止篡改原文的意思
需要翻译的文本: {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)
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}
情感分类:“, # 示例后的后缀,也就是用户的输入
input_variables=["input_text"], # 动态输入的变量 example_separator="
” # 示例之间的分隔符 )
# 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 输出解析器:实现结构化输出
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", "你是一个专业的中英翻译官,翻译准确、地道,严格按照用户要求的格式返回结果,不要添加任何额外内容。
{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“]的方式取值,再也不用自己写正则去匹配大模型的输出了,完美解决了大模型输出格式不稳定的问题!
前面我们学习了提示词模板、大模型、输出解析器这三个核心组件,现在,我们要学习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}到的翻译官,翻译准确、地道、简洁,只返回译文,不添加任何额外内容。"), ("human", "{text}")
])
# 2. 实例化模型和解析器 model = ChatOpenAI(model=”gpt-3.5-turbo“, temperature=0) parser = StrOutputParser()
# 3. 用LCEL构建链,一行代码搞定! chain = prompt | model | parser
# 4. 调用链,只需要传入模板里的变量字典即可 result = chain.invoke()
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():
print(chunk, end="", flush=True)
5.3.2 批量调用
# 批量传入多个参数,一次性处理多个翻译任务 batch_inputs = [
, ,
]
# 批量调用 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传递原始文本 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}
英文译文:{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=["
”, “ ”, “。”, “!”, “?”, “ ”, “”],
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=["
“, ” “, ”。“, ”!“, ”?“, ” “, ”“],
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系列的全部内容,带你从零到一精通大模型应用开发!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/269266.html