📖 本章学习目标
完成本章后,你将能够:
- ✅ 理解模型抽象层的设计理念和核心价值
- ✅ 掌握两种模型配置方式及其适用场景
- ✅ 接入主流 LLM Provider(OpenAI/Anthropic/Google/Ollama)
- ✅ 理解消息格式和多轮对话的工作原理
- ✅ 实现流式输出提升用户体验
- ✅ 使用结构化输出获取类型安全的数据
- ✅ 根据业务场景选择合适的模型
一、为什么需要模型抽象层
在实际开发中,你可能会遇到这样的困境:
场景: 你的团队正在用 OpenAI 的 GPT-4o 开发一个 AI 助手。突然有一天:
- OpenAI 涨价了 50%
- 或者某个功能在 Claude 上表现更好
- 或者公司要求数据不能出境,必须用本地模型
如果没有抽象层,你需要重写大量代码来切换模型。这就是 LangChain.js 模型抽象层要解决的问题。
1、传统方式的痛点
如果直接使用各家的原生 SDK,代码会是这样:
ts
// ❌ 直接绑定 OpenAI SDK
import OpenAI from "openai";
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const response = await openai.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "你好" }]
});
想切换到 Anthropic?需要完全重写:
ts
// ❌ 切换到 Anthropic,API 完全不同
import Anthropic from "@anthropic-ai/sdk";
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const response = await anthropic.messages.create({
model: "claude-3-opus",
messages: [{ role: "user", content: "你好" }]
});
问题所在:
- API 格式不同(参数名、返回结构都不一样)
- 认证方式不同
- 错误处理逻辑不同
- 流式输出的实现方式不同
2、LangChain.js 的解决方案
LangChain.js 提供统一的接口层,无论底层用什么模型,调用方式完全一致:
各 Provider SDK
LangChain.js 抽象层
你的应用代码
createAgent({ model: '...' })
统一接口
ChatModel
@langchain/openai
GPT-4o, o1...
@langchain/anthropic
Claude Opus/Sonnet...
@langchain/google-genai
Gemini 2.0...
@langchain/ollama
本地模型
核心优势:
| 优势 | 说明 | 实际价值 |
|---|---|---|
| 快速切换 | 在不同模型间做对比测试,只需改一个字符串 | 节省数小时的重构时间 |
| 避免供应商锁定 | 即使某个 Provider 涨价或出故障,迁移成本极低 | 降低商业风险 |
| 统一的流式接口 | 不用为每个 Provider 写不同的解析逻辑 | 代码复用率提升 80%+ |
| 统一的错误处理 | 所有 Provider 的错误格式标准化 | 简化异常处理逻辑 |
二、两种模型配置方式
LangChain.js 支持两种方式配置模型,分别适用于不同场景。
1、字符串标识符(推荐用于大多数场景)
在 v1.x 中,最简洁的方式是直接传 "provider:model-name" 格式的字符串:
(1)OpenAI 系列
ts
import { createAgent } from "langchain";
// GPT-4o:综合能力最强,适合复杂任务
const agent1 = createAgent({ model: "openai:gpt-4o" });
// GPT-4o-mini:性价比高,适合简单任务
const agent2 = createAgent({ model: "openai:gpt-4o-mini" });
// o1-mini:专门优化的推理模型,适合数学和逻辑
const agent3 = createAgent({ model: "openai:o1-mini" });
(2)Anthropic 系列
ts
// Claude Opus:最强推理能力,适合复杂分析
const agent4 = createAgent({ model: "anthropic:claude-opus-4-5" });
// Claude Sonnet:平衡性能和成本
const agent5 = createAgent({ model: "anthropic:claude-sonnet-4-6" });
// Claude Haiku:速度最快,成本最低
const agent6 = createAgent({ model: "anthropic:claude-haiku-3-5" });
(3)Google 系列
ts
// Gemini 2.0 Flash:免费额度高,响应速度快
const agent7 = createAgent({ model: "google:gemini-2.0-flash" });
(4)本地模型(Ollama)
ts
// Llama 3.2:Meta 开源模型,可在本地运行
const agent8 = createAgent({ model: "ollama:llama3.2" });
这种方式的优势:
- ✅ 代码简洁,一行搞定
- ✅ 自动处理认证和配置
- ✅ 适合快速原型开发和大多数生产场景
2、显式实例化(需要精细配置时)
当你需要配置温度、超时、最大 Token 等参数时,直接实例化 ChatModel 类:
ts
import { ChatOpenAI } from "@langchain/openai";
import { createAgent } from "langchain";
// 精细配置 OpenAI 模型
const model = new ChatOpenAI({
model: "gpt-4o", // 模型名称
temperature: 0.1, // 输出随机性(0: 最确定,1: 最随机)
maxTokens: 2000, // 限制输出长度
timeout: 30000, // 超时时间(毫秒)
maxRetries: 3, // 失败自动重试次数
});
const agent = createAgent({ model, tools: [] });
常用配置参数详解:
| 参数 | 说明 | 建议值 | 影响 |
|---|---|---|---|
temperature |
控制输出随机性 | 工具调用:0~0.2 创意写作:0.7~1.0 | 值越高,输出越有创造性但也越不可控 |
maxTokens |
最大输出 Token 数 | 根据任务设置 一般 1000~4000 | 限制输出长度,控制成本 |
timeout |
单次调用超时时间 | 30000~60000 ms | 防止网络问题导致长时间挂起 |
maxRetries |
失败自动重试次数 | 2~3 次 | 处理网络抖动和临时故障 |
topP |
核采样参数 | 0.8~0.95 | 与 temperature 配合控制多样性 |
💡 何时使用显式实例化?
- 需要精确控制温度(如结构化输出时必须用低温度)
- 需要自定义超时和重试策略
- 需要使用 Provider 特有的高级参数
- 需要在运行时动态调整配置
三、主流 Provider 接入详解
1、OpenAI(GPT 系列)
OpenAI 是最成熟的 LLM Provider,工具调用能力最强。
(1)安装
bash
pnpm add @langchain/openai
(2)基础用法
ts
import { ChatOpenAI } from "@langchain/openai";
// 创建模型实例
const model = new ChatOpenAI({
model: "gpt-4o",
temperature: 0, // 确定性输出
});
// 直接调用模型(不经过 Agent)
const response = await model.invoke([
{ role: "system", content: "你是一个有帮助的助手。" },
{ role: "user", content: "用一句话解释什么是递归。" },
]);
console.log(response.content);
// 输出:递归是函数调用自身来解决更小规模同类问题的编程技巧。
代码解读:
- 第 4-7 行:创建模型实例,指定模型和温度
- 第 10-13 行:构建消息列表(系统消息 + 用户消息)
- 第 15 行:调用模型并等待响应
- 第 17 行:输出响应内容
(3)OpenAI 特有参数
ts
const model = new ChatOpenAI({
model: "gpt-4o",
// 强制开启 JSON 输出模式
// 注意:这只是保证输出是合法 JSON,不保证字段结构
responseFormat: { type: "json_object" },
// 指定使用的 API Base URL
// 适用于代理服务器或兼容 OpenAI 接口的服务
configuration: {
baseURL: "https://your-proxy.com/v1",
},
});
⚠️ 注意 :
responseFormat: { type: "json_object" }只能保证输出是合法的 JSON,但不能保证字段名称和类型符合预期。如果需要严格的结构化输出,应该使用后面介绍的withStructuredOutput()方法。
2、Anthropic(Claude 系列)
Claude 系列在长文本处理和复杂推理方面表现优秀。
(1)安装
bash
pnpm add @langchain/anthropic
(2)基础用法
ts
import { ChatAnthropic } from "@langchain/anthropic";
const model = new ChatAnthropic({
model: "claude-opus-4-5", // Claude 最强模型
temperature: 0,
maxTokens: 4096, // Claude 需要显式指定 maxTokens
});
const response = await model.invoke([
{ role: "user", content: "用一句话解释什么是递归。" },
]);
console.log(response.content);
Claude 的特点:
| 特点 | 说明 | 适用场景 |
|---|---|---|
| 超长上下文 | Opus/Sonnet 支持 200K tokens | 处理整本书、大型代码库 |
| 优秀的代码理解 | 对代码结构和逻辑把握准确 | 代码审查、重构建议 |
| 复杂的推理能力 | 在多步推理任务中表现出色 | 数据分析、逻辑推导 |
| 自然的对话风格 | 回答更加流畅和人性化 | 客服、教育应用 |
💡 重要提示 :Anthropic 的 API 要求必须设置
maxTokens参数,否则会报错。这与 OpenAI 不同(OpenAI 有默认值)。
3、Google(Gemini 系列)
Gemini 的优势是免费额度高,多模态能力强。
(1)安装
bash
pnpm add @langchain/google-genai
(2)基础用法
ts
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
const model = new ChatGoogleGenerativeAI({
model: "gemini-2.0-flash",
temperature: 0,
});
const response = await model.invoke([
{ role: "user", content: "介绍一下你自己。" },
]);
console.log(response.content);
Gemini 的优势:
- 每月有大量免费额度(适合个人开发者和小团队)
- 原生支持图像、音频等多模态输入
- 响应速度快
4、Ollama(本地模型)
Ollama 允许你在本地运行开源模型,数据不离开你的机器。
(1)安装 Ollama
bash
# macOS/Linux
curl -fsSL https://ollama.ai/install.sh | sh
# Windows
# 从 https://ollama.ai/download 下载安装包
(2)下载并运行模型
bash
# 下载 Llama 3.2 模型(约 2GB)
ollama pull llama3.2
# 测试运行
ollama run llama3.2
# 查看已安装的模型
ollama list
(3)安装 LangChain 集成
bash
pnpm add @langchain/ollama
(4)使用本地模型
ts
import { ChatOllama } from "@langchain/ollama";
const model = new ChatOllama({
model: "llama3.2",
baseUrl: "http://localhost:11434", // Ollama 默认地址
temperature: 0,
});
const response = await model.invoke([
{ role: "user", content: "你好!" },
]);
console.log(response.content);
💡 什么时候用本地模型?
优势:
- ✅ 数据隐私:敏感数据不会发送到外部 API
- ✅ 零成本:本地运行完全免费
- ✅ 离线可用:不需要网络连接
劣势:
- ❌ 硬件要求高:需要较好的 GPU(至少 8GB 显存)
- ❌ 推理速度慢:比 API 慢 5-10 倍
- ❌ 质量稍逊:开源模型在复杂推理上通常不如 GPT-4o 或 Claude
典型场景:
- 企业内部文档问答(数据敏感)
- 开发阶段高频测试(控制成本)
- 边缘设备部署(无网络环境)
四、消息格式:理解多角色对话
LangChain.js 的消息系统与 OpenAI 的 Chat Completion 格式对齐。理解消息类型对于写好 Prompt 至关重要。
1、四种消息角色
system
系统消息
设定角色和规则
human
用户消息
用户的输入
tool
工具返回的信息
assistant
助手消息
模型的历史回复
| 消息类型 | 角色 | 用途 | 示例 |
|---|---|---|---|
SystemMessage |
system |
设定模型的角色、行为规范、背景知识 | "你是一个专业的 Python 程序员" |
HumanMessage |
human/user |
用户的输入 | "如何排序一个列表?" |
AIMessage |
assistant |
模型的历史回复(多轮对话中用到) | "你可以使用 sorted() 函数..." |
ToolMessage |
tool |
工具调用的返回结果(Agent 内部使用) | "{result: [1,2,3]}" |
2、构建多轮对话
ts
import { ChatOpenAI } from "@langchain/openai";
import {
HumanMessage,
AIMessage,
SystemMessage
} from "@langchain/core/messages";
const model = new ChatOpenAI({ model: "gpt-4o" });
// 构建多轮对话历史
const messages = [
// 第一步:系统消息(设定角色)
new SystemMessage("你是一个专业的 TypeScript 开发助手。"),
// 第二步:第一轮对话
new HumanMessage("什么是泛型?"),
new AIMessage("泛型是 TypeScript 中允许类型作为参数的机制,可以编写适用于多种类型的通用代码。"),
// 第三步:当前问题(基于上下文的追问)
new HumanMessage("能给一个实际的例子吗?"),
];
const response = await model.invoke(messages);
console.log(response.content);
// 输出会基于上下文,给出泛型的具体代码示例
执行流程:
- 系统消息告诉模型它的角色和专业领域
- 第一轮对话建立了基础知识
- 第二轮问题基于第一轮的上下文,模型会给出更深入的回答
💡 实际应用提示:
在实际 Agent 开发中,你不需要手动管理这个消息列表------LangChain.js 会自动维护对话历史。但理解消息格式,对于调试 Prompt 和理解 Agent 的工作原理很有帮助。
3、使用对象简写(推荐)
除了使用消息类,你也可以直接用对象表示(更简洁):
ts
const messages = [
{ role: "system", content: "你是一个助手。" },
{ role: "user", content: "你好!" },
{ role: "assistant", content: "你好!有什么可以帮助你的?" },
{ role: "user", content: "谢谢!" },
];
const response = await model.invoke(messages);
两种方式的区别:
- 消息类(
HumanMessage等):提供更多元数据和方法,适合复杂场景 - 对象简写:代码更简洁,适合大多数场景
五、流式输出:提升用户体验
LLM 生成文本是逐 Token 的过程(类似打字机逐个字符输出),等全部生成完才返回会有明显的等待感。
举例: 如果模型要生成 500 个 token,可能需要 5-10 秒。如果等全部生成完再显示,用户会觉得"卡住了"。
流式输出(Streaming) 可以让用户实时看到生成的内容,大幅改善体验。
1、基础流式调用
ts
import { ChatOpenAI } from "@langchain/openai";
const model = new ChatOpenAI({ model: "gpt-4o" });
// 使用 stream() 方法替代 invoke()
const stream = await model.stream([
{ role: "user", content: "用 100 字介绍一下 TypeScript。" },
]);
// 逐块处理输出
process.stdout.write("回答:");
for await (const chunk of stream) {
// chunk.content 是当前块的文本内容
process.stdout.write(chunk.content as string);
}
process.stdout.write("\n");
代码解读:
- 第 5 行:使用
stream()方法,返回一个异步迭代器 - 第 10-13 行:使用
for await...of循环遍历流式数据 - 第 12 行:每收到一块数据就立即输出(实现打字机效果)
效果:打字机效果
回答:TypeScript是JavaScript的超集,添加了静态类型系统。它能在编译时发现类型错误,提高代码可维护性。TypeScript支持接口、泛型、装饰器等高级特性,被广泛应用于大型前端项目。→
2、在 Agent 中获取流式输出
ts
import { createAgent, tool } from "langchain";
import { z } from "zod";
const agent = createAgent({
model: "openai:gpt-4o",
tools: [],
});
// streamMode: "messages" 可以获取逐 Token 的流式输出
const stream = await agent.stream(
{ messages: [{ role: "user", content: "写一首关于编程的短诗。" }] },
{ streamMode: "messages" }
);
for await (const [message, _metadata] of stream) {
// 只处理 AI 的文本输出块
if (message.role === "assistant" && typeof message.content === "string") {
process.stdout.write(message.content);
}
}
streamMode 的三种模式:
| 模式 | 返回格式 | 适用场景 |
|---|---|---|
"messages" |
[message, metadata] 元组 |
对话界面,逐 Token 显示 |
"values" |
完整状态对象 | 需要了解 Agent 的中间思考过程 |
"updates" |
增量变化部分 | 只关心状态变化的场景 |
⚠️ 注意 :不同
streamMode的返回格式不同,需要根据你的需求选择合适的模式。
3、Web 应用中的流式输出
在真实的 Web 应用中,你会通过 Server-Sent Events (SSE) 或 WebSocket 将流式数据推送到前端:
ts
// Express.js 示例
app.get("/chat", async (req, res) => {
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
const stream = await agent.stream({
messages: [{ role: "user", content: req.query.q }]
}, { streamMode: "messages" });
for await (const [message] of stream) {
if (message.role === "assistant") {
res.write(`data: ${JSON.stringify({ content: message.content })}\n\n`);
}
}
res.end();
});
六、结构化输出:让模型返回可靠的数据
LLM 默认返回自由格式的文本,但在实际应用中,我们往往需要模型输出结构化的数据。
典型场景:
- 从文章中提取人名、地点、时间等实体
- 将用户描述解析为 JSON 格式的配置
- 对文本进行分类并返回固定类别
- 生成符合特定 Schema 的代码
1、为什么需要结构化输出?
问题场景: 假设你要从新闻中提取信息:
ts
// ❌ 不使用结构化输出
const response = await model.invoke([
{ role: "user", content: "提取这篇文章的标题、摘要和标签" }
]);
// 返回的是自由文本,难以解析
console.log(response.content);
// "标题:AI技术突破\n摘要:最近AI领域...\n标签:AI, 技术"
// 你需要写复杂的正则表达式来解析
const title = response.content.match(/标题:(.*)/)?.[1];
解决方案: 使用 withStructuredOutput() + Zod Schema
ts
// ✅ 使用结构化输出
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod";
// 定义期望的输出结构
const ArticleSchema = z.object({
title: z.string().describe("文章标题"),
summary: z.string().describe("文章摘要,不超过 100 字"),
tags: z.array(z.string()).describe("文章标签列表,3-5 个"),
difficulty: z.enum(["入门", "中级", "高级"]).describe("文章难度"),
});
const model = new ChatOpenAI({ model: "gpt-4o" });
// 绑定结构化输出 Schema
const structuredModel = model.withStructuredOutput(ArticleSchema);
const result = await structuredModel.invoke([
{
role: "user",
content: `分析这篇文章并提取信息:
"本文介绍了如何使用 React Hooks 优化组件性能,包括 useMemo、useCallback 和 memo 的使用场景与最佳实践,适合有 React 基础的开发者。"`,
},
]);
// result 是完全类型安全的!TypeScript 知道它的结构
console.log(result.title); // string
console.log(result.summary); // string
console.log(result.tags); // string[]
console.log(result.difficulty); // "入门" | "中级" | "高级"
优势对比:
| 方式 | 返回值类型 | 类型安全 | 可靠性 | 易用性 |
|---|---|---|---|---|
| 自由文本 | string |
❌ | ❌ 需要手动解析 | ❌ |
| JSON 模式 | any |
⚠️ 部分 | ⚠️ 字段可能缺失 | ⚠️ |
| 结构化输出 | 定义的 Schema | ✅ 完全 | ✅ 字段保证存在 | ✅ |
2、提取多个实体
ts
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod";
// 定义联系人 Schema
const ContactSchema = z.object({
contacts: z.array(
z.object({
name: z.string().describe("姓名"),
email: z.string().email().optional().describe("邮箱,如果有的话"),
phone: z.string().optional().describe("电话号码,如果有的话"),
company: z.string().optional().describe("公司名称,如果有的话"),
})
).describe("提取出的联系人列表"),
});
const model = new ChatOpenAI({ model: "gpt-4o" });
const extractor = model.withStructuredOutput(ContactSchema);
const text = `
本次会议参与者:
张三(zhangsan@example.com,18800001111,来自 ABC 科技)
李四(lisi@company.com,来自 XYZ 集团)
王五(13900002222)
`;
const result = await extractor.invoke([
{ role: "user", content: `从以下文本中提取联系人信息:\n${text}` }
]);
console.log(result.contacts);
// [
// { name: "张三", email: "zhangsan@example.com", phone: "18800001111", company: "ABC 科技" },
// { name: "李四", email: "lisi@company.com", company: "XYZ 集团" },
// { name: "王五", phone: "13900002222" }
// ]
关键点:
- 使用
.optional()标记可选字段 - 使用
.email()等验证器确保格式正确 - 在
describe()中详细说明每个字段的含义
3、strict 模式(v1.2.0 新增)
v1.2.0 中新增了 strict 参数,强制模型严格按照 Schema 输出:
ts
const structuredModel = model.withStructuredOutput(ArticleSchema, {
strict: true, // 严格模式
});
strict 模式的作用:
- ✅ 减少字段遗漏的概率
- ✅ 减少格式错误的概率
- ✅ 提高输出的可靠性
- ⚠️ 可能会略微增加延迟
💡 最佳实践 :在生产环境中,始终开启
strict: true,除非你有特殊理由。
4、结构化输出 vs JSON 模式
一些 Provider(如 OpenAI)支持 responseFormat: { type: "json_object" } 的 JSON 模式,但这只能保证输出是合法的 JSON,不能保证字段名称和类型符合预期。
对比:
ts
// ❌ JSON 模式:只保证是合法 JSON
const model1 = new ChatOpenAI({
model: "gpt-4o",
responseFormat: { type: "json_object" }
});
// 返回可能是:{"title": "..."} 或 {"Title": "..."} 或 {"name": "..."}
// 字段名不确定!
// ✅ 结构化输出:保证字段名和类型都符合 Schema
const model2 = new ChatOpenAI({ model: "gpt-4o" });
const structured = model2.withStructuredOutput(ArticleSchema);
// 返回一定是:{ title: string, summary: string, tags: string[], ... }
// 字段名和类型都确定!
结论: 在需要精确数据的场景,始终优先使用 withStructuredOutput()。
七、动态模型选择(高级用法)
在某些场景下,你可能希望根据任务复杂度动态切换模型------简单任务用便宜的小模型,复杂任务用性能更强的大模型,以此平衡效果和成本。
实现思路
LangChain.js 通过中间件实现这一点:
ts
import { ChatOpenAI } from "@langchain/openai";
import { createAgent, createMiddleware } from "langchain";
// 定义两个不同档次的模型
const basicModel = new ChatOpenAI({
model: "gpt-4o-mini" // 低成本
});
const advancedModel = new ChatOpenAI({
model: "gpt-4o" // 高质量
});
// 创建动态模型选择中间件
const dynamicModelMiddleware = createMiddleware({
name: "DynamicModelSelection",
// 拦截模型调用请求
wrapModelCall: (request, handler) => {
const messageCount = request.messages.length;
// 超过 10 条消息时,认为任务较复杂,切换到高级模型
const selectedModel = messageCount > 10 ? advancedModel : basicModel;
console.log(`选择模型: ${selectedModel.model} (消息数: ${messageCount})`);
// 用选中的模型处理请求
return handler({ ...request, model: selectedModel });
},
});
// 创建 Agent 并注册中间件
const agent = createAgent({
model: basicModel, // 默认模型
tools: [],
middleware: [dynamicModelMiddleware],
});
工作原理:
- 中间件拦截每次模型调用请求
- 根据请求内容(如消息数量)决定使用哪个模型
- 用选中的模型处理请求
💡 实际应用场景:
- 客服系统:简单问题用 mini 模型,复杂投诉用完整版
- 代码助手:语法查询用 mini,架构设计用完整版
- 成本控制:90% 的请求用便宜模型,只有 10% 用昂贵模型
注意: 中间件系统会在第七章详细讲解,这里只是展示一个直觉性的例子。
八、模型选型建议
在实际项目中,如何选择合适的模型?以下是一份参考矩阵:
场景化推荐
| 场景 | 推荐模型 | 理由 | 成本参考 |
|---|---|---|---|
| 工具调用密集的 Agent | openai:gpt-4o |
工具调用准确率高,多工具并行能力强 | $$$ |
| 长文档分析(>50K tokens) | anthropic:claude-opus-4-5 |
超长上下文窗口,长文阅读理解优秀 | $$$$ |
| 高频低延迟场景 | openai:gpt-4o-mini anthropic:claude-haiku-3-5 |
响应快(<1s),成本低 | $ |
| 复杂推理 / 数学 | openai:o1-mini anthropic:claude-opus-4-5 |
推理能力专门优化 | − - −$ |
| 代码生成 | anthropic:claude-sonnet-4-6 openai:gpt-4o |
代码质量高,理解上下文能力强 | − - −$ |
| 本地部署 / 数据敏感 | ollama:llama3.2 ollama:qwen2.5 |
数据不出本地,免费使用 | 免费 |
| 开发调试阶段 | 任何 *-mini / *-flash 版本 |
响应快、成本低,适合高频测试 | $ |
成本对比(每 1M tokens)
| 模型 | 输入价格 | 输出价格 | 相对成本 |
|---|---|---|---|
| GPT-4o | $2.50 | $10.00 | 基准 |
| GPT-4o-mini | $0.15 | $0.60 | 6% |
| Claude Opus | $15.00 | $75.00 | 600% |
| Claude Sonnet | $3.00 | $15.00 | 120% |
| Claude Haiku | $0.25 | $1.25 | 10% |
| Gemini 2.0 Flash | $0.10 | $0.40 | 4% |
💡 实践建议:
- 开发阶段:优先用便宜的 mini 模型,功能跑通后再切换到高质量模型做效果对比
- A/B 测试:同时用两个模型处理相同任务,对比质量和成本
- 监控成本:接入 LangSmith,实时监控 Token 消耗和费用
- 缓存策略:对重复问题使用缓存,避免重复调用 LLM
九、本章小结
模型抽象层是 LangChain.js 的基础设施之一。这一章我们学习了:
📝 核心知识点回顾
- 统一接口的价值:无论哪家 Provider,调用方式一致,避免供应商锁定
- 两种配置方式 :
- 字符串标识符:简洁,适合大多数场景
- 显式实例化:灵活,适合需要精细控制的场景
- 四大 Provider:OpenAI、Anthropic、Google、Ollama 的特点和接入方式
- 消息格式 :
system/human/assistant/tool四种消息类型的作用 - 流式输出 :
stream()方法和三种streamMode的选择 - 结构化输出 :
withStructuredOutput()+Zod Schema实现类型安全的结构化返回 - 模型选型:根据场景选择合适模型的参考框架
🎯 动手练习
尝试完成以下练习,巩固所学知识:
练习 1:切换模型对比
创建一个简单的问答 Agent,分别用 gpt-4o 和 gpt-4o-mini 回答同一个复杂问题,对比响应时间和质量差异。
练习 2:结构化输出实战
设计一个 Schema,从电影评论中提取:评分(1-5)、情感倾向(正面/负面/中性)、提到的演员名单。
练习 3:流式输出 Web 应用
创建一个简单的 Express.js 应用,实现 SSE 流式输出,在前端页面上实现打字机效果。
练习 4:本地模型测试
安装 Ollama 和 Llama 3.2,对比本地模型和 GPT-4o 在代码生成任务上的表现。