Appearance
24. LangChain 的链式调用(Chain)和 LCEL 是什么关系?
难度 P1 高频 · 岗位 应用 · 频率 ★★★ · 预计阅读 6 min
本题阅读地图
- 💡 简要回答
- 📝 详细解析
- 🎯 面试总结
👔面试官:LangChain 的链式调用(Chain)和 LCEL 是什么关系?
🙋♂️我:LCEL 是新的写法,Chain 是老的写法。
👔面试官:对,但还有更本质的区别:LCEL 是声明式编程,用 | 管道符组合组件;老 Chain 是继承基类、重写方法。你能讲清楚 LCEL 的优势吗?
🙋♂️我:LCEL 写起来更简洁?
👔面试官:对,但还有:可组合性强、支持异步流式、类型提示友好。而且 LCEL 可以和 LangGraph 无缝衔接。你能系统讲吗?
💡 简要回答
关系:LCEL(LangChain Expression Language)是 LangChain v0.1+ 推出的声明式链式编程范式,是老 Chain API 的现代化替代。
| 对比项 | 老 Chain API | LCEL |
|---|---|---|
| 编程方式 | 继承基类、重写方法 | 管道符 | 组合 |
| 可读性 | 需要看类定义 | 一眼看清数据流 |
| 可组合性 | 弱 | 强,组件可任意拼接 |
| 异步/流式 | 支持有限 | 原生支持 |
| 类型提示 | 弱 | 强 |
核心优势:声明式、可组合、与 LangGraph 无缝衔接。
📝 详细解析
老 Chain API 的问题
python
from langchain.chains import LLMChain
# 需要继承、配置、绑定
chain = LLMChain(llm=llm, prompt=prompt)
result = chain.run(input="...")痛点:
- 复杂链需要继承
Chain基类 - 逻辑分散在类定义里
- 难以组合和复用
LCEL 的声明式写法
python
from langchain_core.runnables import RunnablePassthrough
chain = (
RunnablePassthrough.assign(context=lambda x: retriever.get_relevant_documents(x["question"]))
| prompt
| llm
| parser
)
result = chain.invoke({"question": "..."})优势:
- 数据流清晰:从左到右,一眼看清
- 可组合:任意组件用
|连接 - 延迟执行:定义时不执行,invoke 时才运行
LCEL 的核心特性
Runnable 协议: 所有组件都实现 Runnable 接口,支持:
invoke():同步调用ainvoke():异步调用stream():流式输出batch():批量处理
内置组件:
RunnablePassthrough:透传/变换输入RunnableParallel:并行执行多个分支RunnableLambda:包装自定义函数RunnableBranch:条件分支
与 LangGraph 衔接
LCEL 链可以直接作为 LangGraph 的节点:
python
from langgraph.graph import StateGraph
# LCEL 链作为节点
workflow = StateGraph(State)
workflow.add_node("retrieve", retrieval_chain)
workflow.add_node("generate", generation_chain)🎯 面试总结
LCEL 是声明式、管道式的链式编程,比老 Chain API 更简洁、可组合、类型友好。与 LangGraph 无缝衔接。