看langchain理解python中的链式调用

背景

先看两段langchain调用模型的代码

python 复制代码
def chat():
    prompt = ChatPromptTemplate.from_messages([
        ("system", "你是一名资深的开发工程师,请回答用户提的问题"),
        ("human", "{user_input}"),
    ])
    llm = ChatOllama(
        model="qwen3-vl:8b",
        temperature=0,
    )
    ai_msg = llm.invoke(prompt.format_messages(user_input="请给我一个关于机器学习的例子"))
    print(ai_msg)

def chat_chain_call():
    prompt = ChatPromptTemplate.from_messages([
        ("system", "你是一名资深的开发工程师,请回答用户提的问题"),
        ("human", "{user_input}"),
    ])
    llm = ChatOllama(
        model="qwen3-vl:8b",
        temperature=0,
    )
    # 创建链
    chain=prompt | llm
    # 调用
    ai_msg = chain.invoke({"user_input": "请给我一个关于机器学习的例子"})
    print(ai_msg)

核心代码为

python 复制代码
	# 创建链
    chain=prompt | llm
    # 调用
    ai_msg = chain.invoke({"user_input": "请给我一个关于机器学习的例子"})
    print(ai_msg)

这是 LangChain (或类似现代 Python AI 框架,如 LlamaIndex、Haystack)中典型的**链式调用(Chaining)**写法。其核心原理是 利用 Python 的 __or__ 魔术方法(即 | 运算符重载)实现管道式(pipeline)组合

下面从原理到实现一步步解释:


🔧 一、链式调用的本质:函数/对象的组合(Composition)

目标:将多个处理步骤(如 prompt 模板 → LLM → 解析器)像水管一样串起来,数据自动从前一个流向后一个。

传统写法:

python 复制代码
ai_msg = llm.invoke(prompt.format_messages(user_input="请给我一个关于机器学习的例子"))
print(ai_msg)

链式写法(更简洁、可复用、可嵌套):

python 复制代码
	# 创建链
    chain=prompt | llm
    # 调用
    ai_msg = chain.invoke({"user_input": "请给我一个关于机器学习的例子"})
    print(ai_msg)

⚙️ 二、技术原理:__or__ 运算符重载 + Runnable 协议

在 LangChain 中(v0.1+),所有可组合的组件(如 PromptTemplate, LLM, RunnableLambda 等)都继承自 Runnable 基类。

关键机制:

  1. Runnable 类定义了 __or__ 方法

    python 复制代码
    class Runnable:
        def __or__(self, other):
            return RunnableSequence(first=self, second=other)
  2. | 运算符被重载为返回一个新的 RunnableSequence 对象

    • prompt | llm → 返回 RunnableSequence(prompt, llm)
  3. RunnableSequence.invoke() 实现自动流水线执行

    python 复制代码
    def invoke(self, input, config=None):
        output = self.first.invoke(input, config)
        return self.second.invoke(output, config)

所以 chain.invoke(...) 实际上是依次调用每个组件的 .invoke() 方法,并把前一个的输出作为后一个的输入。


🧩 三、数据流示例

python 复制代码
chain = prompt | llm
result = chain.invoke({"text": "Thank you"})

执行过程:

  1. prompt.invoke({"text": "Thank you"})

    → 返回格式化后的字符串,如 "Classify: Thank you -> Positive"

  2. llm.invoke("Classify: Thank you -> Positive")

    → 返回 LLM 的输出,如 "Positive"

  3. 最终 result = "Positive"

✅ 输入是 dict,中间变成 str,输出还是 str ------ LangChain 自动处理类型转换(前提是组件兼容)。


📦 四、扩展:多级链式调用

你可以继续拼接更多组件:

python 复制代码
from langchain_core.output_parsers import StrOutputParser

chain = (
    prompt 
    | llm 
    | StrOutputParser()  # 把 LLM 的 AIMessage 转为纯字符串
)

result = chain.invoke({"text": "Thank you"})  # 直接得到 str,无需 .content

这相当于:

python 复制代码
prompt_str = prompt.format(**{"text": "Thank you"})
ai_msg = llm.invoke(prompt_str)
result = StrOutputParser().invoke(ai_msg)

但链式写法更清晰、模块化、可测试。


🧪 五、自己实现一个简易版(理解原理)

python 复制代码
class MyRunnable:
    def __or__(self, other):
        return MyChain(self, other)
    
    def invoke(self, x):
        raise NotImplementedError

class PromptTemplate(MyRunnable):
    def invoke(self, inputs):
        return f"Input: {inputs['text']}"

class DummyLLM(MyRunnable):
    def invoke(self, prompt):
        return f"Response to '{prompt}'"

class MyChain(MyRunnable):
    def __init__(self, first, second):
        self.first = first
        self.second = second
    
    def invoke(self, x):
        return self.second.invoke(self.first.invoke(x))

# 使用
chain = PromptTemplate() | DummyLLM()
print(chain.invoke({"text": "Hello"}))
# 输出: Response to 'Input: Hello'

这就是 | 链式调用的核心思想!


✅ 总结

概念 说明
链式调用 用 `
底层原理 __or__ 运算符重载 + Runnable.invoke() 协议
优势 代码简洁、可读性强、易于组合和复用
适用框架 LangChain、LlamaIndex(部分)、自定义 AI pipeline

💡 记住:a | b | c 不是"或"逻辑,而是 c(b(a(input))) 的函数组合!

这种设计灵感来源于 Unix 管道(cat file | grep word | sort),是现代 AI 工程中非常优雅的抽象方式。

相关推荐
章鱼丸-2 分钟前
DAY31 文件的拆分和写法
开发语言·python
倾颜13 分钟前
我把本地 AI Chat 项目重构了一遍:用 LangChain.js + Ollama + Streamdown 搭了一个最小可扩展架构
langchain·llm·next.js
唐叔在学习14 分钟前
Python桌面端应用最小化托盘开发实践
后端·python·程序员
2501_9454235415 分钟前
使用Fabric自动化你的部署流程
jvm·数据库·python
2401_8463416517 分钟前
用Pandas处理时间序列数据(Time Series)
jvm·数据库·python
FserSuN17 分钟前
langchain deepagents 框架使用带脚本的Skill
langchain·ai编程
未知鱼27 分钟前
Python安全开发之子域名扫描器(含详细注释)
网络·python·安全·web安全·网络安全
2401_8318249630 分钟前
编写一个Python脚本自动下载壁纸
jvm·数据库·python
2401_8579182940 分钟前
Python在2024年的主要趋势与发展方向
jvm·数据库·python
今儿敲了吗43 分钟前
python基础学习笔记第九章——模块、包
开发语言·python