版本基准: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 支撑。
一个典型调用关系如下:
css
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 运行时底层 |
推荐把包职责记成三层:
bash
应用层: langchain
核心协议层: @langchain/core
集成/兼容层: @langchain/openai、@langchain/community、@langchain/classic、@langchain/textsplitters
3. 安装与项目初始化
官方 v1 文档要求 Node.js 22+。推荐使用 ESM。
kotlin
npm init -y
npm install langchain @langchain/core zod
npm install @langchain/openai
npm install @langchain/textsplitters @langchain/classic
npm install @langchain/langgraph
如果需要社区加载器、向量数据库或搜索工具:
bash
npm install @langchain/community
package.json 建议:
perl
{
"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"
}
}
环境变量示例:
ini
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. 最小可运行示例
php
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);
这个例子的调用链是:
rust
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 使用消息数组表示对话。可以用轻量对象:
ini
const messages = [
{ role: "system", content: "你是一个严谨的中文助手。" },
{ role: "user", content: "解释一下 RAG。" },
];
也可以用类:
javascript
import { SystemMessage, HumanMessage } from "langchain";
const messages = [
new SystemMessage("你是一个严谨的中文助手。"),
new HumanMessage("解释一下 RAG。"),
];
常用消息类型:
| 类型 | 作用 |
|---|---|
SystemMessage |
系统指令,定义角色、边界、输出风格 |
HumanMessage |
用户输入 |
AIMessage |
模型输出,可能包含 tool_calls、usage、内容块 |
ToolMessage |
工具执行结果,通常带 tool_call_id |
BaseMessage |
所有消息的基类 |
模型返回的 AIMessage 可能包含:
arduino
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 形式。
javascript
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);
调用关系:
rust
initChatModel("openai:gpt-4o-mini")
-> 根据 provider 前缀解析具体模型包
-> 返回 BaseChatModel 实例
model.invoke(messages)
-> provider SDK 请求
-> LangChain 标准化为 AIMessage
7.2 使用 provider 具体类
如果你需要 provider 特有参数,直接使用集成包:
php
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 批量调用
ini
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 流式调用
javascript
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
javascript
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());
调用关系:
arduino
ChatPromptTemplate.fromMessages(template)
-> prompt.invoke({ variables })
-> 生成 ChatPromptValue
-> model.invoke(promptValue)
8.2 Prompt + Model + Parser
javascript
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 就是把上一步输出传给下一步:
rust
{ content }
-> ChatPromptTemplate.invoke
-> ChatPromptValue
-> ChatModel.invoke
-> AIMessage
-> StringOutputParser.invoke
-> string
8.3 MessagesPlaceholder
多轮对话时,把历史消息放入模板:
php
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。
csharp
import { RunnableSequence } from "@langchain/core/runnables";
const chain = RunnableSequence.from([
prompt,
model,
new StringOutputParser(),
]);
const output = await chain.invoke({ content: "..." });
9.3 RunnableLambda
当你需要把普通函数插入链中:
typescript
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 经常需要"保留原始问题,同时新增检索上下文":
javascript
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 怎么调用工具?");
第一步对象映射会并行执行:
rust
输入 question
-> question: RunnablePassthrough 返回原输入
-> context: retriever.invoke(question) -> Document[] -> formatDocumentsAsString
-> 合并为 { question, context }
-> prompt -> model -> parser
10. Output Parser API
Output Parser 用于把模型输出转换成应用需要的数据结构。
10.1 StringOutputParser
arduino
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
ini
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
ini
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 支持结构化输出,优先使用:
php
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);
调用关系:
shell
model.withStructuredOutput(schema)
-> 返回 Runnable
-> Runnable.invoke(messages)
-> provider 结构化输出或 tool-calling/fallback 策略
-> Zod/schema 校验
-> typed object
11. Tool API
Tool 是让模型"行动"的接口,例如查天气、查数据库、调用 HTTP API、检索知识库、发邮件等。
11.1 创建工具
php
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 直接调用工具
arduino
const result = await calculator.invoke({
expression: "3 * (4 + 5)",
});
console.log(result);
11.3 工具传给 Agent
php
const agent = createAgent({
model: "openai:gpt-4o-mini",
tools: [calculator],
});
const res = await agent.invoke({
messages: [{ role: "user", content: "3 乘以 9 等于多少?" }],
});
Agent 的工具调用循环:
rust
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 时,也可以手动绑定工具:
ini
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 基础参数
php
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
ini
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 结构化输出
php
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);
调用关系:
rust
createAgent({ responseFormat: ZodSchema })
-> Agent 最终答案阶段要求结构化输出
-> provider native structured output 或 tool strategy
-> schema 校验
-> result.structuredResponse
12.4 流式 Agent
php
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 运行过程中插入治理逻辑。
php
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 的标准流程:
css
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 文档对象
javascript
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:
ini
import { TextLoader } from "@langchain/classic/document_loaders/fs/text";
const loader = new TextLoader("./docs/handbook.txt");
const docs = await loader.load();
社区集成常见路径:
javascript
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 文本切分
ini
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
ini
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 和测试:
javascript
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
ini
const retriever = vectorStore.asRetriever({
k: 4,
});
const relevantDocs = await retriever.invoke("LangChain.js 如何实现 RAG?");
Retriever 是 Runnable,所以可以直接接入 chain:
javascript
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 项目,可能会看到这种写法:
javascript
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 工具
javascript
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 / 多轮对话
最简单的记忆就是由应用保存历史消息,并在下次调用时传回去:
ini
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。
php
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 |
单步抽取:
ini
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 最终结构化输出:
php
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 普通聊天
arduino
initChatModel / new ChatOpenAI
-> model.invoke(messages)
-> AIMessage
16.2 Prompt 链
rust
ChatPromptTemplate
-> prompt.invoke(vars)
-> ChatPromptValue
-> model.invoke(promptValue)
-> AIMessage
-> parser.invoke(AIMessage)
-> app result
16.3 Runnable 链
scss
step1.pipe(step2).pipe(step3)
-> RunnableSequence
-> invoke(input)
-> step1.invoke(input)
-> step2.invoke(step1Output)
-> step3.invoke(step2Output)
16.4 手动工具调用
rust
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 工具调用
rust
createAgent({ model, tools, middleware })
-> agent.invoke({ messages })
-> model call
-> tool calls
-> tool execution
-> model call
-> final messages / structuredResponse
16.6 RAG 链
rust
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
rust
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 级重试
ini
const reliableChain = chain.withRetry({
stopAfterAttempt: 3,
});
const answer = await reliableChain.invoke(input);
17.2 Fallback
ini
const primary = await initChatModel("openai:gpt-4o-mini");
const fallback = await initChatModel("anthropic:claude-sonnet-4-5");
const robustModel = primary.withFallbacks([fallback]);
17.3 超时和取消
javascript
const controller = new AbortController();
setTimeout(() => controller.abort(), 10_000);
await chain.invoke(
{ question: "..." },
{
signal: controller.signal,
timeout: 10_000,
}
);
17.4 Agent 级治理
php
const agent = createAgent({
model: "openai:gpt-4o-mini",
tools,
middleware: [
modelCallLimitMiddleware({ runLimit: 8 }),
toolCallLimitMiddleware({ runLimit: 10 }),
modelRetryMiddleware({ maxRetries: 3 }),
],
});
生产建议:
- 工具要自己做输入校验、权限校验、速率限制和幂等设计。
- 模型重试不能无限重试,避免成本失控。
- 外部副作用工具,如付款、删库、发邮件,应接入人工确认或二次确认。
- RAG 结果为空时不要让模型硬答,应该显式告诉模型"没有检索到依据"。
18. 观测与调试
LangChain.js 和 LangSmith 深度集成。常用环境变量:
ini
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="..."
export LANGSMITH_PROJECT="my-project"
运行配置可加 tags 和 metadata:
php
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 分类路由
php
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 检索增强客服
rust
用户问题
-> 分类:是否需要知识库
-> 需要:Agent 调用 knowledge_search
-> 模型基于检索结果回答
-> 结构化输出:answer + sources + confidence
-> 低 confidence 转人工
19.3 文档抽取流水线
rust
loader -> splitter -> map extraction -> reduce merge -> schema validation -> database
示意代码:
ini
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 安全工具调用
对高风险工具加人审:
rust
模型生成 tool call
-> middleware 检测工具名/参数
-> 高风险:interrupt 给人工审批
-> approve: 执行工具
-> reject: 返回拒绝原因
原则:
- 读操作可以自动化,写操作要分级。
- 金钱、权限、账号、数据删除必须有人审或二次确认。
- 工具描述要写清楚边界,避免模型误用。
20. 迁移和版本边界
LangChain.js v1 把很多旧式链和组件拆到了 @langchain/classic。如果你看到以下导入,多半是 legacy / classic 代码:
javascript
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. 推荐目录结构
bash
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:
javascript
import { initChatModel } from "langchain";
export async function createDefaultModel() {
return initChatModel(process.env.LANGCHAIN_MODEL ?? "openai:gpt-4o-mini", {
temperature: 0.2,
});
}
示例 schemas.ts:
css
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...