LCEL 的全称是 LangChain Expression Language,翻译过来就是 LangChain 表达式语言。
简单说,LCEL 是 LangChain 提供的一种声明式语言,专门用来把多个组件串成一条链。你之前问的那行代码里的 | (管道符),就是它最核心的语法。
为什么需要 LCEL?
在没有 LCEL 之前,要用 LangChain 搭一条链,通常得这么写:
# 传统写法 (SequentialChain 等)
chain = SequentialChain(
chains=[prompt_chain, llm_chain, parser_chain],
input_variables=["input"],
output_variables=["result"]
)
这种写法有几个痛点:
- 不直观:非得套一层
SequentialChain,没法一眼看出数据是怎么流的。 - 难组合:想在中间加个处理步骤,得改一大片代码。
- 功能受限:想用异步、流式、批量处理,得自己写一大堆代码。
而用 LCEL,只需要:
chain = prompt | llm | parser
数据流向一目了然,从左到右,清晰无比。
LCEL 的核心玩法就是 | 管道符
这个 | 是 LangChain 重载过的,它的作用就一个:把前一个组件的输出,传给下一个组件当输入。
chain = component_1 | component_2 | component_3
执行的时候等价于:
output_1 = component_1.invoke(input)
output_2 = component_2.invoke(output_1)
result = component_3.invoke(output_2)
所有实现了 Runnable 协议的对象(比如 ChatPromptTemplate、ChatOpenAI、各种 Parser)都能用 | 自由连接。
LCEL 带来的四大好处
- 天然支持异步:不用你额外写代码,直接就有
chain.ainvoke()、chain.astream()可以用。 - 天然支持流式:同样,
chain.stream()开箱即用。 - 天然支持批量:
chain.batch()自动并行处理多个输入。 - 可观测性一流:所有 LCEL 链都能无缝接入 LangSmith 做调试和追踪。
举个例子,对比一下
假设你要搭一个“生成冷笑话并翻译成中文”的链。
不用 LCEL:
from langchain.chains import LLMChain, TransformChain, SequentialChain
# 得显式定义每一步的 Chain
generate_chain = LLMChain(prompt=...)
translate_chain = LLMChain(prompt=...)
chain = SequentialChain(chains=[generate_chain, translate_chain], ...)
用 LCEL:
generate_prompt = ChatPromptTemplate.from_template("讲一个关于{topic}的冷笑话")
translate_prompt = ChatPromptTemplate.from_template("把下面内容翻译成中文:\n{text}")
chain = (
generate_prompt | llm | StrOutputParser() |
(lambda joke: {"text": joke}) | translate_prompt | llm | StrOutputParser()
)
总结一下,LCEL 就是 LangChain 的“官方流水线语法”,核心就是 | 管道符,让你可以像搭乐高一样把各个组件拼起来,代码简洁、功能强大、维护方便。