LangChain 为什么一定会走向链式调用
LangChain 为什么一定会走向链式调用
先把结论说死。
链式调用不是 LangChain 的特色功能,而是它唯一配得上被学习的核心设计。
如果一个框架只是把 model.invoke() 包一层,那它根本不值钱。
因为调模型这件事太简单了,真正难的从来不是调用,而是把一整套流程组织起来,还别组织成一坨烂泥。
这才是链式调用出现的根本原因。
一、问题不在模型,在流程
刚学大模型时,脑子里只有一个动作:
-
拼 prompt
-
调模型
-
拿结果
这套东西做 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 这条路非常值钱。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)