第 36 课: 框架架构总结与生产实战

3 阅读8分钟

课程目标

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 流程

  1. Fork 仓库,创建 feature 分支
  2. 实现功能,编写测试
  3. 运行 pnpm buildpnpm test 确保通过
  4. 提交 PR,描述变更内容和测试方式
  5. 等待 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 源码精读路线

优先级文件关注点
P0runnables/base.tsRunnable 抽象 — 整个框架的基石
P0language_models/chat_models.tsBaseChatModel — Provider 的模板方法
P1callbacks/manager.tsCallbackManager — 事件系统
P1vectorstores.ts + retrievers/检索层
P2langchain/src/agents/Agent 系统
P2mcp-adapters/src/MCP 协议适配
P3internal/build/src/构建系统

本课收获总结

级别你应该掌握的
🟢 基础建立完整的 LangChain.js 知识体系;能用框架构建简单应用
🔵 中阶掌握从 demo 到生产的关键差距(重试/降级/超时/监控)
🟡 高阶理解框架的测试策略(FakeModel + Standard Tests);能为框架贡献代码
🟠 资深形成技术选型决策框架:何时用 LangChain,何时直接调 API
🔴 架构能提炼六大设计模式,应用到自己的框架设计中

下一步推荐

继续学习

方向资源
LangGraphLangChain 团队的状态机 Agent 框架,比 createReactAgent 更强大
LangSmith生产级追踪和评估平台
LangServe将 LangChain 链部署为 REST API
Vercel AI SDK与 LangChain.js 互补的前端 AI SDK

实践建议

  1. 从小项目开始 — 先构建一个简单的 RAG 问答系统
  2. 逐步增加复杂度 — 加入对话历史、多工具、流式输出
  3. 关注可观测性 — 从第一天就接入 LangSmith 或自定义 Callbacks
  4. 参与社区 — 提交 Issue、PR,阅读其他 Provider 的实现
  5. 阅读源码 — 本课程覆盖的源码路线图是最好的深入学习指南

何时使用 LangChain.js

适合不适合
需要组合多个 LLM 组件的应用只需单次 API 调用的简单场景
需要切换或对比多个 Provider对框架体积敏感的极简部署
需要 RAG、Agent 等高级能力需要极致性能的实时系统
团队有多人协作,需要标准化只有一个人的小实验
需要追踪、测试、评估能力不关心可观测性的原型

恭喜你完成了 LangChain.js 深度精讲的全部 36 课!

从第 1 课的全景概览,到第 36 课的架构总结,你已经系统掌握了这个框架的设计哲学、核心实现和生产实践。接下来,用这些知识去构建真正有价值的 AI 应用吧。