LangChain 为什么一定会走向链式调用

先把结论说死。
链式调用不是 LangChain 的特色功能,而是它唯一配得上被学习的核心设计。

如果一个框架只是把 model.invoke() 包一层,那它根本不值钱。
因为调模型这件事太简单了,真正难的从来不是调用,而是把一整套流程组织起来,还别组织成一坨烂泥

这才是链式调用出现的根本原因。


一、问题不在模型,在流程

刚学大模型时,脑子里只有一个动作:

  1. 拼 prompt

  2. 调模型

  3. 拿结果

这套东西做 demo 够了。
做应用,不够,而且差得远。

真实场景里,你要处理的根本不是一次调用,而是一串步骤:

  • 先改写问题

  • 再补上下文

  • 再检索资料

  • 再生成答案

  • 再解析输出

  • 必要时还要分支、重试、调用工具

问题一下就变了。

这时你会发现,LLM 应用最难的地方,不是生成,而是编排。

LangChain 真正厉害的地方,就在这里。
它很早就看明白了:框架的价值不该停留在“调用模型”,而应该落在“组织流程”。

这一刀切得很准。
不是准一点,是非常准。


二、直接写调用为什么会越写越烂

1. 小代码看着清爽,大项目必烂

最原始的写法一般长这样:

prompt = f"请根据以下上下文回答问题:\n上下文:{context}\n问题:{question}"
result = model.invoke(prompt)
answer = result.content

刚开始你会觉得挺好,简单直接,控制感很强。

但这种控制感很廉价。

因为流程只要稍微长一点,代码马上开始腐烂:

query = rewrite_question(user_input)

docs = retriever.get_relevant_documents(query)

context = "\n".join([doc.page_content for doc in docs])

prompt = f"请根据以下上下文回答问题:\n上下文:{context}\n问题:{query}"

result = model.invoke(prompt)

if "```json" in result.content:
    parsed = parse_json(result.content)
else:
    parsed = {"answer": result.content}

return parsed

这还只是轻度复杂。
你再加工具调用、异常处理、流式输出、结构化返回,代码立刻变成一锅粥。

所以对“手写全流程”这件事,我的评价很明确:

写 demo 可以,长期这么写就是在给未来埋雷。

不是不能跑。
只能跑,不能优雅地活着


三、链式调用到底在解决什么

链式调用本质上只解决一件事:

把原本会写散、写脆、写乱的步骤,变成可以连接、替换、复用的流程。

注意这里最重要的词不是链,而是这三个:

  • 连接

  • 替换

  • 复用

也就是说,LangChain 真正在做的不是“让你更方便调模型”,而是“让你别把流程写废”。

这个方向,我愿意直接夸。

设计思想非常强。

因为它抓住的是 LLM 应用里最本质的矛盾。
不是模型接口不统一,而是流程根本没被工程化。


四、三种调用方式,谁强谁弱,其实很明显

1. 手动串联:自由,但低级

手动串最大的好处是直白。
最大的坏处也是直白。

你什么都自己管,于是什么都缠在一起。

  • prompt 在业务代码里

  • 检索逻辑在业务代码里

  • 输出解析在业务代码里

  • 异常处理还在业务代码里

前期像自由,后期像报应。

适合什么

适合:

  • 学习单步调用

  • 一次性脚本

  • 非正式 demo

不适合:

  • 稍微像样一点的 RAG

  • 有多步骤的数据流

  • 会迭代的业务系统

一句话评价:

它不是错,它只是层次太低。


2. 早期 Chain:方向对了,但不够漂亮

早期 LangChain 喜欢用 LLMChain 这一套。

from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain.chains import LLMChain

prompt = PromptTemplate.from_template("请回答这个问题:{question}")
model = ChatOpenAI()
chain = LLMChain(prompt=prompt, llm=model)

result = chain.run("LangChain 为什么要链式调用?")

它比手动串联强,因为它至少承认了一件事:

prompt、模型、输出,本来就该算一个步骤,而不是三段散装代码。

这个认知没问题。

但早期 Chain 的问题也很明显:

  • 抽象有了,但不统一

  • 能封装,但不好组合

  • 能用,但总有点别扭

所以它的地位很尴尬。

你不能说它差,因为它确实推动了流程抽象。
但你也不能把它吹太高,因为它明显只是过渡形态。

一句话评价:

方向正确,成品一般。


3. Runnable / LCEL:这才是 LangChain 真正值钱的地方

到了 LCEL 这套写法,LangChain 才算真正长脑子了。

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

prompt = ChatPromptTemplate.from_template("请回答这个问题:{question}")
model = ChatOpenAI()
parser = StrOutputParser()

chain = prompt | model | parser

result = chain.invoke({"question": "LangChain 为什么要链式调用?"})

这段代码看着只是简洁了一点。
其实不止。

它真正厉害的地方在于:

LangChain 开始试图把不同组件,统一成同一种可组合接口。

这件事非常关键。

因为一旦接口统一了,系统的气质就变了:

  • Prompt 可以接 Model

  • Model 可以接 Parser

  • Retriever 可以插进来

  • Lambda 可以插进来

  • Branch 可以插进来

于是你写的就不再是胶水代码,而是执行流。

这一步,我直接给高评价:

Runnable/LCEL 才是 LangChain 真正配得上名气的核心设计。

不是因为语法新。
而是因为它终于把“链式调用”从概念做成了体系。


五、它到底好在哪里

1. 它抓住了真正的问题

很多框架忙着做供应商适配、参数兼容、模型封装。

这些不是没用。
但都不够高明。

LangChain 更高明的地方,是它很早就意识到:

LLM 应用真正的难点不是模型,而是流程。

这一点,比很多框架看得都深。


2. 它让复杂系统第一次能像搭积木

以前你写 RAG、写 Agent、写工具调用,本质上是在手工接水管。

能跑。
但不成体系。

LangChain 把流程拆成节点之后,开发者第一次可以用统一思路去搭一个多步骤系统。

这不是语法优化。
这是工程视角的升级。


3. 它逼你认真思考输入输出

这是很多人没意识到,但其实很值钱的一点。

LangChain 的链式设计会逼你想清楚:

  • 这一步输入是什么

  • 这一步输出是什么

  • 下一步怎么接

  • 数据在整个流程里怎么流动

这才是真正的工程思维。

很多人学半天框架,最后最该学会的,其实就是这个。


六、它烂在哪里,也得骂清楚

1. 新手体验差,是真的差

LangChain 最大的问题不是设计差。
表达能力差

它明明想解决一个很好的问题,却总喜欢先拿术语压人:

  • Runnable

  • Parser

  • Chain

  • Message

  • Document

  • Retriever

你模型都没调明白,它先把框架词汇表塞你脸上。

这不是高明。
这是教学欠揍。


2. 框架味太重

有时你会明显感觉到,LangChain 不是在帮你解决问题,而是在要求你先进入它的世界观。

这就过了。

好框架应该让你更快接近业务。
LangChain 有时候恰恰相反:你本来想做个简单流程,它先给你一套抽象工具箱,让你学半天它的语言。

说难听点,这种感觉像什么?

像你只是想做顿饭,结果它先逼你学一套厨房哲学。


3. 历史包袱很重

这是它另一个很烦的地方。

  • 旧写法还没完全死

  • 新写法已经成主流

  • 教程风格又不统一

结果就是很多人学 LangChain 时,见过很多词,但脑子里没有一张完整图。

这不全是用户的问题。
框架自己的演进痕迹也确实太重了。


七、链式调用和 invoke、batch、stream,不是一个维度

这个地方很多人老混。

必须狠狠干脆地分开。

链式调用解决的是:流程怎么组织

比如:

chain = prompt | model | parser

这是在定义流程结构。


invoke / batch / stream 解决的是:流程怎么执行

单次执行

result = chain.invoke({"question": "什么是链式调用?"})

批量执行

results = chain.batch([
    {"question": "什么是链式调用?"},
    {"question": "什么是 Runnable?"}
])

流式执行

for chunk in chain.stream({"question": "解释一下 LCEL"}):
    print(chunk, end="", flush=True)

所以别再混了。

链式调用是结构问题。
invoke、batch、stream 是执行问题。

一个在搭水管。
一个在决定水怎么流。


八、如果我是 LangChain 设计者,我也一定走这条路

因为不走这条路,LangChain 就只是一个模型封装库。

而那种东西,说实话,没多大意思。

模型封装库解决的是“怎么调”。
链式框架解决的是“怎么组织”。

这两者根本不是一个层次。

所以链式调用对 LangChain 来说,不是什么附加能力,而是存在理由。

没有链,它最多算方便。
有了链,它才开始有设计含量。


九、写在最后

LangChain 在链式调用这件事上,判断非常准,设计非常强,LCEL 这条路非常值钱。

 

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐