LangChain设计模式02:责任链模式

LangChain设计模式之责任链模式

LangChain 里随手写出的 prompt | llm | parser,底层并不是三个对象简单相加,而是一条责任链。本文从设计模式定义、源码实现和实战场景三个层面,把它拆清楚。

一、先记住一句话

在 LangChain 中,责任链模式解决的核心问题是:

如何把多个可执行步骤串联起来,让请求按顺序正向传递。

它是最基础、最常用的执行骨架。你看到的 Prompt 构建、模型调用、输出解析、工具调用、格式化,最终都会被组织成一条链。

二、责任链模式是什么

责任链模式是行为型设计模式。经典定义是:

将多个处理者组成一条链,请求沿着链依次传递,直到某个处理者能够处理并返回结果。

它通常包含四个角色:

角色含义LangChain 对应
抽象处理者定义统一处理接口Runnable
具体处理者处理具体请求PromptLLMParser
将处理者串联起来RunnableSequence
请求在链上传递的数据invoke(input, config)

需要特别说明的是,LangChain 中的责任链不是“谁先处理完谁返回”的短链逻辑,而是更偏向固定管线:每个步骤都会执行,上一步的输出作为下一步的输入。它继承的是责任链“解耦步骤、串联执行”的思想,同时吸收管道模式对数据流的约束。

三、LangChain 里的实现:RunnableSequence

在 LangChain 中,| 运算符会把左右两个 Runnable 组合起来。多个组件连续使用 | 时,最终会被封装成 RunnableSequence

prompt | llm | parser
   ↓ 底层等价于
RunnableSequence([prompt, llm, parser])

3.1 统一接口先行

责任链能成立,前提是链上的每个步骤都实现同一个接口。LangChain 用 Runnable 完成这件事:

from abc import ABC, abstractmethod
from typing import Generic, TypeVar, Optional, List

Input = TypeVar("Input")
Output = TypeVar("Output")


class Runnable(Generic[Input, Output], ABC):
    input_type: type
    output_type: type

    @abstractmethod
    def invoke(self, input: Input, config: Optional[dict] = None) -> Output:
        raise NotImplementedError()

所有 Prompt、LLM、Parser、Chain、Tool,以及后续包装出来的中间件对象,都满足这个契约。

3.2 链的组装与执行

下面是贴合 LangChain 实际逻辑的简化版 RunnableSequence

class RunnableSequence(Runnable[Input, Output]):
    def __init__(self, steps: List[Runnable]):
        self.steps = steps
        self._validate_steps()

    def _validate_steps(self) -> None:
        for i in range(len(self.steps) - 1):
            current_output = self.steps[i].output_type
            next_input = self.steps[i + 1].input_type
            if not issubclass(current_output, next_input):
                raise ValueError(
                    f"步骤 {i} 的输出类型 {current_output} "
                    f"不匹配步骤 {i + 1} 的输入类型 {next_input}"
                )

    def invoke(self, input: Input, config: Optional[dict] = None) -> Output:
        value = input
        for i, step in enumerate(self.steps):
            step_config = self._patch_config(config, step_idx=i)
            value = step.invoke(value, step_config)
        return value

    def _patch_config(self, config: Optional[dict], step_idx: int) -> dict:
        config = config or {}
        return {
            **config,
            "step_idx": step_idx,
            "step_tag": f"step{step_idx}",
            "sequence_id": id(self),
        }

3.3 这四点决定了它像责任链

  1. 线性串联:请求从第一个步骤进入,依次传到最后一个步骤。
  2. 步骤解耦:每个 Runnable 只关心自己的输入和输出,不感知前后步骤。
  3. 可扩展:通过 | 可以随时增删步骤或调整顺序。
  4. 上下文传递config 沿链传递,为日志、会话、状态回溯提供基础。

四、实战:从基础链到嵌套链

4.1 基础 Prompt-LLM-Parser 链

这是 LangChain 最常见的一条责任链:

from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个专业的文本总结助手,总结内容需简洁明了,不超过50字。"),
    ("user", "{input}")
])

llm = ChatOpenAI(model="gpt-3.5-turbo")
parser = StrOutputParser()

chain = prompt | llm | parser

input_text = (
    "LangChain 是一个用于构建大语言模型应用的框架,"
    "它提供了丰富的组件和工具,支持快速开发复杂的 LLM 应用。"
)

result = chain.invoke({"input": input_text})
print(result)

执行顺序:

{"input": input_text}
        ↓
     prompt
        ↓
       llm
        ↓
     parser
        ↓
      result

4.2 嵌套责任链:责任链里的责任链

责任链的一个步骤本身也可以是一条责任链,于是形成树形结构:

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableSequence

summary_chain = prompt | llm | parser

translate_prompt = ChatPromptTemplate.from_messages([
    ("system", "将以下文本翻译成英文,保持原意,简洁准确。"),
    ("user", "{input}")
])
translate_chain = translate_prompt | llm | parser

# 先总结,再翻译总结结果
main_chain = RunnableSequence([summary_chain, translate_chain])
result = main_chain.invoke({"input": input_text})
print(result)

这种能力让复杂任务可以被拆成多级子链,而不是写一个巨大的处理函数。

五、它在四大模式中的位置

责任链模式不是孤立存在的。它在 LangChain 内核中负责“正向执行流的骨架”:

模式作用关系
命令模式统一 Runnable 接口责任链的前提
责任链模式串联步骤、正向传递核心骨架
装饰器模式包装链或组件,增强功能对责任链做非侵入扩展
管道模式约束输入输出类型让责任链的数据流更规范

一句话总结:命令模式定接口,责任链模式搭骨架,装饰器模式做增强,管道模式规数据流。

六、总结

LangChain 的责任链模式是怎么实现的:

  1. LangChain 通过 Runnable 接口统一所有可执行组件。
  2. | 运算符把组件组合成 RunnableSequence
  3. RunnableSequence.invoke 把输入依次传给每个步骤,前一步输出作为后一步输入。
  4. 每个步骤只关注自身职责,通过 config 传递上下文。
  5. 责任链既可以扁平串联,也可以嵌套成树形链,支撑复杂任务拆分。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值