我会从 核心概念拆解 → 代码逐行解析 → 运行逻辑梳理 三个层面,带你彻底弄懂它。全程使用通俗语言,不跳过任何基础细节——哪怕你今天第一次听说 LangChain,也能看明白。
我们将从最简单的“一句话解释闭包”开始,再升级到更实用的“详细讲解 + 自动总结”工作流,让你真正理解 LangChain 如何让 AI 应用开发变得像搭积木一样简单。
一、先搞懂核心概念(代码的 “骨架”)
在看具体代码前,必须先建立几个关键认知。否则,代码会显得杂乱无章,像一堆零件堆在一起。
1. 什么是「Chain(链 / 工作流)」?
你的代码注释里其实已经点出了本质:
AI 业务复杂,需要分步骤、按顺序处理,每一步都是一个 “可执行、可配置” 的独立节点,把这些节点按顺序串联起来,就形成了 Chain(工作流 / 链条) 。
▶ 简单场景(单步 Chain)
你想让 AI 回答“什么是闭包?”,但要求它:
- 扮演前端专家
- 只用一句话回答
这就不能直接扔问题给大模型,而要:
构造提示词 → 调用模型 → 输出结果。
这就是一条最简单的 线性 Chain(Sequential Chain) 。
▶ 复杂场景(多步 Chain)
更真实的场景可能是:
先让 AI 详细讲解“闭包”(含定义、原理、用法,≤300 字),
再让它把讲解内容提炼为 3 个核心要点(每点 ≤20 字)。
这就需要 两个 AI 任务串联执行:
讲解 → 总结 → 拼接输出。
这正是 RunnableSequence 的用武之地。
✅ Chain 的价值:把复杂任务拆解为可复用、可组合的小单元,就像搭积木一样灵活。
2. 关键工具 / 类的作用(代码的 “零件”)
| 工具 / 类 | 核心作用 |
|---|---|
dotenv/config | 加载 .env 文件中的环境变量(如 API 密钥),避免硬编码泄露 |
ChatDeepSeek | 对接「深度求索(DeepSeek)」大模型的客户端,负责和大模型服务器通信 |
PromptTemplate | 提示词模板,用于规范化向大模型提问的格式,避免手动拼接字符串的混乱 |
RunnableSequence | 链式执行的核心类,负责将多个 “可运行节点” 按顺序串联,实现自动化工作流 |
pipe() 方法 | 简化版的 “节点连接工具”,本质是创建 RunnableSequence,把前一个节点的输出作为后一个节点的输入 |
invoke() 方法 | 启动工作流的 “开关”,传入初始参数,触发整个链条按顺序执行并返回结果 |
这些“零件”组合起来,就能搭建出一个自动化的 AI 应用流水线。
二、基础版:单步 Chain —— 一句话解释“闭包”
我们先从最简单的例子入手,建立直觉。
1. 加载环境变量(必备配置)
ts
编辑
import 'dotenv/config';
- 作用:自动加载项目根目录下的
.env文件。 - 为什么重要?
DeepSeek 的 API 密钥(如DEEPSEEK_API_KEY=xxx)属于敏感信息,绝不能写死在代码里。 - 没有这行会怎样?
后续调用大模型时因缺少密钥而认证失败,直接报错。
2. 导入需要的工具类
ts
编辑
import { ChatDeepSeek } from '@langchain/deepseek';
import { PromptTemplate } from '@langchain/core/prompts';
@langchain/deepseek:LangChain 官方为 DeepSeek 提供的适配模块。@langchain/core/prompts:处理提示词模板的核心能力。
💡 这些不是通用 JavaScript 功能,而是 LangChain 框架提供的“乐高积木”。
3. 创建提示词模板(规范提问格式)
ts
编辑
const prompt = PromptTemplate.fromTemplate(`
你是一个前端专家,用一句话解释: {topic}
`);
-
{topic}是一个“变量插槽”,后续可动态替换为“闭包”“事件循环”等。 -
好处:避免每次手写
"你是一个前端专家,请解释...",让提示词结构统一、易于维护。 -
✅ 示例:当传入
topic: '闭包',模板自动渲染为:“你是一个前端专家,用一句话解释: 闭包”
4. 初始化大模型
ts
编辑
const model = new ChatDeepSeek({
model: 'deepseek-reasoner', // 推理型模型,适合技术问答
temperature: 0.7, // 平衡严谨性与灵活性
});
- 相当于“创建了一个能和 DeepSeek 对话的机器人”。
temperature: 0.7:既不会死板重复,也不会胡说八道,非常适合技术解释。
5. 串联节点,形成工作流(核心:创建 Chain)
ts
编辑
const chain = prompt.pipe(model);
这是整段代码的灵魂所在。你可能会疑惑:“是不是先创建一条空链子,再把 prompt 和 model 接上去?”
答案是否定的!
▶ pipe() 干了什么?
-
一步到位创建完整链式工作流(Chain)。
-
同时完成两件事:
- 定义执行顺序:先执行
prompt,再执行model - 自动传递数据:
prompt的输出 → 自动作为model的输入
- 定义执行顺序:先执行
🔍 技术上,
prompt.pipe(model)等价于:ts 编辑 const chain = RunnableSequence.from([prompt, model]);所以
chain instanceof RunnableSequence会返回true。
▶ 为什么叫 “pipe(管道)”?
想象水流从水管一端流入,经过过滤器,再流出——pipe() 就是那根“水管”,确保数据按顺序、无损地从前一个节点流向后一个节点。
6. 启动工作流,传入参数并获取结果
ts
编辑
const response = await chain.invoke({ topic: '闭包' });
console.log(response.text);
-
await:因为调用大模型是异步操作(需要网络请求),必须等待响应。 -
chain.invoke(...):启动整个工作流的“开关”。 -
执行过程:
prompt渲染出完整提示词 → “你是一个前端专家,用一句话解释: 闭包”pipe()自动将提示词传给modelmodel调用 DeepSeek → 返回回答response.text是纯文本结果
✅ 示例输出:
“闭包是指一个函数能够访问并保留其定义时所在作用域的变量,即使该函数在其定义作用域外被调用的一种前端编程特性。”
三、进阶版:多步骤工作流 —— 讲解 + 总结
现在升级到真实场景:先详细讲解,再自动总结。
1. 新增依赖:引入 RunnableSequence
ts
编辑
import { RunnableSequence } from '@langchain/core/runnables';
- 用于串联多个异步任务,构建复杂工作流。
2. 定义两个提示词模板
(1)讲解模板:要求全面但简洁
ts
编辑
const explainPrompt = PromptTemplate.fromTemplate(`
你是一个前端专家,请详细介绍以下概念: {topic}
要求:覆盖定义、原理、使用方式,不超过300字。
`);
(2)总结模板:强制提炼要点
ts
编辑
const summaryPrompt = PromptTemplate.fromTemplate(`
请将以下前端概念解释总结为3个核心要点(每点不超过20字):
{explaination}
`);
注意:第二个模板的占位符是
{explaination}(拼写需一致),将由第一步的输出填充。
3. 创建两个单任务链
ts
编辑
const explainChain = explainPrompt.pipe(model); // 输入 topic → 输出详细讲解
const summaryChain = summaryPrompt.pipe(model); // 输入讲解 → 输出3个要点
每个 Chain 都是一个独立、可复用的 AI 任务单元。
4. 用 RunnableSequence 串联两步
ts
编辑
const fullChain = RunnableSequence.from([
// 第一步:执行讲解链
(input) => explainChain.invoke({ topic: input.topic }).then(res => res.content),
// 第二步:用讲解内容执行总结链,并拼接最终结果
(explaination) => summaryChain.invoke({ explaination }).then(res =>
`知识点: ${explaination}\n总结: ${res.content}`
)
]);
▶ 关键机制解析:
- 第一步输入:
input是fullChain.invoke({ topic: '闭包' })传入的对象。 - 数据流转:第一步返回的
res.content(即详细讲解文本)自动作为第二步的参数explaination。 - 异步处理:每个
.invoke()返回 Promise,用.then()提取文本内容。 - 结果拼接:最终返回包含“讲解 + 总结”的完整字符串。
🔑 核心思想:
RunnableSequence让多步骤 AI 任务像工厂流水线一样自动运行。
5. 执行完整工作流(必须包裹在 async 函数中)
ts
编辑
async function run() {
const response = await fullChain.invoke({ topic: '闭包' });
console.log(response);
}
run();
- 必须使用
async/await,因为涉及多次异步 AI 调用。 fullChain.invoke(...)触发整个链条:讲解 → 总结 → 拼接 → 返回。
四、整体运行逻辑梳理(从启动到输出)
基础版流程(单步 Chain):
text
编辑
加载 .env → 导入工具 → 创建 model/prompt → pipe() 串联 → invoke() 执行 → 输出
进阶版流程(多步 Chain):
text
编辑
1. 初始化:model + 两个模板 + 两个单链
2. 调用 fullChain.invoke({ topic: '闭包' })
↓
3. 第一步:explainChain 生成详细讲解(≤300字)
↓
4. 第二步:summaryChain 用讲解内容生成3个要点(每点≤20字)
↓
5. 拼接结果:`知识点: ...\n总结: ...`
↓
6. 控制台打印完整输出
整个过程全自动、无手动干预——这就是 LangChain 工作流的威力。
五、运行前提与完整代码
运行前提:
-
Node.js ≥ v18(支持 ES Module)
-
package.json中添加"type": "module" -
安装依赖:
bash 编辑 npm install dotenv @langchain/deepseek @langchain/core -
创建
.env文件:text 编辑 DEEPSEEK_API_KEY=你的_api_key(从 deepseek.com 获取)
完整可运行代码:
ts
编辑
import { ChatDeepSeek } from '@langchain/deepseek';
import { PromptTemplate } from '@langchain/core/prompts';
import 'dotenv/config';
import { RunnableSequence } from '@langchain/core/runnables';
// 1. 初始化模型
const model = new ChatDeepSeek({
model: 'deepseek-reasoner',
temperature: 0.7,
});
// 2. 定义提示词模板
const explainPrompt = PromptTemplate.fromTemplate(`
你是一个前端专家,请详细介绍以下概念: {topic}
要求:覆盖定义、原理、使用方式,不超过300字。
`);
const summaryPrompt = PromptTemplate.fromTemplate(`
请将以下前端概念解释总结为3个核心要点(每点不超过20字):
{explaination}
`);
// 3. 创建单任务链
const explainChain = explainPrompt.pipe(model);
const summaryChain = summaryPrompt.pipe(model);
// 4. 串联成完整工作流
const fullChain = RunnableSequence.from([
(input) => explainChain.invoke({ topic: input.topic }).then(res => res.content),
(explaination) => summaryChain.invoke({ explaination }).then(res =>
`知识点: ${explaination}\n总结: ${res.content}`
)
]);
// 5. 执行
async function run() {
const response = await fullChain.invoke({ topic: '闭包' });
console.log(response);
}
run();
六、运行结果示例(参考)
plaintext
编辑
知识点: 闭包是指函数能够访问其定义时所在的词法作用域,即使该函数在其词法作用域之外执行。原理:JavaScript 函数在创建时会形成词法环境,闭包会保留对外部词法环境的引用,使其变量不被垃圾回收。使用方式:可用于创建私有变量(如计数器)、延迟执行(如定时器回调)、模块化开发(隐藏内部逻辑),示例:function outer() { let a = 1; return function inner() { console.log(a++); }; } const fn = outer(); fn(); // 1。
总结: 1. 函数可访问自身定义时的词法作用域
2. 保留外部变量引用,避免被垃圾回收
3. 用于创建私有变量与模块化开发
七、核心概念总结表
| 概念 | 作用 | 类比 | |
|---|---|---|---|
| PromptTemplate | 结构化提示词,支持参数填充 | Word 模板 + 填空 | |
| ChatDeepSeek | DeepSeek 模型的封装客户端 | 数据库连接池 | |
| pipe() | 连接两个可运行单元 | Linux 管道 `cmd1 | cmd2` |
| RunnableSequence | 多步骤顺序执行的工作流 | 工厂流水线 | |
| invoke() | 启动整个 Chain 的“开关” | 按下启动按钮 |
八、LangChain 的真正价值
-
简单场景(一句话解释)→ 用
pipe()快速连接 -
复杂场景(讲解 + 总结 + 校验 + 格式化)→ 用
RunnableSequence精细编排 -
核心优势:
- 屏蔽底层细节(不用写
fetch) - 提供高层抽象(模板、链、工具)
- 支持灵活组合(节点可插拔、可复用、可测试)
- 屏蔽底层细节(不用写
🌟 建议:先理解手写 API 调用的原理,再用 LangChain 提效——知其然,更知其所以然。