LangChain 是 LLM 应用框架里争议最大的一个:爱的人说它是生态标准,烦的人说它是"过度抽象的样板代码发生器"。两边都有道理,因为 LangChain 自己一直在剧烈演进。把它的发展史捋清楚,选型自然就清楚了。
演进三部曲
第一阶段:链(Chains)。 0.1 时代的核心抽象是 LLMChain 一类的线性管道:提示模板 → 模型 → 输出解析,像 Unix 管道一样串起来。适合直线流程,但真实 Agent 是有分支、有循环、有状态的——硬塞进链抽象,代码很快变成"链里嵌链、回调套回调"的迷宫。
第二阶段:LCEL(LangChain Expression Language)。 用 | 运算符组合组件(prompt | model | parser),配合流式、并行、重试的统一语义。这一步解决了表达力问题,但本质仍是 DAG——循环(Agent 的"思考→行动→观察"回路)表达依然别扭。
第三阶段:LangGraph。 彻底换成状态机范式:节点是步骤,边是转移,状态是一个显式的、可检查的对象。循环是一等公民,人机协同(human-in-the-loop)有原生支持(节点可以暂停等待人工审批),断点恢复(checkpoint)内建。今天做严肃 Agent 应用,LangChain 官方的答案其实就是 LangGraph。
状态机范式为什么对路
Agent 的本质是带循环的状态转移:
from langgraph.graph import StateGraph, END
class AgentState(TypedDict):
messages: list
plan: list[str]
results: dict
g = StateGraph(AgentState)
g.add_node("plan", plan_node)
g.add_node("act", act_node) # 调工具
g.add_node("reflect", reflect_node) # 检查结果,决定继续还是收敛
g.set_entry_point("plan")
g.add_edge("plan", "act")
g.add_conditional_edges("reflect", lambda s: "act" if s["plan"] else END)
app = g.compile(checkpointer=...) # 状态可持久化、可恢复
状态显式化带来三个工程收益:可测试(给定状态断言转移)、可恢复(checkpoint 恢复中断的长任务)、可观测(每步的状态快照就是 trace)。
框架的真实成本
框架不是免费的,尤其要警惕:
- 抽象税:报错栈穿过五层装饰器,定位问题从"看代码"变成"考古"
- 版本快跑:0.x 版本间 breaking change 频繁,锁版本是纪律
- 调试黑盒:框架替你发的 prompt,优化时找不着北
选型的务实标准
我的判断矩阵,按场景给答案:
| 场景 | 建议 |
|---|---|
| 单次调用 + 结构化输出 | 直连官方 SDK,不需要任何框架 |
| 固定流程的 RAG 管道 | 轻框架或自写 200 行胶水,够用且全透明 |
| 多步 Agent、有循环分支 | LangGraph(状态机范式目前最成熟) |
| 需要跨团队复用组件/观测体系 | 框架生态(LangSmith 观测、组件市场)开始值回票价 |
先写无框架版本,痛了再上框架——很多时候你只是需要一个 while 循环加一个工具分发表,那 100 行自己写的代码比任何框架都好维护。
结语
LangChain 的演进史其实是整个行业的认知史:从"prompt 是管道"到"Agent 是状态机"。理解这条线,用不用框架、用哪家框架,都只是实现细节。