LangChain LCEL Chain 零基础入门指南

LangChain LCEL Chain 零基础入门指南

面向新手,由浅入深梳理 LCEL 链式开发 ,从概念、基础用法、进阶组件到实战避坑,全程配套可运行代码,循序渐进掌握 | 管道串联思维。

前置说明:本文统一使用硅基流动 + DeepSeek-V3 模型演示,所有示例环境配置统一,减少重复工作量;代码均经过精简优化,新手可直接复制运行。


一、开篇:为什么要学 Chain / LCEL?

1.1 传统写法的痛点

在接触 Chain 之前,我们调用大模型需要分步执行:拼接提示词 → 调用模型 → 解析结果,每一步都要手动调用方法,代码零散、复用性差。

传统分步示例(冗余写法)

Python 复制代码
# 1. 拼接提示词
prompt_msg = prompt.invoke({"city": "北京"})
# 2. 调用大模型
llm_result = llm.invoke(prompt_msg)
# 3. 解析结果
final_data = parser.invoke(llm_result)

1.2 LCEL Chain 的优势

LCEL (LangChain Expression Language,LangChain 表达式语言)是官方推出的组件组合语法,核心是用 |(管道符)把多个功能组件拼接成一条流水线(Chain)

改写后一行完成全流程:

Python 复制代码
chain = prompt | llm | parser
final_data = chain.invoke({"city": "北京"})

核心价值:

  1. 代码简洁:多步逻辑合并为一条链路,可读性强;

  2. 统一接口 :整条链自带 invoke/stream/batch 等方法,调用方式一致;

  3. 灵活扩展:支持串行、并行、条件分支、自定义逻辑,适配复杂业务;

  4. 高复用性:一条链可当作独立组件,嵌套组合到其他链路中。

1.3 学完本文你能掌握

  1. 理解 Runnable、LCEL、Chain 核心概念;

  2. 掌握最常用的串行链路(80% 业务场景);

  3. 学会并行、条件分支、数据透传、自定义函数四大进阶组件;

  4. 实现流式输出、批量处理、结构化数据解析;

  5. 避开新手高频报错,独立编写业务链路。


二、前置准备:环境统一配置

2.1 安装依赖

首先安装 LangChain 核心库与环境变量管理工具:

Bash 复制代码
pip install langchain python-dotenv

2.2 环境变量配置

在项目根目录新建 .env 文件,填入你的硅基流动密钥和接口地址:

Plaintext 复制代码
# .env 文件内容
SILICON_KEY=你的硅基API密钥
SILICON_BASE_URL=https://api.siliconflow.cn/v1

2.3 全局初始化 LLM(所有示例复用)

新建基础代码文件,统一初始化模型,后续所有示例无需重复写环境配置

Python 复制代码
# base_config.py 全局基础配置
import os
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model

# 加载 .env 环境变量
load_dotenv()

# 映射硅基接口为 OpenAI 兼容格式
os.environ["OPENAI_API_KEY"] = os.getenv("SILICON_KEY")
os.environ["OPENAI_BASE_URL"] = os.getenv("SILICON_BASE_URL")

# 初始化 DeepSeek-V3 模型(全局通用)
llm = init_chat_model("openai:deepseek-ai/DeepSeek-V3")

后续所有代码,默认从 base_config 导入 llm


三、核心概念:通俗解读(新手必看)

先搞懂 3 个核心术语,再写代码事半功倍:

术语 通俗解释 举例
Runnable LangChain 中所有可执行的组件 (流水线零件),统一支持 invoke/stream 等调用方法 提示词模板、大模型、结果解析器、自定义函数
**` ` 管道符** 数据传输通道:前一个组件的输出 = 后一个组件的输入
Chain(链) 多个 Runnable 用 ` ` 组合而成的完整流水线,本身也是 Runnable

一句话总结:LCEL 就是用管道符,把一个个"功能零件"组装成一条自动化流水线


四、第一阶段:基础串行链(入门核心,必掌握)

串行(RunnableSequence)是 LCEL 最基础、使用最多的形态:组件1 | 组件2 | 组件3,按顺序一步步执行。

标准通用结构:

Plaintext 复制代码
提示词模板(ChatPromptTemplate) → 大模型(LLM) → 结果解析器(OutputParser)

4.1 最简串行链:文本问答

实现功能:传入问题 → 模型回答 → 输出纯文本。

完整代码
Python 复制代码
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

# 1. 定义提示词模板(Runnable 组件)
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是小学老师,用两三句话通俗解释知识点"),
    ("human", "请讲解:{question}"),  # {question} 是占位符,调用时传参
])

# 2. 组装链路:提示词 → 模型 → 文本解析器
chain = prompt | llm | StrOutputParser()

# 3. 调用链:传入字典,key 对应模板占位符
result = chain.invoke({"question": "什么是数独?"})

# 输出结果(纯字符串)
print(result)
print("结果类型:", type(result))
代码解读
  1. ChatPromptTemplate:拼接对话提示词,{question} 是动态占位符;

  2. StrOutputParser:将模型返回的消息对象,转为普通字符串

  3. chain.invoke(字典):字典的键必须和模板占位符一一对应,否则会报错;

  4. 整条链路自动完成「填模板→调模型→转文本」全流程。

4.2 更换解析器:输出 JSON 格式

如果需要结构化数据(字典),只需替换最后一个解析器,链路主体不变。

完整代码
Python 复制代码
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser

# 提示词模板(要求模型输出标准JSON)
prompt = ChatPromptTemplate.from_messages([
    ("system", "只输出JSON,不要多余文字,字段:name(城市名)、population(人口)"),
    ("human", "描述城市:{city}"),
])

# 链路:提示词 → 模型 → JSON解析器
chain = prompt | llm | JsonOutputParser()

# 调用
result = chain.invoke({"city": "北京"})
print(result)
print("结果类型:", type(result))  # <class 'dict'>

4.3 固定模板变量:partial 方法

如果提示词中有固定不变的内容 (如角色、规则),可以用 partial 提前绑定,调用时无需重复传参。

完整代码
Python 复制代码
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是{role},回答简洁明了"),
    ("human", "{question}"),
])

# 提前固定 role=数学老师,后续调用只需要传 question
fixed_prompt = prompt.partial(role="数学老师")

chain = fixed_prompt | llm | StrOutputParser()

# 多次调用,无需再传 role
print(chain.invoke({"question": "什么是余数?"}))
print(chain.invoke({"question": "什么是分数?"}))

4.4 生产级用法:结构化输出(Pydantic)

正式项目中,推荐使用 with_structured_output 替代传统解析器:结合 Pydantic 做强类型校验,自动解析+格式校验,稳定性更高。

完整代码
Python 复制代码
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from pydantic import BaseModel, Field

# 1. 用 Pydantic 定义数据结构(约束字段类型、说明)
class Animal(BaseModel):
    name: str = Field(description="动物名称")
    emoji: str = Field(description="对应表情符号")
    age: int = Field(description="平均寿命")

# 2. 让模型绑定结构化输出(内部自动解析、校验)
structured_llm = llm.with_structured_output(Animal)

# 3. 组装链路(无需额外解析器)
prompt = ChatPromptTemplate.from_messages([
    ("system", "按照要求描述动物"),
    ("human", "介绍一种{type}动物"),
])
chain = prompt | structured_llm

# 调用
result = chain.invoke({"type": "家养宠物"})
print(result.model_dump())  # 转为字典输出

4.5 流式输出:实现聊天打字机效果

聊天界面、实时对话场景必备,使用 chain.stream() 逐块返回内容,模拟逐字输出。

完整代码
Python 复制代码
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是小学老师,通俗讲解知识点"),
    ("human", "讲解:{question}"),
])
chain = prompt | llm | StrOutputParser()

# 流式遍历输出(逐块打印)
print("回答:", end="")
for chunk in chain.stream({"question": "天空为什么是蓝色的?"}):
    print(chunk, end="", flush=True)

4.6 批量处理:batch 批量执行任务

离线场景(批量翻译、批量摘要)使用 chain.batch(),一次性处理多个独立请求。

完整代码
Python 复制代码
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_messages([
    ("system", "用一句话解释知识点"),
    ("human", "{question}"),
])
chain = prompt | llm | StrOutputParser()

# 批量输入:多个独立请求列表
batch_inputs = [
    {"question": "什么是比喻?"},
    {"question": "什么是光合作用?"},
    {"question": "什么是加减法?"},
]

# 批量调用
batch_results = chain.batch(batch_inputs)

# 打印所有结果
for idx, res in enumerate(batch_results, 1):
    print(f"问题{idx}:{batch_inputs[idx-1]['question']}")
    print(f"答案:{res}\n")

4.7 链路复用:封装为通用函数

Chain 本身是可复用组件,可封装成函数,在项目中反复调用。

Python 复制代码
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是{subject}老师,简短回答"),
    ("human", "{question}"),
])
chain = prompt | llm | StrOutputParser()

# 封装函数
def ask_teacher(subject: str, question: str) -> str:
    return chain.invoke({"subject": subject, "question": question})

# 调用
print(ask_teacher("语文", "什么是成语?"))
print(ask_teacher("科学", "水为什么会结冰?"))

五、第二阶段:进阶组件(复杂业务必备)

掌握串行链后,学习 4 个高频进阶组件,解决并行执行、条件判断、数据透传、自定义逻辑四大场景。

5.1 并行执行 RunnableParallel

场景

同一份输入,同时执行多条链路(例如:同一个主题,同时生成笑话+诗歌),多条链路并发运行,最终结果整合为字典。

两种等价写法:

  1. 显式写法:RunnableParallel(键=链路)(推荐新手);

  2. 隐式写法:直接写字典 {"键": 链路},LCEL 自动识别为并行。

完整代码
Python 复制代码
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableParallel

# 定义两条独立子链路
joke_chain = ChatPromptTemplate.from_template("写一个{topic}相关的冷笑话") | llm | StrOutputParser()
poem_chain = ChatPromptTemplate.from_template("写两句{topic}相关的短诗") | llm | StrOutputParser()

# 并行组装:key 为结果标识
parallel_chain = RunnableParallel(
    joke=joke_chain,
    poem=poem_chain
)

# 调用:输入共享给所有子链路
result = parallel_chain.invoke({"topic": "晚霞"})

# 按 key 取结果
print("冷笑话:", result["joke"])
print("短诗:", result["poem"])

5.2 条件分支 RunnableBranch

场景

类似代码中的 if/elif/else:根据输入内容,自动路由到不同链路(例如:用户问笑话走幽默链路,问知识走科普链路)。

语法规则
Python 复制代码
RunnableBranch(
    (条件函数1, 分支链路1),
    (条件函数2, 分支链路2),
    默认链路  # 所有条件都不满足时执行
)
完整代码
Python 复制代码
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableBranch

# 1. 定义条件判断函数
def need_joke(input_dict: dict) -> bool:
    """判断用户是否想要笑话"""
    question = input_dict["question"]
    return any(word in question for word in ["笑话", "搞笑", "段子"])

def need_poem(input_dict: dict) -> bool:
    """判断用户是否想要诗歌"""
    question = input_dict["question"]
    return any(word in question for word in ["诗", "诗歌", "写一首"])

# 2. 定义不同分支的链路
joke_chain = ChatPromptTemplate.from_messages([
    ("system", "你是脱口秀演员,简短讲笑话"),
    ("human", "{question}")
]) | llm | StrOutputParser()

poem_chain = ChatPromptTemplate.from_messages([
    ("system", "你是诗人,写4行以内短诗"),
    ("human", "{question}")
]) | llm | StrOutputParser()

default_chain = ChatPromptTemplate.from_messages([
    ("system", "你是知识助手,通俗解答问题"),
    ("human", "{question}")
]) | llm | StrOutputParser()

# 3. 组装条件分支路由
router = RunnableBranch(
    (need_joke, joke_chain),
    (need_poem, poem_chain),
    default_chain  # 默认分支
)

# 测试不同问题
print(router.invoke({"question": "讲一个程序员的笑话"}))
print(router.invoke({"question": "写一首关于春天的诗"}))
print(router.invoke({"question": "地球是什么形状?"}))

5.3 数据透传 RunnablePassthrough

场景

核心作用:保留原有输入数据,同时追加新字段,是 RAG(检索增强生成)、多链路数据拼接的核心组件。

重点方法:RunnablePassthrough.assign(新字段=链路)

  • 保留原始输入字典;

  • 自动执行指定链路,将结果作为新 key 追加到字典中。

模拟 RAG 场景(检索+问答)
Python 复制代码
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough, RunnableLambda

# 模拟检索器:根据问题返回参考资料(真实项目替换为向量库检索)
mock_retriever = RunnableLambda(lambda x: f"【参考资料】关于{x['question']}的科普内容")

# 组装链路:透传原有问题 + 追加检索结果 → 传入提示词
rag_chain = (
    RunnablePassthrough.assign(docs=mock_retriever)  # 新增字段 docs=检索结果
    | ChatPromptTemplate.from_messages([
        ("system", "根据参考资料回答用户问题:{docs}"),
        ("human", "{question}")
    ])
    | llm
    | StrOutputParser()
)

# 调用:原始输入只有 question,链路自动追加 docs
result = rag_chain.invoke({"question": "数独是什么?"})
print(result)

5.4 自定义逻辑 RunnableLambda

场景

普通 Python 函数转为 Runnable 组件,嵌入链路中,实现数据清洗、格式转换、外部接口调用等自定义逻辑。

完整代码
Python 复制代码
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnableLambda

# 自定义处理函数:加工输入数据
def process_input(input_dict: dict) -> dict:
    new_dict = dict(input_dict)
    # 追加格式化字段
    new_dict["subject_label"] = f"【{new_dict['subject']}】"
    return new_dict

# 链路:自定义函数 → 提示词 → 模型 → 解析器
chain = (
    RunnableLambda(process_input)
    | ChatPromptTemplate.from_messages([
        ("system", "你是{subject_label}老师"),
        ("human", "讲解:{question}")
    ])
    | llm
    | StrOutputParser()
)

# 调用
result = chain.invoke({"subject": "数学", "question": "什么是几何图形?"})
print(result)

六、综合实战:多组件组合案例

真实业务中会嵌套组合多个组件,下面两个案例覆盖主流组合玩法。

案例1:并行生成 + 汇总总结(并行 + 透传 + 串行)

需求:输入一个主题,同时生成笑话和诗歌,再基于两者内容做总结。

Python 复制代码
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

# 子链路
joke_chain = ChatPromptTemplate.from_template("{topic}的冷笑话") | llm | StrOutputParser()
poem_chain = ChatPromptTemplate.from_template("{topic}的两句短诗") | llm | StrOutputParser()

# 第一步:并行生成内容,并透传原始 topic
step1 = RunnablePassthrough.assign(
    joke=joke_chain,
    poem=poem_chain
)

# 第二步:汇总总结
summary_prompt = ChatPromptTemplate.from_messages([
    ("human", "主题:{topic}\n笑话:{joke}\n诗歌:{poem}\n简单总结一下内容")
])

# 完整链路
full_chain = step1 | summary_prompt | llm | StrOutputParser()

# 执行
print(full_chain.invoke({"topic": "大海"}))

案例2:智能路由问答(分支 + 串行)

基于用户输入自动分发到不同人设,前面分支示例已演示,可直接复用扩展。


七、新手高频踩坑&解决方案

整理开发中最常见的报错,按现象分类,快速排错:

报错现象 根因 解决方案
KeyError: xxx 找不到字段 invoke 传入的字典 key 和模板占位符不匹配 核对 {占位符} 和入参字典的键名,保持一致
输出是 AIMessage 对象,不是字符串 链路末尾缺少解析器 追加 StrOutputParser() / JsonOutputParser()
流式输出打印对象而非文本 链路末尾是 LLM,无解析器 链路最后加上解析器;或手动取 chunk.content
并行结果取值为空 并行链路输出是字典,直接打印会报错 必须通过 结果["key"] 取对应分支内容
分支永远走默认链路 条件函数返回值始终为 False 打印输入内容,检查判断逻辑、关键词匹配规则
assign 后模板找不到新字段 assign 定义的字段名 和 模板 {字段} 不一致 统一字段名称

八、知识总结 & 学习路线

8.1 核心语法速查表

功能 写法 适用场景
串行执行 `A B
并行执行 RunnableParallel(k1=A, k2=B) / {k1:A, k2:B} 一输入多输出
条件分支 RunnableBranch((条件,链路), 默认链路) 路由分发、多逻辑分支
数据透传 RunnablePassthrough.assign(k=链路) RAG、追加字段、数据拼接
自定义逻辑 RunnableLambda(函数) 数据预处理、外部调用

8.2 解析器选型建议(生产环境)

  1. 纯文本输出:StrOutputParser()(通用问答);

  2. JSON 字典输出:优先 llm.with_structured_output(Pydantic模型)(强校验),其次 JsonOutputParser

  3. 复杂结构化数据:统一使用 Pydantic + with_structured_output

8.3 新手循序渐进学习路线

  1. 吃透 串行链prompt | llm | 解析器),掌握 invoke/stream/batch/partial

  2. 练习 RunnableLambda 嵌入自定义函数;

  3. 学习 RunnableParallel 并行链路;

  4. 掌握 RunnablePassthrough.assign(为 RAG 打基础);

  5. 最后学习 RunnableBranch 条件分支;

  6. 组合多个组件,开发综合业务链路。


九、附录:最小可运行完整代码

新建 demo.py,搭配 base_config.py.env 文件,直接运行验证环境:

Python 复制代码
# demo.py
from base_config import llm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

# 基础问答链
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是小学老师,简短回答问题"),
    ("human", "{question}")
])

chain = prompt | llm | StrOutputParser()

# 调用
res = chain.invoke({"question": "什么是人工智能?"})
print(res)
相关推荐
颜酱4 小时前
LangChain调用向量模型,存入向量数据库
python·langchain
wuhen_n5 小时前
RAG 核心:向量嵌入与本地向量数据库实战
前端·langchain·ai编程
冷小鱼5 小时前
LangChain 系统性科普:从入门到架构设计
langchain
wuhen_n5 小时前
RAG 关键环节:文本分块策略与最优参数配置
前端·langchain·ai编程
矩阵科学10 小时前
Langchain.js 实战四:工具的使用
langchain·node.js
P-ShineBeam11 小时前
智能体-LangChain框架-Tools工具的使用指南
数据库·人工智能·语言模型·自然语言处理·langchain
易小染1 天前
AI-Agent学习-LangChain-01
学习·langchain
颜酱1 天前
LangChain 输出解析器:把模型回复变成你要的数据
python·langchain
code bean1 天前
【LangChain】 文本分割器全景指南:从 RecursiveCharacterTextSplitter 到各类分割器对比
人工智能·自然语言处理·langchain