课程目标
理解 LangChain.js 解决的核心问题、设计哲学以及在 LLM 应用开发生态中的定位。
1.1 LLM 应用开发的挑战
在直接调用 LLM API 构建应用时,开发者面临一系列工程问题:
1.1.1 模型调用的复杂性
每个 LLM Provider 的 API 格式不同:
// OpenAI 格式
const response = await openai.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "Hello" }],
});
// Anthropic 格式
const response = await anthropic.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello" }],
});
// Google 格式
const result = await model.generateContent("Hello");
直接后果:
- 切换模型需要改大量代码
- 无法在运行时动态选择模型
- 错误处理、重试、降级逻辑需要针对每个 Provider 单独写
1.1.2 工具调用的碎片化
让 LLM 调用外部工具(搜索、计算、数据库查询)是 Agent 的核心能力,但:
- 不同 Provider 的工具调用格式不同(OpenAI 叫 function calling,Anthropic 叫 tool_use)
- 工具的定义、执行、结果回传需要大量胶水代码
- 工具的组合与编排没有统一模式
1.1.3 对话管理的复杂性
多轮对话需要:
- 消息历史的存储和检索
- 上下文窗口的管理(token 超限时如何截断)
- 不同消息类型的处理(系统消息、用户消息、AI 回复、工具结果)
1.1.4 组件组合的困难
一个典型的 AI 应用需要将多个步骤串联:
- 用户输入 → 2. 提示词模板填充 → 3. 模型调用 → 4. 输出解析 → 5. 工具执行 → 6. 结果汇总
没有框架支持时,这些步骤之间的衔接全靠手写胶水代码。
1.2 LangChain.js 的核心理念
LangChain.js 用一个核心设计理念解决上述所有问题:
一切皆 Runnable,Runnable 皆可组合。
1.2.1 什么是 Runnable?
Runnable 是 LangChain.js 的基础抽象。任何组件 — 模型、提示词模板、输出解析器、工具、检索器 — 都实现了同一个接口:
interface Runnable<Input, Output> {
invoke(input: Input): Promise<Output>; // 单次调用
stream(input: Input): AsyncGenerator<Output>; // 流式调用
batch(inputs: Input[]): Promise<Output[]>; // 批量调用
pipe(next: Runnable): RunnableSequence; // 管道组合
}
1.2.2 统一接口的威力
因为所有组件共享同一接口,你可以像搭积木一样组合它们:
// 三个完全不同的组件,但因为都是 Runnable,可以直接 pipe
const chain = promptTemplate // Runnable<{topic: string}, BaseMessage[]>
.pipe(chatModel) // Runnable<BaseMessage[], AIMessage>
.pipe(outputParser); // Runnable<AIMessage, string>
// 一行代码调用整条链
const result = await chain.invoke({ topic: "TypeScript" });
// 流式调用也是一行
for await (const chunk of chain.stream({ topic: "TypeScript" })) {
process.stdout.write(chunk);
}
1.2.3 Provider 无关性
切换模型不需要改链的逻辑:
// 从 OpenAI 切到 Anthropic,只改这一行
const chatModel = new ChatAnthropic({ model: "claude-sonnet-4-20250514" });
// 链的其余部分完全不变
const chain = promptTemplate.pipe(chatModel).pipe(outputParser);
1.3 项目规模与结构
LangChain.js 是一个大型开源项目:
| 维度 | 数据 |
|---|---|
| TypeScript 源文件 | 1034+ 个 |
| npm 包 | 40+ 个 (monorepo) |
| Provider 集成 | 33 个 |
核心文件 runnables/base.ts | 3542 行 |
| 支持运行时 | Node.js, Deno, Bun, Browser, Edge |
| 许可证 | MIT |
1.3.1 三层架构
┌────────────────────────────────────────────────────┐
│ 你的应用代码 │
├────────────────────────────────────────────────────┤
│ langchain (上层) │ Provider 包 (33个) │
│ - Agent 编排 │ - @langchain/openai │
│ - 高级 Chain │ - @langchain/anthropic│
│ - 内置工具 │ - @langchain/google │
│ - Hub 集成 │ - @langchain/ollama │
│ │ - ... │
├────────────────────────────────────────────────────┤
│ @langchain/core (核心) │
│ - Runnable 体系 - Messages 数据模型 │
│ - 模型抽象 - 工具抽象 │
│ - 提示词模板 - 输出解析器 │
│ - 回调/追踪 - 检索器/向量存储 │
└────────────────────────────────────────────────────┘
- @langchain/core:定义所有抽象接口,不依赖任何 LLM Provider。你可以只安装 core + 一个 Provider 包。
- langchain:提供上层实现,如 Agent、高级编排能力。依赖 core。
- Provider 包:每个 LLM 服务一个独立包,用户按需安装。
1.3.2 33 个 Provider 集成
完整列表:
| 类别 | Provider |
|---|---|
| 通用大模型 | OpenAI, Anthropic, Google GenAI, Google VertexAI, DeepSeek, Groq, Mistral, xAI, Perplexity, Fireworks, Together AI, OpenRouter |
| 本地/私有 | Ollama |
| 云服务 | AWS (Bedrock), IBM, Cloudflare |
| 向量数据库 | Pinecone, MongoDB, Qdrant, Weaviate, PGVector, Redis, Turbopuffer, Neo4j, Google Cloud SQL PG, LanceDB |
| 搜索 | Tavily, Exa |
| 工具类 | Cohere (重排) |
1.4 技术栈速览
| 维度 | 选型 | 说明 |
|---|---|---|
| 语言 | TypeScript | strict mode, target ES2022 |
| 包管理 | pnpm 10.14 | workspace monorepo |
| 构建编排 | Turborepo | 增量构建,任务依赖 |
| 编译 | tsdown | ESM + CJS 双输出 |
| 测试 | Vitest | 单元/集成/类型测试 |
| Lint | oxlint | Rust 实现,比 ESLint 快 10-100x |
| 格式化 | oxfmt | Rust 实现,比 Prettier 快 |
| Schema | Zod v3 + v4 | 双版本兼容 |
为什么选这些工具?核心考量是性能。1034+ 个 TypeScript 文件的 monorepo,传统工具(ESLint、Prettier)太慢了。oxlint/oxfmt 用 Rust 写的,速度提升 10-100 倍。
1.5 横向对比
1.5.1 vs LangChain (Python)
| 维度 | LangChain.js | LangChain (Python) |
|---|---|---|
| 语言 | TypeScript | Python |
| 运行时 | Node/Deno/Bun/Browser/Edge | CPython |
| 类型安全 | 编译期泛型检查 | 运行时检查 (Pydantic) |
| 前端集成 | 原生支持 Browser 和 Edge | 需要后端 API |
| 生态成熟度 | 较新,增长快 | 更成熟,社区更大 |
| Agent 框架 | 内置 + LangGraph.js | 内置 + LangGraph |
LangChain.js 的独特优势:可以运行在浏览器和 Edge Functions 中,这是 Python 版做不到的。
1.5.2 vs Vercel AI SDK
| 维度 | LangChain.js | Vercel AI SDK |
|---|---|---|
| 定位 | 通用 LLM 应用框架 | 前端 AI UI 组件 |
| 抽象层级 | Runnable 统一抽象 | Provider 适配 + UI hooks |
| Agent 支持 | 完整 (ReAct, 多 Agent) | 基础 |
| RAG 支持 | 完整 (分割/嵌入/检索) | 无内置 |
| 可观测性 | Callbacks + LangSmith | OpenTelemetry |
| 适合场景 | 复杂 Agent、RAG、编排 | 前端聊天 UI、简单调用 |
1.5.3 vs 直接调用 API
| 维度 | LangChain.js | 直接调用 API |
|---|---|---|
| Provider 切换 | 改一行代码 | 重写调用层 |
| 组件组合 | pipe() 管道 | 手写胶水代码 |
| 流式支持 | 内置 stream/streamEvents | 手动解析 SSE |
| 重试/降级 | withRetry/withFallbacks | 手写 |
| 可观测性 | Callbacks + Tracers | 手写日志 |
| 学习曲线 | 需要理解 Runnable 抽象 | 直接,无额外概念 |
| 灵活性 | 框架约束 | 完全自由 |
什么时候不用 LangChain.js?
- 只调一个模型、不需要组合 → 直接用 Provider SDK
- 前端聊天 UI 为主 → Vercel AI SDK 可能更简单
- 对框架抽象有洁癖 → 直接调 API
什么时候用 LangChain.js?
- 需要多 Provider 支持和切换
- 需要 Agent / 工具调用 / RAG
- 需要复杂的链组合和编排
- 需要生产级可观测性 (LangSmith)
- 需要在 Edge/Browser 运行
1.6 核心概念速览
在后续课程中会深入每个概念,这里先建立整体印象:
| 概念 | 一句话解释 | 对应课程 |
|---|---|---|
| Runnable | 万物基石,所有组件的统一接口 | 第 4-8 课 |
| Messages | 对话的数据模型 (Human/AI/System/Tool) | 第 9 课 |
| ChatModel | LLM 的统一抽象,Provider 只需实现 _generate() | 第 11 课 |
| Prompts | 提示词模板,支持变量、few-shot、组合 | 第 12 课 |
| Tools | 让 LLM 调用外部函数 | 第 14 课 |
| OutputParser | 将 LLM 文本输出解析为结构化数据 | 第 15 课 |
| Callbacks | 事件系统,贯穿整个执行过程 | 第 21 课 |
| Agent | LLM + Tools + 推理循环 | 第 24 课 |
| Retriever | 从知识库检索相关文档 (RAG) | 第 31 课 |
1.7 动手体验:最小示例
import { ChatOpenAI } from "@langchain/openai";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
// 1. 创建组件
const prompt = ChatPromptTemplate.fromMessages([
["system", "你是一个 {role},请用简洁的语言回答。"],
["human", "{question}"],
]);
const model = new ChatOpenAI({ model: "gpt-4o-mini" });
const parser = new StringOutputParser();
// 2. 用 pipe 组合成链
const chain = prompt.pipe(model).pipe(parser);
// 3. 调用
const result = await chain.invoke({
role: "TypeScript 专家",
question: "什么是泛型?",
});
console.log(result);
// → "泛型是 TypeScript 中一种参数化类型的机制,让你编写可复用的..."
这 15 行代码展示了 LangChain.js 的核心能力:
- Prompt 模板化 — 变量
{role}和{question}自动填充 - Runnable 组合 —
pipe()将三个组件串成链 - Provider 无关 — 把
ChatOpenAI换成ChatAnthropic,其余不变
1.8 源码精读路线
| 优先级 | 文件 | 关注点 |
|---|---|---|
| P0 | AGENTS.md | 项目总览、核心抽象说明、开发规范、测试约定 |
| P0 | README.md | 项目定位、生态说明、Quick Start |
| P1 | pnpm-workspace.yaml | workspace 定义,了解包的组织方式 |
| P1 | turbo.json | 构建任务定义,理解包之间的依赖关系 |
| P2 | package.json (根目录) | 脚本命令、devDependencies、工具链选型 |
本课收获总结
| 级别 | 你应该掌握的 |
|---|---|
| 🟢 基础 | LLM 应用的四大挑战;LangChain.js 的"一切皆 Runnable"理念;能描述三层架构 |
| 🔵 中阶 | 理解 Runnable 统一接口的设计动机;知道 core / langchain / providers 的职责边界 |
| 🟡 高阶 | 能对比 LangChain.js 与 Python 版的差异;理解多运行时支持的意义 |
| 🟠 资深 | 能分析 40+ 包 monorepo 的模块拆分策略及其工程收益 |
| 🔴 架构 | 能评估"统一 Runnable 抽象"的 trade-off:灵活性 vs 复杂性 vs 性能 |
下一课预告
第 2 课将深入 Monorepo 架构与工程体系,从零搭建开发环境,理解 pnpm workspace、Turborepo 和 tsdown 的配置与协作。