AI 应用开发新范式:用 LangChain 把大模型变成可组合的“智能积木

77 阅读7分钟

构建可组合的 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)

关键点解析:

  1. PromptTemplate.fromTemplate() 是 LangChain 中用于快速创建结构化提示模板的核心静态方法,它会返回一个PromptTemplate实例对象
  2. 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: '闭包' }) 时,数据自动从左向右流动,无需手动处理中间结果。这正是声明式编程的体现:你描述“要做什么”,而不是“怎么做”。

最终效果

image.png

对比传统写法的优势

若不用 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
└──────────┬────────────┘
           ▼
     最终字符串(拼接结果)

虽然此处使用了箭头函数手动衔接,但在生产环境中,更推荐使用 RunnableLambdaRunnablePassthrough 等原生组件,以获得更好的错误处理、流式支持和 LangSmith 可观测性集成。

最终效果

image.png


结语:从脚本到系统的工程跃迁

通过代码的逐步演进,我们清晰地看到 LangChain 如何将 AI 应用开发从“一次性实验脚本”提升为“可维护、可扩展的工程系统”:

  1. 统一接口抽象 —— 以适配器模式屏蔽模型差异,让切换 LLM 如同更换插件;
  2. 提示即契约 —— PromptTemplate 将模糊的字符串转化为带输入规范的可执行单元;
  3. 单步 Chain 封装 —— .pipe() 将“提示 + 模型”组合为原子化、可复用的任务模块;
  4. 多阶段编排 —— 通过 RunnableSequence 显式表达复杂推理流程,实现“展开-提炼”等高级策略。

这一路径的本质,是 用工程化思维驯服 AI 的不确定性
不是把大模型当作万能黑盒随意调用,而是将其作为标准化组件,嵌入结构清晰、职责分明的工作流中。

LangChain 的真正价值,不在于简化单次调用,而在于提供一套面向复杂性的架构能力。无论未来引入检索增强(RAG)、函数调用(Tool Use),还是构建自主 Agent,这套基于 Runnable 的组合范式都能无缝扩展。

AI 应用的竞争壁垒,正从“能否调通模型”转向“能否高效编排流程”。
而 LangChain,正是你构建下一代智能系统不可或缺的工程底座。

现在,只需一行 prompt.pipe(model),你便已站在了可组合 AI 应用的起点。