课程目标
理解 LangChain.js 的工程基础设施:pnpm workspace、Turborepo、tsdown,并搭建本地开发环境。
2.1 为什么是 Monorepo?
LangChain.js 有 40+ 个 npm 包。如果每个包一个仓库 (polyrepo):
- 跨包改动需要多个 PR、多次发布、版本同步困难
- 共享代码(如构建配置、TS 配置)需要额外的包管理
- CI 测试无法在一次提交中验证所有包的兼容性
Monorepo 的收益:
- 原子提交:一个 PR 可以同时改 core、langchain、openai provider
- 统一构建:一条命令构建所有包,Turborepo 自动处理依赖顺序
- 共享配置:TypeScript 配置、构建工具、lint 规则只维护一份
- 依赖一致:
workspace:*确保包之间始终用最新代码
2.2 pnpm Workspace
2.2.1 工作区定义
# pnpm-workspace.yaml
packages:
- "libs/*" # 核心包: langchain-core, langchain, textsplitters 等
- "libs/providers/*" # Provider 包: langchain-openai, langchain-anthropic 等
- "examples" # 使用示例
- "internal/*" # 内部构建工具
这个配置告诉 pnpm 在这些目录下寻找包(每个目录下的 package.json 构成一个 workspace 成员)。
2.2.2 包间依赖
包之间使用 workspace: 协议互相引用:
// libs/langchain/package.json
{
"dependencies": {
"@langchain/core": "workspace:^" // 始终引用本地最新代码
}
}
// libs/providers/langchain-openai/package.json
{
"peerDependencies": {
"@langchain/core": "^1.0.0" // 发布后由用户提供
},
"devDependencies": {
"@langchain/core": "workspace:^" // 开发时用本地版本
}
}
workspace:^ vs workspace:*:
workspace:^:发布时替换为带^的版本号(如^1.2.3),允许用户用更高版本workspace:*:发布时替换为精确版本号,仅内部工具使用
2.2.3 常用 pnpm 命令
# 安装所有依赖
pnpm install
# 针对特定包执行命令
pnpm --filter @langchain/core build # 构建 core 包
pnpm --filter @langchain/core test # 测试 core 包
pnpm --filter langchain build # 构建 langchain 包
# 针对多个包
pnpm --filter "@langchain/openai" --filter "@langchain/anthropic" test
# 针对所有包
pnpm -r build # 递归所有 workspace 执行 build(不推荐,用 turbo 更好)
2.3 Turborepo — 增量构建编排
2.3.1 核心问题
40+ 个包,如果每次都全量构建,耗时巨大。Turborepo 解决两个问题:
- 依赖顺序:
@langchain/openai依赖@langchain/core,必须先构建 core - 增量构建:没改动的包不重复构建,利用缓存
2.3.2 配置解析
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env", "pnpm-lock.yaml"],
"globalPassThroughEnv": ["CI", "NODE_ENV", "GITHUB_ACTIONS"],
"ui": "stream",
"tasks": {
"build:compile": {
"dependsOn": ["^build:compile"], // ^ 表示先构建上游依赖
"env": ["BUILD_MODE"],
"inputs": ["src/**", "tsconfig.json", "tsdown.config.ts", "package.json"],
"outputs": ["dist/**"] // 缓存产物
},
"test": {
"dependsOn": ["build:compile"], // 测试前先构建(无 ^,只构建自己)
"inputs": ["src/**", "tests/**", "**/*.test.ts", "vitest.config.ts"],
"outputs": [] // 测试无产物
},
"test:single": {
"dependsOn": ["build:compile"],
"cache": false // 单文件测试不缓存
},
"test:integration": {
"dependsOn": ["build:compile"],
"cache": false // 集成测试不缓存(依赖外部 API)
}
}
}
关键语义:
"dependsOn": ["^build:compile"]— 先构建所有上游依赖包"dependsOn": ["build:compile"]— 先构建自己(不递归上游)"inputs"— 这些文件变化才触发重新执行"outputs"— 执行产物,用于缓存"cache": false— 禁用缓存(集成测试等不可缓存场景)
2.3.3 执行流程示例
# 执行 pnpm build(即 turbo build:compile)
# Turborepo 自动分析依赖图:
# 1. 先构建无依赖的包
# @langchain/tsconfig (无依赖)
# @langchain/build (无依赖)
#
# 2. 构建 core(依赖 tsconfig 和 build)
# @langchain/core
#
# 3. 并行构建所有 Provider(都依赖 core)
# @langchain/openai ┐
# @langchain/anthropic │ 并行执行
# @langchain/google │
# ... ┘
#
# 4. 构建 langchain(依赖 core)
# langchain
2.4 tsdown — TypeScript 编译
2.4.1 为什么是 tsdown?
LangChain.js 需要输出两种格式:
- ESM (ES Modules):现代 Node.js、Deno、Browser 使用
- CJS (CommonJS):旧版 Node.js 项目兼容
tsdown 基于 esbuild,速度极快,原生支持双格式输出。
2.4.2 配置解析
以 @langchain/core 的配置为例:
// libs/langchain-core/tsdown.config.ts
import {
getBuildConfig, // 标准化构建配置生成器
cjsCompatPlugin, // CJS 兼容插件
lcSecretsPlugin, // 密钥检测插件
importMapPlugin, // import map 生成插件
importConstantsPlugin, // import 常量插件
} from "@langchain/build";
import pkg from "./package.json" with { type: "json" };
export default getBuildConfig({
entry: [
"./src/index.ts",
"./src/runnables/index.ts",
"./src/messages/index.ts",
"./src/language_models/base.ts",
"./src/language_models/chat_models.ts",
"./src/tools/index.ts",
"./src/prompts/index.ts",
// ... 80+ 个入口文件
],
define: { __PKG_VERSION__: JSON.stringify(pkg.version) },
plugins: [
cjsCompatPlugin({ files: ["dist/", "CHANGELOG.md", "README.md", "LICENSE"] }),
lcSecretsPlugin(), // 构建时检测代码中的硬编码密钥
importMapPlugin(), // 生成 import_map.ts 用于动态加载
importConstantsPlugin(), // 生成 import_constants.ts
],
});
getBuildConfig() 来自 @langchain/build(internal/build/src/index.ts),它生成标准化配置:
- 双格式输出 (ESM + CJS)
- TypeScript 声明文件 (
.d.ts) - Source maps
- 通过 ATTW、publint 验证包质量
2.4.3 构建产物
libs/langchain-core/dist/
├── index.js # ESM 版本
├── index.cjs # CJS 版本
├── index.d.ts # 类型声明
├── index.d.cts # CJS 类型声明
├── runnables/
│ ├── index.js
│ ├── index.cjs
│ ├── index.d.ts
│ └── ...
└── ...
2.5 共享 TypeScript 配置
2.5.1 基础配置
// internal/tsconfig/base.json
{
"compilerOptions": {
"target": "ES2022", // 编译目标
"module": "ESNext", // 模块系统
"moduleResolution": "bundler", // bundler 模式解析
"strict": true, // 严格模式
"declaration": true, // 生成 .d.ts
"declarationMap": true, // 声明映射
"sourceMap": true, // 源码映射
"esModuleInterop": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"isolatedModules": true, // 支持独立编译
"composite": true // 支持项目引用
}
}
关键配置解读:
target: "ES2022"— 使用 ES2022 特性(top-level await、class fields 等)module: "ESNext"— 输出 ESM 模块moduleResolution: "bundler"— 使用 bundler 模式(支持.js扩展名引用.ts文件)strict: true— 开启所有严格检查composite: true— 支持 Turborepo 的增量构建
2.5.2 包级配置
每个包继承基础配置:
// libs/langchain-core/tsconfig.json
{
"extends": "../../internal/tsconfig/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}
2.6 Lint 与格式化
2.6.1 oxlint (不是 ESLint)
pnpm lint # 检查
pnpm lint:fix # 自动修复
关键规则(定义在 .oxlintrc.jsonc):
no-process-env: error— 禁止直接用process.env(用getEnvironmentVariable()代替)no-explicit-any: error— 禁止any类型prefer-template: error— 用模板字符串代替字符串拼接import/extensions: error— import 必须带.js扩展名
2.6.2 oxfmt (不是 Prettier)
pnpm format # 格式化
pnpm format:check # 只检查不修改
oxlint 和 oxfmt 都用 Rust 实现,对 1000+ 文件的 monorepo 来说性能优势明显。
2.7 目录结构全景
langchainjs/
├── libs/ # 所有发布到 npm 的包
│ ├── langchain-core/ # @langchain/core — 核心抽象
│ ├── langchain/ # langchain — 上层实现
│ ├── langchain-textsplitters/ # @langchain/textsplitters — 文本分割
│ ├── langchain-mcp-adapters/ # @langchain/mcp-adapters — MCP 适配
│ ├── langchain-classic/ # @langchain/community — 旧版兼容
│ ├── langchain-standard-tests/ # @langchain/standard-tests — 标准测试
│ └── providers/ # 33 个 Provider 集成
│ ├── langchain-openai/
│ ├── langchain-anthropic/
│ ├── langchain-google-genai/
│ └── ...
│
├── internal/ # 内部构建工具(不发布到 npm)
│ ├── build/ # @langchain/build — 构建配置生成器
│ ├── tsconfig/ # @langchain/tsconfig — 共享 TS 配置
│ ├── standard-tests/ # 标准测试基础设施
│ ├── model-profiles/ # 模型配置信息
│ └── test-helpers/ # 测试辅助工具
│
├── examples/ # 使用示例
│ └── src/
│ ├── createAgent/ # Agent 创建示例
│ ├── multi-agent/ # 多 Agent 协作
│ ├── llms/ # LLM 调用示例
│ └── provider/ # 各 Provider 示例
│
├── package.json # 根 package.json(scripts、devDependencies)
├── pnpm-workspace.yaml # workspace 定义
├── turbo.json # Turborepo 配置
├── .oxlintrc.jsonc # oxlint 配置
├── AGENTS.md # AI Agent 开发指南
└── CONTRIBUTING.md # 贡献指南
2.8 实操:从零搭建开发环境
Step 1: 前置条件
# 确认 Node.js 版本(需要 v20+ ,推荐 v24)
node -v
# v24.x.x
# 确认 pnpm 版本
pnpm -v
# 10.14.0
Step 2: 安装依赖
cd langchainjs
pnpm install
这会:
- 安装所有包的依赖到根
node_modules(pnpm 的 content-addressable store) - 建立 workspace 内部包之间的 symlink
Step 3: 构建核心包
# 必须先构建 core,因为其他包依赖它
pnpm --filter @langchain/core build
Step 4: 验证构建成功
# 运行 core 的单元测试
pnpm --filter @langchain/core test
Step 5: 构建所有包(可选)
# Turborepo 自动按依赖顺序构建
pnpm build
Step 6: 日常开发
# Watch 模式:修改代码自动重新构建
pnpm watch
# 运行单个测试文件
pnpm --filter @langchain/core test src/runnables/tests/runnable.test.ts
# 检查代码风格
pnpm lint
pnpm format:check
2.9 包依赖关系图
@langchain/tsconfig ─────────────────┐
@langchain/build ────────────────────┤
▼
@langchain/core
│
┌──────────────────────┼──────────────────────┐
▼ ▼ ▼
@langchain/openai @langchain/anthropic @langchain/google
@langchain/ollama @langchain/deepseek @langchain/groq
@langchain/pinecone @langchain/mongodb ... (33 个 Provider)
│ │ │
└──────────────────────┼──────────────────────┘
▼
langchain
│
▼
examples
核心原则:
@langchain/core不依赖任何 Provider- Provider 包通过
peerDependencies声明对 core 的依赖 langchain依赖 core,提供上层编排能力- 用户只需安装
@langchain/core+ 需要的 Provider
2.10 源码精读路线
| 优先级 | 文件 | 关注点 |
|---|---|---|
| P0 | pnpm-workspace.yaml | workspace 定义的 4 个路径 |
| P0 | turbo.json | 任务依赖图、dependsOn/inputs/outputs 语义 |
| P1 | internal/tsconfig/base.json | 共享 TypeScript 配置 (target, module, strict) |
| P1 | libs/langchain-core/tsdown.config.ts | tsdown 构建配置、80+ 入口文件、4 个构建插件 |
| P2 | internal/build/src/index.ts | getBuildConfig() 生成器、cjsCompatPlugin、lcSecretsPlugin |
| P2 | package.json (根目录) | 脚本命令:build, test, lint, format |
本课收获总结
| 级别 | 你应该掌握的 |
|---|---|
| 🟢 基础 | 能搭建环境、构建 core、运行测试;知道 pnpm --filter 命令 |
| 🔵 中阶 | 理解 pnpm workspace 的 workspace:^ 语义;理解包之间的依赖关系 |
| 🟡 高阶 | 掌握 turbo.json 的 dependsOn、inputs、outputs;理解增量构建 |
| 🟠 资深 | 理解 tsdown 双输出策略 (ESM+CJS) 的必要性;分析 @langchain/build 的插件设计 |
| 🔴 架构 | 能评估 monorepo 对此项目的工程收益;理解包拆分边界(core vs langchain vs providers) |
下一课预告
第 3 课将聚焦 TypeScript 高级特性在框架中的应用,包括泛型链、异步迭代器、Zod 双版本兼容等。