课程目标
理解 Agent 的核心范式 —— ReAct (Reasoning + Acting)。精读 createReactAgent() 工厂函数与 ReactAgent 类的实现,掌握 Agent 执行循环、节点路由与终止条件。
24.1 Agent vs Chain:本质区别
Chain 是线性管道:Prompt → Model → Parser,数据单向流动,执行一次即结束。
Agent 引入了循环:
用户输入 → LLM 思考 → 需要工具?
├─ 是 → 执行工具 → 将结果反馈给 LLM → 再次思考 → ...
└─ 否 → 直接输出最终回答 → 结束
这就是 ReAct 模式的核心:Reasoning(推理)+ Acting(行动) 的交替执行。LLM 在每一步决定是调用工具还是直接回答。
24.2 createAgent() 与 ReactAgent
LangChain.js 的 Agent 系统基于 LangGraph 的 StateGraph 构建。createAgent() 是工厂函数,返回 ReactAgent 实例。
源码位置: libs/langchain/src/agents/index.ts
export function createAgent(params: CreateAgentParams): ReactAgent {
return new ReactAgent(params);
}
ReactAgent 类的构造函数完成了所有图的构建工作:
源码位置: libs/langchain/src/agents/ReactAgent.ts:161
export class ReactAgent<Types extends AgentTypeConfig> {
#graph: CompiledStateGraph<any, any, any, any, any, any, unknown>;
#agentNode: AgentNode<any, AnyAnnotationRoot>;
#defaultConfig: RunnableConfig;
constructor(public options: CreateAgentParams, defaultConfig?: RunnableConfig) {
// 1. 验证 model 参数
if (!options.model) {
throw new Error("`model` option is required to create an agent.");
}
// 2. 检查 LLM 没有预绑定工具
validateLLMHasNoBoundTools(options.model);
// 3. 合并 middleware 提供的工具
const middlewareTools = options.middleware
?.filter(m => m.tools).flatMap(m => m.tools) ?? [];
const toolClasses = [...(options.tools ?? []), ...middlewareTools];
// 4. 创建状态 schema
const { state, input, output } = createAgentState(...);
// 5. 构建 StateGraph,添加节点和边
const workflow = new StateGraph(state, { input, output, context: ... });
workflow.addNode(AGENT_NODE_NAME, this.#agentNode);
workflow.addNode(TOOLS_NODE_NAME, toolNode);
// 6. 添加条件边(路由逻辑)
workflow.addConditionalEdges(AGENT_NODE_NAME, this.#createModelRouter(...));
// 7. 编译图
this.#graph = workflow.compile({ checkpointer, store, name });
}
}
24.3 ReAct 图的三个核心节点
在 ReAct 模式中,图由三类节点组成:
| 节点 | 常量名 | 职责 |
|---|---|---|
| Agent 节点 | AGENT_NODE_NAME ("model_request") | 调用 LLM,决定下一步行动 |
| Tools 节点 | TOOLS_NODE_NAME ("tools") | 执行工具调用 |
| END | END | 图的终止点 |
执行流程:
START → [beforeAgent] → [beforeModel] → model_request → [afterModel]
│
┌──────────────────────────┤
│ │
有 tool_calls 无 tool_calls
│ │
▼ ▼
tools ─────────────→ [afterAgent] → END
(执行工具) (回到 beforeModel 继续循环)
24.4 模型路由:决定继续还是终止
#createModelRouter() 是路由的核心,它检查 LLM 的输出决定下一步去向:
源码位置: libs/langchain/src/agents/ReactAgent.ts:803
#createModelRouter(exitNode: string | typeof END = END) {
return (state: Record<string, unknown>) => {
const builtInState = state as unknown as BuiltInState;
const messages = builtInState.messages;
const lastMessage = messages.at(-1);
// 如果最后一条消息不是 AIMessage,或者没有 tool_calls → 终止
if (
!AIMessage.isInstance(lastMessage) ||
!lastMessage.tool_calls ||
lastMessage.tool_calls.length === 0
) {
return exitNode; // 路由到 END
}
// 有 tool_calls → 路由到 tools 节点
// v2 模式:每个 tool_call 作为独立的 Send 任务
const regularToolCalls = lastMessage.tool_calls.filter(
(toolCall) => !toolCall.name.startsWith("extract-")
);
return regularToolCalls.map(
(toolCall) => new Send(TOOLS_NODE_NAME, { ...state, lg_tool_call: toolCall })
);
};
}
终止条件总结:
- LLM 返回纯文本(无 tool_calls)→ 直接终止
- LLM 返回的 tool_calls 都是结构化输出提取(
extract-前缀)→ 终止 - 达到
recursionLimit(LangGraph 层面的安全阀)→ 强制终止
24.5 工具执行版本:v1 vs v2
ReactAgent 支持两种工具执行策略,通过 version 参数控制:
| 版本 | 策略 | 适用场景 |
|---|---|---|
| v1 | 所有 tool_calls 在一个节点内通过 Promise.all 并行执行 | 工具调用子图或长时间异步操作 |
| v2(默认) | 每个 tool_call 通过 Send API 分派为独立图任务 | 需要每次调用独立 checkpoint、独立容错 |
// v2 模式下的路由
return regularToolCalls.map(
(toolCall) => new Send(TOOLS_NODE_NAME, { ...state, lg_tool_call: toolCall })
);
24.6 AgentNode — 模型调用节点
AgentNode 负责实际调用 LLM。它是 RunnableCallable 的子类。
源码位置: libs/langchain/src/agents/nodes/AgentNode.ts
核心职责:
- 将工具列表绑定到模型(
bindTools()) - 注入系统消息(
systemPrompt) - 处理中间件的
wrapModelCall钩子 - 处理结构化输出响应(
responseFormat)
24.7 模型类型判断
Agent 系统需要判断模型实例的类型,以决定如何绑定工具:
源码位置: libs/langchain/src/agents/model.ts
export type AgentLanguageModelLike = RunnableInterface<
BaseLanguageModelInput, LanguageModelOutput
>;
export function isBaseChatModel(model: AgentLanguageModelLike): model is BaseChatModel {
return (
"invoke" in model &&
typeof model.invoke === "function" &&
"_streamResponseChunks" in model
);
}
createAgent 支持两种模型输入方式:
- 字符串:
"openai:gpt-4o"— 通过initChatModel()动态初始化 - 实例:
new ChatOpenAI({ model: "gpt-4o" })— 直接使用
24.8 响应处理:ToolStrategy 与 ProviderStrategy
responseFormat 参数控制如何获取结构化输出:
源码位置: libs/langchain/src/agents/responses.ts
| 策略 | 实现方式 | 适用场景 |
|---|---|---|
ToolStrategy | 将 schema 转为工具,让 LLM 通过 tool_call 返回结构化数据 | 通用,兼容性好 |
ProviderStrategy | 使用 Provider 的原生 JSON schema 输出能力 | OpenAI gpt-4o 等支持的模型 |
// 自动选择策略
const useProviderStrategy = hasSupportForJsonSchemaOutput(model);
if (isInteropZodObject(responseFormat)) {
return useProviderStrategy
? [ProviderStrategy.fromSchema(responseFormat)]
: [ToolStrategy.fromSchema(responseFormat)];
}
24.9 实战练习:创建第一个 ReAct Agent
import { z } from "zod";
import { createAgent, tool } from "langchain";
// 定义工具
const calculator = tool(
async ({ expression }) => {
try {
return String(eval(expression)); // 仅作示例
} catch {
return "计算错误,请检查表达式";
}
},
{
name: "calculator",
description: "计算数学表达式",
schema: z.object({
expression: z.string().describe("要计算的数学表达式"),
}),
}
);
const search = tool(
async ({ query }) => `搜索结果:关于「${query}」的信息...`,
{
name: "search",
description: "搜索互联网信息",
schema: z.object({
query: z.string().describe("搜索关键词"),
}),
}
);
// 创建 Agent
const agent = createAgent({
model: "openai:gpt-4o",
tools: [calculator, search],
systemPrompt: "你是一个有用的助手,可以使用计算器和搜索工具。",
});
// 调用 Agent
const result = await agent.invoke({
messages: [{ role: "user", content: "计算 (15 * 23) + 42 等于多少?" }],
});
// 观察完整的消息历史(包括推理过程)
for (const msg of result.messages) {
console.log(`[${msg.constructor.name}] ${msg.content}`);
}
// 流式执行
const stream = await agent.stream({
messages: [{ role: "user", content: "搜索 LangChain.js 的最新版本" }],
});
for await (const step of stream) {
for (const update of Object.values(step)) {
if (update && typeof update === "object" && "messages" in update) {
for (const message of update.messages) {
console.log(message.content);
}
}
}
}
24.10 源码精读路线
| 优先级 | 文件 | 关注点 |
|---|---|---|
| P0 | agents/ReactAgent.ts:161-700 | ReactAgent 构造函数 — 图的构建逻辑 |
| P0 | agents/ReactAgent.ts:803-854 | #createModelRouter() — 路由决策核心 |
| P0 | agents/index.ts:668-697 | createAgent() 工厂函数与重载签名 |
| P1 | agents/model.ts | 模型类型判断辅助函数 |
| P1 | agents/responses.ts:54-162 | ToolStrategy — 结构化输出的工具策略 |
| P2 | agents/nodes/AgentNode.ts | Agent 节点的 LLM 调用实现 |
| P2 | agents/nodes/ToolNode.ts | 工具节点的执行逻辑 |
本课收获总结
| 级别 | 你应该掌握的 |
|---|---|
| 🟢 基础 | 理解 Agent = LLM + Tools + 推理循环;能用 createAgent() 创建基本 Agent |
| 🔵 中阶 | 掌握 ReAct 图的三个核心节点和执行流程;理解终止条件 |
| 🟡 高阶 | 理解 #createModelRouter() 的路由逻辑;区分 v1/v2 工具执行版本 |
| 🟠 资深 | 分析 Agent 的状态管理与消息累积策略;理解 ToolStrategy vs ProviderStrategy |
| 🔴 架构 | 评估 ReAct vs Plan-and-Execute 等不同 Agent 范式;理解基于 StateGraph 的 Agent 架构设计 |
下一课预告
第 25 课深入 Agent 状态与注解系统 —— 理解 AgentState、Annotation 系统和 reducer 函数如何管理 Agent 的对话状态。