langchainjs入门(一)简介和模型调用

81 阅读9分钟

langchain & langgraph

简介

langchain

设计理念
langchain 的设计目标是把各种与大语言模型(LLM)交互的常见构建块抽象成高度可组合、可重用的组件,降低将模型能力嵌入应用的门槛。核心思想是“把模型作为函数来调用并组合这些函数”——通过统一的接口(如 Runnable)来链接提示模板、模型调用、解析器、检索器和工具等,从而以链式方式快速构建文本处理流水线。

特点

  • 组件化与可组合性:大多数组件实现相同的 Runnable 接口,支持 invokebatchstream 等统一调用方式,便于通过 pipe 或其他组合方法构建复杂流程。
  • 丰富的集成:与主流模型提供商(如 OpenAI、Anthropic、Google 等)有对接包,支持检索(retriever)、向量数据库、工具调用、外部 API 等。抹平了供应商之间的不同.
  • 轻量与灵活:适合实现短时、无状态或弱状态的任务,适配快速原型和单次调用场景。
  • 开发体验:提供提示模板、解析器、常用链(chains)和代理(agents)模式,降低构建常见功能(如问答、摘要、信息抽取)的复杂度。

适用场景

  • 单轮问答系统(如知识库查询)
  • 文档摘要与抽取
  • 固定流程的数据处理(例如数据清洗后调用模型生成报告)
  • 快速原型与 PoC(Proof of Concept)
  • 基础的代理模式与工具调用(如 ReAct 模式)

这些场景通常不需要复杂的循环逻辑或长期状态管理,适合使用链式架构快速构建并迭代。

langgraph

设计理念
langgraph 的设计目标是把智能应用的控制流从线性链式抽象提升为有向图(graph)结构,以便更好地表达多步骤决策、条件分支、并行子任务、长期状态与人机协同。通过把每一步工作流建模为节点(node)并用边(edge)描述数据与控制流,提供更强的可观测性、重试、持久化与可插拔的人工干预点。

特点

  • 图式工作流编排:使用有向图表达复杂流程,节点可复用、子图嵌套,支持条件分支与并行执行。
  • 状态与持久化:内置或可配置的检查点(checkpoint)与持久化机制,适合长任务与可恢复的流程。
  • 人机协同:天然支持人工干预点(human-in-the-loop)、审批流与回滚机制,便于在高风险场景中介入。
  • 多智能体与子图:支持多个智能体或子图协作、通信与结果整合,适合复杂协作场景。
  • 观测与调试:通常配合可视化工具或追踪系统(tracing)来观察执行路径、监控运行时数据与诊断失败原因。

适用场景

  • 需要多步骤决策的智能客服系统(例如:按用户问题动态选择检索 → 问答 → 人工审批)
  • 长期交互的对话式应用(如教育辅导、持续任务管理)
  • 金融或合规审批流程(根据规则和金额决定是否需要人工审批)
  • 多智能体协作系统(如团队任务分配与进度协调)
  • 高风险操作流程(例如生产系统变更需人工确认)
  • 支持回滚、持久化与长任务的自动化流程(如复杂文档生成、数据处理管道)

这些场景通常需要精细的流程控制、长期状态管理或复杂决策逻辑,适合使用图结构进行编排。

安装

主包

npm install langchain @langchain/core //当前最新版本是1.0.2
Copy

@langchain/core 是最底层包,langchain 生态系统中除了 langsmith 其他所有软件包都依赖该包。它包含了其他软件包所需要使用的基类。

集成包

各个第三方提供的集成包依赖主包,例如:@langchain/anthropic(专门与 Anthropic 提供的模型对接)、@langchain/community(收集一些由社区贡献但并未被 langchain 收纳的包)。这些包不需要在项目启动时全部安装,按需引入即可。但要注意:集成包都依赖主包,最好在项目中强制指定主包版本:

// package.json
"overrides": {
  "@langchain/core": "^1.0.2"
}
Copy

常见集成包示例:

  • @langchain/community:一些由社区贡献但并未被 langchain 收纳的包
  • @langchain/openai:在 langchain 中使用 OpenAI 的大模型服务
  • @langchain/langgraph:使用有向图的方式构建多智能体或有状态应用
  • langsmith:用于对智能体应用监控与观测的库

langchain 包的组织依赖关系:。

image-20250823225140268.png

Runnable

在正式开始之前我们先了解一下什么是 Runnable

在 LangChain.js 中,Runnable 是一个核心的接口,它定义了一套统一的、可组合的方法,用于执行和管理各种组件。几乎所有 LangChain 组件,如语言模型、提示模板、链、解析器、检索器等,都实现了 Runnable 接口。因此 langchain 中的大部分组件都具备一组相同的标准化调用方式,可以极大地简化组件的使用和组合。

对于任意实现了 Runnable<I, O> 接口的对象(其中 I 是输入类型,O 是输出类型),它都提供了以下核心执行方法:

方法名参数返回值功能与用途
invoke(input, options?)input: I
options?: Partial<RunnableConfig>
Promise<O>基础调用:接收单个输入 input 并执行 Runnable,返回一个 Promise,解析为最终输出 Ooptions 可传运行时配置(回调、标签、元数据等)。
batch(inputs, options?)inputs: I[]
options?: Partial<RunnableConfig> Partial<RunnableConfig>[]
Promise<O[]>批量调用: 高效地处理一组输入 inputs。返回一个 Promise,该 Promise 会解析为一个输出数组 O[]options 可以是一个配置对象(应用于所有输入)或一个配置对象数组(每个输入对应一个配置)。底层实现(如 API 调用)通常能优化批量请求。
stream(input, options?)input: I
options?: Partial<RunnableConfig>
AsyncGenerator<O, void, unknown>流式输出:返回异步生成器,适用于低延迟、逐步输出(如聊天逐字输出)。
streamLog(input, options?)input: I
options?: Partial<RunnableConfig>
AsyncGenerator<RunLogPatch, void, unknown>流式日志:以流的形式返回执行过程的日志补丁,包含中间值、状态变化与错误信息,便于监控与调试。

除了核心执行方法,Runnable 还提供了一系列组合与配置方法,这些方法不执行 Runnable,而是返回一个新的 Runnable 实例,从而实现函数式编程与链式构建:

方法名参数返回值功能与用途
pipe(co)co: RunnableLike<NewOutput>Runnable<I, NewOutput>管道组合:将当前 Runnable 的输出作为下一个 RunnableLike 的输入,返回新的线性执行流程。
withConfig(config)config: RunnableConfigthis (新实例)绑定默认配置:返回带默认运行时配置的 Runnable 实例,便于预设回调、标签等。
withListParser(parser)parser: ListParserRunnable<I, string[]>列表解析:返回新 Runnable,其输出会经过 ListParser 转换为字符串数组。
withTypes<NewI, NewO>()(泛型参数)Runnable<NewI, NewO>类型转换(TypeScript):不改变行为,仅改变类型签名,便于类型适配。

模型调用

开发智能应用的第一步是将大模型集成到项目中。这部分工作可以通过 langchain 提供的集成包来实现。

由于各个模型厂商提供的模型接口差异,在 langchain 中调用不同的模型首先要安装对应的集成包,目前常见的模型厂商包括:

  • openai@langchain/openai
  • anthropic@langchain/anthropic
  • google-gemini@langchain/google-genai
  • mistralai@langchain/mistralai
  • groq@langchain/groq
  • vertexai@langchain/google-vertexai

这里以 deepseek(或任意支持聊天接口的模型)为例,其他模型包可参照相应的集成文档。如果使用的是本地部署模型,请查看对应的 LLM 集成说明。

提示:如果使用第三方代理(gateway)兼容某个标准(例如 OpenAI 标准),在很多情况下只需使用对应标准的集成包(例如 @langchain/openai)即可与该代理通信。

申请 key

在调用大模型之前需要到模型提供商处申请 API key。演示中提到使用 deepseek 的 key,注册后在平台生成 key 并设置到环境变量中即可。

安装集成包(示例)

npm i @langchain/deepseek
import { ChatDeepSeek } from '@langchain/deepseek'
Copy

创建模型

  1. 添加环境变量

    @langchain/deepseek 包在初始化时,会默认使用 DEEPSEEK_API_KEY 中的值来读取 API key。开发时也可以直接在代码中传入 apiKey,但生产环境建议使用环境变量。

    const model = new ChatDeepSeek({
      model: '你的模型名称deepseek-chat/deepseek-reasoner', // deepseek 提供的模型名称
      temperature: 0.5,
      apiKey: 'xxxxx'
    });
    

    更推荐使用 dotenv 注入环境变量:

    1. 新建 .env 文件并设置 key

      // .env
      DEEPSEEK_API_KEY=your-api-key
      Copy
      
    2. 安装并加载 dotenv

      npm i dotenv
      
    3. 在代码中注入环境变量

      import dotenv from 'dotenv'
      dotenv.config()
      console.log(process.env.DEEPSEEK_API_KEY)
      
  2. 实例化模型

const model = new ChatDeepSeek({
  model: "deepseek-chat",
  temperature: 0
})

3. 设置模型参数  

常见的模型参数包括:

*   `model`:要使用的模型名称或标识符(例如 `"deepseek-chat"`)。
*   `temperature`:控制输出随机性(越高越随机)。
*   `maxTokens`:限制生成的最大 token 数量。
*   `stop`:停止序列,指示模型何时结束生成。
*   `apiKey`:用于鉴权的 API key(推荐通过环境变量提供)。

注意:并不是所有集成包都支持所有参数,请参照对应集成包文档。

调用模型

下面介绍两种常用调用方式:普通输出(invoke)和流式输出(stream)。

invoke

实例化模型后可以直接调用 invoke 与模型通信。由于模型对象是 Runnable,它具有统一接口:

const res = await model.invoke('你好,你是谁')

// 返回一个 AIMessage 对象
AIMessage {
  "id": "467ec80fa202490eae7bcf7019ab4e38",
  "content": "我是DeepSeek Chat,由深度求索公司(DeepSeek)开发的智能AI助手!....",
  "additional_kwargs": {
    "function_call": null,
    "tool_calls": null
  },
  "response_metadata": {
    "tokenUsage": {
      "promptTokens": 4,
      "completionTokens": 71,
      "totalTokens": 75
    },
    "finish_reason": "stop",
    "model_name": "DeepSeek-V3"
  },
  "tool_calls": [],
  "invalid_tool_calls": [],
  "usage_metadata": {
    "output_tokens": 71,
    "input_tokens": 4,
    "total_tokens": 75,
    "input_token_details": {},
    "output_token_details": {}
  }
}

invoke 支持多种输入格式:

// 直接字符串
await llm.invoke('你是谁')

// 消息数组
await llm.invoke([
  { role: 'user', content: '你是谁' }
])

// 使用消息类
await llm.invoke([new HumanMessage('你是谁')])

// 二元数组形式
await llm.invoke([["user", "你是谁"]])

stream

调用 stream 可以开启流式输出,返回一个异步可迭代对象,通过 for await 可以逐步获得输出片段,适用于低延迟交互或逐步渲染文本的场景。

const res = await model.stream(userQuest);

for await (const chunk of res) {
  process.stdout.write(chunk.content); // 每一个 chunk 都是一个 AIMessage 片段
}

练习: 使用自己的key调用大模型

本章的内容就到这里,如果您希望继续更新相关内容,请点赞支持一下,您的点赞是我更新的动力!!