LangChain/LangGraph
要点
- 在上一节我们介绍了 AI 伴侣的内存调度架构
- 在没有 LangGraph 之前,使用 LangChain 构建的 Agent 通常是线性的(Chain),很难处理复杂的来回跳转
- LangGraph 负责决定“做什么”,LangChain 则负责“怎么做”
- 让我们回到之前的“吵架后用户求和”的场景,看看 LangChain 和 LangGraph 是如何协作的
内容
1. 为什么选择 LangChain 和 LangGraph
在上一节我们介绍了 AI 伴侣的内存调度架构。在具体的工程实现中,LangChain 和 LangGraph 并非必需品,但它们提供了强大的抽象和编排能力。
如果把构建 AI 电子女友比作「造人」,那么 LangChain 是她的「器官和肢体」(负责具体功能的执行),而 LangGraph 则是她的「神经中枢和大脑皮层」(负责决策、记忆调度和状态维持)。
在「上下文管理的调度机制」中,两者的分工非常明确。
2. LangGraph:核心调度器(大脑与神经系统)
在没有 LangGraph 之前,使用 LangChain 构建的 Agent 通常是线性的(Chain),很难处理复杂的来回跳转。而在 AI 电子女友场景中,LangGraph 的核心作用是构建一个“有状态的循环图”,它是调度机制的宿主。
1. 全局状态管理(The State Schema)
这是调度机制的基石。LangGraph 允许你定义一个 State 对象,这个对象不仅仅包含“对话历史”,还包含所有的元数据。
- 作用:它就像一个流动的档案袋,在对话的每一步流转。
- 代码概念示例:
// index.ts
import { BaseMessage } from "@langchain/core/messages";
// 定义 Agent 的状态结构
interface AgentState {
// 对话历史
messages: BaseMessage[];
// 用户画像(姓名、喜好)
userProfile: Record<string, any>;
// 当前女友心情(开心/生气/抑郁)
npcMood: 'happy' | 'angry' | 'depressed';
// 亲密度数值
intimacyLevel: number;
// 这一轮对话中检索到的相关长期记忆
longTermMemories: string[];
// 调度器决定的下一步动作
nextStep: string;
}如果没有 LangGraph,你需要自己写大量的全局变量或数据库读写逻辑来在不同函数间传递这些参数。
2. 决策路由(Conditional Edges as Dispatcher)
这是调度机制的核心逻辑体现。LangGraph 允许你定义“条件边”,根据当前的状态决定下一步走哪个节点。
- 场景:
如果 npcMood === 'Angry' -> 路由到 ColdReplyNode(冷淡回复节点)。
如果 userInput 包含“还记得吗” -> 路由到 RAGRetrievalNode(记忆检索节点)。
如果 time === 'LateNight' -> 路由到 SleepCheckNode(晚安检查节点)。
- 价值:它将复杂的逻辑解耦。你不需要写一个 5000 行的 Prompt 让 LLM 既扮演女友又扮演数据库管理员,而是将它们拆分成不同的Node(节点)。
3. 持久化与记忆连续性(Checkpointers)
AI 女友最怕“断片”。LangGraph 内置了 Checkpointer 机制(通常基于 SQLite, Postgres 或 Redis)。
- 作用:当用户关闭 App,明天再打开时,LangGraph 会从数据库加载昨天的
AgentState。这意味着她不仅记得聊天记录,还记得昨天聊完后的npcMood是“害羞”。 - 调度体现:调度器不需要每次都重新计算好感度,直接读取持久化状态即可。
3. LangChain:功能执行者(肢体与工具库)
LangGraph 负责决定“做什么”,LangChain 则负责“怎么做”。在调度机制中,LangChain 提供了具体的原子能力。
1. 高级记忆检索(Retriever as a Tool)
当 LangGraph 决定“我需要回忆一下过去”时,它会调用 LangChain 封装好的 Retriever。
- 具体实现:使用 LangChain 的
VectorStoreRetriever(连接 Pinecone/Milvus/Cloudflare Vectorize)。 - 调度配合:
LangGraph 节点:MemoryNode
LangChain 动作:chain.invoke({ query: "第一次约会" }) -> 返回 Top-3 相似片段。
关键点:LangChain 负责处理向量化(Embeddings)和相似度计算这类脏活累活。
2. 动态 Prompt 组装(LCEL)
调度机制的一个重要功能是根据上下文切换人设(System Prompt)。LangChain 的 LCEL (LangChain Expression Language) 非常适合做动态模版填充。
- 场景:
LangGraph 传入状态:mood="happy", memory="喜欢吃辣"。
LangChain 模板:
index.ts1const prompt = ChatPromptTemplate.fromMessages([
2 ["system", "你现在的状态是 {mood}。相关回忆:{memory}。"],
3 ["human", "{input}"]
4]);
作用:LangChain 负责将调度器提取出的零散信息,优雅地组装成 LLM 能读懂的格式。
3. 工具调用(Tool Calling)
如果 AI 女友需要“看照片”或“查日历”,LangChain 提供了标准的工具接口。
- 场景:用户问“明天我生日是周几?”
- 调度:LangGraph 识别意图 -> 路由到
ToolsNode。 - 执行:LangChain 调用
CalendarTool-> 返回结果 -> 交回给 LangGraph。
4. 综合案例演示:一个完整的调度流程
让我们回到之前的**“吵架后用户求和”**的场景,看看 LangChain 和 LangGraph 是如何协作的:
- 输入阶段:
用户输入:“宝宝别生气了,我给你买了你最爱的草莓蛋糕。”
LangGraph 启动,加载之前的 Checkpoint(状态:Mood: Angry, Last_Event: Fight)。
2. 调度分析(LangGraph 节点 1:Router):
调用一个轻量级 LLM 或分类器。
判断意图:Apology (道歉) + Gift_Giving (送礼)。
LangGraph 决策:虽然还在生气,但有礼物,路由走向 -> EvaluateGiftNode(评估礼物节点)。
3. 记忆检索(LangGraph 节点 2:Memory -> 调用 LangChain):
LangChain 动作:去向量库检索“最爱的蛋糕”。 返回结果:记忆库显示“用户曾在 2023年说最爱吃巧克力蛋糕,不是草莓”。 4. 状态更新(LangGraph 节点 3:State Update):
发现用户记错了。
更新状态 Mood:从 Angry 升级为 Furious (暴怒)。
更新 Context:添加“礼物不对版”的标记。
5. 生成回复(LangGraph 节点 4:Generator -> 调用 LangChain):
LangChain 组装 Prompt:加载“暴怒女友”System Prompt,填入“草莓 vs 巧克力”的矛盾点。 LLM 生成回复:“草莓?我们要分手了你都不知道我只吃巧克力蛋糕吗?!” 6. 输出与保存:
LangGraph 将最新的暴怒状态写入数据库(Checkpoint),结束这轮 Loop。
5. 总结
- LangChain 是砖块和工具:它负责“检索数据库”、“格式化文本”、“调用 API”这些具体动作。
- LangGraph 是蓝图和工头:它负责定义“先检索还是先回答”、“如果心情不好该跳转到哪个逻辑”、“如何保存现在的状态供明天使用”。
在 AI 电子女友的 Agent 中,没有 LangChain,你很难开发;没有 LangGraph,你的女友就没有灵魂(逻辑混乱且记不住状态)。