深入浅出 LangChain:构建可编程、可配置的 AI 应用工作流

73 阅读8分钟

2023 年以来,随着大模型(LLM)技术的爆发式发展,AI 正在从“玩具”走向“工具”,越来越多的开发者开始尝试将语言模型集成到自己的产品中。但直接调用 API 往往只是第一步——真正难的是如何让 AI 的行为可控、可预测、可复用、可维护

这时候,一个名为 LangChain 的框架进入了我们的视野。

它不是最火的,却可能是当前最成熟的 AI 应用开发框架。今天我们就以实际代码为引子,带你一步步理解 LangChain 的核心思想与实战技巧,深入其背后的设计哲学。


一、什么是 LangChain?lang + chain = ?

很多人第一次听到这个名字都会疑惑:“Lang” 是语言,“Chain” 是链条,合起来是“语言链”?

其实更准确的理解是:

  • Lang:代表 Language Model(语言模型),也就是我们常说的大模型如 GPT、DeepSeek 等;
  • Chain:代表“链式结构”,即把多个处理步骤像管道一样连接起来,形成一条完整的执行流程。

所以,LangChain = 使用语言模型构建可编排的工作流系统

它的目标很明确:把复杂的 AI 业务拆解成一个个小而清晰的模块,并通过“链”的方式组织它们,最终实现工程化的 AI 应用开发

这就像前端中的 React 组件化思维 —— 不再写一整块逻辑,而是设计一个个高内聚、低耦合的功能单元。


二、为什么需要 LangChain?原生调用 LLM 够用吗?

假设你正在做一个前端知识问答机器人,用户问:“什么是闭包?” 你想让它先详细解释,再总结成三个要点。

如果只用原生 API 调用,你会怎么写?

const res1 = await fetch('/api/llm', {
  method: 'POST',
  body: JSON.stringify({ prompt: '请解释什么是闭包...' })
});
const explanation = await res1.json();

const res2 = await fetch('/api/llm', {
  method: 'POST',
  body: JSON.stringify({ prompt: `总结以下内容为三点:${explanation}` })
});
const summary = await res2.json();

问题来了:

  • 流程散落在各处,难以复用;
  • 错误处理复杂;
  • 中间数据传递不清晰;
  • 模型切换成本高(比如换 DeepSeek 到 Qwen);
  • 提示词无法统一管理。

而 LangChain 的出现,正是为了解决这些“胶水代码”带来的混乱


三、LangChain 核心理念:一切皆 Runnable

LangChain 最核心的设计思想是:所有操作都应该是“可运行的”(Runnable)

这意味着无论是提示词模板、模型调用、后处理函数,还是整个工作流,都可以被 .invoke() 执行,也可以通过 .pipe() 连接。

这种设计带来了极大的灵活性和组合性。

在langchain中,各个多个模块紧密联系

PixPin_2025-12-28_15-03-32.png

下面我们通过几个实际案例,层层递进地讲解 LangChain 的关键能力。


四、案例一:使用 Chain 构建多步工作流(Pipeline)

我们来看第一个文件 1.js,它的目标是完成这样一个任务:

用户输入一个前端概念 → 让 AI 先详细解释 → 再自动提炼成三个核心要点。

这个过程天然分为两个阶段,我们可以将其抽象为两个“节点”:

  1. 生成详细解释
  2. 提取核心要点

第一步:定义 Prompt 模板

const examplePrompt = PromptTemplate.fromTemplate(`
  你是一个前端专家。
  请详细介绍以下概念:{topic},
  要求:覆盖定义、原理、使用方式,不超过300字。
`);

这里用了 PromptTemplate,它是 LangChain 提供的提示词模版工具。好处是:

  • 支持变量注入(如 {topic});
  • 可复用、可测试;
  • 易于国际化或多语言支持。

接着我们创建第二个模板用于总结:

const summatyPrompt = PromptTemplate.fromTemplate(`
  请将以下前端概念解释总结为三个核心要点(每点不超过20字):
  {explanation}
`);

第二步:绑定模型,形成可执行链

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

const explanationChain = examplePrompt.pipe(modal);
const summaryChain = summatyPrompt.pipe(modal);

.pipe() 就像是 Unix 的管道操作符 |,表示前一个节点的输出作为下一个节点的输入。

此时,explanationChain 就是一个完整的“提示词 → 模型”的可运行对象,可以直接调用:

const result = await explanationChain.invoke({ topic: '闭包' });
console.log(result.content); // 输出关于闭包的详细解释

第三步:串联成完整工作流

现在我们要把两步串起来。LangChain 提供了 RunnableSequence 来实现顺序执行:

const fullChain = RunnableSequence.from([
  (input) => explanationChain.invoke({ topic: input.topic }).then(res => res.text),
  (explanation) => summaryChain.invoke({ explanation }).then(res => `知识点:${explanation} 总结:${res.text}`)
]);

注意这里的写法:

  • 数组中的每一项都是一个异步函数;
  • 上一步的结果会自动传给下一步;
  • 最终返回的是一个全新的、可调用的 Runnable 实例。

最后调用:

const response = await fullChain.invoke({ topic: '什么是闭包' });
console.log(response);

PixPin_2025-12-28_15-42-45.png

这就是 Chain 的价值:将复杂逻辑封装成一条流水线,对外暴露简洁接口。


五、案例二:Output Parser —— 让 AI 输出结构化数据

虽然 LLM 很强大,但它本质是个“文本生成器”。当我们希望它返回 JSON 数据时,往往会出现格式错误、字段缺失等问题。

例如,我们需要 AI 返回某个前端概念的结构化信息:

interface FrontendConcept {
  name: string;
  core: string;
  usecase: string[];
  difficulty: '简单' | '中等' | '复杂';
}

怎么办?靠人工解析?当然不行!

LangChain 提供了强大的 Output Parser 机制,配合 Zod 这样的校验库,可以做到:

  • 强制模型输出指定格式;
  • 自动验证输出合法性;
  • 在 JS/TS 中获得类型安全的对象。

我们来看 2.js 的实现:

定义 Schema(使用 Zod)

import { z } from 'zod';

const FrontendConceptSchema = z.object({
  name: z.string().describe('概念名称'),
  core: z.string().describe('核心要点'),
  usecase: z.array(z.string()).describe('常见使用场景'),
  difficulty: z.enum(['简单','中等','复杂']).describe('学习难度')
});

Zod 不仅能做运行时校验,还能生成文档说明、转换为 JSON Schema。

创建 JsonOutputParser

const jsonParser = new JsonOutputParser(FrontendConceptSchema);

这个 parser 有一个神奇的方法:

jsonParser.getFormatInstructions()

它会自动生成一段提示词指令,告诉模型该怎么输出合法 JSON。比如:

返回的 JSON 必须包含字段:name(字符串)、core(字符串)、usecase(字符串数组)、difficulty(枚举值之一)。不允许增加或减少字段,必须能被 JSON.parse 解析。

注入提示词模板

const prompt = PromptTemplate.fromTemplate(`
  你是一个只会输出 JSON 的 API,不允许输出任何解释性文字。

  ⚠️ 你必须【只返回】符合以下 Schema 的 JSON:
  {format_instructions}

  前端概念:{topic}
`);

关键点在于:我们将 format_instructions 动态插入到了 prompt 中,相当于“动态约束模型行为”。

构建完整 Chain

const chain = prompt.pipe(model).pipe(jsonParser);

const response = await chain.invoke({
  topic: 'Promise',
  format_instructions: jsonParser.getFormatInstructions(),
});

此时 response 已经是一个经过类型校验的 JavaScript 对象,可以直接用于后续业务逻辑:

console.log(response.name);        // "Promise"
console.log(response.difficulty); // "中等"

PixPin_2025-12-28_13-36-42.png

💡 这就是 Output Parser 的威力:把非结构化的文本输出,变成类型安全的数据结构,极大提升程序健壮性。


六、案例三 & 四:Memory —— 让 AI 拥有记忆能力

我们知道,HTTP 请求是无状态的,每次调用 LLM 都像是第一次见面。但真实场景中,用户往往需要多轮交互。

比如:

用户:“我叫张三。”
AI:“你好,张三!”
用户:“我喜欢吃橙子。”
AI:“好的,张三,我知道你喜欢吃橙子。”
用户:“我叫什么名字?”
AI:“你叫张三。”

这就要求 AI “记得”之前的对话内容。

LangChain 如何实现这一点?答案是:Memory

我们来看 4.js 的实现。

使用 ChatPromptTemplate 支持消息历史

const prompt = ChatPromptTemplate.fromMessages([
  ['system', '你是一个有记忆的问答助手'],
  ['placeholder', '{history}'], // 占位符,将来会被替换为真实的历史消息
  ['human', '{input}']
]);

这里的 {history} 是关键,它会在运行时被替换成真正的对话记录。

构建带记忆的 Runnable

const runnable = prompt.pipe(model);

const messageHistory = new InMemoryChatMessageHistory();
// 存储在内存中的聊天记录,适合单会话测试

然后使用 RunnableWithMessageHistory 包装原始链:

const chain = new RunnableWithMessageHistory({
  runnable,
  getMessageHistory: async () => messageHistory,
  inputMessagesKey: 'input',
  historyMessagesKey: 'history'
});

这样每次调用时,LangChain 会自动:

  1. 获取该会话的历史消息;
  2. 插入到 prompt 中;
  3. 调用模型;
  4. 将新消息追加到历史中。

多轮对话演示

await chain.invoke(
  { input: '我叫张三,喜欢吃橙子' },
  { configurable: { sessionId: 'makefriend' } }
);

await chain.invoke(
  { input: '我叫什么名字' },
  { configurable: { sessionId: 'makefriend' } }
);

第二次调用时,由于共享同一个 sessionId,所以能读取到之前的消息,从而正确回答“你叫张三”。

PixPin_2025-12-28_15-40-30.png

🧠 这就是 Memory 的本质:通过维护对话历史,在无状态的 API 上模拟出“有状态”的体验。


七、LangChain 的工程化价值总结

通过以上四个案例,我们可以提炼出 LangChain 的四大核心能力:

能力解决的问题关键组件
🔗 Chain多步骤 AI 流程难以组织RunnableSequence, .pipe()
🧩 PromptTemplate提示词散乱、不易维护PromptTemplate, ChatPromptTemplate
📦 OutputParser输出不可控、难解析JsonOutputParser, zod 集成
💬 Memory无法支持多轮对话RunnableWithMessageHistory, InMemoryChatMessageHistory

这些能力共同构成了 AI 应用的工程化基础设施


八、LangChain 的设计哲学:适配器模式 + 统一接口

还有一个容易被忽略但极其重要的点:LangChain 是如何兼容不同 LLM 的?

比如你可以轻松地把 ChatDeepSeek 换成 ChatOpenAIChatAnthropic,而几乎不需要改其他代码。

这是因为 LangChain 采用了 适配器模式(Adapter Pattern)

  • 所有 LLM 提供商都被封装成统一接口;
  • 开发者只需关注“做什么”,而不是“怎么做”;
  • 更换模型就像更换数据库驱动一样简单。

这也解释了为什么推荐安装:

pnpm i @langchain/deepseek     # DeepSeek 适配器
pnpm i @langchain/core         # 核心类库(prompt、runnable、parser 等)

LangChain 把 LLM 当作“可插拔组件”,极大地提升了系统的可扩展性和可维护性。


九、给前端开发者的建议:如何上手 LangChain?

如果你是一名前端开发者,想快速入门 LangChain,建议按以下路径学习:

✅ 第一步:环境准备

确保项目使用 ESM 模块系统:

// package.json
{
  "type": "module"
}

安装必要依赖:

pnpm add @langchain/core @langchain/deepseek dotenv zod

配置 .env 文件:

DEEPSEEK_API_KEY=your_api_key_here

✅ 第二步:从最小例子开始

import { ChatDeepSeek } from '@langchain/deepseek';
import 'dotenv/config';

const model = new ChatDeepSeek();
const res = await model.invoke('你好');
console.log(res.content);

跑通第一个请求,建立信心。

✅ 第三步:逐步引入高级特性

  1. 加入 PromptTemplate 管理提示词;
  2. .pipe() 连接多个步骤;
  3. 引入 JsonOutputParser + zod 控制输出;
  4. 使用 RunnableWithMessageHistory 实现记忆对话。

每一步都要动手实践,理解“为什么需要这个组件”。


十、结语:LangChain 是 AI 时代的“Express 框架”

如果说 Express 是 Node.js 时代 Web 开发的基石,那么 LangChain 就是当下 AI 应用开发的事实标准。

它不追求炫技,而是专注于解决实际问题:

  • 如何组织复杂的 AI 逻辑?
  • 如何保证输出稳定可靠?
  • 如何让 AI 记住上下文?
  • 如何方便地替换底层模型?

这些问题的答案,都在 LangChain 的设计之中。

未来,AI 应用不会是“调一次 API 就完事”,而是像传统软件一样讲究架构、分层、可测试性。而 LangChain,正是这条路上最重要的工具之一。


参考资料


📌 如果你觉得这篇文章对你有帮助,请点赞、收藏、转发,让更多人看到!也欢迎在评论区分享你的 LangChain 实战经验~