用 LangChain 构建 AI 应用:从提示工程到智能工作流实战

65 阅读9分钟

用 LangChain 构建 AI 应用:从框架理解到工程实践

第一部分:LangChain 是什么?—— AI 应用的“乐高底板”

在大语言模型(LLM)如 ChatGPT、DeepSeek 爆火之后,开发者很快发现一个问题:直接调用模型 API 只能做“一次性问答” ,而真实场景往往需要多轮交互、外部工具调用、记忆上下文、流程编排……这就像只有一块砖,却想盖一栋楼。

于是,LangChain 应运而生——它不是一个模型,而是一个专为 LLM 应用打造的开发框架

🔧 LangChain = Language(语言) + Chain(链)
它的核心思想是:把复杂的 AI 任务拆解成一个个可组合的“节点”,再用“链”把它们串起来,形成可运行、可调试、可复用的工作流。

这听起来是不是很像自动化工具 n8nCoze?没错!LangChain 本质上就是用代码实现的 AI 工作流引擎,只不过它是基于 Node.js(或 Python)开发的,更灵活、更贴近工程实际。

本文将带你从零开始,用 Node.js + DeepSeek 模型,亲手搭建一个可扩展的 AI 应用骨架。

为什么需要 LangChain?

  1. 模型太多,接口不一
    OpenAI、DeepSeek、Claude、通义千问……每个厂商的 API 参数、格式都不同。LangChain 通过 “适配器模式” 提供统一接口,让你用同一套代码切换模型,就像换电池一样简单。
  2. Prompt 需要工程化管理
    硬编码字符串 "请解释闭包" 很脆弱。LangChain 提供 PromptTemplate,让提示词变成带变量的模板,支持版本控制、测试和复用。
  3. 任务天然具有流程性
    比如:“查天气 → 判断是否下雨 → 生成穿衣建议”。这种多步骤任务,LangChain 用 Chain 组织成管道(pipe),每一步输出自动作为下一步输入。
  4. 模型即服务,可插拔
    你可以根据性价比、响应速度、功能特性,在不同环节使用不同模型。比如用便宜模型做初筛,用高性能模型做最终生成——LangChain 让这种“混合调度”变得轻而易举。

🧱
如果把 LLM 比作“智能积木”,那 LangChain 就是带卡扣的乐高底板——它不提供积木本身,但让你能把各种积木(模型、工具、数据)稳稳拼在一起,搭出复杂结构。


第二部分:动手实践 —— 从一行代码到智能工作流

有了上述认知,我们来看如何用代码一步步实现 LangChain 的核心能力。以下示例基于 Node.js + DeepSeek 模型。

✅ 步骤 0:环境准备 —— 搭好舞台,才能登台表演

在编写任何 AI 应用之前,我们需要先准备好“工具箱”和“通行证”。

pnpm i langchain @langchain/deepseek dotenv
  • langchain:LangChain 的核心包,提供 Chain、Prompt、Runnable 等基础能力。
  • @langchain/deepseek:DeepSeek 模型的官方适配器。LangChain 把每个大模型都做成独立插件,实现“可拔插”设计。
  • dotenv:用于加载 .env 文件中的环境变量,避免把 API 密钥硬编码在代码里(安全最佳实践)。

接着创建 .env 文件:

DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxx

并在主文件顶部引入:

import 'dotenv/config';

🔒 为什么重要?
这行代码会在程序启动时自动读取 .env,并将其中的变量注入到 process.env。后续 LangChain 初始化 DeepSeek 时,会自动从 process.env.DEEPSEEK_API_KEY 读取密钥,你无需手动传参。

✅ 步骤1:基础调用 + 提示模板 —— 让 AI 听懂你的“人话”

第一步:实例化模型
import { ChatDeepSeek } from '@langchain/deepseek';

const model = new ChatDeepSeek({
  model: 'deepseek-reasoner',
  temperature: 0.7
});
  • ChatDeepSeek 是 LangChain 为 DeepSeek 提供的聊天接口封装。

  • model:指定使用哪个具体模型(如 reasoning 能力更强的 deepseek-reasoner)。

  • temperature:控制输出的“随机性”。

    • 0 → 确定性回答(适合事实查询)
    • 1 → 创意性强但可能跑偏(适合写故事)
    • 0.7 是通用平衡值。

⚠️ 注意:不同模型支持的参数不同,LangChain 会自动映射到对应 API 字段。

第二步:使用 PromptTemplate 构造提示
import { PromptTemplate } from '@langchain/core/prompts';

const prompt = PromptTemplate.fromTemplate(`
你是一个{role}.
请用不超过 {limit} 字回答以下问题:
{question}  
`)
  • fromTemplate 是一个静态方法,用于从字符串模板创建可复用的 Prompt 对象。
  • {role}{limit}{question} 是占位符,后续通过 .format() 填入真实值。
const promptStr = await prompt.format({
  role: '前端面试官',
  limit: '50',
  question: '什么是闭包'
})

format()LangChain 中 PromptTemplate 类的一个核心方法,用于将模板中的占位符(如 {role}{question})替换为实际的值,从而生成一个完整的、可直接用于大模型的提示字符串(prompt string)

这会生成一段结构清晰、语义明确的提示文本

💡 为什么不用字符串拼接?
因为直接拼接容易出错(比如忘记空格、引号冲突),而 PromptTemplate 支持:

  • 自动转义特殊字符
  • 多语言支持
  • 与 LangChain 其他组件(如 Memory、OutputParser)无缝集成
第三步:调用模型并获取结果
const response = await model.invoke(formatted);
console.log(response.content);
  • invoke() 是 LangChain 统一的执行方法,无论底层是 OpenAI 还是 DeepSeek,调用方式一致。
  • 返回值是一个 AIMessage 对象,其 .content 属性才是真正的文本回答。

🎯 关键收获
通过 PromptTemplate + Model.invoke,我们实现了结构化输入 → 标准化输出,这是所有 AI 应用的最小闭环。

输出结果: image.png


步骤1完整代码:

// pnpm i @langchain/deepseek
// pnpm i @langchain/core 
import 'dotenv/config';
import { ChatDeepSeek } from '@langchain/deepseek';
import { PromptTemplate } from '@langchain/core/prompts';

const prompt = PromptTemplate.fromTemplate(`
你是一个{role}.
请用不超过 {limit} 字回答以下问题:
{question}  
`);

const promptStr = await prompt.format({
  role: '前端面试官',
  limit: '50',
  question: '什么是闭包'
});

const model = new ChatDeepSeek({
  model: 'deepseek-reasoner',
  temperature: 0.7
});

const res = await model.invoke(promptStr);
console.log(res.content);

✅ 步骤2:构建第一个 Chain —— 把“提示+模型”打包成流水线

当你的应用需要反复执行“填模板 → 调模型”这个流程时,每次都写两行代码太啰嗦。LangChain 提供 Chain 来封装这一组合。

🔍 什么是 Chain?

在 LangChain 中,Chain 并不是一个具体的类,而是一种“可运行单元(Runnable)的组合模式”
它的核心思想是:

把 AI 应用拆解为若干个独立、可测试、可替换的步骤(如:输入处理 → 提示生成 → 模型调用 → 输出解析),然后像搭积木一样把它们连起来。

  • 每个步骤都是一个 Runnable(实现了 .invoke(), .stream() 等方法的对象)
  • Chain 就是这些 Runnable顺序组合
  • 最终形成的 Chain 本身也是一个 Runnable,可以被其他 Chain 再次组合

这使得复杂 AI 应用的开发变得模块化、可维护、可测试


🧪 .pipe() 是如何工作的?

.pipe() 是 LangChain 中用于连接 Runnable 的核心操作符,语法为:

const workflow = step1.pipe(step2).pipe(step3);

它会自动将前一个步骤的输出作为后一个步骤的输入,形成数据流:

输入 → step1 → step2 → step3 → 输出

const chain = prompt.pipe(model);
  • .pipe() 是 LangChain 的核心组合操作符,它将两个“可运行单元”(Runnable)连接起来。
  • prompt 是一个 Runnable(能接收输入并输出字符串),
  • model 也是一个 Runnable(能接收字符串并输出 AI 回答),
  • 所以 prompt.pipe(model) 生成一个新的 Runnable:输入 → Prompt → LLM → 输出

然后直接调用:

const prompt = PromptTemplate.fromTemplate(`
你是一个前端专家,用一句话解释:{topic} 
`);

const response = await chain.invoke({
    topic: '闭包'
}) 
console.log(response.text);//  // 注意:这里用 .text 而不是 .content

为什么是 .text
当你直接使用 prompt.pipe(model) 时,最终输出类型是 AIMessage(LangChain 的消息对象)。
为了方便,LangChain 在 AIMessage 上定义了 .text 属性作为 .content 的别名(尤其在较新版本中统一接口),两者通常等价。
但更推荐的做法是:显式添加 StringOutputParser,让输出直接是字符串,避免字段混淆。

✅ Chain 的核心优势
优势说明
简洁性一行代码封装完整流程
复用性同一个 chain 可用于不同输入(如 topic: '原型链'
组合性chain 可嵌套、可拼接,构建复杂 Agent
可测试性每个步骤可单独 mock 或验证
一致性所有组件遵循 Runnable 接口,无缝集成

输出结果:

image.png

步骤二完整代码:

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} 
`);

const chain = prompt.pipe(model);
const response = await chain.invoke({
  topic: '闭包'
});
console.log(response.text);

✅ 步骤3:多阶段 Chain —— 让多个 AI “角色”协同工作

现实中的智能任务往往不是一步到位的。例如:先让领域专家详细讲解一个概念,再让编辑将其提炼为简洁要点。这种“分阶段、多角色”的协作模式,正是 LangChain 中 多阶段 Chain(Multi-step Chain) 的用武之地。

LangChain 提供了 RunnableSequence显式定义串行处理流程,让多个 AI 步骤像流水线一样协同工作。


🔧 什么是 RunnableSequence

RunnableSequence 是 LangChain 中用于构建顺序执行工作流的核心工具类。

  • 它接收一个 按顺序执行的函数或 Runnable 列表
  • 每个步骤的输出自动作为下一个步骤的输入
  • 所有步骤支持 异步执行(async/await)
  • 整个序列本身也是一个 Runnable,可被其他链复用或嵌套;
  • 特别适合实现 “思考 → 回答 → 校验 → 总结” 等复杂推理流程。

💡 你可以把它理解为 JavaScript 中的 .then().then().then() 链,但专为 AI 工作流设计,并具备类型安全和 LangChain 生态集成能力。


第一阶段:深度解释
const explainPrompt = PromptTemplate.fromTemplate(`
你是一个前端专家,请详细介绍以下概念:{topic}
要求:覆盖定义、原理、使用方式,不超过300字.
`);
const explainChain = explainPrompt.pipe(model);

这个 Chain 接收 {topic},调用模型生成一段专业、详细的解释。

第二阶段:提炼要点
const summaryPrompt = PromptTemplate.fromTemplate(`
请将以下前端概念解释总结为3个核心要点(每点不超过20字):
{explanation}
`);
const summaryChain = summaryPrompt.pipe(model);

该 Chain 接收上一阶段生成的解释文本(作为 {explanation}),输出高度凝练的摘要。


🧩 组合成完整工作流:使用 RunnableSequence
import { RunnableSequence } from '@langchain/core/runnables';

const fullChain = RunnableSequence.from([
    (input) => explainChain.invoke({topic: input.topic}).then( res => res.text),
    // 返回纯文本,作为下一阶段输入
    (explanation) => summaryChain.invoke({explanation })
    // 基于解释生成摘要
    .then( res => `知识点:${explanation}总结:${res.text}`),
])
const response = await fullChain.invoke({
    topic: '闭包'
});
console.log(response);
  • RunnableSequence.from() 接收一个处理函数数组,每个函数代表一个逻辑阶段;
  • 函数可以是普通函数、异步函数,也可以是 Runnable 对象(如 Chain);
  • 数据在阶段间自动传递,无需手动管理中间变量;
  • 你可以轻松插入日志、校验、缓存等中间逻辑。

总结:从“调用一次”到“构建系统”

阶段能力类比
步骤0环境与认证办理入场证
步骤1结构化提示 + 单次调用学会说清楚需求
步骤2封装提示+模型为 Chain把常用操作做成快捷按钮
步骤3多 Chain 串联为工作流组建自动化流水线

LangChain 的真正威力,不在于它能让你“更快地问一个问题”,而在于它提供了工程化构建复杂 AI 应用的骨架。当你开始用 Chain 思维思考问题,你就已经从“AI 用户”迈向了“AI 工程师”。