版本基准:LangChain.js v1 系列,资料核对日期:2026-07-07。
本手册面向 Node.js / TypeScript 开发者,目标不是逐字翻译官方文档,而是把 LangChain.js 的核心 API、调用关系、常见组合方式和工程实践整理成一份可以直接落地的中文开发文档。
1. LangChain.js 是什么
LangChain.js 是一个用于构建 LLM 应用的 JavaScript / TypeScript 框架。它把大模型应用拆成若干可组合模块:模型、消息、提示词、工具、Agent、RAG 检索、结构化输出、流式事件、记忆和观测。
在 v1 系列里,LangChain.js 的主线是:
- 用
createAgent快速创建可调用工具、可流式输出、可加中间件的生产级 Agent。 - 用
initChatModel或具体 provider 包创建聊天模型。 - 用标准
messages表示对话上下文。 - 用
tool暴露外部函数、API、数据库、搜索等能力。 - 用
Runnable/ LCEL 把 Prompt、Model、Parser、Retriever 等步骤组合成调用链。 - 用
@langchain/classic兼容旧版 chains、内存向量库和部分老式 RAG API。 - 复杂状态机、分支、多 Agent 编排底层由 LangGraph 支撑。
一个典型调用关系如下:
flowchart LR
U["用户输入"] --> M["messages"]
M --> A["Agent 或 Runnable Chain"]
A --> L["Chat Model"]
L -->|需要外部动作| T["Tool"]
T --> A
A -->|需要知识库| R["Retriever / VectorStore"]
R --> A
A --> O["Output Parser / Structured Response"]
O --> RES["应用响应"]
2. 版本和包结构
截至 2026-07-07,通过 npm 核对到的版本:
| 包 | 当前核对版本 | 主要用途 |
|---|---|---|
langchain | 1.5.2 | v1 顶层 API:createAgent、initChatModel、中间件、消息类、顶层 tool 等 |
@langchain/core | 1.2.1 | 核心抽象:messages、prompts、runnables、output parsers、documents、retrievers、vectorstore interface |
@langchain/openai | 1.5.3 | OpenAI / Azure OpenAI 模型、Embedding、内置工具封装 |
@langchain/community | 1.1.29 | 社区集成:大量 loaders、vector stores、search tools 等 |
@langchain/classic | 1.0.38 | 旧版 chains、部分 document loaders、MemoryVectorStore、legacy retrievers |
@langchain/textsplitters | 1.0.1 | 文本切分器:RecursiveCharacterTextSplitter、TokenTextSplitter 等 |
@langchain/langgraph | 1.4.7 | 状态图、多步编排、Agent 运行时底层 |
推荐把包职责记成三层:
应用层: langchain
核心协议层: @langchain/core
集成/兼容层: @langchain/openai、@langchain/community、@langchain/classic、@langchain/textsplitters
3. 安装与项目初始化
官方 v1 文档要求 Node.js 22+。推荐使用 ESM。
npm init -y
npm install langchain @langchain/core zod
npm install @langchain/openai
npm install @langchain/textsplitters @langchain/classic
npm install @langchain/langgraph
如果需要社区加载器、向量数据库或搜索工具:
npm install @langchain/community
package.json 建议:
{
"type": "module",
"scripts": {
"dev": "tsx src/index.ts"
},
"dependencies": {
"langchain": "^1.5.2",
"@langchain/core": "^1.2.1",
"@langchain/openai": "^1.5.3",
"@langchain/textsplitters": "^1.0.1",
"@langchain/classic": "^1.0.38",
"@langchain/langgraph": "^1.4.7",
"zod": "^4"
},
"devDependencies": {
"tsx": "^4"
}
}
环境变量示例:
export OPENAI_API_KEY="..."
export LANGCHAIN_MODEL="openai:gpt-4o-mini"
# 可选:开启 LangSmith tracing
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="..."
export LANGSMITH_PROJECT="langchain-js-demo"
生产环境不要把 provider API key 暴露到浏览器端。需要在浏览器里调用时,通常由你的后端或边缘函数代理。
4. 最小可运行示例
import { createAgent, tool } from "langchain";
import { z } from "zod";
const getWeather = tool(
async ({ city }) => {
return `${city} 今天晴,25 摄氏度。`;
},
{
name: "get_weather",
description: "查询城市天气",
schema: z.object({
city: z.string().describe("城市名称"),
}),
}
);
const agent = createAgent({
model: process.env.LANGCHAIN_MODEL ?? "openai:gpt-4o-mini",
tools: [getWeather],
prompt: "你是一个简洁、可靠的中文助手。需要实时信息时先调用工具。",
});
const result = await agent.invoke({
messages: [
{
role: "user",
content: "上海今天适合户外跑步吗?",
},
],
});
console.log(result.messages.at(-1)?.content);
这个例子的调用链是:
agent.invoke({ messages })
-> Agent 读取 messages + prompt
-> Chat Model 判断是否需要工具
-> 生成 tool call: get_weather({ city: "上海" })
-> LangChain 调用 getWeather 工具函数
-> 工具结果作为 ToolMessage 回到 Agent 状态
-> Chat Model 结合工具结果生成最终回复
-> result.messages 返回完整消息轨迹
5. 核心概念总览
| 概念 | 代表 API | 输入 | 输出 | 常见位置 |
|---|---|---|---|---|
| Message | HumanMessage、AIMessage、ToolMessage | 文本、内容块、工具结果 | 标准消息对象 | 所有聊天模型和 Agent |
| Chat Model | initChatModel、ChatOpenAI | messages / prompt value | AIMessage / stream chunk | 推理核心 |
| Prompt | ChatPromptTemplate | 变量对象 | prompt value / messages | 模型调用前 |
| Tool | tool、DynamicStructuredTool | schema 验证后的参数 | 字符串或结构化结果 | Agent 或 tool-calling 模型 |
| Runnable | RunnableSequence、.pipe() | 泛型输入 | 泛型输出 | LCEL 组合链 |
| Parser | StringOutputParser、JsonOutputParser | 模型输出 | string / JSON / typed object | 模型调用后 |
| Document | Document | pageContent + metadata | 文档对象 | RAG |
| Text Splitter | RecursiveCharacterTextSplitter | 文档或文本 | 文档切片 | 入库前 |
| Embeddings | OpenAIEmbeddings | 文本 | 向量 | 向量库 |
| VectorStore | MemoryVectorStore、Chroma、PGVector | documents + embeddings | retriever / search results | RAG |
| Retriever | vectorStore.asRetriever() | query | Document[] | RAG 和 Agent 工具 |
| Agent | createAgent | messages + state/context | messages + structured response | 复杂任务执行 |
| Middleware | modelRetryMiddleware 等 | Agent 请求/状态/工具调用 | 改写、重试、拦截 | 生产治理 |
6. Message API
LangChain.js 使用消息数组表示对话。可以用轻量对象:
const messages = [
{ role: "system", content: "你是一个严谨的中文助手。" },
{ role: "user", content: "解释一下 RAG。" },
];
也可以用类:
import { SystemMessage, HumanMessage } from "langchain";
const messages = [
new SystemMessage("你是一个严谨的中文助手。"),
new HumanMessage("解释一下 RAG。"),
];
常用消息类型:
| 类型 | 作用 |
|---|---|
SystemMessage | 系统指令,定义角色、边界、输出风格 |
HumanMessage | 用户输入 |
AIMessage | 模型输出,可能包含 tool_calls、usage、内容块 |
ToolMessage | 工具执行结果,通常带 tool_call_id |
BaseMessage | 所有消息的基类 |
模型返回的 AIMessage 可能包含:
const ai = await model.invoke(messages);
console.log(ai.content); // 文本或内容数组
console.log(ai.tool_calls); // 模型请求调用的工具
console.log(ai.response_metadata);
console.log(ai.usage_metadata);
v1 还支持标准内容块。不同 provider 的原始格式可能不同,但 LangChain 会尽量通过 contentBlocks 暴露标准化视图,适合处理文本、工具调用、多模态内容等。
7. Model API
7.1 使用 initChatModel
initChatModel 是 v1 推荐的统一初始化方式,字符串通常采用 provider:model 形式。
import { initChatModel } from "langchain";
const model = await initChatModel(
process.env.LANGCHAIN_MODEL ?? "openai:gpt-4o-mini",
{
temperature: 0.2,
}
);
const response = await model.invoke([
{ role: "user", content: "用三句话介绍 LangChain.js。" },
]);
console.log(response.content);
调用关系:
initChatModel("openai:gpt-4o-mini")
-> 根据 provider 前缀解析具体模型包
-> 返回 BaseChatModel 实例
model.invoke(messages)
-> provider SDK 请求
-> LangChain 标准化为 AIMessage
7.2 使用 provider 具体类
如果你需要 provider 特有参数,直接使用集成包:
import { ChatOpenAI } from "@langchain/openai";
const model = new ChatOpenAI({
model: "gpt-4o-mini",
temperature: 0,
timeout: 30_000,
});
const res = await model.invoke([
{ role: "user", content: "返回一个 JSON 对象:name=LangChain.js" },
]);
7.3 常用模型方法
| 方法 | 说明 | 典型用途 |
|---|---|---|
invoke(input, options?) | 单次调用 | 普通问答 |
batch(inputs, options?) | 批量调用 | 批处理分类、抽取 |
stream(input, options?) | 流式 token / chunk | 前端边生成边展示 |
streamEvents(input, options?) | 事件流 | 细粒度 UI、观测、工具调用过程 |
bindTools(tools, kwargs?) | 把工具 schema 绑定给模型 | 手动 tool calling |
withStructuredOutput(schema, config?) | 约束输出为结构化对象 | 信息抽取、分类 |
withConfig(config) | 绑定运行配置 | tags、metadata、timeout、callbacks |
withRetry(fields?) | 调用失败重试 | 网络/限流容错 |
withFallbacks([...]) | 主模型失败时切换模型 | 多 provider 高可用 |
7.4 批量调用
const inputs = [
[{ role: "user", content: "把 good 翻译成中文" }],
[{ role: "user", content: "把 reliable 翻译成中文" }],
];
const outputs = await model.batch(inputs, {
maxConcurrency: 3,
});
for (const output of outputs) {
console.log(output.content);
}
7.5 流式调用
const stream = await model.stream([
{ role: "user", content: "用中文写一段 100 字的产品介绍。" },
]);
for await (const chunk of stream) {
process.stdout.write(String(chunk.content ?? ""));
}
如果你在做复杂 UI,优先看 streamEvents 或 Agent 的 streamMode,它能区分模型开始、内容块、工具调用、工具结果等事件。
8. Prompt API
Prompt API 的作用是把模板变量转换成模型能理解的 prompt value 或 messages。
8.1 ChatPromptTemplate
import { ChatPromptTemplate } from "@langchain/core/prompts";
const prompt = ChatPromptTemplate.fromMessages([
["system", "你是一个{role},回答必须使用中文。"],
["human", "{question}"],
]);
const value = await prompt.invoke({
role: "资深 Node.js 工程师",
question: "什么是 LCEL?",
});
console.log(value.toChatMessages());
调用关系:
ChatPromptTemplate.fromMessages(template)
-> prompt.invoke({ variables })
-> 生成 ChatPromptValue
-> model.invoke(promptValue)
8.2 Prompt + Model + Parser
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
import { initChatModel } from "langchain";
const model = await initChatModel("openai:gpt-4o-mini", { temperature: 0 });
const prompt = ChatPromptTemplate.fromMessages([
["system", "你是一个善于总结的中文助手。"],
["human", "请把下面内容压缩成 3 个要点:\n{content}"],
]);
const chain = prompt.pipe(model).pipe(new StringOutputParser());
const answer = await chain.invoke({
content: "LangChain.js 提供模型、工具、Agent、RAG 等能力...",
});
console.log(answer);
这里的 pipe 就是把上一步输出传给下一步:
{ content }
-> ChatPromptTemplate.invoke
-> ChatPromptValue
-> ChatModel.invoke
-> AIMessage
-> StringOutputParser.invoke
-> string
8.3 MessagesPlaceholder
多轮对话时,把历史消息放入模板:
import {
ChatPromptTemplate,
MessagesPlaceholder,
} from "@langchain/core/prompts";
const prompt = ChatPromptTemplate.fromMessages([
["system", "你是客服助手。"],
new MessagesPlaceholder("history"),
["human", "{input}"],
]);
const chain = prompt.pipe(model);
const res = await chain.invoke({
history: [
{ role: "user", content: "我买了会员。" },
{ role: "assistant", content: "好的,请问需要什么帮助?" },
],
input: "怎么开发票?",
});
9. Runnable / LCEL
Runnable 是 LangChain.js 的“统一可执行接口”。Prompt、Model、Parser、Retriever、Tool 都可以被看成 Runnable 或类 Runnable 对象。
9.1 Runnable 的核心方法
| 方法 | 语义 |
|---|---|
invoke(input, options?) | 单次执行 |
batch(inputs, options?) | 批量执行 |
stream(input, options?) | 流式执行 |
streamEvents(input, options?) | 流式事件 |
pipe(next) | 串联下一个 Runnable |
withConfig(config) | 绑定配置 |
withRetry({ stopAfterAttempt }) | 包装重试 |
withFallbacks([fallback]) | 包装 fallback |
getGraph() | 获取执行图,适合调试 |
9.2 RunnableSequence
.pipe() 最终会形成顺序执行的 RunnableSequence。
import { RunnableSequence } from "@langchain/core/runnables";
const chain = RunnableSequence.from([
prompt,
model,
new StringOutputParser(),
]);
const output = await chain.invoke({ content: "..." });
9.3 RunnableLambda
当你需要把普通函数插入链中:
import { RunnableLambda } from "@langchain/core/runnables";
const trimInput = RunnableLambda.from((input: { text: string }) => ({
text: input.text.trim(),
}));
const chain = trimInput.pipe(prompt).pipe(model).pipe(new StringOutputParser());
9.4 RunnablePassthrough 和并行映射
RAG 经常需要“保留原始问题,同时新增检索上下文”:
import {
RunnablePassthrough,
RunnableSequence,
} from "@langchain/core/runnables";
import { formatDocumentsAsString } from "@langchain/classic/util/document";
const ragChain = RunnableSequence.from([
{
question: new RunnablePassthrough(),
context: retriever.pipe(formatDocumentsAsString),
},
prompt,
model,
new StringOutputParser(),
]);
const answer = await ragChain.invoke("LangChain.js 的 Agent 怎么调用工具?");
第一步对象映射会并行执行:
输入 question
-> question: RunnablePassthrough 返回原输入
-> context: retriever.invoke(question) -> Document[] -> formatDocumentsAsString
-> 合并为 { question, context }
-> prompt -> model -> parser
10. Output Parser API
Output Parser 用于把模型输出转换成应用需要的数据结构。
10.1 StringOutputParser
import { StringOutputParser } from "@langchain/core/output_parsers";
const chain = prompt.pipe(model).pipe(new StringOutputParser());
const text = await chain.invoke({ topic: "LangChain.js" });
10.2 JsonOutputParser
import { JsonOutputParser } from "@langchain/core/output_parsers";
const parser = new JsonOutputParser<{
title: string;
tags: string[];
}>();
const chain = prompt.pipe(model).pipe(parser);
const json = await chain.invoke({ text: "..." });
注意:JsonOutputParser 依赖模型遵循 JSON 指令。更可靠的方式是使用 withStructuredOutput 或 Agent 的 responseFormat。
10.3 StructuredOutputParser
import { StructuredOutputParser } from "@langchain/core/output_parsers";
import { z } from "zod";
const schema = z.object({
intent: z.enum(["refund", "invoice", "other"]),
confidence: z.number().min(0).max(1),
});
const parser = StructuredOutputParser.fromZodSchema(schema);
const prompt = ChatPromptTemplate.fromMessages([
["system", "根据用户输入识别意图。{format_instructions}"],
["human", "{input}"],
]).partial({
format_instructions: parser.getFormatInstructions(),
});
const chain = prompt.pipe(model).pipe(parser);
const result = await chain.invoke({ input: "我想开发票" });
10.4 模型原生结构化输出
如果 provider 支持结构化输出,优先使用:
import { z } from "zod";
const Ticket = z.object({
category: z.enum(["bug", "billing", "feature"]),
priority: z.enum(["low", "medium", "high"]),
summary: z.string(),
});
const structuredModel = model.withStructuredOutput(Ticket);
const ticket = await structuredModel.invoke([
{ role: "user", content: "用户说付款成功但会员没到账。" },
]);
console.log(ticket.category);
调用关系:
model.withStructuredOutput(schema)
-> 返回 Runnable
-> Runnable.invoke(messages)
-> provider 结构化输出或 tool-calling/fallback 策略
-> Zod/schema 校验
-> typed object
11. Tool API
Tool 是让模型“行动”的接口,例如查天气、查数据库、调用 HTTP API、检索知识库、发邮件等。
11.1 创建工具
import { tool } from "langchain";
import { z } from "zod";
const calculator = tool(
async ({ expression }) => {
// 生产环境不要直接 eval,这里只展示调用结构。
return `表达式是:${expression}`;
},
{
name: "calculator",
description: "计算数学表达式",
schema: z.object({
expression: z.string().describe("数学表达式,例如 3 * (4 + 5)"),
}),
}
);
Tool 定义包含三件事:
| 字段 | 作用 |
|---|---|
name | 模型选择工具时使用的稳定标识 |
description | 告诉模型什么时候应该调用这个工具 |
schema | 用 Zod / JSON Schema 描述参数,负责校验和提示 |
11.2 直接调用工具
const result = await calculator.invoke({
expression: "3 * (4 + 5)",
});
console.log(result);
11.3 工具传给 Agent
const agent = createAgent({
model: "openai:gpt-4o-mini",
tools: [calculator],
});
const res = await agent.invoke({
messages: [{ role: "user", content: "3 乘以 9 等于多少?" }],
});
Agent 的工具调用循环:
sequenceDiagram
participant App as 应用
participant Agent as LangChain Agent
participant Model as Chat Model
participant Tool as Tool
App->>Agent: invoke({ messages })
Agent->>Model: messages + tool schemas
Model-->>Agent: AIMessage(tool_calls)
Agent->>Tool: invoke(validated args)
Tool-->>Agent: tool result
Agent->>Model: messages + ToolMessage
Model-->>Agent: final AIMessage
Agent-->>App: state/messages
11.4 手动 tool calling
不使用 Agent 时,也可以手动绑定工具:
const modelWithTools = model.bindTools?.([calculator]);
if (!modelWithTools) {
throw new Error("当前模型不支持 bindTools");
}
const aiMessage = await modelWithTools.invoke([
{ role: "user", content: "帮我计算 18 * 42" },
]);
console.log(aiMessage.tool_calls);
手动模式需要你自己执行 tool_calls,再把 ToolMessage 放回消息数组。Agent 则会替你管理这套循环。
12. Agent API
createAgent 是 v1 的核心 API。它创建的是一个可运行的 ReAct Agent:模型会在“思考 -> 决定工具 -> 调用工具 -> 观察结果 -> 继续推理”之间循环,直到生成最终答案或被中断。
12.1 基础参数
const agent = createAgent({
model: "openai:gpt-4o-mini",
tools: [searchTool, calculator],
prompt: "你是企业知识库助手。回答必须中文,必要时调用工具。",
});
常用参数:
| 参数 | 类型 | 作用 |
|---|---|---|
model | string 或模型配置 | 通过 "provider:model" 快速指定模型 |
llm | Chat model instance | 已经初始化好的模型实例 |
tools | tool array 或 ToolNode | Agent 可调用的工具 |
prompt | string / SystemMessage / function | 系统指令或动态提示词 |
responseFormat | Zod schema / JSON Schema | 结构化最终输出 |
middleware | middleware array | 重试、fallback、PII、人工审核、动态系统提示等 |
stateSchema | LangGraph StateSchema | 自定义状态和短期记忆 |
contextSchema | schema | 每次调用传入的运行上下文 |
streamTransformers | transformer array | 自定义流式转换 |
12.2 调用 Agent
const result = await agent.invoke({
messages: [
{ role: "user", content: "帮我查一下订单 123 的状态。" },
],
});
const finalMessage = result.messages.at(-1);
console.log(finalMessage?.content);
Agent 的输入输出核心是状态对象。最常见状态字段是 messages,如果启用结构化输出,还会有 structuredResponse。
12.3 结构化输出
import { createAgent } from "langchain";
import { z } from "zod";
const ContactInfo = z.object({
name: z.string(),
email: z.string().email(),
phone: z.string().optional(),
});
const agent = createAgent({
model: "openai:gpt-4o-mini",
tools: [],
responseFormat: ContactInfo,
});
const result = await agent.invoke({
messages: [
{
role: "user",
content: "提取联系人:张三,zhangsan@example.com,电话 13800138000",
},
],
});
console.log(result.structuredResponse);
调用关系:
createAgent({ responseFormat: ZodSchema })
-> Agent 最终答案阶段要求结构化输出
-> provider native structured output 或 tool strategy
-> schema 校验
-> result.structuredResponse
12.4 流式 Agent
const stream = await agent.stream(
{
messages: [{ role: "user", content: "查天气并给出穿衣建议。" }],
},
{
streamMode: "values",
}
);
for await (const chunk of stream) {
const last = chunk.messages?.at(-1);
if (last?.content) {
console.log(last.content);
}
}
常见流式模式:
| 模式 | 适合场景 |
|---|---|
values | 每次返回当前完整状态,容易调试 |
updates | 返回每个节点的增量更新,适合进度 UI |
messages | 关注模型 token / message chunk |
custom | 自定义事件流 |
具体支持情况会随版本演进,使用前建议查当前官方 streaming 文档。
12.5 中间件
中间件让你在 Agent 运行过程中插入治理逻辑。
import {
createAgent,
modelRetryMiddleware,
toolRetryMiddleware,
modelFallbackMiddleware,
} from "langchain";
const agent = createAgent({
model: "openai:gpt-4o-mini",
tools: [searchTool],
middleware: [
modelRetryMiddleware({
maxRetries: 3,
}),
toolRetryMiddleware({
maxRetries: 2,
}),
modelFallbackMiddleware("anthropic:claude-sonnet-4-5"),
],
});
常用中间件类别:
| 中间件 | 作用 |
|---|---|
modelRetryMiddleware | 模型调用失败重试 |
toolRetryMiddleware | 工具失败重试 |
modelFallbackMiddleware | 主模型失败时切换备用模型 |
modelCallLimitMiddleware | 限制模型调用次数 |
toolCallLimitMiddleware | 限制工具调用次数 |
dynamicSystemPromptMiddleware | 按上下文动态生成系统提示 |
summarizationMiddleware | 长对话自动摘要 |
piiMiddleware / piiRedactionMiddleware | 检测或脱敏敏感信息 |
humanInTheLoopMiddleware | 对高风险工具调用做人审 |
openAIModerationMiddleware | provider moderation |
13. RAG:加载、切分、向量化、检索、生成
RAG 的标准流程:
flowchart LR
A["Document Loader"] --> B["Text Splitter"]
B --> C["Embeddings"]
C --> D["VectorStore"]
D --> E["Retriever"]
E --> F["Prompt"]
F --> G["Model"]
G --> H["Parser / Answer"]
13.1 文档对象
import { Document } from "@langchain/core/documents";
const doc = new Document({
pageContent: "LangChain.js 支持 Agent、RAG 和工具调用。",
metadata: {
source: "manual",
section: "intro",
},
});
pageContent 是用于检索和上下文注入的正文,metadata 存来源、标题、时间、权限、标签等。
13.2 加载文档
简单文本文件可用 @langchain/classic:
import { TextLoader } from "@langchain/classic/document_loaders/fs/text";
const loader = new TextLoader("./docs/handbook.txt");
const docs = await loader.load();
社区集成常见路径:
import { PDFLoader } from "@langchain/community/document_loaders/fs/pdf";
import { CSVLoader } from "@langchain/community/document_loaders/fs/csv";
import { CheerioWebBaseLoader } from "@langchain/community/document_loaders/web/cheerio";
13.3 文本切分
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 800,
chunkOverlap: 120,
});
const splits = await splitter.splitDocuments(docs);
切分建议:
- 普通中文文档可以从
chunkSize: 500-1000、chunkOverlap: 80-150开始。 - API 文档、法律条款、财报等高结构文本,应按标题、段落、表格边界保留语义。
metadata.source、metadata.page、metadata.heading很重要,最终答案需要引用来源时会用到。
13.4 Embeddings
import { OpenAIEmbeddings } from "@langchain/openai";
const embeddings = new OpenAIEmbeddings({
model: "text-embedding-3-small",
});
const queryVector = await embeddings.embedQuery("什么是 Agent?");
const docVectors = await embeddings.embedDocuments([
"Agent 可以调用工具。",
"Retriever 用于检索文档。",
]);
13.5 向量库
内存向量库适合 demo 和测试:
import { MemoryVectorStore } from "@langchain/classic/vectorstores/memory";
const vectorStore = await MemoryVectorStore.fromDocuments(
splits,
embeddings
);
const results = await vectorStore.similaritySearch("Agent 如何调用工具?", 3);
console.log(results.map((doc) => doc.pageContent));
生产环境一般使用 Chroma、PGVector、Pinecone、Weaviate、Milvus、Elasticsearch 等持久化向量库。
13.6 Retriever
const retriever = vectorStore.asRetriever({
k: 4,
});
const relevantDocs = await retriever.invoke("LangChain.js 如何实现 RAG?");
Retriever 是 Runnable,所以可以直接接入 chain:
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
import { RunnableSequence, RunnablePassthrough } from "@langchain/core/runnables";
import { formatDocumentsAsString } from "@langchain/classic/util/document";
const prompt = ChatPromptTemplate.fromMessages([
[
"system",
"你是知识库问答助手。只根据 context 回答;不知道就说不知道。\n\ncontext:\n{context}",
],
["human", "{question}"],
]);
const ragChain = RunnableSequence.from([
{
question: new RunnablePassthrough(),
context: retriever.pipe(formatDocumentsAsString),
},
prompt,
model,
new StringOutputParser(),
]);
const answer = await ragChain.invoke("LangChain.js 的 Runnable 是什么?");
13.7 classic createRetrievalChain
如果你维护旧版 LangChain.js 项目,可能会看到这种写法:
import { createRetrievalChain } from "@langchain/classic/chains/retrieval";
import { createStuffDocumentsChain } from "@langchain/classic/chains/combine_documents";
import { ChatPromptTemplate } from "@langchain/core/prompts";
const qaPrompt = ChatPromptTemplate.fromMessages([
[
"system",
"根据 context 回答问题。\n\ncontext:\n{context}",
],
["human", "{input}"],
]);
const combineDocsChain = await createStuffDocumentsChain({
llm: model,
prompt: qaPrompt,
});
const retrievalChain = await createRetrievalChain({
retriever,
combineDocsChain,
});
const response = await retrievalChain.invoke({
input: "LangChain.js 的 tool 是什么?",
});
console.log(response.answer);
这套 API 位于 @langchain/classic,适合兼容旧项目。新项目可以优先考虑 v1 Agent 或直接用 Runnable 组合。
13.8 把 Retriever 做成 Agent 工具
import { tool } from "langchain";
import { z } from "zod";
const knowledgeSearch = tool(
async ({ query }) => {
const docs = await retriever.invoke(query);
return docs
.map((doc, index) => {
const source = doc.metadata?.source ?? "unknown";
return `#${index + 1} [${source}]\n${doc.pageContent}`;
})
.join("\n\n");
},
{
name: "knowledge_search",
description: "检索公司知识库,适合回答产品、政策、内部文档问题。",
schema: z.object({
query: z.string(),
}),
}
);
const agent = createAgent({
model: "openai:gpt-4o-mini",
tools: [knowledgeSearch],
prompt: "你是公司知识库助手。需要事实依据时先调用 knowledge_search。",
});
这种方式让模型自己判断什么时候需要检索;而 Runnable RAG 链则是每次都先检索。
14. Memory / 多轮对话
最简单的记忆就是由应用保存历史消息,并在下次调用时传回去:
const history = [
{ role: "user", content: "我叫李雷。" },
{ role: "assistant", content: "好的,我记住了。" },
];
const result = await agent.invoke({
messages: [
...history,
{ role: "user", content: "我叫什么?" },
],
});
Agent 也可以通过 checkpointer 和 thread id 管理短期记忆,适合多轮会话。关键点是:创建 Agent 时要传入 checkpointer,调用时用同一个 thread_id。
import { createAgent } from "langchain";
import { MemorySaver } from "@langchain/langgraph";
const checkpointer = new MemorySaver();
const agent = createAgent({
model: "openai:gpt-4o-mini",
tools: [],
checkpointer,
});
const result1 = await agent.invoke(
{
messages: [{ role: "user", content: "我叫李雷。" }],
},
{
configurable: {
thread_id: "user-42",
},
}
);
const result2 = await agent.invoke(
{
messages: [{ role: "user", content: "我叫什么?" }],
},
{
configurable: {
thread_id: "user-42",
},
}
);
工程建议:
- “会话历史”适合短期上下文,不适合长期知识。
- 长期知识应进入数据库、向量库或 profile store。
- 长对话要配合摘要、裁剪或检索,否则 token 成本和幻觉风险都会上升。
- thread id 要稳定,通常使用
tenantId:userId:conversationId。
15. 结构化输出策略
有三种常见方式:
| 方式 | 推荐程度 | 适合场景 |
|---|---|---|
model.withStructuredOutput(schema) | 高 | 单步抽取、分类、路由 |
createAgent({ responseFormat }) | 高 | Agent 最终输出需要结构化 |
StructuredOutputParser + format instructions | 中 | provider 不支持原生结构化输出,或兼容旧链 |
| 纯 prompt 要求 JSON | 低 | 临时 demo |
单步抽取:
const Extract = z.object({
company: z.string(),
amount: z.number(),
currency: z.string(),
});
const extractor = model.withStructuredOutput(Extract);
const data = await extractor.invoke([
{
role: "user",
content: "ACME 在本季度采购了 12.5 万美元的服务。",
},
]);
Agent 最终结构化输出:
const SupportAnswer = z.object({
answer: z.string(),
citedSources: z.array(z.string()),
needsHuman: z.boolean(),
});
const supportAgent = createAgent({
model: "openai:gpt-4o-mini",
tools: [knowledgeSearch],
responseFormat: SupportAnswer,
});
注意:结构化输出并不等于事实正确,它只保证形状更稳定。事实性仍要靠检索、工具、校验和来源引用。
16. API 调用关系速查
16.1 普通聊天
initChatModel / new ChatOpenAI
-> model.invoke(messages)
-> AIMessage
16.2 Prompt 链
ChatPromptTemplate
-> prompt.invoke(vars)
-> ChatPromptValue
-> model.invoke(promptValue)
-> AIMessage
-> parser.invoke(AIMessage)
-> app result
16.3 Runnable 链
step1.pipe(step2).pipe(step3)
-> RunnableSequence
-> invoke(input)
-> step1.invoke(input)
-> step2.invoke(step1Output)
-> step3.invoke(step2Output)
16.4 手动工具调用
tool(fn, schema)
-> model.bindTools([tool])
-> model.invoke(messages)
-> AIMessage.tool_calls
-> app executes tool.invoke(args)
-> app appends ToolMessage
-> model.invoke(updatedMessages)
16.5 Agent 工具调用
createAgent({ model, tools, middleware })
-> agent.invoke({ messages })
-> model call
-> tool calls
-> tool execution
-> model call
-> final messages / structuredResponse
16.6 RAG 链
loader.load()
-> splitter.splitDocuments(docs)
-> embeddings.embedDocuments(chunks)
-> vectorStore.addDocuments(chunks)
-> retriever.invoke(question)
-> prompt({ context, question })
-> model.invoke
-> parser.invoke
16.7 RAG Agent
retriever -> wrapped as tool
createAgent({ tools: [knowledgeSearch] })
-> model decides whether to search
-> knowledgeSearch invokes retriever
-> docs returned as tool result
-> model answers with retrieved context
17. 错误处理、超时、重试
17.1 Runnable 级重试
const reliableChain = chain.withRetry({
stopAfterAttempt: 3,
});
const answer = await reliableChain.invoke(input);
17.2 Fallback
const primary = await initChatModel("openai:gpt-4o-mini");
const fallback = await initChatModel("anthropic:claude-sonnet-4-5");
const robustModel = primary.withFallbacks([fallback]);
17.3 超时和取消
const controller = new AbortController();
setTimeout(() => controller.abort(), 10_000);
await chain.invoke(
{ question: "..." },
{
signal: controller.signal,
timeout: 10_000,
}
);
17.4 Agent 级治理
const agent = createAgent({
model: "openai:gpt-4o-mini",
tools,
middleware: [
modelCallLimitMiddleware({ runLimit: 8 }),
toolCallLimitMiddleware({ runLimit: 10 }),
modelRetryMiddleware({ maxRetries: 3 }),
],
});
生产建议:
- 工具要自己做输入校验、权限校验、速率限制和幂等设计。
- 模型重试不能无限重试,避免成本失控。
- 外部副作用工具,如付款、删库、发邮件,应接入人工确认或二次确认。
- RAG 结果为空时不要让模型硬答,应该显式告诉模型“没有检索到依据”。
18. 观测与调试
LangChain.js 和 LangSmith 深度集成。常用环境变量:
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="..."
export LANGSMITH_PROJECT="my-project"
运行配置可加 tags 和 metadata:
await chain.invoke(
{ question: "..." },
{
tags: ["rag", "support"],
metadata: {
userId: "u_123",
route: "support_chat",
},
runName: "support-rag-chain",
}
);
调试思路:
- 先看输入 messages 是否包含预期系统指令。
- 再看模型是否产生 tool call。
- 再看 tool 参数是否通过 schema。
- 再看工具返回内容是否足够模型回答。
- 最后看 parser / schema 校验失败的具体字段。
19. 常见工程模式
19.1 分类路由
const Route = z.object({
route: z.enum(["billing", "tech", "sales"]),
reason: z.string(),
});
const router = model.withStructuredOutput(Route);
const decision = await router.invoke([
{ role: "user", content: "我想升级套餐并开发票。" },
]);
switch (decision.route) {
case "billing":
// 调用财务客服 Agent
break;
case "tech":
// 调用技术支持 Agent
break;
case "sales":
// 调用销售 Agent
break;
}
19.2 检索增强客服
用户问题
-> 分类:是否需要知识库
-> 需要:Agent 调用 knowledge_search
-> 模型基于检索结果回答
-> 结构化输出:answer + sources + confidence
-> 低 confidence 转人工
19.3 文档抽取流水线
loader -> splitter -> map extraction -> reduce merge -> schema validation -> database
示意代码:
const Item = z.object({
title: z.string(),
amount: z.number().optional(),
});
const extractor = model.withStructuredOutput(
z.object({
items: z.array(Item),
})
);
const chunks = await splitter.splitDocuments(docs);
const results = await extractor.batch(
chunks.map((doc) => [
{ role: "user", content: `从文本中抽取条目:\n${doc.pageContent}` },
]),
{ maxConcurrency: 5 }
);
19.4 安全工具调用
对高风险工具加人审:
模型生成 tool call
-> middleware 检测工具名/参数
-> 高风险:interrupt 给人工审批
-> approve: 执行工具
-> reject: 返回拒绝原因
原则:
- 读操作可以自动化,写操作要分级。
- 金钱、权限、账号、数据删除必须有人审或二次确认。
- 工具描述要写清楚边界,避免模型误用。
20. 迁移和版本边界
LangChain.js v1 把很多旧式链和组件拆到了 @langchain/classic。如果你看到以下导入,多半是 legacy / classic 代码:
import { createRetrievalChain } from "@langchain/classic/chains/retrieval";
import { createStuffDocumentsChain } from "@langchain/classic/chains/combine_documents";
import { MemoryVectorStore } from "@langchain/classic/vectorstores/memory";
新项目建议:
- Agent 任务优先用
createAgent。 - 固定流程优先用 Runnable / LCEL。
- 旧版 chain 能用,但要明确它属于 classic。
- 复杂工作流、循环、并行、人工审核、多 Agent,直接看 LangGraph。
- 不要混用多个教程年代的导入路径。遇到报错先核对包版本和 export path。
21. API 选择指南
| 需求 | 推荐 API |
|---|---|
| 简单问答 | initChatModel + model.invoke |
| 模板化问答 | ChatPromptTemplate.pipe(model).pipe(parser) |
| 需要 JSON / 类型稳定 | model.withStructuredOutput |
| 需要工具调用 | createAgent({ tools }) |
| 手动控制工具循环 | model.bindTools |
| 固定 RAG | Retriever + Runnable chain |
| Agent 自主检索 | Retriever 包成 tool,传给 Agent |
| 多轮会话 | messages history 或 Agent thread/checkpointer |
| 长上下文会话 | summarization middleware + retrieval |
| 生产重试 | withRetry 或 modelRetryMiddleware |
| 高风险工具 | humanInTheLoopMiddleware |
| 旧版 chains | @langchain/classic |
22. 常见坑
22.1 把系统提示放在用户消息里
系统级约束应放在 system message 或 Agent prompt,不要混在 user content 里。
22.2 工具描述太短
工具描述是模型选择工具的依据。只写“搜索”不够,应该说明:
- 这个工具查什么数据源。
- 什么时候应该调用。
- 输入参数单位和约束。
- 返回内容格式。
22.3 RAG 检索结果直接塞太多
检索结果越多不一定越好。要控制:
k- chunk 大小
- metadata filter
- rerank / compression
- 最大 context token
22.4 只依赖模型输出 JSON
如果 JSON 是业务接口输入,必须做 schema 校验。优先用 Zod 和结构化输出 API。
22.5 忘记处理空检索
RAG 检索为空时,应显式让模型回答“不知道”或触发人工流程。
22.6 浏览器端泄露密钥
LangChain.js 可以在 JS 环境运行,但 provider key 不应进入前端 bundle。浏览器应用要走后端代理。
23. 推荐目录结构
src/
ai/
models.ts # 初始化模型
prompts.ts # Prompt 模板
tools/
index.ts
knowledge.ts
weather.ts
agents/
supportAgent.ts
rag/
ingest.ts # 文档入库
retriever.ts
chains.ts
schemas.ts # Zod schema
tracing.ts
routes/
jobs/
示例 models.ts:
import { initChatModel } from "langchain";
export async function createDefaultModel() {
return initChatModel(process.env.LANGCHAIN_MODEL ?? "openai:gpt-4o-mini", {
temperature: 0.2,
});
}
示例 schemas.ts:
import { z } from "zod";
export const SupportResponse = z.object({
answer: z.string(),
sources: z.array(z.string()).default([]),
confidence: z.number().min(0).max(1),
needsHuman: z.boolean(),
});
24. 参考资料
- LangChain.js v1 Overview: docs.langchain.com/oss/javascr…
- Install: docs.langchain.com/oss/javascr…
- Agents: docs.langchain.com/oss/javascr…
- Models: docs.langchain.com/oss/javascr…
- Messages: docs.langchain.com/oss/javascr…
- Tools: docs.langchain.com/oss/javascr…
- Streaming: docs.langchain.com/oss/javascr…
- Structured Output: docs.langchain.com/oss/javascr…
- Short-term Memory: docs.langchain.com/oss/javascr…
- Retrieval: docs.langchain.com/oss/javascr…
- npm
langchain: www.npmjs.com/package/lan… - npm
@langchain/core: www.npmjs.com/package/@la… - npm
@langchain/openai: www.npmjs.com/package/@la…