构建可组合的 AI 应用:LangChain 核心模式与工程实践
随着大语言模型(LLM)能力的快速演进,AI 应用开发正从“单次提示调用”迈向“复杂工作流编排”的新阶段。如何高效、可靠地构建具备多步推理、模块复用和良好可维护性的 AI 系统,成为开发者面临的关键挑战。
LangChain 作为领先的 AI 应用开发框架,通过其核心抽象——Runnable 协议与链式组合(Chaining)机制,为这一问题提供了系统性解决方案。本文将以一个典型的 工程为例,逐步展示如何从零开始,利用 LangChain 构建一个结构清晰、易于扩展的 AI 应用。
统一接口 —— 用适配器模式解耦模型依赖
在直接调用 LLM API 时,我们常陷入厂商绑定的困境:OpenAI、DeepSeek、通义千问……每家的请求格式、认证方式、消息结构都不尽相同。LangChain 通过 适配器模式,将所有模型抽象为统一的 ChatModel 接口:
import {ChatDeepSeek} from '@langchain/deepseek';
const model =new ChatDeepSeek({
model:'deepseek-reasoner',
temperature:0,
})
// invoke 执行
const res =await model.invoke('用一句话解释什么是RAG')
console.log(res.content)
无论底层使用哪家模型,上层代码只需调用 model.invoke(),框架会自动处理:
- 请求封装(如将字符串转为
HumanMessage) - 认证(通过环境变量注入 API Key)
- 响应解析(返回标准化的
AIMessage对象)
相对与传统的大模型调用,我们不需要再写baseURL和APIkey
更重要的是,所有 ChatModel 实例都实现了 Runnable 接口,这意味着它们天然具备可组合性——这是后续构建链条的基础。
从提示模板到模型调用:LangChain 基础工作流
有了统一模型,下一步是定义任务。LangChain 的 PromptTemplate 将提示词从硬编码字符串升级为参数化、可执行的对象:
import 'dotenv/config';
import {ChatDeepSeek} from '@langchain/deepseek'; //适配器 Provider 省去了适配工作
import {PromptTemplate} from '@langchain/core/prompts';
const prompt =PromptTemplate.fromTemplate(`
你是一个{role},
请用不超过{limit}个字回答以下问题:
{question}
`)//返回一个PromptTemplate实例对象
//console.log(prompt);
const promptStr = await prompt.format({
role:'前端面试官',
limit:'50',
question:'什么是闭包'
})
// console.log(promptStr);
// const prompt2 =await prompt.format({
// role:'后端面试官',
// limit:'50',
// question:'什么是MVC'
// })
// console.log(prompt2);
const model =new ChatDeepSeek({
model:'deepseek-reasoner',
temperature:0.7
})
const res =await model.invoke(promptStr)
console.log(res.content)
关键点解析:
PromptTemplate.fromTemplate()是 LangChain 中用于快速创建结构化提示模板的核心静态方法,它会返回一个PromptTemplate实例对象PromptTemplate.fromTemplate()使用到的模板字符串必须在format中声明,可以是无序的,但是不能缺少
单步 Chain —— Prompt + Model 的原子单元
在 LangChain 的设计哲学中,最基础却最关键的构建块,是将提示模板(Prompt) 与 语言模型(Model) 组合成一个可执行的原子单元。这种组合被称为“单步 Chain”,它封装了“输入 → 提示渲染 → 模型调用 → 输出”的完整生命周期,成为后续复杂流程的基石。
来看一段典型的实现
// chain
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.content)
.pipe():连接 Runnable 的声明式胶水
这段代码的核心在于 prompt.pipe(model)。.pipe() 是 LangChain 在 Runnable 协议上提供的链式组合操作符,其作用是将两个可运行单元按顺序连接,形成一个新的、更复杂的 Runnable。
具体来说:prompt是一个runable,model也是一个runable,二者通过pipe()相连接形成了一个新的runable(RunnableSequence 可运行序列),也就是chain,而这里的所有节点都是按顺序执行,形成的也就是一个SequentialChain 顺序链,是不是很像Coze和n8n中的工作流?
调用 chain.invoke({ topic: '闭包' }) 时,数据自动从左向右流动,无需手动处理中间结果。这正是声明式编程的体现:你描述“要做什么”,而不是“怎么做”。
最终效果
对比传统写法的优势
若不用 Chain,我们通常这样写:
const formatted = await prompt.format({ topic: '闭包' });
const res = await model.invoke(formatted);
console.log(res.content);
这种方式虽然直观,但存在明显问题:
- 手动调用format方法
- 逻辑分散,难以封装;
- 无法直接复用整个“任务”;
而通过 .pipe() 构建的 Chain,将整个任务抽象为一个函数式组件,既简洁又具备良好的工程属性。
提示即接口,模型即服务,
.pipe()即胶水。
单步 Chain,是 LangChain 工程化思维的第一块积木——小而完整,可插可拔。
工程化进阶 —— 多阶段推理与复合链条
当任务复杂度提升(如“先解释,再总结”),我们需要多次调用 LLM。此时,不应在一个链条里堆砌逻辑,而应分步构建子链,再组合成主链。
4.1 定义原子子链
const explainPrompt = PromptTemplate.fromTemplate(`
你是一个前端专家,请详细介绍以下概念:{topic}
要求:覆盖定义、原理、使用方式,不超过三百字。
`);
const summaryPrompt = PromptTemplate.fromTemplate(`
请将以下前端概念解释总结为3个核心要点(每个要点不超过20字):
{explanation}
`);
// 子链1:生成详细解释
const explainChain = explainPrompt.pipe(model);
// 子链2:基于解释生成总结
const summaryChain = summaryPrompt.pipe(model);
每个子链职责单一,可独立调试或用于其他流程(如“解释+举例”、“解释+对比”等)。
注意:这里 explainChain.invoke(...) 返回的是 AIMessage 对象,其文本内容需通过 .content 属性获取。
4.2 编排复合主链
LangChain 提供 RunnableSequence.from() 支持显式定义多阶段流程:
import { RunnableSequence } from '@langchain/core/runnables';
const fullChain = RunnableSequence.from([
// 阶段1:调用 explainChain
(input) => explainChain.invoke({ topic: input.topic }),
// 阶段2:将解释结果传给 summaryChain
(explanationMsg) => {
const explanation = explanationMsg.content; // 提取文本
return summaryChain.invoke({ explanation }).then(summaryMsg =>
`知识点:\n${explanation}\n\n总结:\n${summaryMsg.content}`
);
}
]);
// 执行端到端推理
const result = await fullChain.invoke({ topic: '闭包' });
console.log(result);
等价于以下 可视化数据流:
{ topic: "闭包" }
│
▼
┌───────────────────────┐
│ explainPrompt │ → 渲染提示词
└──────────┬────────────┘
▼
┌───────────────────────┐
│ ChatDeepSeek │ → 第1次调用 LLM
└──────────┬────────────┘
▼
explanation (string)
│
▼
┌───────────────────────┐
│ summaryPrompt │ → 渲染总结提示词
└──────────┬────────────┘
▼
┌───────────────────────┐
│ ChatDeepSeek │ → 第2次调用 LLM
└──────────┬────────────┘
▼
最终字符串(拼接结果)
虽然此处使用了箭头函数手动衔接,但在生产环境中,更推荐使用 RunnableLambda 或 RunnablePassthrough 等原生组件,以获得更好的错误处理、流式支持和 LangSmith 可观测性集成。
最终效果
结语:从脚本到系统的工程跃迁
通过代码的逐步演进,我们清晰地看到 LangChain 如何将 AI 应用开发从“一次性实验脚本”提升为“可维护、可扩展的工程系统”:
- 统一接口抽象 —— 以适配器模式屏蔽模型差异,让切换 LLM 如同更换插件;
- 提示即契约 ——
PromptTemplate将模糊的字符串转化为带输入规范的可执行单元; - 单步 Chain 封装 ——
.pipe()将“提示 + 模型”组合为原子化、可复用的任务模块; - 多阶段编排 —— 通过
RunnableSequence显式表达复杂推理流程,实现“展开-提炼”等高级策略。
这一路径的本质,是 用工程化思维驯服 AI 的不确定性:
不是把大模型当作万能黑盒随意调用,而是将其作为标准化组件,嵌入结构清晰、职责分明的工作流中。
LangChain 的真正价值,不在于简化单次调用,而在于提供一套面向复杂性的架构能力。无论未来引入检索增强(RAG)、函数调用(Tool Use),还是构建自主 Agent,这套基于 Runnable 的组合范式都能无缝扩展。
AI 应用的竞争壁垒,正从“能否调通模型”转向“能否高效编排流程”。
而 LangChain,正是你构建下一代智能系统不可或缺的工程底座。
现在,只需一行 prompt.pipe(model),你便已站在了可组合 AI 应用的起点。