LangChain / LangGraph
本节定位
很多人第一次接触 Agent 框架时,会把 LangChain 和 LangGraph 混在一起。
但从工程视角看,它们解决的重心并不完全一样:
- LangChain 更像“把常见组件串起来”
- LangGraph 更像“把复杂状态流画成图”
理解这两者的差别,比背接口重要得多。
学习目标
- 理解 LangChain 更适合哪些场景
- 理解 LangGraph 为什么更适合复杂状态流
- 看懂“链式抽象”和“图式抽象”的真实差别
- 学会判断什么时候应该从链式流程升级到图式流程
一、为什么会先有 LangChain,后来又有 LangGraph?
1.1 早期需求通常是线性的
很多 LLM 应用一开始都长这样:
- 接收输入
- 改写 query
- 检索文档
- 调模型回答
这类流程很像一条直线:
上一步输出,喂给下一步。
在这种情况下,“链(chain)”是一种很自然的抽象。
1.2 但系统很快就会变复杂
一旦你开始有这些需求:
- 如果检索为空怎么办?
- 如果回答不可信要不要重试?
- 要不要先工具调用,再回到问答?
- 某些情况要人工确认
流程就不再是直线了,而会变成:
- 有分支
- 有状态
- 有回路
这时你需要的就不只是“把步骤串起来”,而是:
显式 表示状态和边。
这也是 LangGraph 之所以重要的根源。
二、先理解 LangChain:它到底在抽象什么?
2.1 它最适合的,是“组件管道”
LangChain 的典型长处在于把这些东西接起来:
- prompt 模板
- 模型调用
- 输出解析
- 检索模块
- 工具模块
你可以把它理解成:
一个偏组件编排层的框架。
它很像把“提示词、模型、检索器、解析器”这些零件做成了更容易拼装的积木。
2.2 一个最小链式思维示例
下面这个例子虽然不用真实 LangChain,但它已经有 LangChain 风格。
class SimpleChain:
def __init__(self, steps):
self.steps = steps
def run(self, value):
for step in self.steps:
value = step(value)
return value
def normalize_query(text):
return text.strip().lower()
def retrieve_docs(query):
if "退款" in query:
return {"query": query, "docs": ["课程购买后 7 天内可退款"]}
return {"query": query, "docs": []}
def format_answer(payload):
if payload["docs"]:
return f"根据资料:{payload['docs'][0]}"
return "没有找到相关资料。"
chain = SimpleChain([
normalize_query,
retrieve_docs,
format_answer
])
print(chain.run(" 退款政策是什么? "))