LangChain 源码剖析(六):可序列化 + 可配置的 “智能组件“——RunnableSerializable

每一篇文章都短小精悍,不啰嗦。

今天我们来解析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_fieldsmax_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 测试:对比不同模型的效果

五、设计亮点:灵活与安全的平衡

  1. 兼容性设计:继承Runnable的所有能力,同时新增序列化和配置功能,不破坏原有使用方式。

  2. 安全检查configurable_fields会先验证字段是否存在,避免配置不存在的参数(比如给没有 "温度" 参数的组件配置温度值)。

  3. 非侵入式扩展:所有配置操作都返回新对象,不修改原对象,避免意外影响其他地方的使用(比如一个组件在两个地方用,各自可以有不同的配置)。

总结:为什么需要 RunnableSerializable?

这个类解决了 AI 应用开发中的两个核心问题:

  1. "存档复用":配置好的组件可以序列化保存,下次直接使用,不用重复配置。
  2. "动态适应":运行时可以灵活调整参数或切换实现,不用改代码就能适应不同场景。

它就像一个 "智能乐高积木"—— 既能和其他积木组合,又能记住自己的状态,还能根据需要变形,是构建灵活、可维护 AI 应用的关键组件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值