1. 概述
通过上一章的学习,我们知道,优秀的 AI Agent 需要一个强大的内存调度架构。而 langChain 和 langGraph 则为此提供了具体的抽象能力,是构建 AI 伴侣 Agent 的得力助手
当然,langChain/langGraph* 并非构建 Agent 的必备项,当我们的 Agent 比较简单时,我们可以自己轻松处理任务节点的编排,之所以选择 langChain/langGraph 是因为我们预设了我们的 Agent 在未来要面对复杂的编排和复杂的调度逻辑*
假设用户向 AI 伴侣发送了一句话:
你还记得我最喜欢什么蛋糕吗?
系统要给出自然且可信的回答,通常需要完成几项工作:理解用户正在询问过去的偏好,查询长期记忆,把检索结果和最近对话整理成上下文,调用模型生成回复,并把这一轮产生的新状态保存下来。
我们可以从需求的发展历程来理解 LangChain 和 LangGraph 的定位
刚开始开发时,需求非常简单,这些步骤可以 仅仅写在一个请求函数里
但是,当越来越多类似的需求出现时,我们可能就会考虑将这些步骤进行抽象,并形成一个一个可复用的功能模块,并在此基础之上快速组装出新的 Agent,我们需要统一接入模型、定义工具,组织功能节点之间的先后执行顺序,这个时候,我们就可以用到 langChain
继续发展下去,系统还会出现条件路由、跨请求状态、节点中断和恢复执行等需求。这时问题已经从 怎样组合能力 变成 怎样控制流程 ,LangGraph 则为这种显式调度提供了具体实现
2. 链式调用
链式调用是 langChain 提供的一种非常基础的能力,它允许我们通过 pipe() 方法将多个 Runnable 连接在一起,形成一个链式调用。
chain.ts
import { StringOutputParser } from '@langchain/core/output_parsers'
import { createDemoChatModel } from '../_shared/create-demo-chat-model'
import { companionPrompt } from './prompt'
interface RunCompanionChainOptions {
question: string
settings: any
abortSignal: AbortSignal
}
export async function runCompanionChain({ question, settings, abortSignal }: RunCompanionChainOptions) {
const model = await createDemoChatModel(settings)
const parser = new StringOutputParser()
// !mark
const chain = companionPrompt.pipe(model).pipe(parser)
const content = await chain.invoke(
{ question }, // 为用户的输入,由 UI 组件传入
{ signal: abortSignal },
)
return { content, model: settings.modelId }
}
prompt.ts
import { ChatPromptTemplate } from '@langchain/core/prompts'
export const companionPrompt = ChatPromptTemplate.fromMessages([
['system', '你是一名温和、自然的陪伴型助手。'],
['human', '{question}'],
])
pipe() 连接的是三个节点。前一个节点的输出会成为后一个节点的输入,因此调用方只需要向整条链提供初始参数。
这里所说的固定,指的是执行节点流程的固定,而不是模型每次都会返回完全相同的文字。无论用户输入什么,数据都会按照 Prompt → Model → Parser 的顺序向后流动;链本身不会临时决定跳过 Parser,也不会自行插入一个工具节点
这种结构适合 Prompt 格式化、文本改写、摘要、分类和结构化解析等步骤明确的任务。链也可以携带历史消息和使用流式输出,但这些能力不会改变它的固定执行关系。
下面的案例把最近对话放入 MessagesPlaceholder,再通过 prompt.pipe(model).pipe(parser) 生成回复。你可以通过这个案例观察链式节点的固定调用
连续发送两条消息可以观察历史如何进入下一轮;模型选择器右侧的重置按钮可以清空这个案例的对话历史
3、createAgent
当我们无法预先固定执行节点流程时,单向链式调用就无法满足需求了。比如,当用户的输入是:
你还记得我最喜欢什么蛋糕吗?
我们需要去查询历史记忆,并根据查询到的结果生成回复。但是如果用户输入的是:
睡前给我一句简短的晚安问候。
那我们在实现上,就不应该去查询历史记忆,而是应该直接生成回复
在 langChain 中,我们可以通过 createAgent() 来决定是否调用工具。如下案例所示,观察 2 次不同的输入,节点执行的流程是否相同
agent.ts
import { createAgent } from 'langchain'
import { searchMemory } from './search-memory-tool'
const agent = createAgent({
model: 'deepseek-v4-flash',
tools: [searchMemory],
systemPrompt: `你是一名陪伴型助手。
当用户询问过去的偏好或共同经历时,先调用记忆工具核实,不要猜测。`,
})
const result = await agent.invoke({
messages: [{
role: 'user',
content: '你还记得我最喜欢什么蛋糕吗?',
}],
})
search-memory-tool.ts
import { tool } from 'langchain'
import { z } from 'zod'
export const searchMemory = tool(
async ({ query }) => {
if (query.includes('蛋糕')) {
return '用户最喜欢巧克力榛子蛋糕,不喜欢草莓奶油。'
}
return '没有找到相关记忆。'
},
{
name: 'search_memory',
description: '查询与当前用户有关的长期记忆',
schema: z.object({
query: z.string().describe('需要检索的记忆主题'),
}),
},
)
tool() 把普通函数转换成模型能够理解的工具。名称和描述帮助模型判断工具用途,Zod Schema 则约束调用参数。
这段循环是 createAgent() 的行为,不是所有 langChain 程序的默认形态。langChain* 的 createAgent() 底层使用 langGraph 的运行时,但开发标准工具型 Agent 时,通常只需要使用 langChain 提供的高层 API。只有当业务需要显式控制节点、条件分支、中断和恢复时,才需要直接进入 langGraph*。
4. LangGraph
注意观察上面的代码,你会发现,是否调用 searchMemory 工具,是由模型通过提示词来决定的,而不是基于我们的代码逻辑决定的
但是更多时候,我们做的 Agent 产品要求某些步骤和分支必须由业务规则控制,那这个时候,就需要把处理过程显式建模出来,这就是 langGraph 的用武之地了。
angGraph 使用三个核心概念描述这类流程:
State是当前工作流的数据快照,节点通过它交换消息和业务状态Node是执行单元,可以调用模型、数据库、工具或普通业务函数Edge描述节点之间的流转关系,可以是固定连接,也可以根据 State 动态选择分支
利用 langGraph,我们可以对流程进行更精细的控制,例如随时可以中断正在执行的节点,中断之后,还可以从当前中断的节点继续执行,而不是从头开始重新执行
下面这个案例是一个可以被中断的案例,当用户输入
你还记得我最喜欢什么蛋糕吗?
执行流程我们拆成四个明确节点:安全检测、意图识别、长期记忆查询和回复。长期记忆工具由 langChain tool() 定义,当前返回一条写死的模拟记忆;langGraph 负责节点顺序、条件路由和 checkpoint
案例默认不会预设固定的中断节点。用户不做额外操作时,工作流会依次执行并自然到达最终回复;执行过程中主动点击输入框最右侧的停止按钮,案例会终止当前 graph run,并从 Checkpointer 读取仍在 next 中的当前节点。时间线把这个节点标记为“执行中断”,
中断之后,当用户输入 继续执行 时,langGraph 会携带前序节点已经写入 State 的安全结果、意图和记忆,从被中断的节点重新执行,而不是创建一张新图
完整案例代码逻辑非常复杂,这里就不再一一展示代码,后续章节会详细介绍 langGraph 的用法
5. 总结
LangChain 和 LangGraph 处在模型应用技术栈的不同层级。LangChain 通过 Runnable 与 LCEL 组合固定的数据处理链,也通过 createAgent() 提供预构建的工具调用循环;LangGraph 提供状态与工作流运行时,让开发者精确控制节点、分支、循环、持久化和恢复过程。
步骤固定的模型管线可以从 Runnable 与 LCEL 开始,标准工具调用可以从 createAgent() 开始。当记忆检索、情绪更新、安全检查或人工确认需要按照明确的业务顺序执行时,再使用 StateGraph 描述完整流程。外层图与节点内 Agent 也可以组合,从而兼顾整体流程的确定性与局部任务的灵活性