langchain & langgraph
简介
langchain
设计理念
langchain 的设计目标是把各种与大语言模型(LLM)交互的常见构建块抽象成高度可组合、可重用的组件,降低将模型能力嵌入应用的门槛。核心思想是“把模型作为函数来调用并组合这些函数”——通过统一的接口(如 Runnable)来链接提示模板、模型调用、解析器、检索器和工具等,从而以链式方式快速构建文本处理流水线。
特点
- 组件化与可组合性:大多数组件实现相同的
Runnable接口,支持invoke、batch、stream等统一调用方式,便于通过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 包的组织依赖关系:。
Runnable
在正式开始之前我们先了解一下什么是 Runnable。
在 LangChain.js 中,Runnable 是一个核心的接口,它定义了一套统一的、可组合的方法,用于执行和管理各种组件。几乎所有 LangChain 组件,如语言模型、提示模板、链、解析器、检索器等,都实现了 Runnable 接口。因此 langchain 中的大部分组件都具备一组相同的标准化调用方式,可以极大地简化组件的使用和组合。
对于任意实现了 Runnable<I, O> 接口的对象(其中 I 是输入类型,O 是输出类型),它都提供了以下核心执行方法:
| 方法名 | 参数 | 返回值 | 功能与用途 |
|---|---|---|---|
invoke(input, options?) | input: Ioptions?: Partial<RunnableConfig> | Promise<O> | 基础调用:接收单个输入 input 并执行 Runnable,返回一个 Promise,解析为最终输出 O。options 可传运行时配置(回调、标签、元数据等)。 |
batch(inputs, options?) | inputs: I[]options?: Partial<RunnableConfig> Partial<RunnableConfig>[] | Promise<O[]> | 批量调用: 高效地处理一组输入 inputs。返回一个 Promise,该 Promise 会解析为一个输出数组 O[]。options 可以是一个配置对象(应用于所有输入)或一个配置对象数组(每个输入对应一个配置)。底层实现(如 API 调用)通常能优化批量请求。 |
stream(input, options?) | input: Ioptions?: Partial<RunnableConfig> | AsyncGenerator<O, void, unknown> | 流式输出:返回异步生成器,适用于低延迟、逐步输出(如聊天逐字输出)。 |
streamLog(input, options?) | input: Ioptions?: Partial<RunnableConfig> | AsyncGenerator<RunLogPatch, void, unknown> | 流式日志:以流的形式返回执行过程的日志补丁,包含中间值、状态变化与错误信息,便于监控与调试。 |
除了核心执行方法,Runnable 还提供了一系列组合与配置方法,这些方法不执行 Runnable,而是返回一个新的 Runnable 实例,从而实现函数式编程与链式构建:
| 方法名 | 参数 | 返回值 | 功能与用途 |
|---|---|---|---|
pipe(co) | co: RunnableLike<NewOutput> | Runnable<I, NewOutput> | 管道组合:将当前 Runnable 的输出作为下一个 RunnableLike 的输入,返回新的线性执行流程。 |
withConfig(config) | config: RunnableConfig | this (新实例) | 绑定默认配置:返回带默认运行时配置的 Runnable 实例,便于预设回调、标签等。 |
withListParser(parser) | parser: ListParser | Runnable<I, string[]> | 列表解析:返回新 Runnable,其输出会经过 ListParser 转换为字符串数组。 |
withTypes<NewI, NewO>() | (泛型参数) | Runnable<NewI, NewO> | 类型转换(TypeScript):不改变行为,仅改变类型签名,便于类型适配。 |
模型调用
开发智能应用的第一步是将大模型集成到项目中。这部分工作可以通过 langchain 提供的集成包来实现。
由于各个模型厂商提供的模型接口差异,在 langchain 中调用不同的模型首先要安装对应的集成包,目前常见的模型厂商包括:
openai:@langchain/openaianthropic:@langchain/anthropicgoogle-gemini:@langchain/google-genaimistralai:@langchain/mistralaigroq:@langchain/groqvertexai:@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
创建模型
-
添加环境变量
@langchain/deepseek包在初始化时,会默认使用DEEPSEEK_API_KEY中的值来读取 API key。开发时也可以直接在代码中传入apiKey,但生产环境建议使用环境变量。const model = new ChatDeepSeek({ model: '你的模型名称deepseek-chat/deepseek-reasoner', // deepseek 提供的模型名称 temperature: 0.5, apiKey: 'xxxxx' });更推荐使用
dotenv注入环境变量:-
新建
.env文件并设置 key// .env DEEPSEEK_API_KEY=your-api-key Copy -
安装并加载
dotenvnpm i dotenv -
在代码中注入环境变量
import dotenv from 'dotenv' dotenv.config() console.log(process.env.DEEPSEEK_API_KEY)
-
-
实例化模型
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调用大模型
本章的内容就到这里,如果您希望继续更新相关内容,请点赞支持一下,您的点赞是我更新的动力!!