AI大模型工程师-应用篇 系列目录:
├── LangChain
│ ├── 提示词模板、对话管理与结构化输出核心用法
│ ├── LCEL 表达式语法(本文)
│ └── 多模态聊天机器人实战
├── Embedding
│ └── Embedding 与向量数据库简单应用------从文本向量化到 RAG 检索增强生成
├── LangGraph
│ └── 工作流与 Agent 开发(即将发布)
└── MCP
└── 协议与 Agent 通信实战(即将发布)
本文旨在从基础语法出发,系统介绍 LangChain 中 LCEL(LangChain Expression Language)表达式的核心用法,涵盖组件封装、链式调用、并行执行、数据透传、Fallback 与 Retry、动态路由等关键能力,帮助开发者快速掌握 LCEL 的编排思想,构建灵活、可靠的 AI 应用链路。
文章目录
- 环境准备
- [一、什么是 LCEL?](#一、什么是 LCEL?)
- [二、Runnable------LCEL 的基本构建单元](#二、Runnable——LCEL 的基本构建单元)
-
- [2.1 RunnableLambda:将函数封装为节点](#2.1 RunnableLambda:将函数封装为节点)
- [2.2 三种调用方式:invoke / batch / stream](#2.2 三种调用方式:invoke / batch / stream)
- 三、链的组合------串行与并行
-
- [3.1 串行链:管道操作符 `|`](#3.1 串行链:管道操作符
|) - [3.2 并行链:RunnableParallel](#3.2 并行链:RunnableParallel)
- [3.3 串行 + 并行:自由嵌套](#3.3 串行 + 并行:自由嵌套)
- [3.1 串行链:管道操作符 `|`](#3.1 串行链:管道操作符
- 四、数据透传与中间处理------RunnablePassthrough
-
- [4.1 原样透传](#4.1 原样透传)
- [4.2 assign:透传的同时追加新字段](#4.2 assign:透传的同时追加新字段)
- [4.3 pick:从字典中筛选指定字段](#4.3 pick:从字典中筛选指定字段)
- [4.4 实战场景:在 RAG 中透传用户问题](#4.4 实战场景:在 RAG 中透传用户问题)
- [五、Fallback 与 Retry------链路的异常恢复策略](#五、Fallback 与 Retry——链路的异常恢复策略)
-
- [5.1 with_fallbacks:降级回退](#5.1 with_fallbacks:降级回退)
- [5.2 with_retry:自动重试](#5.2 with_retry:自动重试)
- 六、动态路由------条件分支链
-
- [6.1 基于 RunnableLambda 的简单条件分支](#6.1 基于 RunnableLambda 的简单条件分支)
- [6.2 基于 RouterRunnable 的多路由调度](#6.2 基于 RouterRunnable 的多路由调度)
- 七、生命周期管理------with_listeners
- 八、实战案例
-
- [8.1 案例一:多阶段链式调用------生成 + 审核](#8.1 案例一:多阶段链式调用——生成 + 审核)
- [8.2 案例二:多阶段提示词编排------旅行规划](#8.2 案例二:多阶段提示词编排——旅行规划)
- [8.3 案例三:带上下文记忆的对话链](#8.3 案例三:带上下文记忆的对话链)
- [九、总结:LCEL 核心组件速查表](#九、总结:LCEL 核心组件速查表)
- 写在最后
环境准备
本文使用 uv 作为 Python 包管理工具。将以下内容保存为项目根目录下的 pyproject.toml 文件,然后在终端执行 uv sync,即可自动创建虚拟环境并安装所有依赖:
toml
[project]
name = "lcel-expression-demo"
version = "0.1.0"
description = "LangChain LCEL 表达式语法核心用法"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"dotenv>=0.9.9",
"langchain>=1.2.10",
"langchain-community>=0.4.1",
"langchain-openai>=1.1.10",
"openai>=2.24.0",
]
一、什么是 LCEL?
LCEL(LangChain Expression Language)是 LangChain 提供的一套声明式链路编排语法 。它的核心思想是:将提示词模板、大模型、输出解析器、自定义函数等组件视为可组合的节点(Runnable) ,通过管道操作符 | 将它们串联成一条完整的处理链。
下面是一个最简单的 LCEL 链路示例:
python
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from models import llm
parser = StrOutputParser()
prompt = ChatPromptTemplate.from_messages([
('system', '你是一个专业的技术顾问'),
('human', '{input}')
])
# LCEL 表达式:用 | 将组件串联
chain = prompt | llm | parser
result = chain.invoke({'input': '用一句话解释什么是微服务架构'})
print(result)
核心价值:
- 声明式:只需描述"数据流经哪些节点",无需手动编排调用顺序。
- 统一接口 :所有节点都实现
Runnable协议,支持invoke、batch、stream等统一调用方式。 - 可组合:链与链之间可以自由嵌套、并行和路由,构建出任意复杂度的工作流。
二、Runnable------LCEL 的基本构建单元
在 LCEL 中,一切皆 Runnable。提示词模板、LLM、解析器本身已经是 Runnable,而普通的 Python 函数则需要通过 RunnableLambda 包装后才能接入链路。
2.1 RunnableLambda:将函数封装为节点
核心技术 :RunnableLambda 可以将任意 Python 函数封装为一个标准的 Runnable 组件,使其具备 invoke、batch、stream 等能力。
python
from langchain_core.runnables import RunnableLambda
def add_ten(x: int):
return x + 10
# 将普通函数封装为 Runnable 节点
r1 = RunnableLambda(add_ten)
result = r1.invoke(4)
print(result) # 14
2.2 三种调用方式:invoke / batch / stream
每个 Runnable 节点都原生支持以下三种调用模式:
| 方法 | 说明 | 返回值 |
|---|---|---|
invoke(input) |
单次调用 | 单个结果 |
batch([input1, input2, ...]) |
批量调用 | 结果列表 |
stream(input) |
流式调用 | 生成器(逐块返回) |
python
# 1. 单次调用
r1.invoke(4) # 14
# 2. 批量调用:对多个输入并行处理
r1.batch([4, 5]) # [14, 15]
# 3. 流式调用:适合处理大段文本的逐步输出
def tokenize(prompt: str):
for item in prompt.split(' '):
yield item
r2 = RunnableLambda(tokenize)
for chunk in r2.stream('This is a Dog.'):
print(chunk)
# 输出:This / is / a / Dog.
原理解析:
batch本质是对多个输入并发执行invoke,无需手动编写循环。stream要求被封装的函数是一个生成器函数 (使用yield),返回的是一个可迭代对象,调用方可逐块接收结果,适用于大模型的流式输出场景。
三、链的组合------串行与并行
3.1 串行链:管道操作符 |
使用 | 操作符可以将多个 Runnable 节点按顺序串联。前一个节点的输出会自动作为下一个节点的输入。
python
from langchain_core.runnables import RunnableLambda
r1 = RunnableLambda(lambda x: x + 10)
r2 = RunnableLambda(lambda x: x * 2)
# 串行链:先 +10,再 ×2
chain = r1 | r2
print(chain.invoke(2)) # (2 + 10) * 2 = 24
3.2 并行链:RunnableParallel
当需要对同一个输入同时执行多个独立操作 时,使用 RunnableParallel。
python
from langchain_core.runnables import RunnableLambda, RunnableParallel
r1 = RunnableLambda(lambda x: x + 10)
r2 = RunnableLambda(lambda x: x * 2)
# 并行链:对同一个输入同时执行 r1 和 r2
chain = RunnableParallel(add_result=r1, mul_result=r2)
print(chain.invoke(2))
# {'add_result': 12, 'mul_result': 4}
关键要点:
RunnableParallel的关键字参数名(如add_result、mul_result)就是输出字典的 key。- 可通过
config={'max_concurrency': N}控制最大并发数。
3.3 串行 + 并行:自由嵌套
串行链和并行链可以自由组合。例如,先串行处理,再对结果并行分叉:
python
chain1 = r1 | r2 # 串行:先 +10 再 ×2
chain2 = RunnableParallel(branch_a=r1, branch_b=r2) # 并行
combined = chain1 | chain2 # 先串行,再并行
print(combined.invoke(2))
# chain1 输出 24 → chain2 对 24 同时执行 r1 和 r2
# {'branch_a': 34, 'branch_b': 48}
可以调用
chain.get_graph().print_ascii()打印链的拓扑结构图,直观地查看数据流向。
四、数据透传与中间处理------RunnablePassthrough
在复杂链路中,经常需要将原始输入或中间数据"透传"给后续节点,同时可能需要对其进行补充或筛选。RunnablePassthrough 正是为此设计的。
4.1 原样透传
RunnablePassthrough() 不做任何修改,直接将上游数据传递给下游。
python
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
r1 = RunnableLambda(lambda x: {'key1': x})
# RunnablePassthrough() 原样透传,不做任何修改
chain = r1 | RunnablePassthrough()
print(chain.invoke(2)) # {'key1': 2}
4.2 assign:透传的同时追加新字段
.assign() 可以在透传原始数据的同时,额外计算并追加一个新字段到输出字典中。
python
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
r1 = RunnableLambda(lambda x: {'key1': x})
r2 = RunnableLambda(lambda x: x['key1'] + 10)
# 透传 r1 的输出,同时追加一个 new_key 字段(值由 r2 计算)
chain = r1 | RunnablePassthrough.assign(new_key=r2)
print(chain.invoke(2))
# {'key1': 2, 'new_key': 12}
数据流分析:
r1.invoke(2)→{'key1': 2}RunnablePassthrough.assign(new_key=r2)会将{'key1': 2}同时传给 r2 和自身:- r2 收到
{'key1': 2},计算2 + 10 = 12 - 原数据
{'key1': 2}与新字段{'new_key': 12}合并
- r2 收到
- 最终输出:
{'key1': 2, 'new_key': 12}
4.3 pick:从字典中筛选指定字段
当中间数据包含多个字段,但下游只需要其中一部分时,使用 .pick() 进行过滤。
python
from langchain_core.runnables import RunnableLambda, RunnableParallel, RunnablePassthrough
r1 = RunnableLambda(lambda x: {'key1': x})
r2 = RunnableLambda(lambda x: x['key1'] + 10)
r3 = RunnableLambda(lambda x: x['new_key']['key2'])
# 复杂组合:并行分叉 → 筛选 → 提取
chain = (
r1
| RunnableParallel(
foo=RunnablePassthrough(),
new_key=RunnablePassthrough.assign(key2=r2)
)
| RunnablePassthrough().pick(['new_key'])
| r3
)
print(chain.invoke(2)) # 12
总结:
| 工具 | 能力 | 适用场景 |
|---|---|---|
RunnablePassthrough() |
原样透传 | 保留上游数据不变 |
.assign(key=runnable) |
透传 + 追加字段 | 在不丢失原数据的前提下补充信息 |
.pick(keys) |
按 key 过滤 | 从复杂字典中提取下游所需的部分 |
4.4 实战场景:在 RAG 中透传用户问题
RunnablePassthrough 最典型的应用场景是 RAG(检索增强生成):在将检索结果注入提示词的同时,需要将用户的原始问题一并透传给模板。
python
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough, RunnableLambda
from models import llm
# 模拟一个检索器:根据问题返回相关文档片段
def fake_retriever(query: dict):
docs = {
"Python": "Python 是一种解释型、面向对象的高级编程语言,由 Guido van Rossum 于 1991 年发布。",
"default": "暂未检索到相关资料。"
}
question = query["question"]
return docs.get("Python", docs["default"]) if "Python" in question else docs["default"]
# RAG 提示词模板:同时需要 context(检索结果)和 question(用户原问题)
prompt = ChatPromptTemplate.from_template(
"请根据以下参考资料回答用户问题。\n\n参考资料:{context}\n\n用户问题:{question}"
)
# 核心:RunnablePassthrough.assign 透传原始输入,同时追加 context 字段
chain = (
RunnablePassthrough.assign(context=RunnableLambda(fake_retriever))
| prompt
| llm
| StrOutputParser()
)
print(chain.invoke({"question": "Python 是什么?"}))
数据流分析:
- 输入
{"question": "Python 是什么?"} RunnablePassthrough.assign(context=...)同时执行两件事:- 透传 :保留原始的
{"question": "Python 是什么?"} - 追加 :调用
fake_retriever计算context字段
- 透传 :保留原始的
- 合并后输出
{"question": "Python 是什么?", "context": "Python 是一种解释型..."} - 该字典恰好匹配
prompt模板中的{question}和{context}两个变量
五、Fallback 与 Retry------链路的异常恢复策略
生产环境中,LLM 调用可能因网络波动、服务超时、速率限制等原因抛出异常。LCEL 在 Runnable 协议中内置了 Fallback(降级回退) 和 Retry(自动重试) 两种异常恢复策略,保障链路的稳定运行。
5.1 with_fallbacks:降级回退
当主节点抛出异常时,自动捕获并降级至备用节点执行,确保链路不会因单点故障而中断。
python
from langchain_core.runnables import RunnableLambda
def add_ten(x: int):
return x + 10
r1 = RunnableLambda(add_ten)
r2 = RunnableLambda(lambda x: int(x) + 20)
# r1 为主链路,r2 为降级链路
chain = r1.with_fallbacks([r2])
# 传入字符串 '2',r1 执行 '2' + 10 (str + int) 抛出 TypeError → 自动降级至 r2
print(chain.invoke('2')) # 22
典型应用场景:为 LLM 调用配置多模型降级策略,例如主用 GPT-4o,异常时自动回退至 DeepSeek:
python
chain = (prompt | gpt4o_llm | parser).with_fallbacks(
[prompt | deepseek_llm | parser]
)
5.2 with_retry:自动重试
对于瞬态故障(Transient Errors),如网络抖动、服务限流(HTTP 429),可配置自动重试策略。
python
from langchain_core.runnables import RunnableLambda
counter = -1
def unstable_function(x):
"""模拟不稳定的函数:第一次调用会除零报错"""
global counter
counter += 1
print(f'执行了 {counter} 次')
return x / counter # counter=0 时会抛出 ZeroDivisionError
# 最多执行 4 次(含首次调用,即最多重试 3 次)
r1 = RunnableLambda(unstable_function).with_retry(stop_after_attempt=4)
print(r1.invoke(2))
# 执行了 0 次 → 报错
# 执行了 1 次 → 成功,返回 2.0
原理 :with_retry 会捕获异常并在设定次数内自动重新执行该节点,适合应对网络超时、速率限制等瞬态故障。官方建议将重试范围限定在最小粒度的节点上,而非整条链路。
六、动态路由------条件分支链
某些场景下,我们需要根据运行时的中间结果来决定后续执行哪条链路。LCEL 提供了两种方式实现动态路由。
6.1 基于 RunnableLambda 的简单条件分支
python
from langchain_core.runnables import RunnableLambda
r1 = RunnableLambda(lambda x: x + 10)
r2 = RunnableLambda(lambda x: [x] * 2)
# 根据 r1 的输出决定后续走向
chain = r1 | RunnableLambda(
lambda x: r2 if x > 12 else RunnableLambda(lambda y: y)
)
print(chain.invoke(1)) # 1+10=11, 11<=12, 直接输出 11
print(chain.invoke(5)) # 5+10=15, 15>12, 执行 r2 → [15, 15]
原理 :RunnableLambda 内部返回的可以是另一个 Runnable,LCEL 会自动对其调用 invoke。这种模式适合分支逻辑简单的场景。
6.2 基于 RouterRunnable 的多路由调度
业务场景:用户提问涵盖多个领域(数学、物理、历史、计算机等),需要先对问题进行分类,再动态分发到对应领域的专属提示词模板处理。
python
from langchain_core.output_parsers import StrOutputParser, JsonOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableLambda, RouterRunnable, RunnableSequence
from models import llm
# Step 1:定义各领域的专属提示词模板
physics_chain = ChatPromptTemplate.from_template(
"你是一位物理学教授,擅长用简洁易懂的方式回答物理问题。问题:{input}"
) | llm
math_chain = ChatPromptTemplate.from_template(
"你是一位数学家,擅长分步骤解决数学问题。问题:{input}"
) | llm
history_chain = ChatPromptTemplate.from_template(
"你是一位历史学家,对历史事件有深入研究。问题:{input}"
) | llm
default_chain = ChatPromptTemplate.from_template(
"输入内容无法归类,请直接回答:{input}"
) | llm
# Step 2:定义路由函数(根据分类结果分发)
def route(input):
if '物理' in input['type']:
return {"key": 'physics', "input": input['input']}
elif '数学' in input['type']:
return {"key": 'math', "input": input['input']}
elif '历史' in input['type']:
return {"key": 'history', "input": input['input']}
else:
return {"key": 'default', "input": input['input']}
# Step 3:构建路由调度器
router = RouterRunnable(runnables={
'physics': physics_chain,
'math': math_chain,
'history': history_chain,
'default': default_chain
})
# Step 4:第一个 LLM 负责分类,输出 JSON
classify_prompt = ChatPromptTemplate.from_template(
"不要回答用户的问题,只需判断分类,类别有[物理,历史,计算机,数学,其他]。\n"
"用户输入:{input}\n"
"输出 JSON 格式,类别 key 为 type,用户输入 key 为 input"
)
classify_chain = classify_prompt | llm | JsonOutputParser()
# Step 5:组装完整链路
full_chain = RunnableSequence(
classify_chain,
RunnableLambda(route),
router,
StrOutputParser()
)
# 测试
inputs = [
{"input": "光的波粒二象性如何理解?"}, # 物理问题
{"input": "求解方程 x² - 5x + 6 = 0。"}, # 数学问题
{"input": "丝绸之路的起源和影响是什么?"}, # 历史问题
]
for inp in inputs:
result = full_chain.invoke(inp)
print(f'问题: {inp["input"]}\n回答: {result}\n')
数据流分析:
用户输入 → [分类 LLM + JSON 解析] → {"type": "物理", "input": "..."}
→ [路由函数] → {"key": "physics", "input": "..."}
→ [RouterRunnable] → 自动选择 physics_chain 执行
→ [StrOutputParser] → 最终文本结果
RunnableSequence(a, b, c)等价于a | b | c,是管道操作符的显式写法,适合链路较长时提升可读性。
七、生命周期管理------with_listeners
LCEL 允许为节点注册生命周期回调,在节点启动和结束时自动触发,适用于日志记录、性能监控等场景。
python
import time
from langchain_core.runnables import RunnableLambda
from langchain_core.tracers import Run
def slow_task(n: int):
time.sleep(n)
return n * 2
r1 = RunnableLambda(slow_task)
# 注册生命周期监听器
def on_start(run_obj: Run):
print('节点启动时间:', run_obj.start_time)
def on_end(run_obj: Run):
print('节点结束时间:', run_obj.end_time)
chain = r1.with_listeners(on_start=on_start, on_end=on_end)
print(chain.invoke(2))
# 节点启动时间:2025-xx-xx xx:xx:xx
# 节点结束时间:2025-xx-xx xx:xx:xx
# 4
应用场景:
- 性能监控:记录每个节点的执行耗时,定位瓶颈。
- 日志审计:追踪链路中每一步的执行状态。
- 异常告警 :在
on_end回调中检测执行过程中是否出现异常。
八、实战案例
8.1 案例一:多阶段链式调用------生成 + 审核
需求:先由 LLM 根据关键词生成一段产品广告文案,再由 LLM 从专业角度对文案进行质量审核与打分。两个阶段通过 LCEL 串联为一条完整链路。
python
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnableLambda
from models import llm
# 第一步:生成广告文案
prompt1 = PromptTemplate.from_template(
'请为{product}写一段{style}风格的广告文案,字数不超过{count}。'
)
# 第二步:质量审核
prompt2 = PromptTemplate.from_template(
'请从创意性、吸引力、准确性三个维度审核以下广告文案,满分10分,给出评分:\n{text_content}'
)
# 组装第一段链
chain1 = prompt1 | llm | StrOutputParser()
# 用 RunnableLambda 做中间数据转换,将文本映射为 prompt2 需要的字典格式
def bridge(text):
print(text) # 打印中间生成的文案
print('--' * 30)
return {'text_content': text}
# 组装完整链路
chain = chain1 | RunnableLambda(bridge) | prompt2 | llm | StrOutputParser()
print(chain.invoke({'product': '智能手表', 'style': '科技感', 'count': 200}))
关键技巧 :当两段链路的输入/输出格式不匹配时,使用 RunnableLambda 作为"桥接器"进行数据转换。也可以用字典简写代替:
python
# 简写方式:用字典将 chain1 的输出映射为 prompt2 的输入
chain = {'text_content': chain1} | prompt2 | llm | StrOutputParser()
8.2 案例二:多阶段提示词编排------旅行规划
需求:构建三阶段处理管线------需求提取 → 行程规划 → 摘要生成。
python
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from models import llm
prompt1 = ChatPromptTemplate.from_template(
"用户描述了一些旅行偏好:{input1}\n请将用户的偏好提炼为明确的出行需求:"
)
prompt2 = ChatPromptTemplate.from_template(
"基于以下出行需求:{input2}\n请规划一份 3 天的旅行行程,并说明每日亮点:"
)
prompt3 = ChatPromptTemplate.from_template(
"以下是详细的旅行行程规划:\n{input3}\n请浓缩为 2-3 句话的行程摘要,方便用户快速预览:"
)
# 三段式串联:prompt → LLM → prompt → LLM → prompt → LLM → 解析
chain = prompt1 | llm | prompt2 | llm | prompt3 | llm | StrOutputParser()
print(chain.invoke({'input1': '想去海边度假,预算有限,最好有当地美食体验。'}))
此处体现了 LCEL 的隐式类型转换机制:当 LLM 输出的
AIMessage直接传入下一个ChatPromptTemplate时,LangChain 会自动提取AIMessage.content填入模板变量。因此多阶段 Prompt 可以直接串联,无需手动进行格式转换。
8.3 案例三:带上下文记忆的对话链
需求:构建一个支持多轮对话的编程助手,历史消息持久化到本地 SQLite 数据库。
python
from langchain_community.chat_message_histories import SQLChatMessageHistory
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnableWithMessageHistory
from models import llm
parser = StrOutputParser()
prompt = ChatPromptTemplate.from_messages([
('system', '你是一个专业的编程助手,擅长用简洁的语言解释技术概念'),
MessagesPlaceholder(variable_name='history'), # 历史消息占位符
('human', '{input}')
])
# LCEL 链路
chain = prompt | llm | parser
# 根据会话 ID 获取对应的历史记录存储
def get_session_history(sid):
return SQLChatMessageHistory(sid, 'sqlite:///history.db')
# 包装为带记忆的 Runnable
runnable = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key='input', # 指定输入中哪个 key 是当前消息
history_messages_key='history' # 指定模板中哪个占位符接收历史
)
# 同一 session_id 下的多轮对话
res1 = runnable.invoke(
{'input': 'Python 中列表和元组有什么区别?'},
config={'configurable': {'session_id': 'user_001'}}
)
print(res1)
res2 = runnable.invoke(
{'input': '那它们的性能差异大吗?'},
config={'configurable': {'session_id': 'user_001'}}
)
print(res2) # 模型能根据历史记录理解"它们"指代列表和元组
核心要点:
RunnableWithMessageHistory会自动在每次调用前读取历史、调用后保存新消息。session_id用于隔离不同用户/会话的历史记录。- 存储后端可替换为 Redis、MongoDB 等,只需实现
BaseChatMessageHistory接口。
九、总结:LCEL 核心组件速查表
| 组件 | 核心能力 | 典型应用场景 |
|---|---|---|
RunnableLambda |
将函数封装为 Runnable 节点 | 自定义数据处理、桥接转换 |
RunnableParallel |
对同一输入并行执行多个分支 | 多任务并发处理 |
RunnablePassthrough |
数据透传 / 追加字段 / 字段筛选 | 保留上游数据、数据增强 |
RunnableSequence |
显式串行组合(等价于 ` | `) |
RouterRunnable |
根据 key 动态分发到不同链路 | 多领域路由、条件分支 |
with_fallbacks |
异常时降级至备用链路 | 多模型降级、高可用保障 |
with_retry |
瞬态故障自动重试 | 网络超时、速率限制 |
with_listeners |
注册生命周期回调 | 日志、监控、性能分析 |
RunnableWithMessageHistory |
自动管理对话历史 | 带记忆的多轮对话 |
写在最后
LCEL 的设计哲学是"一切皆 Runnable,万物皆可组合"。掌握了本文介绍的核心组件后,开发者可以灵活编排从简单到复杂的 AI 处理链路。结合上一篇文章中的提示词模板与结构化输出,我们已经具备了链路编排、数据流转、异常恢复等方面的基础能力。
下一篇文章将把这些知识串联起来,动手构建一个支持图片、音频等多模态输入的聊天机器人,在实战中综合运用提示词模板、LCEL 链式编排、会话记忆管理等技术,真正从零搭建一个完整的 AI 应用,敬请期待。
如有疑问或建议,欢迎留言讨论!