LCEL(LangChain Expression Language)语法全解

LCEL(LangChain Expression Language)语法全解

LCEL 是 LangChain 推出的声明式链式编排语法 ,基于统一的 Runnable 接口标准,通过管道符 | 拼接提示词、大模型、输出解析器、工具等组件,构建完整的大模型应用链路。它替代了早期 LLMChainSequentialChain 等面向对象的繁琐写法,是当前 LangChain 构建应用的官方标准范式。

一、核心底层原理

  1. 统一 Runnable 接口
    LangChain 中所有可执行组件(提示词、模型、解析器、工具、自定义函数)都实现了 Runnable 基类,拥有完全一致的调用规范,这是组件可以自由拼接的底层基础。
  2. 管道符 | 语法糖
    它本质是对 Python __or__ 方法的重载,作用是将左侧组件的输出,自动作为右侧组件的输入,和 Unix Shell 的管道逻辑完全一致,数据流严格从左向右流动。

二、基础语法:标准三段式链路

最经典、最常用的 LCEL 结构是「提示词模板 → 大模型 → 输出解析器」,对应「填模板→调用模型→解析结果」的标准流程。

python 复制代码
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI

# 1. 定义单个组件
prompt = ChatPromptTemplate.from_template("请用通俗语言解释{concept},不超过100字")
model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
parser = StrOutputParser()

# 2. LCEL 管道拼接成链
chain = prompt | model | parser

# 3. 统一调用
result = chain.invoke({"concept": "LCEL"})
print(result)

执行逻辑:

  1. 输入字典 {"concept": "LCEL"} 传入提示词模板,填充变量生成完整 Prompt
  2. 填充后的 Prompt 自动传入大模型,生成 AI 消息对象
  3. 消息对象传入字符串解析器,提取纯文本内容作为最终结果

三、统一调用方法

所有 LCEL 链都共享同一套调用接口,无需针对不同组件修改写法:

调用方法 说明 适用场景
.invoke(input) 同步单次调用,阻塞等待完整结果 常规问答、短文本生成
.stream(input) 流式逐块返回结果,无需等待全文 聊天界面、长文本生成
.batch([input1, input2]) 批量并发处理多个输入 批量数据处理、批量生成
.ainvoke(input) 异步单次调用 高并发 Web 服务
.astream(input) 异步流式调用 异步聊天接口

四、常用基础组件

1. 输入透传:RunnablePassthrough

原样保留输入内容,常用于并行链路中传递原始参数,是 RAG 等场景的必备组件。

python 复制代码
from langchain_core.runnables import RunnablePassthrough

# 原始输入会被原样透传
chain = RunnablePassthrough() | (lambda x: f"收到:{x}")
print(chain.invoke("你好"))
# 输出:收到:你好
2. 自定义逻辑:RunnableLambda

将普通 Python 函数包装为 Runnable 组件,无缝接入管道,实现自定义数据清洗、格式转换等逻辑。

python 复制代码
from langchain_core.runnables import RunnableLambda

def clean_text(text):
    return text.strip().replace("\n", "")

# 自定义清洗 → 提示词 → 模型 → 解析器
chain = RunnableLambda(clean_text) | prompt | model | parser
3. 结构化输出解析

将模型输出转为结构化数据,三类最常用的解析器:

  • StrOutputParser:提取模型输出的纯文本,日常开发最常用
  • JsonOutputParser:将模型输出解析为字典/JSON 格式
  • PydanticOutputParser:强制输出符合 Pydantic 定义的数据结构

五、进阶编排语法

1. 并行执行:RunnableParallel

同时运行多个独立子链路,最终将所有分支结果合并为字典返回,常用于 RAG、多维度分析场景。支持两种写法,字典简写更常用:

python 复制代码
# 写法1:字典简写(LCEL 会自动转为 RunnableParallel)
parallel_chain = {
    "双倍": lambda x: x["num"] * 2,
    "加十": lambda x: x["num"] + 10
}

print(parallel_chain.invoke({"num": 5}))
# 输出: {'双倍': 10, '加十': 15}

典型 RAG 场景用法

python 复制代码
# 检索分支 + 原始问题透传,两路结果一同传给提示词
rag_chain = {
    "context": retriever,       # 分支1:检索知识库返回上下文
    "question": RunnablePassthrough()  # 分支2:保留原始用户问题
} | prompt | model | parser
2. 条件分支:RunnableBranch

根据输入内容动态选择执行链路,实现路由逻辑,类似代码里的 if-elif-else 结构。

python 复制代码
from langchain_core.runnables import RunnableBranch

route_chain = RunnableBranch(
    (lambda x: x["type"] == "数学", lambda x: f"数学题:{x['question']}"),
    (lambda x: x["type"] == "语文", lambda x: f"语文题:{x['question']}"),
    lambda x: f"通用问题:{x['question']}"  # 默认兜底分支
)
3. 容错降级:with_fallbacks

给主链路添加备用方案,主链路调用失败时自动切换到备用链路,是生产环境提升稳定性的标准手段。

python 复制代码
main_model = ChatOpenAI(model="gpt-4")
backup_model = ChatOpenAI(model="gpt-3.5-turbo")

# 主模型调用失败时,自动走备用模型
reliable_chain = prompt | main_model.with_fallbacks([backup_model]) | parser
4. 工具调用绑定

通过 bind_tools 将工具函数绑定到模型,让模型可以自主判断是否调用工具、生成调用参数。

python 复制代码
from langchain_core.tools import tool

@tool
def get_weather(city: str) -> str:
    """查询指定城市的实时天气"""
    return f"{city}今日晴,气温25℃"

# 绑定工具到模型
model_with_tools = model.bind_tools([get_weather])

# 接入管道
tool_chain = prompt | model_with_tools

六、核心优势总结

  1. 声明式、可读性强:代码即数据流,从左到右一目了然,比嵌套类写法更易维护
  2. 组件高度解耦:所有组件遵循统一标准,可自由替换、组合,无需修改链路代码
  3. 原生工程能力:零额外开发,天然支持流式、批量、异步、容错降级
  4. 可观测性友好:无缝对接 LangSmith 调试平台,自动追踪每一步执行状态
  5. 生产级适配:可直接通过 LangServe 部署为 API 接口,快速落地
python 复制代码
import os
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough, RunnableLambda
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_text_splitters import RecursiveCharacterTextSplitter

# ===================== 1. 基础配置 =====================
# 替换为自己的 API Key;兼容所有 OpenAI 协议的模型
os.environ["OPENAI_API_KEY"] = "sk-你的API密钥"
# 如需使用本地/第三方兼容模型,可配置代理地址
# os.environ["OPENAI_BASE_URL"] = "https://你的接口地址/v1"

# ===================== 2. 准备知识库文档 =====================
# 模拟业务知识库,可替换为 PDF/Word/网页等读取的文本内容
raw_knowledge = """
MLCC(片式多层陶瓷电容器)是被动元件的核心品类,被称为"电子大米",核心作用是稳压、滤波、储能,广泛应用于消费电子、汽车电子、AI服务器等领域。
MLCC的核心上游材料是陶瓷粉体、金属内电极浆料,国内主流厂商包括风华高科、三环集团、火炬电子等。

PCB(印制电路板)是电子元器件的承载基板,负责电气连接,是所有电子设备的基础部件,被称为"电子系统之母"。
PCB按层数可分为单面板、双面板、多层板,高阶HDI、封装载板是当前高端PCB的核心方向,国内主流厂商包括沪电股份、深南电路、鹏鼎控股。

CPO(共封装光学)是一种光封装技术,将光引擎与交换芯片共同封装在同一块基板上,可大幅降低功耗、提升传输密度,是AI高速互联的核心技术路线。
CPO产业链中,PCB作为高速承载基板,规格要求显著升级;MLCC作为电源滤波元件,单机用量随功耗提升而增加。
"""

# 文档切片:将长文本切分为适合检索的小块
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=200,       # 单块最大字符数
    chunk_overlap=30,     # 块间重叠字符数,避免语义断裂
    separators=["\n\n", "\n", "。", " "]  # 优先按语义分割
)
doc_splits = text_splitter.create_documents([raw_knowledge])

# ===================== 3. 构建向量库与检索器 =====================
# 使用 Chroma 内存向量库,无需额外安装数据库;如需持久化可加 persist_directory 参数
vectorstore = Chroma.from_documents(
    documents=doc_splits,
    embedding=OpenAIEmbeddings(model="text-embedding-3-small")
)

# 创建检索器,召回最相关的 Top 3 文档片段
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

# 工具函数:将检索到的文档对象拼接为纯文本,供大模型读取
def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

# ===================== 4. 定义提示词与模型组件 =====================
# RAG 专用提示词模板,强制基于上下文回答,抑制幻觉
rag_prompt = ChatPromptTemplate.from_template("""
你是专业的电子行业知识库助手,仅可基于下方提供的上下文回答问题。
如果上下文中没有对应答案,请直接回答「知识库中暂无相关信息」,禁止编造内容。

【参考上下文】
{context}

【用户问题】
{question}

【正式回答】
""")

# 初始化大模型与输出解析器
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
output_parser = StrOutputParser()

# ===================== 5. 核心:LCEL 搭建 RAG 链路 =====================
rag_chain = (
    # 并行执行两路分支,最终合并为字典传入提示词
    {
        "context": retriever | RunnableLambda(format_docs),  # 分支1:检索+格式化上下文
        "question": RunnablePassthrough()                    # 分支2:原样透传用户原始问题
    }
    | rag_prompt    # 填充提示词模板
    | llm           # 调用大模型生成答案
    | output_parser # 提取纯文本结果
)

# ===================== 6. 调用测试 =====================
if __name__ == "__main__":
    # 方式1:同步阻塞调用,一次性返回完整结果
    question_1 = "MLCC和PCB在CPO产业链中分别有什么作用?"
    result = rag_chain.invoke(question_1)
    print("=== 同步调用结果 ===")
    print(result)
    print("\n" + "-"*60 + "\n")

    # 方式2:流式调用,逐字返回,适配聊天界面场景
    question_2 = "国内MLCC的主流厂商有哪些?"
    print("=== 流式调用结果 ===")
    for chunk in rag_chain.stream(question_2):
        print(chunk, end="", flush=True)
相关推荐
DreamLife☼1 小时前
OpenBCI-可穿戴脑电设备设计与优化
网络·开源硬件·脑机接口·cca·ssvep·openbci·视觉刺激
ctrl_v助手1 小时前
VisionPro (R) QuickBuild相机的连接
服务器·笔记·数码相机·c#
酣大智1 小时前
RIP路由协议
网络·路由器·路由·rip
沪漂阿龙1 小时前
Context Engineering:比 Prompt Engineering 更重要的上下文工程
人工智能·langchain·prompt
rcms152702692181 小时前
ADAS STB282 工业专用总线板卡
网络
沪漂阿龙1 小时前
《LangChain 系列》用 LangGraph 搭建智能客服 Agent
人工智能·架构·langchain
by————组态2 小时前
Ricon组态技术架构 - 企业级Web组态解决方案
运维·服务器·前端·物联网·架构·组态·组态软件
zbtlink2 小时前
Mesh组网:真需求还是被制造的需求?
网络·智能路由器
CHINA红旗下2 小时前
固定虚拟机的IP地址
运维·服务器·网络