课程目标
Part 1: 回顾 LangChain.js 的六大核心设计模式。Part 2: 生产化检查清单。Part 3: 贡献代码指南。Part 4: 综合实战项目 — 构建一个完整的 AI 助手。
Part 1: 架构总复盘
36.1 六大核心设计模式
模式一: 统一接口模式 (Runnable)
核心思想: 框架中的一切组件实现同一抽象。
Serializable
└── Runnable<RunInput, RunOutput>
├── BaseChatModel (第 11 课)
├── BasePromptTemplate (第 12 课)
├── BaseOutputParser (第 15 课)
├── StructuredTool (第 14 课)
├── BaseRetriever (第 31 课)
├── RunnableSequence (第 5 课)
├── RunnableParallel (第 7 课)
├── RunnableLambda (第 6 课)
└── RunnableBranch (第 8 课)
价值: 任何两个组件都可以通过 pipe() 组合,无需适配器。
参见: 第 4 课 — Runnable 抽象类的 invoke/stream/batch 三大方法。
模式二: 管道组合模式 (pipe)
核心思想: 组件像积木一样拼接。
const chain = prompt.pipe(model).pipe(parser);
// 等价于
const chain = RunnableSequence.from([prompt, model, parser]);
RunnableSequence 内部的 first -> middle[] -> last 三段式结构支持:
- 类型安全的链式推断
- 流式传播(
_transform链) - 错误在管道中的传播与中断
参见: 第 5 课 — RunnableSequence 的结构与流式传播。
模式三: 模板方法模式 (_generate / _invoke)
核心思想: 框架定义流程骨架,子类填充具体实现。
// 框架提供 public invoke() — 处理 callbacks, config, 错误
async invoke(input, options) {
const runManager = await callbackManager.handleStart(...);
try {
const result = await this._invoke(input, runManager); // 子类实现
await runManager.handleEnd(result);
return result;
} catch (error) {
await runManager.handleError(error);
throw error;
}
}
// 子类只需实现 _invoke / _generate / _getRelevantDocuments
protected abstract _invoke(input, runManager): Promise<Output>;
参见: 第 11 课 — BaseChatModel._generate()。
模式四: 适配器模式 (Provider)
核心思想: 统一外部差异。
┌── ChatOpenAI._generate() -> OpenAI API 格式
BaseChatModel ──────┼── ChatAnthropic._generate() -> Anthropic API 格式
├── ChatOllama._generate() -> Ollama API 格式
└── ChatGoogle._generate() -> Google API 格式
上层代码调用 model.invoke(messages) 时完全不关心底层是哪个 Provider。
参见: 第 18-19 课 — OpenAI 与 Anthropic Provider 对比。
模式五: 观察者模式 (Callbacks)
核心思想: 事件驱动的可观测性。
Runnable 执行
├── handleChainStart → CallbackHandler.handleChainStart()
├── handleLLMStart → CallbackHandler.handleLLMStart()
├── handleLLMNewToken → CallbackHandler.handleLLMNewToken() (流式)
├── handleLLMEnd → CallbackHandler.handleLLMEnd()
├── handleToolStart → CallbackHandler.handleToolStart()
└── handleChainEnd → CallbackHandler.handleChainEnd()
Callbacks 通过 RunnableConfig.callbacks 在链中自动传播,子 run 继承父 run 的 callbacks。
参见: 第 21-22 课 — Callbacks 系统与 Tracers。
模式六: 上下文传播模式 (AsyncLocalStorage)
核心思想: 隐式跨层通信。
// 设置上下文变量
setContextVariable("traceId", "abc-123");
// 在链的任意深度读取
const traceId = getContextVariable("traceId"); // "abc-123"
通过 Node.js 的 AsyncLocalStorage,上下文变量可以跨越任意异步边界自动传播。
参见: 第 17 课 — 上下文变量与单例系统。
36.2 包依赖关系全景图
@langchain/core (核心抽象)
│
├── @langchain/openai, @langchain/anthropic, @langchain/google ... (Provider)
│
├── langchain (上层能力: Agent, Storage, Hub, Universal ChatModel)
│
├── @langchain/mcp-adapters (MCP 协议适配)
│
├── @langchain/textsplitters (文本分割)
│
└── @langchain/standard-tests (标准测试套件)
internal/
├── @langchain/build (构建工具)
└── @langchain/tsconfig (共享 TS 配置)
核心原则: @langchain/core 不依赖任何 Provider,Provider 只依赖 @langchain/core。
36.3 langchain-classic 兼容层
源码位置: libs/langchain-classic/
langchain-classic 包为旧版 API 提供过渡期兼容:
- 旧版
langchain包的导入路径在langchain-classic中保留 - 实际实现指向新包中的对应类
- 允许存量代码逐步迁移
Part 2: 生产化检查清单
36.4 可靠性
| 检查项 | 实现方式 | 源码参考 |
|---|---|---|
| 自动重试 | model.withRetry({ stopAfterAttempt: 3 }) | 第 4 课 |
| 降级方案 | model.withFallbacks([backupModel]) | 第 4 课 |
| 超时控制 | RunnableConfig.timeout | 第 4 课 |
| 中止信号 | RunnableConfig.signal (AbortSignal) | 第 4 课 |
| 递归限制 | RunnableConfig.recursionLimit (默认 25) | 第 4 课 |
| Agent 最大迭代 | maxIterations 配置 | 第 28 课 |
const reliableModel = model
.withRetry({ stopAfterAttempt: 3 })
.withFallbacks([backupModel]);
await reliableModel.invoke(input, {
timeout: 30000,
signal: AbortSignal.timeout(30000),
});
36.5 可观测性
| 检查项 | 实现方式 | 源码参考 |
|---|---|---|
| 执行追踪 | LangChainTracer + LangSmith | 第 22 课 |
| 结构化日志 | ConsoleCallbackHandler | 第 21 课 |
| 事件流 | streamEvents("v2") | 第 35 课 |
| 运行收集 | RunCollectorCallbackHandler | 第 22 课 |
| 自定义指标 | 自定义 CallbackHandler | 第 21 课 |
const result = await chain.invoke(input, {
tags: ["production", "v2"],
metadata: { userId: "user-123", requestId: "req-456" },
callbacks: [new LangChainTracer({ projectName: "my-app" })],
});
36.6 安全性
| 检查项 | 实现方式 |
|---|---|
| 工具白名单 | 只绑定已审核的工具 |
| 输入校验 | Zod schema 验证用户输入 |
| 输出过滤 | OutputParser 拒绝异常格式 |
| Secret 保护 | lc_secrets 避免序列化明文 |
| 反序列化安全 | 不对不受信任的数据调用 load() |
| MCP 钩子审计 | beforeToolCall 记录工具调用 |
36.7 性能
| 检查项 | 实现方式 |
|---|---|
| LLM 缓存 | InMemoryCache 或 Redis 缓存 |
| 并行执行 | RunnableParallel / batch() |
| 流式输出 | stream() / streamEvents() |
| 并发控制 | maxConcurrency 限制 |
| 增量索引 | RecordManager 跳过已处理文档 |
36.8 成本
| 检查项 | 实现方式 |
|---|---|
| Token 监控 | CallbackHandler 统计 token 用量 |
| 模型分级 | Haiku (轻量) / Sonnet (编码) / Opus (推理) |
| 缓存命中率 | 监控 cache hit/miss 比率 |
| 批量处理 | batch() 减少 API 调用次数 |
Part 3: 贡献代码指南
36.9 代码规范
LangChain.js 使用 oxlint 进行代码质量检查:
# 运行 lint
pnpm --filter @langchain/core lint
# 自动修复
pnpm --filter @langchain/core lint --fix
关键规则:
- 使用
oxlint-disable-next-line而非eslint-disable - 避免
instanceof检查(跨包时可能失败)— 使用isInstance()静态方法 - 优先使用
import type避免循环依赖
36.10 测试要求
单元测试(*.test.ts)
pnpm --filter @langchain/core test
- 使用 Vitest 测试框架
- 使用
FakeChatModel/FakeListChatModel替代真实 API - 不需要 API Key,CI 中始终运行
集成测试(*.int.test.ts)
pnpm --filter @langchain/openai test:integration
- 调用真实 API,需要配置环境变量
- CI 中通过 secret 注入运行
- 验证真实行为
Standard Tests
@langchain/standard-tests 提供标准化测试套件,验证 Provider 实现的正确性:
import { ChatModelIntegrationTests } from "@langchain/standard-tests";
class MyChatModelTests extends ChatModelIntegrationTests {
get chatModelConstructor() { return MyChatModel; }
get chatModelParams() { return { model: "my-model" }; }
}
const tests = new MyChatModelTests();
await tests.testInvoke();
await tests.testStream();
await tests.testBindTools();
36.11 PR 流程
- Fork 仓库,创建 feature 分支
- 实现功能,编写测试
- 运行
pnpm build和pnpm test确保通过 - 提交 PR,描述变更内容和测试方式
- 等待 CI 通过和 maintainer review
新 Provider 接入:使用 npx create-langchain-integration 脚手架生成项目骨架(参见第 20 课)。
Part 4: 综合实战项目
36.12 项目: 完整 AI 助手
构建一个集成所有核心能力的 AI 助手:
1) 多 Provider 支持
import { initChatModel } from "langchain/chat_models/universal";
// 使用 Universal ChatModel 支持运行时切换
const primaryModel = await initChatModel("gpt-4o");
const backupModel = await initChatModel("claude-3-5-sonnet-latest", {
modelProvider: "anthropic",
});
// 自动降级
const resilientModel = primaryModel.withFallbacks([backupModel]);
2) RAG 知识库
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
import { Document } from "@langchain/core/documents";
// 准备知识库文档
const docs = loadMyDocuments();
const splitter = new RecursiveCharacterTextSplitter({ chunkSize: 500, chunkOverlap: 50 });
const splitDocs = await splitter.splitDocuments(docs);
// 嵌入并存储
await vectorStore.addDocuments(splitDocs);
const retriever = vectorStore.asRetriever({ k: 4, searchType: "mmr" });
3) 多工具 Agent
import { tool } from "@langchain/core/tools";
import { z } from "zod";
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
// 本地工具
const calculator = tool(
async ({ expression }) => {
try { return String(eval(expression)); }
catch { return "计算错误"; }
},
{ name: "calculator", description: "计算数学表达式", schema: z.object({ expression: z.string() }) }
);
// MCP 工具
const mcpClient = new MultiServerMCPClient({
mcpServers: {
search: { transport: "http", url: "http://localhost:3001/mcp" },
},
});
const mcpTools = await mcpClient.getTools();
// 组合所有工具
const allTools = [calculator, ...mcpTools];
4) 带历史的 RAG Agent
import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts";
import { RunnableWithMessageHistory } from "@langchain/core/runnables";
const agentPrompt = ChatPromptTemplate.fromMessages([
["system", `你是一个智能助手,可以使用工具和知识库回答问题。
知识库上下文: {context}`],
new MessagesPlaceholder("chat_history"),
["human", "{input}"],
]);
// 构建 Agent (伪代码展示结构)
// 实际使用 createReactAgent 参见第 24 课
5) 流式输出
const eventStream = agent.streamEvents(
{ input: "帮我查一下 LangChain 的最新版本" },
{ version: "v2", configurable: { sessionId: "user-1" } }
);
for await (const event of eventStream) {
if (event.event === "on_retriever_end") {
console.log(`检索到 ${event.data.output.length} 个相关文档`);
}
if (event.event === "on_llm_stream") {
process.stdout.write(event.data.chunk.content);
}
if (event.event === "on_tool_end") {
console.log(`工具 ${event.name} 执行完成`);
}
}
6) 错误处理与优雅降级
const robustModel = primaryModel
.withRetry({ stopAfterAttempt: 3 })
.withFallbacks([backupModel])
.withConfig({
timeout: 30000,
tags: ["production"],
metadata: { version: "1.0" },
});
7) 测试
import { FakeListChatModel } from "@langchain/core/utils/testing";
import { describe, it, expect } from "vitest";
describe("RAG Chain", () => {
it("应该检索相关文档并生成回答", async () => {
const fakeModel = new FakeListChatModel({
responses: ["根据知识库,LangChain.js 是一个 TypeScript 框架。"],
});
const testChain = RunnableSequence.from([
{ context: retriever.pipe(formatDocs), question: new RunnablePassthrough() },
ragPrompt,
fakeModel,
new StringOutputParser(),
]);
const result = await testChain.invoke("什么是 LangChain?");
expect(result).toContain("TypeScript");
});
});
36.13 源码精读路线
| 优先级 | 文件 | 关注点 |
|---|---|---|
| P0 | runnables/base.ts | Runnable 抽象 — 整个框架的基石 |
| P0 | language_models/chat_models.ts | BaseChatModel — Provider 的模板方法 |
| P1 | callbacks/manager.ts | CallbackManager — 事件系统 |
| P1 | vectorstores.ts + retrievers/ | 检索层 |
| P2 | langchain/src/agents/ | Agent 系统 |
| P2 | mcp-adapters/src/ | MCP 协议适配 |
| P3 | internal/build/src/ | 构建系统 |
本课收获总结
| 级别 | 你应该掌握的 |
|---|---|
| 🟢 基础 | 建立完整的 LangChain.js 知识体系;能用框架构建简单应用 |
| 🔵 中阶 | 掌握从 demo 到生产的关键差距(重试/降级/超时/监控) |
| 🟡 高阶 | 理解框架的测试策略(FakeModel + Standard Tests);能为框架贡献代码 |
| 🟠 资深 | 形成技术选型决策框架:何时用 LangChain,何时直接调 API |
| 🔴 架构 | 能提炼六大设计模式,应用到自己的框架设计中 |
下一步推荐
继续学习
| 方向 | 资源 |
|---|---|
| LangGraph | LangChain 团队的状态机 Agent 框架,比 createReactAgent 更强大 |
| LangSmith | 生产级追踪和评估平台 |
| LangServe | 将 LangChain 链部署为 REST API |
| Vercel AI SDK | 与 LangChain.js 互补的前端 AI SDK |
实践建议
- 从小项目开始 — 先构建一个简单的 RAG 问答系统
- 逐步增加复杂度 — 加入对话历史、多工具、流式输出
- 关注可观测性 — 从第一天就接入 LangSmith 或自定义 Callbacks
- 参与社区 — 提交 Issue、PR,阅读其他 Provider 的实现
- 阅读源码 — 本课程覆盖的源码路线图是最好的深入学习指南
何时使用 LangChain.js
| 适合 | 不适合 |
|---|---|
| 需要组合多个 LLM 组件的应用 | 只需单次 API 调用的简单场景 |
| 需要切换或对比多个 Provider | 对框架体积敏感的极简部署 |
| 需要 RAG、Agent 等高级能力 | 需要极致性能的实时系统 |
| 团队有多人协作,需要标准化 | 只有一个人的小实验 |
| 需要追踪、测试、评估能力 | 不关心可观测性的原型 |
恭喜你完成了 LangChain.js 深度精讲的全部 36 课!
从第 1 课的全景概览,到第 36 课的架构总结,你已经系统掌握了这个框架的设计哲学、核心实现和生产实践。接下来,用这些知识去构建真正有价值的 AI 应用吧。