前言
2022 年 ChatGPT 横空出世,Transformer 架构开启了 AIGC 时代。而 LangChain 作为 AI 应用开发框架,实际上比 ChatGPT 更早推出了 1.0+ 版本。
LangChain = Language + Chain,它通过统一的接口连接不同的 LLM(大语言模型),并将复杂的 AI 任务拆分成可执行的链式工作流,就像 n8n、Coze 这样的节点式工作流工具。
不用框架(直接调用 API)
// 需要手动处理所有细节
import fetch from 'node-fetch';
async function chatWithoutFramework(question) {
const response = await fetch('https://api.deepseek.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.DEEPSEEK_API_KEY}`
},
body: JSON.stringify({
model: 'deepseek-reasoner',
messages: [
{ role: 'user', content: question }
],
temperature: 0.7
})
});
const data = await response.json();
return data.choices[0].message.content;
}
// 使用
const answer = await chatWithoutFramework('你好');
直接调用大模型 API 的方式需要手动处理 HTTP 请求、响应解析、错误处理等底层细节,不仅繁琐而且容易出错。
同时,不同平台(如 OpenAI、DeepSeek、Claude)的接口格式各不相同,导致代码难以复用,每次切换模型都需要重写大量逻辑,增加了开发和维护成本。
用 LangChain
import { ChatDeepseek } from '@langchain/deepseek';
const model = new ChatDeepseek({
model: 'deepseek-reasoner',
apiKey: process.env.DEEPSEEK_API_KEY
});
// 使用 - 超级简单
const response = await model.invoke('你好');
console.log(response.content);
相比之下,使用 LangChain 可以极大简化这一过程。它封装了各类模型的调用细节,提供统一的编程接口,开发者只需几行代码即可完成模型调用。无论是更换模型还是切换服务商,都无需修改核心逻辑,显著提升了开发效率与代码的可维护性。
初始化langchain
现在我会将带你从零开始,使用 LangChain 快速接入 DeepSeek 模型,体验高效、整洁的大模型调用方式
我们首先初始化项目:
npm init -y
接着安装 LangChain 核心包:
npm i langchain
然后安装 DeepSeek 的专用集成模块:
npm i @langchain/deepseek
最后,为了方便管理 API 密钥等敏感信息,我们安装 dotenv 来加载环境变量:
npm i dotenv
我们要在.env下加入我们deepseek的APIKEY:
DEEPSEEK_API_KEY=your-api-key
我们可以先创建一个 main.js 文件,快速体验 LangChain 开发的简洁与高效。
import 'dotenv/config';
import { ChatDeepSeek } from '@langchain/deepseek';
const model = new ChatDeepSeek({
model:'deepseek-reasoner',
temperature:0,
// langchain 帮我们适配了市面上大多数的 llm
// baseURL ? 不用 适配器模式 Provider
// apiKey
})
// invoke 调用
const res = await model.invoke('用一句话解释什么是RAG?');
console.log(res.content);
PromptTemplate —— 提示词模板化
问题场景
直接拼接提示词存在明显局限:
const question = '什么是闭包?';
const prompt = `你是一个前端面试官,请用不超过50字回答:${question}`;
// 问题:硬编码、缺乏灵活性、难以复用
这种方式将逻辑与提示内容耦合在一起,一旦需求变化(比如角色、字数限制或问题类型),就需要修改代码,维护成本高。
解决方案
使用 PromptTemplate 实现提示词的模板化管理:
import { PromptTemplate } from '@langchain/core/prompts';
// 定义模板,使用 {变量名} 作为占位符
const prompt = PromptTemplate.fromTemplate(`
你是一个{role}。
请用不超过 {limit} 字回答以下问题:
{question}
`);
// 动态传入变量进行填充
const promptStr = await prompt.format({
role: '前端面试官',
limit: '50',
question: '什么是闭包?'
});
const res = await model.invoke(promptStr)
console.log(res.content);
// 生成结果:
// "你是一个前端面试官。请用不超过 50 字回答以下问题:什么是闭包?"
调用
.format()方法,传入一个对象,键名对应模板中的占位符,LangChain 会自动替换。
核心优势
可复用:定义一次模板,适用于多种输入组合
可维护:提示词逻辑集中管理,便于迭代和调试
动态灵活:根据运行时上下文生成定制化提示
结构清晰:支持变量校验,减少遗漏或拼写错误,提升健壮性
RunnableSequence(或 .pipe())—— 简洁的链式调用
问题场景
典型的 AI 应用往往包含多个步骤:
- 格式化提示词
- 调用大模型
- 处理返回结果
如果手动串联这些步骤,代码会显得分散且难以复用:
const formattedPrompt = await prompt.format({ topic: '闭包' });
const response = await model.invoke(formattedPrompt);
const answer = response.content;
// 问题:逻辑割裂,不易封装,难以测试或复用
更糟糕的是,若在 RunnableSequence.from() 中直接递归调用自身(例如 fullChain.invoke(...)),会导致无限嵌套,甚至内存溢出:
// 错误示例:自引用导致栈溢出
const fullChain = RunnableSequence.from([
(input) => fullChain.invoke({ topic: input.topic })
]);
正确的做法是组合独立的子链,而非自我调用。
解决方案:使用 .pipe() 构建工作流
LangChain 提供了 .pipe() 方法,可将多个可运行单元(如 PromptTemplate、LLM、自定义函数等)像管道一样连接起来,形成自动流转的处理链。
import 'dotenv/config';
import { ChatDeepSeek } from '@langchain/deepseek';
import { PromptTemplate } from '@langchain/core/prompts';
const model = new ChatDeepSeek({
model: 'deepseek-reasoner',
temperature: 0.7,
});
const prompt = PromptTemplate.fromTemplate(`
你是一个前端专家,用一句话解释:{topic}
`);
// 使用 .pipe() 将提示模板与模型连接成一条链
const chain = prompt.pipe(model);
// 一行调用,自动完成格式化 + 模型推理
const response = await chain.invoke({ topic: '闭包?' });
console.log(response.content); // 注意:DeepSeek 返回的是 .content,不是 .text
核心优势
✅ 自动流转:各步骤按顺序执行,无需手动传递中间结果
✅ 代码简洁:多步逻辑压缩为一行调用
✅ 高度可组合:每个节点都是独立的 Runnable,可自由拼接、测试或替换
RunnableSequence.from —— 构建复杂多步骤链
问题场景
在真实业务中,AI 任务往往不是“问一句答一句”那么简单,而是包含多个处理阶段。例如:
用户问题 → 详细解释 → 提炼要点 → 格式化输出
如果用传统方式手动串联,代码会变得冗长且难以维护:
// 步骤1:生成详细解释
const explanation = await explainChain.invoke({ topic: '闭包' });
// 步骤2:基于解释生成摘要
const summary = await summaryChain.invoke({ explanation: explanation.content });
// 步骤3:手动拼接最终结果
const result = `知识点: ${explanation.content} 总结: ${summary.content}`;
// 问题:步骤之间强耦合,逻辑分散,难以复用或测试
这种写法不仅可读性差,而且一旦流程变更(比如增加校验、重试或日志),就需要到处修改。
解决方案:使用 RunnableSequence.from() 编排多步流水线
LangChain 的 RunnableSequence.from() 允许我们将多个处理单元(如提示模板、模型调用、自定义函数)组合成一条声明式的执行链,自动传递中间结果。
import { RunnableSequence } from '@langchain/core/runnables';
import { PromptTemplate } from '@langchain/core/prompts';
import { ChatDeepSeek } from '@langchain/deepseek';
// 初始化模型
const model = new ChatDeepSeek({
model: 'deepseek-reasoner',
temperature: 0.7,
});
// 1. 详细解释模板
const explainPrompt = PromptTemplate.fromTemplate(`
你是一个前端专家,请详细介绍以下概念:{topic}
要求:覆盖定义、原理、使用方式,不超过300字。
`);
// 2. 摘要提炼模板
const summaryPrompt = PromptTemplate.fromTemplate(`
请将以下概念解释总结为三个核心要点(每点不超过20字):
{explanation}
`);
// 创建子链
const explainChain = explainPrompt.pipe(model);
const summaryChain = summaryPrompt.pipe(model);
// 构建完整处理链
const fullChain = RunnableSequence.from([
// 步骤1:获取详细解释
async (input) => {
const res = await explainChain.invoke({ topic: input.topic });
return res.content; // 提取文本内容作为下一步输入
},
// 步骤2:基于解释生成摘要,并格式化最终输出
async (explanation) => {
const res = await summaryChain.invoke({ explanation });
return `知识点: ${explanation}\n总结: ${res.content}`;
}
]);
// 一行调用,自动执行全流程
const response = await fullChain.invoke({ topic: '闭包' });
console.log(response);
deepseek给我生成的内容如下:
知识点:**闭包(Closure)** 指一个函数能够记住并访问其词法作用域,即使该函数在其词法作用 域之外执行。
**定义与原理**:在JavaScript中,函数在创建时会绑定其所在的词法环境(作用域链)。当一个函数内部定义了另一个函数,且内层函数引用了外层函数的变量时,就形成了闭包。这使得外层函数的作用域在内层函数执行期间依然被保留,不会被垃圾回收。
**使用方式**:
1. **数据封装/私有变量**:通过闭包创建只有特定函数能访问的“私有”数据。
```javascript
function createCounter() {
let count = 0; // 私有变量
return function() {
return ++count;
};
}
```
2. **函数工厂与柯里化**:基于不同参数动态生成特定功能的函数。
3. **模块模式**:在模块化编码中隔离作用域,避免全局污染。
闭包是JavaScript实现作用域控制、数据封装的基石,但也需注意不当使用可能导致内存无法释放。 总结: 1. 函数能记住并访问其词法作用域。
2. 内层函数引用外层变量形成闭包。
3. 用于封装私有变量,需注意内存释放。
优势
流程清晰:每一步职责单一,易于理解与调试
自动衔接:前一步的输出自动作为后一步的输入
高度可组合:子链可独立测试、复用或替换
易于扩展:后续可轻松插入日志、验证、缓存等中间件
通过 RunnableSequence.from(),我们可以将复杂的 AI 工作流转化为声明式、模块化、可维护的代码结构,真正实现“像搭积木一样构建智能应用”。
总结
通过本文的实战演示,我们从最基础的模型调用出发,逐步深入到提示词模板化(PromptTemplate)、链式工作流(.pipe())以及多步骤复杂流程编排(RunnableSequence.from),完整体验了 LangChain 如何将原本琐碎、易错的大模型交互过程,转化为模块化、可组合、可维护的开发范式。
LangChain 的核心价值,并不在于“封装了一个 API”,而在于它提供了一套面向 AI 应用的工程化思维:把提示词当作配置、把模型调用当作节点、把业务逻辑拆解为流水线。这种设计不仅大幅降低了开发门槛,更重要的是让 AI 应用具备了传统软件应有的可测试性、可复用性和可扩展性。
无论是构建一个简单的问答机器人,还是设计支持 RAG、工具调用、多轮对话的智能客服系统(如我在 从 TRAE 脚手架 到 Coze 智能体 :打造支持 RAG 的编程教育客服系统中所实践的),LangChain 都能为你提供坚实的底层抽象和灵活的组合能力。
未来,随着更多 LLM 厂商和工具生态的接入,LangChain 这类框架将成为连接“模型能力”与“真实业务”的关键桥梁。而作为开发者,掌握这套“链式思维”,或许就是迈入下一代应用开发的第一步。