每一篇文章都短小精悍,不啰嗦。
今天我们来解析RunnableSerializable
这个类,它是 LangChain 框架中一个非常实用的增强型组件。如果把普通的Runnable
比作 "能干活的工具",那么RunnableSerializable
就是 "既能干活、又能存档、还能灵活调整参数" 的智能工具。
一、类的基本定位:双重身份的优势
class RunnableSerializable(Serializable, Runnable[Input, Output]):
"""Runnable that can be serialized to JSON."""
这个类同时继承了两个核心父类:
Runnable
:赋予它 "可执行" 的能力(可以被调用、组合、批量处理等)Serializable
:赋予它 "可序列化" 的能力(可以转换成 JSON 格式保存或传输)
打个比方:就像一个带 "记忆芯片" 的多功能工具 —— 既能完成具体任务,又能把自己的参数设置 "记下来",方便下次直接使用。
二、核心功能 1:序列化(把自己 "存档")
@override
def to_json(self) -> Union[SerializedConstructor, SerializedNotImplemented]:
dumped = super().to_json() # 先调用父类的序列化方法
with contextlib.suppress(Exception): # 即使添加name失败也不崩溃
dumped["name"] = self.get_name() # 给序列化结果加个"名字"
return dumped
通俗解释:
序列化就是把对象转换成 JSON 格式,就像给工具拍一张 "参数快照"。比如你配置了一个复杂的大模型调用组件(设置了模型名、温度值、最大 token 数等),通过to_json()
可以把这些参数全部保存下来,下次直接 "读档" 就能复用,不用重新配置。
with contextlib.suppress(Exception)
是个很巧妙的设计:即使获取名字失败(比如没设置 name),也不会影响整个序列化过程,保证了代码的健壮性。
三、核心功能 2:动态配置字段(给工具加 "调节旋钮")
def configurable_fields(self, **kwargs: AnyConfigurableField) -> RunnableSerializable[Input, Output]:
# 检查要配置的字段是否存在,不存在就报错
model_fields = type(self).model_fields
for key in kwargs:
if key not in model_fields:
raise ValueError(f"配置键{key}不存在,可用的有{model_fields.keys()}")
# 返回一个支持动态配置的新对象
return RunnableConfigurableFields(default=self, fields=kwargs)
通俗解释:
这个方法允许你给组件的某些字段 "装上调节旋钮",让这些参数能在运行时动态修改,而不用修改代码。
举个例子(结合代码中的示例):
假设你创建了一个大模型调用组件,默认最多生成 20 个 token:
model = ChatOpenAI(max_tokens=20)
但你希望这个值能灵活调整(比如有时需要短回复,有时需要长回复),就可以用configurable_fields
给max_tokens
字段加个 "旋钮":
model = model.configurable_fields(
max_tokens=ConfigurableField(
id="output_token_number", # 旋钮的"编号"
name="最大输出token数", # 旋钮的"标签"
description="控制回复长度" # 旋钮的"说明"
)
)
之后就能随时通过with_config
转动这个 "旋钮":
# 临时把最大token数改成200
model.with_config(configurable={"output_token_number": 200}).invoke("写篇长文章")
为什么需要这个功能?
比如做一个聊天机器人:给免费用户用的时候限制回复长度(省成本),给付费用户用的时候放开限制。不用改代码,通过动态配置就能实现。
四、核心功能 3:动态切换实现(给工具加 "备用方案")
def configurable_alternatives(self, which: ConfigurableField, ...) -> RunnableSerializable[Input, Output]:
return RunnableConfigurableAlternatives(
which=which, # 用哪个字段选择方案
default=self, # 默认用自己
alternatives=kwargs # 备选方案列表
)
通俗解释:
这个方法允许你给组件设置 "备用方案",运行时可以随时切换。就像一把多功能瑞士军刀,默认用小刀,必要时可以换成螺丝刀。
举个例子(结合代码中的示例):
默认用 Anthropic 的 Claude 模型,但保留切换到 OpenAI 模型的能力:
model = ChatAnthropic(model_name="claude-3-sonnet-20240229").configurable_alternatives(
ConfigurableField(id="llm"), # 用"llm"这个字段选择模型
default_key="anthropic", # 默认用Anthropic
openai=ChatOpenAI() # 备选方案:OpenAI模型
)
使用时可以随时切换:
# 默认用Anthropic模型
model.invoke("你是谁开发的?")
# 切换到OpenAI模型
model.with_config(configurable={"llm": "openai"}).invoke("你是谁开发的?")
实际应用场景:
- 模型容错:A 模型故障时自动切换到 B 模型
- 多场景适配:普通用户用轻量模型,专业用户用高精度模型
- A/B 测试:对比不同模型的效果
五、设计亮点:灵活与安全的平衡
-
兼容性设计:继承
Runnable
的所有能力,同时新增序列化和配置功能,不破坏原有使用方式。 -
安全检查:
configurable_fields
会先验证字段是否存在,避免配置不存在的参数(比如给没有 "温度" 参数的组件配置温度值)。 -
非侵入式扩展:所有配置操作都返回新对象,不修改原对象,避免意外影响其他地方的使用(比如一个组件在两个地方用,各自可以有不同的配置)。
总结:为什么需要 RunnableSerializable?
这个类解决了 AI 应用开发中的两个核心问题:
- "存档复用":配置好的组件可以序列化保存,下次直接使用,不用重复配置。
- "动态适应":运行时可以灵活调整参数或切换实现,不用改代码就能适应不同场景。
它就像一个 "智能乐高积木"—— 既能和其他积木组合,又能记住自己的状态,还能根据需要变形,是构建灵活、可维护 AI 应用的关键组件。