LangChain基础补全-Runnable

LangChain有两个重要的概念:LangChain表达式(LCEL)组件。我们使用组件,构建整个RAG应用中各种点单的操作,然后使用LCEL将这些组件进行连接,按照一定顺序运行,最终实现我们的目的。相关概念可在这里进一步理解。

Runnable

LCEL通过简洁的形式调用各类组件,实现方式是使用|串联所有实现了Runnable接口的组件。简而言之,LangChain的所有组件均实现了Runnable接口,通过LCEL的方式进行相连,然后按照顺序执行每个组件,最终得到结果。

概念

Runnable是LangChain中的一个抽象接口,凡是实现这个接口的均代表一个可执行单元,可通过标准化方法执行,处理并生成输出。其涉及目标是:

  • 统一接口,为不同的组件提供统一的调用方式;
  • 便于LCEL调用,组合完成复杂任务;
  • 支持同步、异步、流式、批量调用等适合各种场景。

核心方法

invoke:同步单个调用

ainvoke:异步单个调用,适合高并发场景

stream:流式调用

batch:同步批量调用

abatch:异步批量调用

LangChain提供的常见的Runnable实现

RunnableSequence

例子:

from langchain_core.runnables import RunnableSequence
from langchain_core.output_parsers import StrOutputParser

# chain_of_sequence_v1 =  RunnableSequence(prompt, llm, StrOutputParser())

# template_chain = prompt | llm
# chain_of_sequence_v2 = RunnableSequence(first=template_chain, last=StrOutputParser())

chain = prompt | llm | StrOutputParser()

chain.invoke({"input":"你好"})

RunnableSequence有三个参数:firstmiddlelast,可以赋值实现了Runnable的组件,或者一个链。RunnableSequence等价于常用符号|

RunnableParallel

例子:

from langchain_core.runnables import RunnableParallel

system_prompt_of_parallel = "你是一个非常棒的助手,能根据用户的问题给出精准的回答。。"


prompt_1 = ChatPromptTemplate(
    [
        ("system", system_prompt_of_parallel),
        ("human", "请讲一个关于{object}的冷笑话。"),
    ]
)

prompt_2 = ChatPromptTemplate(
    [
        ("system", system_prompt_of_parallel),
        ("human", "请详细介绍{object}。"),
    ]
)

chain_1 = prompt_1 | llm | StrOutputParser()
chain_2 = prompt_2 | llm | StrOutputParser()

chain_of_parallel = RunnableParallel({"chain_1":chain_1, "chain_2":chain_2})

print(chain_of_parallel.invoke({"object":"苹果"}))

RunnableParallel的作用是,将两条链并行执行,并根据每条链的key输出对应的回答。并行执行后,也可以按照key取到对应的值,并执行后续操作。如对chain_of_parallel进行改造如下:

from langchain_core.runnables import RunnableParallel,RunnableLambda

system_prompt_of_parallel = "你是一个非常棒的助手,能根据用户的问题给出精准的回答。。"

prompt_1 = ChatPromptTemplate(
    [
        ("system", system_prompt_of_parallel),
        ("human", "请讲一个关于{object}的冷笑话。"),
    ]
)

prompt_2 = ChatPromptTemplate(
    [
        ("system", system_prompt_of_parallel),
        ("human", "请详细介绍{object}。"),
    ]
)

prompt_3 = ChatPromptTemplate(
    [
        ("system", system_prompt_of_parallel),
        ("human", "评价一下 \n\n {chain_1} \n\n这个冷笑话怎么样,并且判断一下 \n\n {chain_2} \n\n 描述是否准确"),
    ]
)

chain_1 = prompt_1 | llm | StrOutputParser()
chain_2 = prompt_2 | llm | StrOutputParser()
chain_3 = prompt_3 | llm | StrOutputParser()

chain_of_parallel = RunnableParallel({"chain_1":chain_1, "chain_2":chain_2}) | RunnableLambda(lambda x: {"chain_1":x["chain_1"], "chain_2":x["chain_2"]}) | chain_3

print(chain_of_parallel.invoke({"object":"苹果"}))

上述代码可实现,在并行执行的链后,提取执行结果,并进一步对执行结果处理。

RunnablePassthrough

RunnablePassthrough是构建链式任务时直接传递输入数据或上下文,同时支持附加额外数据以增强后续处理能力。

例子:

from langchain_core.runnables import RunnablePassthrough

system_prompt_of_passthrough = "你是一个非常棒的助手,能根据用户的问题给出精准的回答。。"


prompt_of_passthrough = ChatPromptTemplate(
    [
        ("system", system_prompt_of_parallel),
        ("human", "请讲一个关于{object}的冷笑话。"),
    ]
)

chain_of_passthrough = RunnablePassthrough() | llm | StrOutputParser()

# chain_of_passthrough_1 = RunnablePassthrough.assign(object=RunnableLambda(lambda x:"西瓜"))| prompt_of_passthrough | StrOutputParser()
chain_of_passthrough.invoke({"object":"苹果"})

需要注意的是,RunnablePassthrough.assign()可以修改后添加参数,如chain_of_passthrough_1所示,其中assign函数的参数为key=funckey为需要修改或新增参数的key,func为修改或新增的参数的函数。

RunnableLambda

可以将Python函数包装成为Runnable的实现,应用于链中。

例子:

from langchain_core.runnables import RunnableLambda

chain_of_lambda = RunnableLambda(lambda x:x["object"])| StrOutputParser()

# chain_of_lambda_v2 =  (lambda x:x["object"]) | StrOutputParser()

chain_of_lambda_v2.invoke({"object":"苹果"})

此处使用lambda函数作为例子,也可以使用def定义的python函数。另外需要说明的,在链中出现的函数,即使是没有使用RunnableLambda进行包装,链的底层也会自动将其进行包装。

RunnableBranch

例子:

from langchain_core.runnables import RunnableBranch

default_branch = (lambda x:"这个是default_branch") | StrOutputParser()

chain_of_branch_1 = (lambda x:"这个是chain_of_branch_1") | StrOutputParser()

chain_of_branch_2 = (lambda x:"这个是chain_of_branch_2") | StrOutputParser()

chain_of_branch = RunnableBranch(
    (lambda x:x == 1,chain_of_branch_1),
    (lambda x:x == 2,chain_of_branch_2),
    default_branch
)

chain_of_branch.invoke({"object":"苹果"})

根据条件选择执行不同的 Runnable 分支。

RunnableWithMessageHistory

添加对话历史管理和多轮对话跟踪,具体用法详见:这里

核心组件

  • 提示词模板(Prompt Templates):用于动态生成提示词;
  • 大语言模型(LLMs):提供统一的对外访问API
  • 链(Chains):将多个简单操作组合执行,实现复杂功能
  • 记忆功能(Memory):记录对话内容,实现多轮对话
  • Agent:大模型自主决策执行、动态调用工具

除了上述核心组件外,还有许多其他组件,如:检索器(Retrievers)、向量存储(Vector Store)、工具(tools)等,不一一列举,均可在这里找到。

posted @ 2025-06-10 19:08  AfroNicky  阅读(90)  评论(0)    收藏  举报