【AI-21 LangChain-1/Lesson80(2025-12-23)】LangChain 与 DeepSeek:构建下一代 AI 应用的工程化实践指南

6 阅读8分钟

🧠在人工智能技术迅猛发展的今天,大型语言模型(LLM)如 ChatGPT、DeepSeek 等已经成为开发者工具箱中的核心组件。然而,直接调用 LLM API 虽然简单,但在构建复杂、可维护、可扩展的 AI 应用时,往往显得力不从心。LangChain 正是在这样的背景下应运而生,它提供了一套完整的框架,将 LLM 的能力模块化、流程化,极大地提升了 AI 应用的开发效率和工程化水平。

本文将深入探讨如何利用 LangChain 框架,结合 DeepSeek 大模型,从零开始构建一个结构清晰、功能强大的 AI 应用。我们将覆盖从项目初始化、环境配置到高级工作流编排的完整过程,并详细解析其中的核心概念。


🚀 项目初始化与依赖安装

任何现代 JavaScript/TypeScript 项目的起点都是初始化。我们使用 npmpnpm(推荐,因其并行安装速度更快)来创建项目骨架。

npm init -y
# 或
pnpm init -y

这会生成一个 package.json 文件。为了使用 ES 模块(ESM)语法(即 import/export),我们必须明确指定模块类型:

{
  "type": "module"
}

接下来,安装核心依赖。LangChain 的设计哲学是“可拔插”,因此我们首先安装核心框架,再根据需要安装特定模型的适配器。

# 安装 LangChain 核心
npm i langchain
# 安装 DeepSeek 模型的官方适配器
npm i @langchain/deepseek
# 安装 dotenv 用于管理环境变量
npm i dotenv

关键点@langchain/deepseek 是一个 适配器(Adapter) 。它实现了 LangChain 定义的统一接口,将 DeepSeek API 的细节封装起来。这意味着,如果你未来想切换到 OpenAI 或 Anthropic,只需更换适配器,而无需重写业务逻辑。这就是 LangChain “统一接口”理念的价值所在。

最终的 package.json 文件内容如下:

{
  "name": "demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "type": "module",
  "dependencies": {
    "@langchain/deepseek": "^1.0.3",
    "dotenv": "^17.2.3"
  }
}

🔑 环境变量与 API 密钥管理

安全地管理 API 密钥至关重要。我们绝不应该将密钥硬编码在源代码中。dotenv 包帮助我们轻松实现这一点。

  1. 在项目根目录创建 .env 文件。
  2. 将你的 DeepSeek API 密钥填入其中。
DEEPSEEK_API_KEY=xxx

注意.env 文件通常会被添加到 .gitignore 中,以防止意外提交到代码仓库。

在代码的最顶部,通过 import 'dotenv/config'; 这一行,dotenv 会自动读取 .env 文件,并将其中的变量加载到 process.env 对象中。后续的 DeepSeek 适配器会自动从 process.env.DEEPSEEK_API_KEY 中读取密钥,无需手动传递。


🧪 基础交互:invokeChatDeepSeek

一切的起点都是与模型进行一次简单的对话。main.js 展示了最基础的用法。

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

// 初始化模型实例
const model = new ChatDeepSeek({
  model: 'deepseek-reasoner', // 指定使用 DeepSeek 的 Reasoner 模型
  temperature: 0 // 控制输出的随机性,0 表示最确定、最保守
});

// 使用 invoke 方法发送请求并等待响应
const res = await model.invoke('用一句话解释什么是RAG?');
console.log(res.content); // 打印模型返回的内容

核心概念解析

  • ChatDeepSeek: 这是从 @langchain/deepseek 包导入的类,它是 DeepSeek 聊天模型的 LangChain 封装。它继承自 LangChain Core 定义的 BaseChatModel 抽象类,保证了接口的一致性。

  • model 参数: 指定要使用的具体模型。DeepSeek 提供了多种模型,如 deepseek-coderdeepseek-chatdeepseek-reasoner。Reasoner 模型专为复杂推理任务设计。

  • temperature: 这是一个关键的生成参数。值域通常在 [0, 1][0, 2] 之间。

    • temperature = 0: 模型每次都会选择概率最高的 token,输出结果高度一致且确定,适合事实性问答、代码生成等场景。
    • temperature > 0: 引入随机性,值越大,输出越有创意但也可能更不准确,适合创意写作、头脑风暴等场景。
  • invoke: 这是 LangChain 中所有“可运行对象”(Runnable)的标准方法,用于同步执行单个操作并返回结果。

  • res.content: invoke 返回的是一个 AIMessage 对象,其 content 属性包含了模型生成的实际文本。


✨ 提示词工程:PromptTemplate

直接拼接字符串来构造提示词(Prompt)既脆弱又难以维护。LangChain 提供了 PromptTemplate 来解决这个问题,它让提示词变得像模板一样可复用和参数化。

1.js 展示了这一强大功能:

import { PromptTemplate } from '@langchain/core/prompts';

// 定义一个带有占位符的模板
const prompt = PromptTemplate.fromTemplate(`
  你是一个{role}. 请用不超过{limit} 字回答以下问题: {question}
`);

// 使用 .format() 方法填充模板
const promptStr = await prompt.format({
  role: '前端面试官',
  limit: 50,
  question: '什么是闭包',
});

console.log(promptStr);
// 输出: "你是一个前端面试官. 请用不超过50 字回答以下问题: 什么是闭包"

// 将格式化后的提示词字符串传给模型
const res = await model.invoke(promptStr);
console.log(res.content);

优势

  • 清晰分离:将提示词的结构(模板)与动态数据(参数)分离。
  • 可复用:同一个模板可以用于不同的输入,生成不同但结构一致的提示。
  • 可维护:修改提示词逻辑只需修改模板,无需改动多处代码。

⛓️ 构建工作流:pipeRunnableSequence

现实世界的 AI 应用很少只包含一步操作。例如,你可能需要先让模型解释一个概念,再让它对解释进行总结。LangChain 通过 链(Chain) 的概念来组织这些步骤。

2.js 引入了 pipe 操作符,它是构建链的基础:

import { PromptTemplate } from '@langchain/core/prompts';

const model = new ChatDeepSeek({ model: 'deepseek-reasoner', temperature: 0.7 });
const prompt = PromptTemplate.fromTemplate(`你是一个前端专家,用一句话解释: {topic}`);

// 使用 pipe 连接提示词模板和模型
const chain = prompt.pipe(model);

// 调用链
const res = await chain.invoke({ topic: '闭包' });
console.log(res.text); // 注意这里使用 .text 而非 .content

关键概念

  • pipe: 这是一个函数组合操作符。prompt.pipe(model) 创建了一个新的可运行对象。当你调用 chain.invoke(input) 时,它会先将 input 传递给 promptprompt 会格式化出一个字符串,然后这个字符串被自动传递给 model 进行调用。
  • RunnableSequence: pipe 操作的结果实际上就是一个 RunnableSequence 实例。它代表了一个按顺序执行的可运行节点序列。
  • .text vs .content: 当你直接调用 model.invoke() 时,返回的是 AIMessage,所以用 .content。但当模型作为链的一部分被调用时,LangChain 为了简化后续处理,通常会自动提取 .content 并将其作为 .text 属性返回。这是一种便利设计。

🏗️ 高级编排:复杂 RunnableSequence

对于更复杂的逻辑,比如需要中间结果、条件分支或并行处理,3.js 展示了如何使用 RunnableSequence.from 进行精细控制。

import { RunnableSequence } from '@langchain/core/runnables';

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

// 定义两个不同的提示模板
const explainPrompt = PromptTemplate.fromTemplate(`...{topic}...`);
const summaryPrompt = PromptTemplate.fromTemplate(`...{explanation}...`);

// 创建两个子链
const explainChain = explainPrompt.pipe(model);
const summaryChain = summaryPrompt.pipe(model);

// 使用 RunnableSequence.from 构建一个自定义工作流
const fullChain = RunnableSequence.from([
  // 第一步:调用解释链,并提取其文本结果
  (input) => explainChain.invoke({ topic: input.topic }).then(res => res.text),
  // 第二步:将上一步的结果作为输入,调用总结链,并组合最终输出
  (explanation) => summaryChain.invoke({ explanation }).then(res => 
    `知识点:\n${explanation}\n\n总结:\n${res.text}`
  )
]);

const fullRes = await fullChain.invoke({ topic: '闭包' });
console.log(fullRes);

工作流详解

  1. 输入fullChain.invoke({ topic: '闭包' }) 接收一个包含 topic 的对象。
  2. 第一步函数:接收整个输入对象,从中取出 topic,调用 explainChainexplainChain 内部会先格式化提示词,再调用模型。我们通过 .then(res => res.text) 确保只将纯文本解释传递给下一步。
  3. 第二步函数:接收上一步的纯文本解释(explanation),将其作为参数调用 summaryChain。最后,它将原始解释和新生成的总结组合成一个格式化的字符串作为最终输出。

这种方式赋予了开发者极大的灵活性,可以构建任意复杂的、多步骤的 AI 应用逻辑,同时保持代码的清晰和模块化。


📦 依赖关系深度剖析

通过分析 package-lock.jsonpnpm-lock.yaml,我们可以看到 LangChain 生态的精巧设计。

  • @langchain/deepseek@1.0.3:

    • 它直接依赖于 @langchain/openai@1.2.0。这是因为 DeepSeek 的 API 协议与 OpenAI 高度兼容,所以 DeepSeek 适配器复用了 OpenAI 适配器的大部分逻辑,这是一种高效的实现方式。
    • 它声明了对 @langchain/core@^1.0.0对等依赖(peer dependency) 。这意味着项目本身必须安装 @langchain/core@langchain/deepseek 才能正常工作。pnpmnpm 会自动处理这种关系。
  • @langchain/core@1.1.8:

    • 这是整个 LangChain JS 生态的基石。它定义了所有核心抽象,如 BaseLanguageModel, BaseChatModel, PromptTemplate, Runnable, RunnableSequence 等。
    • 它还集成了 langsmith(用于追踪和调试 AI 应用)、js-tiktoken(用于精确计算 token 数量)等关键工具。

这种分层架构(Core + Provider Adapters)确保了 LangChain 的高内聚、低耦合,使其能够快速支持新的大模型,同时保持 API 的稳定性。


💎 总结

LangChain 不仅仅是一个 SDK,它是一套完整的 AI 应用工程化方法论。通过本文的实践,我们看到了它如何系统性地解决 AI 开发中的核心痛点:

  1. 模型抽象:通过适配器模式,统一不同 LLM 的接口。
  2. 提示词管理:通过 PromptTemplate 实现提示词的参数化和复用。
  3. 工作流编排:通过 RunnablepipeRunnableSequence 将复杂的 AI 逻辑分解为可组合、可测试的单元。
  4. 工程化支撑:通过 dotenv 管理密钥,通过清晰的依赖管理保证项目稳定。

main.js 的简单对话,到 3.js 的多步骤知识处理流水线,LangChain 为我们提供了一条从原型到产品的平滑路径。掌握这些核心概念,你就能构建出远超简单聊天机器人的、真正有价值的智能应用。