⛓️ LangChain 表达式语言(LCEL)入门与实战:从 Prompt 到复杂多链的声明式编程
一、本章概览
第20章《LangChain 表达式语言(LCEL)入门与实战》是课程中聚焦 LangChain 核心编程范式的关键章节——全面介绍 LCEL(LangChain Expression Language)这一声明式的链式组合语言,从设计理念、Runnable 协议、基础用法,到与传统调用方式的对比、批量处理、流式输出、异步调用、回退机制,再到复杂多链(AI 辩论链)的实战构建。
核心内容速览:
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
二、LangChain 技术生态全景
在深入 LCEL 之前,先了解 LangChain 的完整生态体系:
LangChain 技术生态
├── LangChain ───────── LLMs 应用开发框架(Python / JavaScript)
├── LangChain-Core ──── LCEL 等核心协议(基础抽象层)
├── LangChain-Community ── 第三方集成(模型、向量库、工具等)
├── LangChain Templates ── 开箱即用的 APP 示例模板
├── LangServe ────────── Chains 生产部署(REST API)
└── LangSmith ────────── 一站式开发者平台
├── 可观测性(Observability)
├── 监控(Monitoring)
├── 反馈(Feedback)
├── 评估(Evaluation)
├── 标注(Annotation)
└── 测试(Testing)
★LCEL 位于 LangChain-Core 层,是整个生态的协议基石,为所有组件提供了统一的组合与调用接口。
三、LCEL 是什么?
3.1 基本定义
LCEL(LangChain Expression Language) 是一种声明式的链式组合语言,能够从简单的 Prompt + LLM 链到复杂的生产级链(可运行 100 多个步骤)统一表达。
★LCEL 的设计初衷是支持将原型快速投入生产,而无需更改代码。
3.2 核心设计理念
竖线管道操作符 |:
LCEL 的核心是 | 操作符,类似于 Unix 管道,它将不同组件链接在一起,将一个组件的输出作为下一个组件的输入。
Prompt Template → Model → Output Parser
| | |
生成输入 LLM调用 解析输出
标准化的大模型抽象 Model I/O:
输入: X = "foo", y = "bar"
↓
Prompt Template: "Does {x} like {y}, and why?"
↓
Chat Model / LLM
↓
Output Parser: {"likes": True, "reason": "Because ..."}
3.3 核心组件模块
|
|
|
|---|---|
| Model I/O |
|
| Retrieval |
|
| Agents |
|
四、LCEL Runnable 协议
4.1 Runnable 接口
LangChain 实现了 Runnable 协议来简化创建自定义链的过程。许多 LangChain 组件都实现了 Runnable 协议,包括:
-
Chat Models -
LLMs -
Output Parsers -
Retrievers -
Prompt Templates
4.2 组件的输入/输出类型
|
|
|
|
|---|---|---|
| Prompt |
|
|
| ChatModel |
|
|
| LLM |
|
|
| OutputParser |
|
|
| Retriever |
|
|
| Tool |
|
|
4.3 Schema 方法
所有 Runnable 对象都显式描述输入和输出 Schema:
# 查看 chain 的输入类型
chain.input_schema.schema()
# 输出:{'title': 'PromptInput', 'type': 'object',
# 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}}
# 查看 Prompt 的输入类型
prompt.input_schema.schema()
# 输出:同上(Chain 的输入从 Prompt 开始)
4.4 Runnable 核心方法
|
|
|
|
|---|---|---|
| invoke |
|
|
| stream |
|
|
| batch |
|
|
| ainvoke |
|
|
| astream |
|
|
| abatch |
|
|
五、基础代码示例:最简 LCEL 链
5.1 最简单的 LCEL 链
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
# 初始化 ChatOpenAI 模型
model = ChatOpenAI(model="gpt-3.5-turbo-0125")
# 创建聊天提示模板
prompt = ChatPromptTemplate.from_template("讲个关于{topic}的笑话吧")
# 初始化输出解析器
output_parser = StrOutputParser()
# 构建处理链(使用 | 管道操作符)
chain = prompt | model | output_parser
# 调用链
result = chain.invoke({"topic": "程序员"})
print(result)
# 输出:'为什么程序员总是喜欢用"Ctrl+C"和"Ctrl+V"呢?\n\n因为他们喜欢复制粘贴!!'
★🔑 核心语法:
chain = prompt | model | output_parser,一行代码完成链式构建!
六、LCEL vs 古典语法:7大场景对比
6.1 简单调用
|
|
|
|
|---|---|---|
|
|
|
~5行 |
|
|
|
prompt | model | output_parser |
Without LCEL:
prompt_template = "Tell me a short joke about {topic}"
client = openai.OpenAI()
def call_chat_model(messages: List[dict]) -> str:
response = client.chat.completions.create(
model="gpt-3.5-turbo", messages=messages,
)
return response.choices[0].message.content
def invoke_chain(topic: str) -> str:
prompt_value = prompt_template.format(topic=topic)
messages = [{"role": "user", "content": prompt_value}]
return call_chat_model(messages)
invoke_chain("ice cream")
With LCEL:
chain = ({"topic": RunnablePassthrough()} | prompt | model | output_parser)
chain.invoke("ice cream")
6.2 流式输出
|
|
|
|
|---|---|---|
|
|
|
1行 |
|
|
|
chain.stream() |
With LCEL 只需一行:
for chunk in chain.stream("ice cream"):
print(chunk, end="", flush=True)
6.3 批量并行处理
|
|
|
|
|---|---|---|
|
|
|
1行 |
|
|
|
chain.batch() |
With LCEL 只需一行:
chain.batch(["ice cream", "spaghetti", "dumplings"])
6.4 异步调用
|
|
|
|
|---|---|---|
|
|
|
1行 |
|
|
|
chain.ainvoke() |
With LCEL 只需一行:
await chain.ainvoke("ice cream")
6.5 更换模型提供商(OpenAI → Anthropic)
|
|
|
|
|---|---|---|
|
|
|
~3行 |
|
|
|
|
With LCEL:
from langchain_anthropic import ChatAnthropic
anthropic = ChatAnthropic(model="claude-2")
anthropic_chain = (
{"topic": RunnablePassthrough()} | prompt | anthropic | output_parser
)
anthropic_chain.invoke("ice cream")
6.6 回退机制(Fallbacks)
|
|
|
|
|---|---|---|
|
|
|
1行 |
|
|
|
chain.with_fallbacks() |
With LCEL 只需几行:
fallback_chain = chain.with_fallbacks([anthropic_chain])
fallback_chain.invoke("ice cream") # 同步
await fallback_chain.ainvoke("ice cream") # 异步
fallback_chain.batch([...]) # 批量
6.7 使用 LLM 替代 Chat Model
from langchain_openai import OpenAI
# 使用 Completion 端点
llm = OpenAI(model="gpt-3.5-turbo-instruct")
llm_chain = ({"topic": RunnablePassthrough()} | prompt | llm | output_parser)
llm_chain.invoke("ice cream")
七、LCEL 进阶:AI 辩论链(多链组合)
7.1 辩论链结构
输入话题 → 原始观点 → 正面论述 → 反面论述 → 最终总结
7.2 完整代码实现
from operator import itemgetter
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.runnables import RunnablePassthrough
# 1️⃣ 计划器:生成关于给定输入的论点
planner = (
ChatPromptTemplate.from_template("生成关于以下内容的论点:{input}")
| ChatOpenAI()
| StrOutputParser()
| {"base_response": RunnablePassthrough()}
)
# 2️⃣ 正面论证:列出关于基础回应的正面方面
arguments_for = (
ChatPromptTemplate.from_template(
"列出关于{base_response}的正面或有利的方面"
)
| ChatOpenAI()
| StrOutputParser()
)
# 3️⃣ 反面论证:列出关于基础回应的反面方面
arguments_against = (
ChatPromptTemplate.from_template(
"列出关于{base_response}的反面或不利的方面"
)
| ChatOpenAI()
| StrOutputParser()
)
# 4️⃣ 最终响应者:综合原始回应和正反论点生成最终回应
final_responder = (
ChatPromptTemplate.from_messages([
("ai", "{original_response}"),
("human", "正面观点:\n{results_1}\n\n反面观点:\n{results_2}"),
("system", "给出批评后生成最终回应"),
])
| ChatOpenAI()
| StrOutputParser()
)
# 5️⃣ 构建完整处理链
chain = (
planner
| {
"results_1": arguments_for,
"results_2": arguments_against,
"original_response": itemgetter("base_response"),
}
| final_responder
)
# 调用辩论链
chain.invoke({"input": "房地产低迷"})
7.3 输出示例
★在面对房地产低迷的情况下,需要综合考虑正面和反面观点,以找到平衡和解决问题的方法。同时,房地产市场的低迷也可能为购房者提供更好的机会,并寻求合适的解决方案,以实现经济的平稳发展和社会的和谐进步。
八、LCEL 核心优势总结
|
|
|
|---|---|
|
|
|
|
|
| 管道符,代码简洁优雅
|
|
|
chain.batch()
|
|
|
chain.stream()
|
|
|
chain.ainvoke()
|
|
|
chain.with_fallbacks()
|
|
|
|
|
|
|
|
|
|
|
|
|
📌 本章核心要点总结
|
|
|
|
|---|---|---|
|
|
LCEL 是什么 |
| 管道符连接组件,原型到生产零改代码
|
|
|
LangChain 生态全景 |
|
|
|
Runnable 协议 |
|
|
|
invoke / stream / batch |
|
|
|
LCEL vs 古典语法 |
|
|
|
回退机制(Fallbacks) | chain.with_fallbacks()
|
|
|
模型无关性 |
prompt | model | parser 结构,更换模型只需替换 Model 组件
|
|
|
Schema 校验 | input_schema
output_schema 自动生成,Pydantic 模型校验输入输出
|
|
|
AI 辩论链 |
|
|
|
生产级特性 |
|
★📚 下一章预告:第21章——生产级大模型应用开发平台 LangSmith,敬请期待!🚀
本课程系列文章持续更新中,欢迎关注!
本文整理自《AI 大模型应用开发实战营》第20章,讲师:彭靖田

