LangChain.js:打造自己的 LLM 应用

背景

相信很多小伙伴在刷 BOSS 直聘时会看到AI工程师开发岗位基本都要求掌握 LangChain.js 框架。那么LangChain.js 框架到底是什么呢? 很多岗位 JD 要求必须掌握LangChain.js。下面跟随笔者快速掌握LangChain.js。

LangChain.js 是 LangChain 的 JavaScript / TypeScript 版本,它是一个用于构建基于大语言模型(LLMs)的应用程序的开发框架。LangChain 最早是 Python 版本,后来推出了 JS 版本,以便前端和全栈开发者也能方便地构建智能应用。

各种大模型(LLMs)本身提供 HTTP/WS 等多种方式提供服务,为什么还需要使用 LangChain.js 访问大模型呢?

作用

相比直接调用大模型接口,LangChain.js 有很多优势:

  • 对 Prompt 管理和链式执行很友好
  • 内置 Agent 支持(调用工具)
  • 对接多种数据源(RAG)
  • 模块化能力强,适合构建复杂链条
  • 跨平台能力好

下面详细说明这些优势

对 Prompt 管理和链式执行很友好

LangChain.js 提供 PromptTemplateChainMemory 等模块可以让开发人员管理复杂prompt 模板、复用提示词逻辑、支持上下文记忆(这一点非常重要)、以及串联多个步骤形成链条等功能。这些开箱即用的功能让程序员将精力聚焦在业务开发上。

LangChain.js 的 PromptTemplate 是用来管理和组织 Prompt(提示词)模板的核心工具。帮助构建、复用、动态插值 prompt,非常适合构建复杂的 LLM 调用逻辑

在 AI 程序开发中,我们直接写 prompt 的格式是这样的

js 复制代码
const prompt = `请写一封主题为"${topic}"的中文邮件,语气要正式。`;

这虽然简单,但在构建复杂的 AI 应用时,容易出现:多个 prompt 写重复代码,Prompt 结构不清晰,维护麻烦,变量插值不安全或不一致等问题

而使用 LangChain.js 后,可以利用它定义一个结构清晰的模板:

js 复制代码
const formatted = await prompt.format({
  topic: "会议通知",
  tone: "正式",
});

最后的formatted结果是

txt 复制代码
请写一封主题为"`会议通知`"的中文邮件,语气要正式。

上面说的是简单模板,下面看看复杂模板的例子

js 复制代码
const template = `
你是一位{role}。

请根据以下任务生成内容:
任务描述:{task}

要求:
1. 语言风格:{style}
2. 字数限制:{length}字以内

请开始:
`;

const prompt = new PromptTemplate({
  template,
  inputVariables: ["role", "task", "style", "length"],
});

"role", "task", "style", "length"等都支持变量输入,显著提高模板准确性。上面的模板与LLMChain 联用

js 复制代码
import { LLMChain } from "langchain/chains";
import { ChatOpenAI } from "langchain/chat_models/openai";

const llm = new ChatOpenAI({ temperature: 0.7 });

const chain = new LLMChain({
  llm,
  prompt,
});

const result = await chain.call({
  role: "营销专家",
  task: "推广一款新型运动饮料",
  style: "轻松幽默",
  length: "100",
});

这就完成了一个完整的「Prompt → 调用模型 → 返回结果」链条。

LangChain.js 中的 Chain 是整个框架的核心之一,它代表的是一个可组合、可复用的推理过程。你可以把它理解为一条「流水线」,每一步都基于上一步的结果,可以串联多个模块、多个大模型、多个工具,最终完成一个任务。

在 LangChain.js 里,Chain 是一个有输入、有输出的执行单元,通常包含以下几个部分:

  • 输入(input):来自用户或上一步链条的结果
  • 处理逻辑(prompt、模型调用、工具调用等)
  • 输出(output):用于展示、保存、或传给下一个 Chain

Chain 的类型有很多,LLMChain 是最常用的链。使用PromptTemplate 构建提示词,喂给 AI 模型,生成结果。如下所示

js 复制代码
import { LLMChain } from "langchain/chains";
import { PromptTemplate } from "langchain/prompts";
import { ChatOpenAI } from "langchain/chat_models/openai";

const prompt = new PromptTemplate({
  template: "写一篇关于{topic}的科普文章,语气要{tone}。",
  inputVariables: ["topic", "tone"],
});

const model = new ChatOpenAI({ temperature: 0.7 });

const chain = new LLMChain({ llm: model, prompt });

const res = await chain.call({
  topic: "量子计算",
  tone: "通俗易懂",
});

console.log(res.text);

SimpleSequentialChain 是顺序链,把多个 LLMChain 串起来,前一个的输出是后一个的输入。

js 复制代码
import { SimpleSequentialChain } from "langchain/chains";

// chain1: 根据主题生成文章大纲
// chain2: 根据大纲生成文章内容

const chain = new SimpleSequentialChain({
  chains: [chain1, chain2],
  verbose: true,
});

const res = await chain.run("人工智能教育");

一步一步处理的流程,比如先写大纲 → 再扩写内容 → 再润色。

MultiPromptChain 是多 prompt 选择链,根据输入的不同选择不同prompt 来调用模型,适合场景切换。

js 复制代码
// 如果你输入是"写代码",就用编码 prompt; 
// 如果你输入是"写诗",就用文艺 prompt。

RetrievalQAChain 是基于知识库问答,结合向量数据库和文档检索,实现 RAG(检索增强生成)

js 复制代码
import { RetrievalQAChain } from "langchain/chains";
import { ChatOpenAI } from "langchain/chat_models/openai";

const chain = RetrievalQAChain.fromLLM(model, retriever);

const res = await chain.call({
  query: "ComfyUI 如何使用节点连接?",
});

ConversationalChain 是带记忆的对话链,用于实现多轮对话的上下文记忆,适用于聊天机器人

上面说了这么多内置的 Chain,实际上 LangChain.js 支持自定义 Chain,根据你的业务场景,通过继承 BaseChain 自定义链,或者组合多个 Chain、Tool、Agent构建高级流程

LangChain.js 中最后一个重要的模块是Memory模块。大家使用 ChatGPT 时经常会对一个问题进行多轮对话,小伙伴们开发这类产品时需要将多轮对话的内容传给 AI 模型,这样才利于AI 模型解决问题,而LangChain.js的Memory模块就是在多轮对话中保存和管理上下文信息,并在每次调用 LLM(大语言模型)时自动注入这些上下文内容。

在 LangChain 中,无论是 RunnableChain 还是 Agent,都可以通过 Memory 插件实现上下文记忆功能。

下面是一些常用的 Memory:

  • BufferMemory 保存对话的完整历史。
  • ConversationSummaryMemory 将对话内容通过 LLM 压缩为摘要,节省 token
  • BufferWindowMemory 和 BufferMemory 类似,但只保留最近 N 条对话,控制上下文大小。
  • ChatMessageHistory 这是一个更底层的模块,BufferMemory 也用它来管理历史消息。可以自定义实现,比如保存到数据库、Redis 等。

通过一个例子熟悉如何使用 Memory 模块

js 复制代码
import { ConversationChain } from "langchain/chains";
import { ChatOpenAI } from "langchain/chat_models/openai";

const model = new ChatOpenAI({ temperature: 0 });
const chain = new ConversationChain({ llm: model, memory });

const res1 = await chain.call({ input: "你好!" });
const res2 = await chain.call({ input: "刚刚我们聊到哪了?" });

第二次调用时,它会自动带上第一次的上下文。

内置 Agent 支持

LangChain.js 中的 Agent 是其最强大也最复杂的部分之一,允许开发人员构建可以"思考"和"行动"的智能体。这些 Agent 可以根据用户输入自动选择合适的工具(Tools)来执行任务,是实现 AI 助理、RPA、智能搜索等高级功能的关键。

在LangChain.js中,Agent 是一种可以 动态选择工具并调用它们来完成任务 的架构。它不是一段静态的 Chain,而是一个具有决策能力的系统。它会分析输入 → 决定用哪个工具 → 使用工具获得结果 → 再判断是否继续。

Agent 的核心组成部分:

  1. LLM(大语言模型) :负责思考与决策
  2. Tools(工具) :可以调用的实际功能,比如搜索、计算、数据库查询等
  3. AgentExecutor:驱动 Agent 运行的引擎
  4. Memory(可选) :用于保存历史,提高上下文智能

下面以 ZeroShotAgent 举例演示如何构建简单的 Agent

js 复制代码
import { initializeAgentExecutorWithOptions } from "langchain/agents";
import { ChatOpenAI } from "langchain/chat_models/openai";
import { Calculator } from "langchain/tools/calculator";

const model = new ChatOpenAI({ temperature: 0 });
const tools = [new Calculator()];

const executor = await initializeAgentExecutorWithOptions(tools, model, {
  agentType: "zero-shot-react-description",
});

const result = await executor.call({ input: "What is 25% of (456 * 34)?" });
console.log(result.output);

上面是一个简单的推理 Agent。有关 Agent 更多使用内容,请阅读官方文档

对接多种数据源(RAG)

RAG 是 Retrieval-Augmented Generation 的缩写,中文常翻译为"检索增强生成"。它是一种结合了信息检索和**生成式 AI(如大型语言模型)**的技术,广泛用于构建问答系统、文档助手、知识库问答等应用。

传统大模型(如 GPT)是"封闭式"的:它只能回答它训练数据中包含的信息。而 RAG 增强了这个过程:

  • Retrieval(检索):首先从一个外部知识库(可以是文档、数据库、网页等)中,根据用户的问题检索出最相关的内容。
  • Augmented(增强) :把检索到的内容作为上下文输入,拼接到用户的问题前,一起交给语言模型处理。
  • Generation(生成) :模型结合上下文内容,生成更加准确、有依据的回答。

多数据源是什么呢?在现实生活中,我们的知识来方方面面,包括不限于:

  • 文档(PDF、Markdown、TXT)
  • 数据库(MySQL、MongoDB 等)
  • API 数据(如天气、股票、内部业务系统)
  • 向量数据库(Pinecone、Weaviate、Supabase 等)
  • 云存储(如 Notion、Google Drive、S3)
  • ... 等等

LangChain.js 对接多种数据源是说 LangChain.js 从多个不同的数据源中并行或统一检索信息,整合为上下文,让模型回答更全面。

对接多种数据源会用到下列组件:

  • Retriever 检索器,从某个数据源中检索文档
  • VectorStore 向量数据库,用于相似度搜索
  • DocumentLoader 数据加载器,从不同格式中读取文档
  • Chain 串联多个组件形成问答流程
  • MultiRetriever 支持多个 Retriever 的组合(LangChain 的高级特性)

比如从各类文档中检索数据

js 复制代码
import { PDFLoader } from "langchain/document_loaders/fs/pdf";
const loader = new PDFLoader("file.pdf");
const docs = await loader.load();

从数据库中检索数据

js 复制代码
import mysql from "mysql2/promise";

const connection = await mysql.createConnection({ host, user, password, database });
const [rows] = await connection.execute("SELECT * FROM knowledge_base");

const docs = rows.map(row => ({
  pageContent: row.content,
  metadata: { source: "mysql", id: row.id }
}));

从 Web/API 中检索数据

js 复制代码
import axios from "axios";

const res = await axios.get("https://api.com/data");
const docs = res.data.items.map(item => ({
  pageContent: item.description,
  metadata: { source: "api", id: item.id }
}));

将上面的数据源通过嵌入模型、构建向量库

js 复制代码
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { OpenAIEmbeddings } from "langchain/embeddings/openai";

const allDocs = [...docsFromPDF, ...docsFromMySQL, ...docsFromAPI];
const vectorStore = await MemoryVectorStore.fromDocuments(allDocs, new OpenAIEmbeddings());

const retriever = vectorStore.asRetriever();

最后构建RAG流程

js 复制代码
import { RetrievalQAChain } from "langchain/chains";

const chain = RetrievalQAChain.fromLLM(openai, multiRetriever);

const res = await chain.call({ query: "关于A和B的知识是什么?" });
console.log(res.text);

对接多种数据源主要解决什么问题?

因为每个LLM的训练的知识不是最新的,如果要获取今天或者昨天的数据,大模型不能提供,那么通过LangChain.js 去网络中搜索对应的知识,进行向量化、再思考优化回复问题,这样做到闭环

模块化能力强,适合构建复杂链条

笔者前面讲述了LangChain.js 的prompt 模版、Chain 和对接多数据源,可以发现这些都是 LangChain.js 提供的各种模块做的,所以说LangChain.js的模块化能力强。

LangChain.js 提供了很多"独立的功能模块",各个功能模块都解耦独立,可以像拼积木一样任意组合、替换、嵌套,来构建自己的 AI 工作流。

LangChain.js 常见的"独立的功能模块"如下:

模块名 作用
LLM 调用大语言模型(如 OpenAI、Claude、LLama)
PromptTemplate 生成提示词模板
Chain 串联模块形成"处理链"
Retriever 用于从向量库等中检索文档
Memory 记录对话历史等上下文
Tool 插件能力,可调用 API、函数等
Agent 智能体,拥有思考和调用工具的能力
VectorStore 向量数据库(如 Pinecone、Weaviate)
DocumentLoader 加载不同格式数据为文档

根据自己的产品业务,选择不同的模块进行拼接,搭建出 AI 应用

跨平台能力好

LangChain.js 的跨平台能力非常强,这是它相较于 Python 版本的一个突出优势。它能够在 Web 前端、Node.js 服务端、移动端甚至 Serverless 环境中灵活运行,为开发 AI 产品(如网页 AI 助理、移动应用、浏览器插件等)提供了极大的便利。

我们知道很多 AI 工具都是用 Python 写的,相关的生态工具也是 Python 写的。LangChain.js 完全使用 TypeScript/JavaScript 编写,没有 Python 库依赖,不需要额外环境配置。适合前端开发者直接上手,尤其是做 MPA、SPA、PWA、小程序、Expo和 Electron等,非常适合前端开发人员使用

下面是LangChain.js支持的运行环境

平台 说明
Node.js 最主要平台,支持大部分功能
浏览器 (Web) 支持运行在浏览器中(无后端)
移动端 (React Native, Expo) 可用,依赖 fetch 和一些 polyfill
Edge / Serverless (Vercel, Cloudflare Workers) 函数部署轻松
Bun / Deno 因为 JS 本身特性,也能支持一些使用

LangChain.js 使用场景

  • 构建智能问答系统(例如 ChatGPT 接入企业知识库)
  • Agent 应用(模型会调用搜索、数据库、API)
  • 多轮对话系统(例如客服机器人)
  • 智能总结、翻译、内容生成

实战

接下来笔者以一个完整的小项目体现 LangChain.js 的运用。用 LangChain.js 设计天气推送机器人 AI Agent,从 0 到 1 设计一个完整的智能体系统,既可以每天获取天气信息,又能通过邮件推送,完全自动化。

架构设计

  1. 配置和风天气 API
  2. 用大模型生成播报文本
  3. 邮件发送
  4. 总调度器 + 定时任务

配置和风天气 API

第三方天气API很多,笔者在这里选用的是和风天气的API。和风天气是一个非常稳定好用的天气 API 平台,适合开发天气查询、天气推送、气象分析等功能。

进入官网注册账户后,在「控制台」中申请 API Key,每个 Key 有不同的权限范围。我们选用今日天气预报。接口路径如下

bash 复制代码
/v7/weather/now

除此之外,你还需要配置your_api_host。最后完整的 getWeather.js 内容如下

js 复制代码
export async function getWeather() {
  try {
    const res = await fetch(
      "https://mh6fr67wbe.re.qweatherapi.com/v7/weather/now?location=101200105&lang=en",
      {
        method: "GET",
        headers: {
          "X-QW-Api-Key": "your Api-Key",
        },
      }
    ).then((res) => res.json());

    if (res.code === "200") {
      return {
        text: res?.now?.text,
        temp: res?.now?.temp,
      };
    }

    return {};
  } catch (error) {
    console.error("Error fetching weather data:", error);
    return {};
  }
}

其中 X-QW-Api-Key 是你的 API_KEY

用大模型生成播报文本

我们使用 LangChain.js 封装星火大模型去生成播报文本。

js 复制代码
// ChatSpark.js

import { BaseChatModel } from "@langchain/core/language_models/chat_models";
import crypto from "crypto";
import WebSocket from "ws";

export class ChatSpark extends BaseChatModel {
  constructor(fields) {
    super(fields);
    this.appId = fields.appId;
    this.apiKey = fields.apiKey;
    this.apiSecret = fields.apiSecret;
    this.temperature = fields.temperature ?? 0.5;
    this.maxTokens = fields.maxTokens ?? 1024;
  }

  _llmType() {
    return "spark";
  }

  async _call(messages) {
    const prompt = this.formatMessages(messages);
    return await this.callSpark(prompt);
  }

  formatMessages(messages) {
    return messages.map((msg) => {
      if (msg._getType() === "human") {
        return { role: "user", content: msg.content };
      } else {
        return { role: "assistant", content: msg.content };
      }
    });
  }

  async callSpark(messages) {
    return new Promise((resolve, reject) => {
      const host = "spark-api.xf-yun.com";
      const path = "/v4.0/chat";
      const date = new Date().toUTCString();

      const signatureOrigin = `host: ${host}\ndate: ${date}\nGET ${path} HTTP/1.1`;
      const signatureSha = crypto
        .createHmac("sha256", this.apiSecret)
        .update(signatureOrigin)
        .digest("base64");

      const authorization = `api_key="${this.apiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${signatureSha}"`;
      const authorizationBase64 = Buffer.from(authorization).toString("base64");

      const url = `wss://${host}${path}?authorization=${authorizationBase64}&date=${encodeURIComponent(
        date
      )}&host=${host}`;

      const ws = new WebSocket(url);
      let result = "";

      ws.on("open", () => {
        const payload = {
          header: {
            app_id: this.appId,
          },
          parameter: {
            chat: {
              domain: "4.0Ultra",
              temperature: this.temperature,
              max_tokens: this.maxTokens,
            },
          },
          payload: {
            message: {
              text: messages,
            },
          },
        };
        ws.send(JSON.stringify(payload));
      });

      ws.on("message", (data) => {
        const resData = JSON.parse(data.toString());
        const choices = resData.payload?.choices?.text || [];
        for (const item of choices) {
          result += item.content;
        }

        if (resData.header?.status === 2) {
          ws.close();
          resolve(result);
        }
      });

      ws.on("error", reject);
      ws.on("close", () => {});
    });
  }
}

启动文件代码如下

js 复制代码
// bootstrap.js

import { ChatSpark } from "./ChatSpark.js";
import { HumanMessage } from "@langchain/core/messages";
import nodemailer from "nodemailer";
import { getWeather } from "./getWeather.js";

const APP_ID = "your APP_ID";
const API_KEY = "your API_KEY";
const API_SECRET = "your API_SECRET";

const chat = new ChatSpark({
  appId: APP_ID,
  apiKey: API_KEY,
  apiSecret: API_SECRET,
  temperature: 0.5,
});

async function bootstrap() {
  const { text, temp } = await getWeather();
  const prompt = `今天天气如下:气温是${JSON.stringify(
    temp
  )}、状态是${text}。请用简洁、亲切的语气,为用户生成一段天气播报(中文)`;
  const answer = await chat._call([new HumanMessage(prompt)]);

  console.log("answer", answer);

  emailPush(answer);
}

bootstrap();

邮件服务

node.js 社区提供一个 nodemailer 功能模块。用于邮件推送服务,笔者选用网易邮箱进行发送,根据要求配置网易邮箱。代码如下

js 复制代码
async function emailPush(htmlContent) {
  const user = "user email";

  const transporter = nodemailer.createTransport({
    host: "smtp.163.com",
    port: 587,
    secure: true,
    auth: {
      user,
      pass: "your pass",
    },
  });

  const subject = getSubject();

  const info = await transporter.sendMail({
    from: user,
    to: "user email",
    subject,
    html: htmlContent,
  });

  console.log("Message sent: %s", info.messageId);
}

function getSubject() {
  const years = new Date().getFullYear();
  const month = new Date().getMonth() + 1;
  const day = new Date().getDate();

  return `${years}年${month}月${day}天气预报`;
}

总调度器 + 定时任务

笔者这里为了简单,直接利用 GitHub Action 执行定时任务

yml 复制代码
name: Run Every Day

on:
  workflow_dispatch:
  schedule:
    - cron: "0 23 * * *"

jobs:
  upcoming_movies:
    runs-on: ubuntu-24.04

    steps:
      - name: Checkout Code
        uses: actions/checkout@v2

      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: "20"

      - name: Install dependencies
        run: npm install --legacy-peer-deps

      - name: Start
        run: npm run start

因为GitHub Action用的是UTC 时间,中国在东八区,设置的23 也就是北京时间早上7点

结果如下

总结

LangChain.js 是做AI应用开发必备技能,提供很多开箱即用的功能模块,可以像搭乐高一样搭建 AI 应用

相关推荐
fleur14 小时前
LoRA微调大模型实践
llm
仙人掌_lz14 小时前
详解如何复现DeepSeek R1:从零开始利用Python构建
开发语言·python·ai·llm·deepseek
量子位14 小时前
字节视频基础大模型发布!单 GPU 就可生成 1080P,蒋路领衔 Seed 视频团队曝光
人工智能·llm
仙人掌_lz17 小时前
如何在本地使用Ollama运行 Hugging Face 模型
java·人工智能·servlet·ai·大模型·llm·ollama
明明跟你说过21 小时前
基于【Lang Chain】构建智能问答系统的实战指南
人工智能·语言模型·chatgpt·langchain
玲小珑1 天前
5分钟学会LLM开发系列教程(五)Agent的最终形态LangGraph
langchain·node.js·ai编程
掘金安东尼1 天前
DeepSeek-R1 全托管无服务器上线亚马逊云 Bedrock,为何值得关注?
人工智能·llm
掘金安东尼1 天前
颠覆 LLM?Meta 提出 LCM 这个新范式
人工智能·llm
Goboy1 天前
Java版的深度学习 · 手撕 DeepLearning4J实现手写数字识别 (附UI效果展示)
llm·aigc·ai编程