LangChain表达式语言(LCEL)原理

这种管道操作符的底层实现基于 ​Runnable 协议 和 ​运算符重载 的设计模式

... 

final_prompt = ChatPromptTemplate.from_messages(
    [
        few_shot_prompt,
        ("human", "{input}"), #这里的human是用户的输入。chain.invoke({"input": "xxxx"}) 里面的input
    ]
)

final_prompt
print(final_prompt)

chain = final_prompt | llm


response = chain.invoke({"input": "艾米需要4分钟才能爬到滑梯顶部,她花了1分钟才滑下来,水滑梯将在15分钟后关闭,请问在关闭之前她能滑多少次?"})
print(response.content)

看看上面的例子:
如果是 0.1 的版本是这么实现的

chain = LLMChain(final_prompt,llm)
response = chain.invoke({"input": "艾米需要4分钟才能爬到滑梯顶部,她花了1分钟才滑下来,水滑梯将在15分钟后关闭,请问在关闭之前她能滑多少次?"})
print(response.content)

从原理上看就是第一个组件执行结果作为第二个组件的输入。

底层原理

1. 运算符重载 (| 的实现)

当使用 | 操作符时,LangChain 通过 Python 的 __or__ 方法重载机制,将两个组件连接成一个新的 可运行序列 (RunnableSequence)

# 伪代码示例
class Runnable:
    def __or__(self, other):
        return RunnableSequence(self, other)

这意味着以下两行代码是等价的:

chain = final_prompt | llm
chain = RunnableSequence(final_prompt, llm)

2. 输入输出处理流程

当调用 chain.invoke({"input": ...}) 时,执行流程如下:

步骤 1 - 执行提示模板

# final_prompt 是一个 ChatPromptTemplate 实例
messages = final_prompt.invoke({"input": "问题内容..."})
# 输出格式示例:
# [
#   SystemMessage(content="你是一个助手..."),
#   HumanMessage(content="艾米需要4分钟...")
# ]

步骤 2 - 传递到 LLM

# llm 是一个 ChatOpenAI 实例
response = llm.invoke(messages)
# 输出格式示例:
# AIMessage(content="艾米可以滑3次...")

3 组件的类型预先定义

所有 LangChain 组件(称为 Runnable)都有明确的输入输出类型定义,这些类型通过 Python 的 类型注解 和 LangChain 的 Pydantic 模型 实现。

核心类型示例

组件类型 输入类型 输出类型
ChatPromptTemplate Dict[str, Any] List[BaseMessage]
ChatOpenAI (LLM) List[BaseMessage] AIMessage
StrOutputParser AIMessage str

参考资料

posted @ 2025-03-25 18:03  向着朝阳  阅读(154)  评论(0)    收藏  举报