看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 工程中非常优雅的抽象方式。

相关推荐
敏编程4 小时前
一天一个Python库:jsonschema - JSON 数据验证利器
python
是一碗螺丝粉4 小时前
LangChain 链(Chains)完全指南:从线性流程到智能路由
前端·langchain·aigc
前端付豪5 小时前
LangChain记忆:通过Memory记住上次的对话细节
人工智能·python·langchain
databook5 小时前
ManimCE v0.20.1 发布:LaTeX 渲染修复与动画稳定性提升
python·动效
神秘的猪头5 小时前
🔌 给 AI 装上“三头六臂”!实战大模型接入第三方 MCP 全攻略
langchain·llm·mcp
花酒锄作田18 小时前
使用 pkgutil 实现动态插件系统
python
前端付豪21 小时前
LangChain链 写一篇完美推文?用SequencialChain链接不同的组件
人工智能·python·langchain
曲幽1 天前
FastAPI实战:打造本地文生图接口,ollama+diffusers让AI绘画更听话
python·fastapi·web·cors·diffusers·lcm·ollama·dreamshaper8·txt2img
老赵全栈实战1 天前
Pydantic配置管理最佳实践(一)
python
神秘的猪头1 天前
🔌 把 MCP 装进大脑!手把手带你构建能“热插拔”工具的 AI Agent
langchain·llm·mcp