LangChain 是当前 AI 应用开发中最受欢迎的框架之一。它以“语言(lang)+ 链(chain)”为核心理念,通过模块化、可组合的方式,将大语言模型(LLM)的能力封装成可复用、可配置、可串联的工作单元。本文将围绕一套由浅入深的代码示例,系统讲解如何使用 LangChain 构建结构清晰、逻辑明确的 AI 应用,并完整保留原始代码中的注释,帮助读者深入理解每一步的设计意图。
环境准备与基础调用
在开始之前,我们需要完成基本的项目初始化和依赖安装:
npm init -y
在 package.json 中添加 "type": "module" 以启用 ES 模块语法,并安装必要的依赖:
npm install langchain @langchain/deepseek dotenv
.env 文件用于存放 API 密钥等敏感信息。LangChain 能自动从 process.env 中读取对应服务所需的密钥,无需手动传入。
最简单的调用方式如下(main.js):
import 'dotenv/config'
import { ChatDeepSeek } from '@langchain/deepseek'
const model = new ChatDeepSeek({
model: 'deepseek-reasoner',
temperature: 0
// baseURL ?
// apiKey ? 不需要传入 会自动查找
// 适配器模式
// langchain 帮我们适配了市面上大多数的llm deepseek Qwen
})
// invoke 执行调用
const res = await model.invoke('用一句话解释什么是RAG ?')
console.log(res.content)
这段代码展示了 LangChain 的适配器模式:无论底层使用的是 DeepSeek、Qwen 还是其他厂商的大模型,LangChain 都提供了统一的接口(如 ChatDeepSeek、ChatQwen),开发者只需更换导入语句和构造函数即可切换模型,极大降低了集成成本。注释中提到“apiKey 不需要传入 会自动查找”,这正是通过 dotenv/config 加载 .env 文件后,LangChain 自动从环境变量中读取密钥的能力。
引入提示词模板:结构化输入
直接拼接字符串作为提示词容易出错且难以维护。LangChain 提供了 PromptTemplate 模块,用于定义带有占位符的结构化提示模板。
在 1.js 中,我们定义了一个通用的角色问答模板:
import 'dotenv/config'
// 导入.env中的环境变量
import { ChatDeepSeek } from '@langchain/deepseek'
// 适配器 Provider 帮我们省去了适配工作
// 适配大模型也是工作量
import { PromptTemplate } from '@langchain/core/prompts'
//提示词模块
// fromTemplate static方法 是属于类的 不是实例的
const prompt = PromptTemplate.fromTemplate(`
你是一个{role},
请用不超过{limit}字回答以下问题:
{question}
`)
const promptStr = await prompt.format({
role: '前端面试官',
limit: '50',
question: '什么是闭包'
})
// const promptStr2 = await prompt.format({
// role: '后端面试官',
// limit: '50',
// question: '什么是MVC'
// })
// console.log(promptStr)
const model = new ChatDeepSeek({
model: 'deepseek-reasoner',
temperature: 0.7
})
const res = await model.invoke(promptStr)
console.log(res.content)
这里的关键在于注释所强调的:“fromTemplate static方法 是属于类的 不是实例的”。这意味着我们直接通过类调用该方法创建模板,而不需要先实例化 PromptTemplate。同时,注释也指出“适配大模型也是工作量”,LangChain 正是通过封装这些细节,让开发者聚焦于业务逻辑而非底层适配。
通过 .format() 方法,可以将实际参数注入模板,生成完整的提示字符串。这种方式不仅提升了提示词的可读性和复用性,还避免了手动字符串拼接可能引入的格式错误。
构建第一个 Chain:自动化提示生成与调用
随着应用复杂度提升,手动调用 .format() 再传给模型显得冗余。LangChain 的核心思想之一就是将多个操作节点连接成链(Chain) ,实现端到端的自动化。
在 2.js 中,我们使用 RunnableSequence 构建了一个简单的链:
// chain
// AI 业务是复杂的 任务的拆分 分步骤处理 每一步做到可执行可配置
// 连接起来 形成工作流 -> Agent -> AI应用
// chain 是有先后顺序 有流程的 组织起来的
import 'dotenv/config'
import { ChatDeepSeek } from '@langchain/deepseek'
import { PromptTemplate } from'@langchain/core/prommts'
import { RunnableSequence } from '@langchain/core/runnables'
const model = new ChatDeepSeek({
model: 'deepseek-reasoner',
temperature: 0.7 // 随机性
})
const prompt = PromptTemplate.fromTemplate(`
你是一个前端专家,用一句话解释:{topic}
`)
// prompt 模版生成节点 -> model 代表LLM节点 -> invoke 结束节点 调用大模型 发起请求
// pipe 管道 连接节点 形成工作流 连接成一个顺序执行的链 chain
const chain = prompt.pipe(model)
console.log(chain, chain instanceof RunnableSequence)
// RunnableSequence 构造函数 验证chain是RunnableSequence的实例 说明它是一个可运行的有序工作流
// runnable sequencial workflow
// SequencialChain
const response = await chain.invoke({
topic: '闭包'
})
// 输入 -> prompt.format() -> 生成完整prompt -> model.invoke() -> 输出
/*
在这里没有手动调用prompt.format() 而是自己在chain.invoke({ topic: '闭包' }) 传入参数
这背后是langchain自动完成了格式化操作
langchain在RunnableSequence执行时 自动识别PromptTemplate需要的输入变量(如 topic)
并调用其内部的.invoke() 或 .format() 方法完成模版渲染 再将结果传递给下一个节点(LLM)
*/
console.log(response.content)
注释清晰地描述了 Chain 的本质:“AI 业务是复杂的,任务的拆分,分步骤处理,每一步做到可执行可配置,连接起来形成工作流”。prompt.pipe(model) 创建了一个顺序执行的工作流:输入 → 提示模板渲染 → 模型调用 → 输出。
特别值得注意的是,注释解释了为何无需手动调用 .format():“langchain在RunnableSequence执行时自动识别PromptTemplate需要的输入变量(如 topic),并调用其内部的 .invoke() 或 .format() 方法完成模版渲染,再将结果传递给下一个节点(LLM)”。这种自动化机制大大简化了开发流程。
此外,通过 chain instanceof RunnableSequence 的验证,确认了所构建的对象确实是一个可运行的有序工作流,体现了 LangChain 对类型安全和可预测性的重视。
多阶段 Chain:任务拆解与结果加工
真实场景中,单一调用往往无法满足需求。例如,我们可能希望先让模型详细解释一个概念,再对其输出进行摘要。这就需要多阶段 Chain。
在 3.js 中,我们定义了两个独立的子链:
import 'dotenv/config'
import { ChatDeepSeek } from "@langchain/deepseek"
import { PromptTemplate } from '@langchain/core/prompts'
import { RunnableSequence } from "@langchain/core/runnables"
// AI 应用的编程方式
// LLM 黑盒 打开 key prompt
// langchain AI应用的工程化
const model = new ChatDeepSeek({
model: 'deepseek-reasoner',
temperature: 0.7
})
const explainPrompt = PromptTemplate.fromTemplate(`
你是一个前端专家,请详细介绍以下概念: {topic}
要求: 覆盖定义、原理、使用方法,不超过300字。
`)
const summaryPrompt = PromptTemplate.fromTemplate(`
请将以下前端概念解释总结为3个核心要点 (每点不超过20字):
{explanation}
`)
const explainChain = explainPrompt.pipe(model)
console.log(explainChain)
const summaryChain = summaryPrompt.pipe(model)
const fullChain = RunnableSequence.from([
(input) => explainChain.invoke({topic: input.topic}).then(res => res.text),
(explanation) => summaryChain.invoke({explanation}).then(res => `知识点: ${explanation} 总结: ${res.text}`)
])// 这里的explanation自动接收explainChain输出的解释文本
const response = await fullChain.invoke({
topic: '闭包'
})
console.log(response)
注释点明了 LangChain 的定位:“AI 应用的编程方式”、“LLM 黑盒打开”、“langchain AI应用的工程化”。这表明 LangChain 不仅是调用工具,更是工程实践的载体。
在这个例子中,fullChain 由两个异步函数组成:
- 第一个接收原始输入(如
{ topic: '闭包' }),调用explainChain并提取.text; - 第二个接收上一步的输出(即详细解释文本),作为
summaryChain的输入。
注释特别说明:“这里的explanation自动接收explainChain输出的解释文本”,体现了 Chain 之间数据流的自然衔接。
最终,整个流程实现了“解释 → 摘要”的两阶段处理,展示了如何将复杂任务分解为多个可管理的子任务,并通过 Chain 编排成完整工作流。
LangChain 的工程化优势
1. 统一接口,模型可插拔
无论是 DeepSeek、Qwen、OpenAI 还是本地部署的 Llama,LangChain 都通过 ChatModel 抽象层提供一致的 .invoke()、.stream() 等方法。切换模型只需修改两行代码:
// 从 DeepSeek 切换到 Qwen
import { ChatQwen } from '@langchain/qwen'
const model = new ChatQwen({ model: 'qwen-max', temperature: 0 })
这种“拔插式”设计让开发者能灵活应对模型迭代、成本变化或合规要求。
2. 提示工程结构化
PromptTemplate 不仅支持静态模板,还支持动态变量、条件逻辑,使提示词成为可版本控制、可测试的代码资产,而非散落在各处的魔法字符串。
总结:从调用到构建
回顾我们的四段代码及其详尽注释:
main.js展示了最基础的模型调用,并强调了适配器模式与自动密钥加载;1.js引入了结构化提示模板,突出fromTemplate的静态特性与复用价值;2.js实现了自动化的单链流程,解释了 Chain 如何自动完成提示渲染;3.js构建了多阶段、多任务的复合 Chain,体现任务拆解与数据流传递。
这正是 LangChain 学习路径的缩影:从“如何调用 LLM”走向“如何构建 AI 应用” 。
LangChain 并不试图取代 LLM,而是为其提供工程脚手架。它把提示词、模型、工具、记忆等元素抽象为可组合的积木,让开发者能像搭建流水线一样构建智能应用。在这个 AIGC 时代,掌握 LangChain 这样的框架,意味着你不仅能使用 AI,更能工程化地驾驭 AI。
对于前端或全栈开发者而言,LangChain 的 Node.js 支持使其无缝融入现有技术栈。无论是构建智能客服、文档助手,还是自动化内容生成系统,LangChain 都提供了一条清晰、稳健的实现路径——而这一切,都始于一行 .pipe() 和一条精心设计的提示模板。