主题
概述
要点
- LangChain 的定位不是「让模型更聪明」,而是把模型、消息、Prompt、工具、链路和 Agent 组装成一套可维护的调用结构。
- 单 Agent 的核心任务是:在一轮请求里理解输入、组织上下文、判断是否调用工具、执行工具并生成回复。
- LangChain 的包结构分为四层:
@langchain/core定义协议,langchain提供高层 API,@langchain/{provider}接具体模型,@langchain/classic保留旧抽象。 - 一个 Agent 至少由模型、消息、Prompt、Runnable、Tool 和
createAgent()组装而成,缺一不可。
1. 背景:为什么需要 LangChain
直接调用模型 API 时,代码会快速分成几块:模型调用、Prompt 拼接、工具调用、输出解析。每一块单独看都不复杂,但组合起来之后,缺少统一的组织方式。
以一条典型请求为例:
帮我记一下明天下午三点开会,再查一下上海明天会不会下雨。
要让模型正确处理这句话,系统内部至少要完成:
- 接住用户消息。
- 把系统设定、工具说明整理成模型可读的上下文。
- 把输入交给模型,让它判断是否需要调用工具。
- 执行工具(创建提醒、查询天气)。
- 把工具结果回送给模型。
- 生成最终回复。
这些步骤如果全部手写,功能一多就会散开。LangChain 的作用,是把它们放进一套统一的写法里,让模型、Prompt、工具、链路和 Agent 可以稳定组合。
2. LangChain 的包结构
LangChain 当前版本的包结构大致分为四层,每层承担的职责不同。
2.1 @langchain/core
@langchain/core 是基础抽象层,负责定义通用协议,让上层组件按同样的方式组合。它包括:
- 消息类型:
HumanMessage、SystemMessage、AIMessage、ToolMessage。 - Prompt 模板:
ChatPromptTemplate、MessagesPlaceholder。 - Runnable 协议:
RunnableParallel、RunnableSequence等。 - 输出解析器:
StringOutputParser、JsonOutputParser等。
typescript
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";这一层也可以从 langchain 主包中重新导出,例如:
typescript
import { HumanMessage, SystemMessage } from "langchain";两种导入方式在功能上是一致的,只是入口不同。如果代码只在 @langchain/core 中能找到对应类型,就从 core 导入;如果是常用高层类型,从 langchain 导入也可以。
2.2 langchain
langchain 是应用层最常用的入口,主要提供:
createAgent():组装一个可运行的 Agent。tool():把函数包装成模型可调用的工具。initChatModel():按模型名快速初始化模型。middleware:运行时的中间件能力。- 常用消息类型和高层能力的 re-export。
单 Agent 场景下,这一章大多数代码都会从 langchain 包开始写。
2.3 @langchain/
这一层用来接具体模型厂商。例如:
@langchain/openai@langchain/anthropic@langchain/google-genai
如果只是快速开始,可以用 initChatModel():
typescript
import { initChatModel } from "langchain";
const model = await initChatModel("gpt-4.1-mini", {
modelProvider: "openai",
});如果需要更细的 provider 配置,再显式创建模型对象:
typescript
import { ChatOpenAI } from "@langchain/openai";
const model = new ChatOpenAI({
model: "gpt-4.1-mini",
temperature: 0.2,
});2.4 @langchain/classic
老版本里常见的 chains、memory、indexing 抽象,现在不少已经移到 @langchain/classic 包里。如果你在旧资料里看到 ConversationBufferMemory、老的 chain 封装或早期 retrieval 组合方式,需要知道它们已经不在 langchain 主包中了。
3. 一个最小可用的 Agent 例子
先从一个能跑起来的例子开始,再回过来拆结构。下面的代码实现了一个能创建提醒和查询天气的任务助手:
typescript
import * as z from "zod";
import { createAgent, initChatModel, tool } from "langchain";
const model = await initChatModel("gpt-4.1-mini", {
modelProvider: "openai",
});
const createReminder = tool(
async ({ title, time }) => `提醒已创建:${time} ${title}`,
{
name: "create_reminder",
description: "创建提醒事项",
schema: z.object({
title: z.string().describe("提醒内容"),
time: z.string().describe("提醒时间"),
}),
},
);
const getWeather = tool(
async ({ city }) => `${city} 明天有小雨,出门记得带伞`,
{
name: "get_weather",
description: "查询城市天气",
schema: z.object({
city: z.string().describe("要查询天气的城市"),
}),
},
);
const agent = createAgent({
model,
tools: [createReminder, getWeather],
systemPrompt: "你是一个细心、自然的任务助手。",
});
const result = await agent.invoke({
messages: [
{
role: "user",
content:
"我明天下午三点要开会,帮我记一下。顺便查一下上海明天会不会下雨。",
},
],
});
console.log(result.messages.at(-1)?.content);这段代码已经覆盖了 LangChain 单 Agent 场景里最重要的几样东西:
initChatModel():把模型接进来。tool():把外部能力包装成工具。createAgent():把模型、工具和系统设定组装成一个 Agent。agent.invoke():把一轮消息交给 Agent 处理。
后面的章节会围绕这四件事展开。
4. 核心组件:用一个 Agent 的结构来看
为了不把内容讲散,我们继续盯着一个 Agent 的结构看。一个完整的 Agent 至少有下面这些部分:
- 一个模型(大脑)
- 一组工具
- 一段系统设定
- 一轮一轮收到的消息
- 一个对外执行任务的方法
invoke()
LangChain 处理的,就是这些部分怎样接到一起。
4.1 模型:先把推理能力接进来
模型是最底层的推理能力来源。在 LangChain 里,模型接入之后,会尽量统一成相似的调用方式。这样做的直接好处是:换模型时,上层代码不至于全部推倒重来。
typescript
import { initChatModel } from "langchain";
const model = await initChatModel("gpt-4.1-mini", {
modelProvider: "openai",
});typescript
import { ChatOpenAI } from "@langchain/openai";
const model = new ChatOpenAI({
model: "gpt-4.1-mini",
temperature: 0.2,
});前一种更适合快速开始;后一种适合需要显式控制 provider 细节的场景。
4.2 消息:聊天模型的输入不是纯字符串
聊天模型处理的核心输入,通常不是一段字符串,而是一组带角色的消息。例如:
systemuserassistanttool
在 LangChain 里,消息可以写成对象字面量,也可以写成消息类。
typescript
const result = await agent.invoke({
messages: [
{ role: "system", content: "你是一个细心的任务助手。" },
{ role: "user", content: "帮我记一下明天上午九点开会。" },
],
});如果只是一次性生成,直接传字符串给模型也可以:
typescript
const response = await model.invoke("帮我写一句晚安留言");但只要进入对话、工具调用或历史消息场景,消息结构就会比纯字符串更自然。
4.3 Prompt:把零散输入整理成可维护的上下文
单个 Agent 真正难写的地方,通常不是调用模型,而是怎么组织输入。在一个真实场景里,交给模型的内容往往包括:
- 系统设定
- 角色信息
- 历史消息
- 检索结果
- 工具说明
如果靠模板字符串硬拼,后面会越来越难维护。LangChain 提供了 Prompt 相关抽象,让你可以把输入拆成稳定部分和动态部分。
typescript
import { ChatPromptTemplate } from "@langchain/core/prompts";
const prompt = ChatPromptTemplate.fromMessages([
["system", "你是{name},你的角色设定是:{persona}"],
["human", "{input}"],
]);
const messages = await prompt.invoke({
name: "任务助手",
persona: "说话自然、做事有条理",
input: "我今天下班特别晚,有点累",
});这一块在后面的 Prompt 章节会单独展开。
4.4 Runnable:把多个步骤串成链
模型、Prompt、输出解析这些组件放在一起之后,下一步就是把它们接成一条链。LangChain 里常用的方式是 Runnable 协议。只要组件遵守这套协议,就能用类似方式调用,也能用 .pipe() 串起来。
typescript
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
const prompt = ChatPromptTemplate.fromMessages([
["system", "你是一个很会安慰人的助手。"],
["human", "{input}"],
]);
const chain = prompt.pipe(model).pipe(new StringOutputParser());
const reply = await chain.invoke({
input: "今天工作压力有点大",
});这里有一个边界要记住:
prompt.pipe(model).pipe(parser)这种写法属于普通链路。createAgent()属于 agent runtime。
普通链路里,步骤怎么走,基本由你自己安排。Agent 则是在运行时让模型决定要不要调用工具、先调用哪个工具、拿到工具结果后要不要继续。这一层差别,后面写多工具 Agent 时会很明显。
4.5 Tool:让 Agent 从「会回答」变成「会做事」
如果没有工具,模型再聪明,也只能在已有上下文里生成内容。接上工具以后,Agent 才能开始动手。常见工具包括:
- 创建提醒
- 查询天气
- 检索长期记忆
- 查询日程
LangChain 提供的 tool() 主要做的是标准化包装。它把一个普通函数包装成 Agent 可识别的工具,并补上描述和参数 schema。
typescript
import * as z from "zod";
import { tool } from "langchain";
const searchMemory = tool(
async ({ query }) => `检索到和「${query}」相关的历史记录`,
{
name: "search_memory",
description: "检索与用户相关的长期记忆",
schema: z.object({
query: z.string().describe("要检索的内容"),
}),
},
);这个工具的业务逻辑还是你自己实现。LangChain 负责的是把它包装成模型能理解、能调用的形式。
4.6 Agent:把这些能力装进一个可以接任务的对象
当前这条主线的终点,就是 createAgent()。你可以把它理解成:前面准备好的模型、工具、系统设定,最终都要在这里合体。
typescript
import { createAgent, initChatModel } from "langchain";
const model = await initChatModel("gpt-4.1-mini", {
modelProvider: "openai",
});
const agent = createAgent({
model,
tools: [createReminder, getWeather, searchMemory],
systemPrompt: "你是一个温和、细心、做事有条理的任务助手。",
});
const result = await agent.invoke({
messages: [
{
role: "user",
content:
"帮我记一下周五晚上七点和朋友吃饭,再看看北京周五晚上会不会下雨。",
},
],
});这时候的运行过程,已经不是简单的「Prompt 进,文本出」了:
- Agent 接住消息。
- 模型判断需不需要工具。
- 如果需要,就发起工具调用。
- 工具执行完成后,把结果回给模型。
- 模型生成最终回复。
这正是 LangChain 这一章后面要逐步拆开的内容。
5. 总结
LangChain 的核心价值,是把模型、消息、Prompt、工具、链路和 Agent 组装成一套可维护的调用结构。它的包结构分为四层:
@langchain/core:定义协议和基础抽象。langchain:提供createAgent()、tool()、initChatModel()等高层 API。@langchain/{provider}:接具体模型厂商。@langchain/classic:保留旧版本的链、记忆、索引等抽象。
一个 Agent 至少由模型、消息、Prompt、Runnable、Tool 和 createAgent() 组装而成。理解这六样东西的边界和连接方式,是后续学习 Prompt 模板、输出解析、链路编排、记忆持久化和多工具 Agent 的基础。