深入浅出 LangChain —— 第七章:Agent 架构深度解析与LangGraph 核心概念

📖 本章学习目标

完成本章后,你将能够:

  • ✅ 理解 createAgent() 内部的 LangGraph 图结构
  • ✅ 掌握 ReAct 推理模式的执行流程和边界条件
  • ✅ 使用 LangGraph API 手动构建等效的 Agent
  • ✅ 编写中间件拦截和修改 Agent 行为
  • ✅ 实现 Human-in-the-loop 人工确认机制
  • ✅ 判断何时需要使用底层 LangGraph API

一、揭开 createAgent() 的内部

在前几章,我们一直在用 createAgent() 这个高层 API。它简洁易用,但理解其内部机制,是从"能用"跨越到"用好"的关键。

1、createAgent() 的本质

createAgent() 本质上是在 LangGraph 之上构建了一个标准化的 Agent 图。

  • createAgent() 快速方便,适合大多数场景
  • LangGraph:灵活可控,适合定制化需求

2、Agent 图的完整结构

flowchart TD Start(["__start__
图的入口"]) --> Agent subgraph AgentLoop["Agent 执行循环"] direction TB Agent["agent 节点
调用 LLM 做推理决策"] -->|"有工具调用"| Tools Tools["tools 节点
执行工具调用"] --> Agent end Agent -->|"无工具调用
最终回答"| End(["__end__
图的出口"]) style Start fill:#e8f4fd,stroke:#1890ff,stroke-width:3px style End fill:#f6ffed,stroke:#52c41a,stroke-width:3px style Agent fill:#fff7e6,stroke:#fa8c16,stroke-width:3px style Tools fill:#fff0f6,stroke:#eb2f96,stroke-width:3px

关键组件说明:

组件 类型 作用
__start__ 特殊节点 图的入口,接收用户输入
agent 普通节点 调用 LLM,决定下一步行动
tools 普通节点 执行工具调用
__end__ 特殊节点 图的出口,返回最终结果
条件边 动态路由 根据 LLM 输出决定流向

3、数据流详解

让我们跟踪一次完整的 Agent 执行过程:

第 1 步:用户输入进入

typescript 复制代码
const result = await agent.invoke({
  messages: [{ role: "user", content: "北京今天天气如何?" }]
});

状态变化:

typescript 复制代码
// 初始状态
{
  messages: [HumanMessage("北京今天天气如何?")]
}

第 2 步:进入 agent 节点

typescript 复制代码
async function agentNode(state) {
  // 1. 将所有消息发送给 LLM
  const response = await modelWithTools.invoke(state.messages);
  
  // 2. 将 LLM 响应追加到消息列表
  return { messages: [response] };
}

可能的 LLM 输出:

typescript 复制代码
AIMessage({
  content: "",
  tool_calls: [{
    name: "get_weather",
    args: { city: "北京" }
  }]
})

第 3 步:条件判断

typescript 复制代码
function shouldContinue(state) {
  const lastMessage = state.messages.at(-1);
  
  if (lastMessage.tool_calls?.length) {
    return "tools";   // 有工具调用,转到 tools 节点
  }
  return END;          // 没有工具调用,结束
}

第 4 步:执行工具

typescript 复制代码
// tools 节点自动执行所有工具调用
const toolResults = await executeTools(toolCalls);
// 返回:[{ name: "get_weather", result: "北京晴,22°C" }]

第 5 步:回到 agent 节点

LLM 基于工具结果再次推理,可能:

  • 继续调用其他工具
  • 给出最终回答

第 6 步:结束

当 LLM 不再调用工具时,流程结束。


二、ReAct 推理模式

ReAct 是目前最主流的 Agent 推理框架,源自 2022 年的同名论文。

1、什么是 ReAct?

ReAct = Reasoning(推理)+ Acting(行动)

核心思想:把推理和行动交替进行,每次行动的结果都成为下一轮推理的输入。

【辅助理解】想象你在解决一个复杂问题:

  1. 思考:我需要查什么信息?
  2. 行动:上网搜索
  3. 观察:看到搜索结果
  4. 再思考:还需要什么信息?
  5. 再行动:打开具体网页
  6. 观察:阅读详细内容
  7. 得出结论:综合所有信息回答问题

这就是 ReAct 的工作方式。

2、ReAct 的完整执行过程

让我们通过一个实际例子来理解:

用户请求: "帮我查一下 LangChain.js 的最新版本号,并告诉我有没有新的 API"

第 1 轮:初始推理

bash 复制代码
┌────────────────────────────────────────────┐
│ Thought(思考):                           │
│ 用户想知道 LangChain.js 的最新版本,         │
│ 我需要搜索最新信息。                         │
│ 应该先搜索 LangChain.js 的 changelog 或      │
│ npm 页面。                                  │
│                                            │
│ Action(行动):                            │
│ 调用 search(query="LangChain.js latest      │
│         version 2025")                      │
└─────────────────────────────────────────────┘

第 1 次观察

bash 复制代码
┌─────────────────────────────────────────────┐
│ Observation(观察):                          │
│ 搜索结果:LangChain.js v1.3.1 于              │
│ 2025年12月发布...                             │
└─────────────────────────────────────────────┘

第 2 轮:基于观察的推理

bash 复制代码
┌─────────────────────────────────────────────┐
│ Thought(思考):                              │
│ 找到了版本号是 1.3.1。                        │
│ 还需要了解新 API,应该进一步搜索变更日志。      │
│                                              │
│ Action(行动):                               │
│ 调用 fetch_webpage(url="https://docs.         │
│   langchain.com/.../changelog")               │
└─────────────────────────────────────────────┘

第 2 次观察

bash 复制代码
┌─────────────────────────────────────────────┐
│ Observation(观察):                          │
│ v1.3.0 新增 Anthropic 服务端工具、            │
│ MCP 协议适配器支持...                         │
└─────────────────────────────────────────────┘

最终回答

bash 复制代码
┌─────────────────────────────────────────────┐
│ Final Answer(最终答案):                     │
│ LangChain.js 最新版本是 v1.3.1。主要新增了:  │
│ 1. Anthropic 服务端工具支持...                │
│ 2. MCP 协议适配器...                          │
└─────────────────────────────────────────────┘

3、ReAct 的优势

优势 说明 对比
可解释性强 每一步推理都清晰可见 vs 直接生成答案
准确性高 基于真实信息回答 vs 依赖训练数据
灵活性好 可根据情况调整策略 vs 固定流程
易于调试 可以追踪每步决策 vs 黑盒模型

4、ReAct 的边界条件

ReAct 循环不会无限执行下去,有以下终止条件:

(1)配置最大迭代次数

typescript 复制代码
const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [searchTool],
  
  // 配置最大迭代次数(防止死循环)
  maxIterations: 10,  // 默认值,可以根据需要调整
});

(2)终止条件对比

条件 触发时机 处理方式 示例
正常结束 LLM 不再发出工具调用 返回最终回答 "根据搜索结果..."
达到最大迭代 超过 maxIterations 强制结束,返回当前状态 "已达到最大尝试次数"
工具连续失败 可通过中间件自定义 抛出错误或降级处理 "工具不可用,无法完成任务"

(3)监控迭代次数

typescript 复制代码
import { createMiddleware } from "langchain";

const iterationTracker = createMiddleware({
  name: "IterationTracker",
  beforeModel: async (request) => {
    // 统计已执行的轮数
    const toolMessages = request.messages.filter(
      m => m.role === "tool"
    );
    console.log(`当前迭代次数:${toolMessages.length}`);
    return request;
  },
});

三、LangGraph 核心概念

理解 LangGraph 的核心抽象,帮助你在需要时下探到底层进行精细控制。

🔍 深入探讨 : 完整的LangGraph教程请阅读专栏《深入浅出LangGraph》

1、四大核心概念

mindmap root((LangGraph 核心)) State 状态 定义图的数据结构 在节点间流动 Annotation 定义 Reducer Node 节点 图的执行单元 接收状态 返回状态更新 Edge 边 普通边 固定路由 条件边 动态路由 连接节点 Graph 图 StateGraph 定义图结构 compile 编译为 Runnable 支持 checkpointer 持久化

2、概念详解

State(状态)

状态是图的数据结构,在节点间流动。

typescript 复制代码
// 简单状态示例
const MyState = Annotation.Root({
  messages: Annotation<BaseMessage[]>({
    reducer: (current, next) => [...current, ...next],
    default: () => [],
  }),
  counter: Annotation<number>({
    reducer: (_, next) => next,
    default: () => 0,
  }),
});

关键点:

  • reducer:定义如何合并新旧状态
  • default:提供初始值
  • 状态是不可变的,每次更新产生新状态

Node(节点)

节点是图的执行单元,接收状态,返回状态更新。

typescript 复制代码
async function myNode(state: typeof MyState.State) {
  // 读取当前状态
  const currentCount = state.counter;
  
  // 执行业务逻辑
  const newCount = currentCount + 1;
  
  // 返回状态更新(不是完整状态)
  return {
    counter: newCount,
    messages: [new AIMessage(`计数:${newCount}`)],
  };
}

返回值说明:

  • 返回的是状态更新,不是完整状态
  • LangGraph 会自动合并到当前状态
  • 只返回需要改变的字段

Edge(边)

边连接节点,分为两种类型:

普通边(固定路由):

typescript 复制代码
workflow.addEdge("nodeA", "nodeB");
// nodeA 执行完后,总是转到 nodeB

条件边(动态路由):

typescript 复制代码
workflow.addConditionalEdges("agent", shouldContinue, {
  tools: "tools",
  __end__: END,
});

function shouldContinue(state) {
  if (hasToolCalls(state)) {
    return "tools";  // 转到 tools 节点
  }
  return END;         // 结束
}

Graph(图)

图是所有节点和边的集合。

typescript 复制代码
const workflow = new StateGraph(MyState)
  .addNode("nodeA", myNodeA)
  .addNode("nodeB", myNodeB)
  .addEdge(START, "nodeA")
  .addEdge("nodeA", "nodeB")
  .addEdge("nodeB", END);

const app = workflow.compile();  // 编译为可执行对象

3、手动构建等效的 Agent 图

下面这段代码与 createAgent() 在功能上等效,但直接使用 LangGraph API。

完整实现

typescript 复制代码
import { 
  StateGraph, 
  MessagesAnnotation, 
  END, 
  START 
} from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
import { ToolNode } from "@langchain/langgraph/prebuilt";
import { AIMessage } from "@langchain/core/messages";

// 第一步:准备模型和工具
const model = new ChatOpenAI({ model: "gpt-4o" });
const tools = [searchTool, calculatorTool];

// 绑定工具到模型
const modelWithTools = model.bindTools(tools);

// 第二步:定义 agent 节点
async function agentNode(state: typeof MessagesAnnotation.State) {
  // 调用绑定了工具的模型
  const response = await modelWithTools.invoke(state.messages);
  
  // 返回状态更新
  return { messages: [response] };
}

// 第三步:定义条件判断函数
function shouldContinue(state: typeof MessagesAnnotation.State) {
  const lastMessage = state.messages.at(-1) as AIMessage;
  
  if (lastMessage.tool_calls?.length) {
    return "tools";   // 有工具调用,转到 tools 节点
  }
  return END;          // 没有工具调用,结束
}

// 第四步:构建图
const workflow = new StateGraph(MessagesAnnotation)
  .addNode("agent", agentNode)                    // agent 节点
  .addNode("tools", new ToolNode(tools))          // tools 节点
  .addEdge(START, "agent")                        // 入口 → agent
  .addConditionalEdges("agent", shouldContinue)   // agent → tools 或 END
  .addEdge("tools", "agent");                     // tools → agent

// 第五步:编译为可执行对象
const app = workflow.compile();

// 第六步:执行
const result = await app.invoke({
  messages: [{ role: "user", content: "2 + 3 等于多少?" }],
});

代码分步解读:

  1. 第 11-14 行:准备模型和工具

    • 创建 ChatOpenAI 实例
    • 定义工具列表
    • 使用 bindTools() 将工具绑定到模型
  2. 第 17-22 行:定义 agent 节点

    • 调用模型,传入所有历史消息
    • 返回模型响应(追加到消息列表)
  3. 第 25-32 行:定义条件判断

    • 检查最后一条消息是否有工具调用
    • 返回下一个节点的名称
  4. 第 35-40 行:构建图结构

    • 添加两个节点:agent 和 tools
    • 定义边的连接关系
  5. 第 43 行:编译

    • 将图结构编译为可执行的 Runnable
  6. 第 46-48 行:执行

    • 传入初始消息
    • 获取最终结果

4、什么时候需要直接用 LangGraph?

大多数时候,createAgent() 就够用了。以下场景需要用 LangGraph:

场景 为什么需要 LangGraph 示例
多 Agent 协作 需要定义多个 Agent 节点之间的路由逻辑 研究员 Agent → 作家 Agent → 编辑 Agent
复杂条件分支 需要根据业务逻辑动态决定下一步 根据用户等级走不同流程
Human-in-the-loop 需要在特定节点暂停等待人工确认 删除操作前需要确认
子图(Subgraph) 把复杂流程模块化为可复用的子图 订单处理子图、退款子图
自定义状态流转 默认的 Agent 循环无法满足需求 需要额外的状态字段和流转逻辑

决策建议:

flowchart TD A["开始构建 Agent"] --> B{"是否需要
自定义流程?"} B -- 否 --> C["使用 createAgent()"] B -- 是 --> D{"是否涉及
多 Agent 协作?"} D -- 否 --> E["使用 LangGraph
单图"] D -- 是 --> F["使用 LangGraph
多图/子图"] C --> G["快速开发"] E --> H["灵活控制"] F --> I["复杂编排"] style C fill:#f6ffed,stroke:#52c41a,stroke-width:3px style E fill:#fff7e6,stroke:#fa8c16,stroke-width:3px style F fill:#e8f4fd,stroke:#1890ff,stroke-width:3px

四、中间件系统

中间件(Middleware) 是 LangChain.js v1.x 的重要新特性,允许你在 Agent 执行的不同阶段注入自定义逻辑,而不需要修改核心代码。

1、中间件的执行时机

flowchart LR Input["用户输入"] --> BM subgraph MiddlewarePipeline["中间件管道"] BM["beforeModel
模型调用前"] --> Model["LLM 调用"] Model --> AM["afterModel
模型调用后"] end AM --> TW subgraph ToolExecution["工具执行"] TW["wrapToolCall
工具调用包装"] end TW --> Output["返回结果"] style BM fill:#e8f4fd,stroke:#1890ff style AM fill:#f6ffed,stroke:#52c41a style TW fill:#fff0f6,stroke:#eb2f96

2、四种中间件钩子

钩子总览

钩子 执行时机 用途 可修改内容
beforeModel LLM 调用前 日志、审核、限流 请求参数
afterModel LLM 调用后 成本追踪、后处理 响应结果
wrapToolCall 工具调用时 错误处理、性能监控 工具执行
wrapModelCall 完整模型调用 重试、缓存 整个调用过程

完整示例

typescript 复制代码
import { createMiddleware } from "langchain";

const loggingMiddleware = createMiddleware({
  name: "Logger",

  // 钩子 1:在 LLM 调用之前执行
  beforeModel: async (request) => {
    console.log(`[LLM] 调用模型,消息数量:${request.messages.length}`);
    
    // 可以修改请求
    // request.messages.push(new SystemMessage("额外提示"));
    
    return request;  // 返回(可修改的)request
  },

  // 钩子 2:在 LLM 调用之后执行
  afterModel: async (response) => {
    console.log(`[LLM] 模型响应,Token 用量:${response.usage?.total_tokens}`);
    
    // 可以修改响应
    // response.message.content += "\n\n[由助手生成]";
    
    return response;
  },

  // 钩子 3:包装工具调用
  wrapToolCall: async (request, handler) => {
    const start = Date.now();
    console.log(`[Tool] 调用工具:${request.toolCall.name}`);
    
    try {
      // 执行原始的工具调用
      const result = await handler(request);
      
      const duration = Date.now() - start;
      console.log(`[Tool] 工具执行耗时:${duration}ms`);
      
      return result;
    } catch (error) {
      console.error(`[Tool] 工具调用失败:`, error);
      throw error;
    }
  },

  // 钩子 4:包装完整的模型调用
  wrapModelCall: async (request, handler) => {
    console.log("[Model] 开始模型调用");
    
    try {
      const result = await handler(request);
      console.log("[Model] 模型调用成功");
      return result;
    } catch (error) {
      console.error("[Model] 模型调用失败:", error);
      throw error;
    }
  },
});

// 注册中间件
const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  middleware: [loggingMiddleware],
});

3、常用中间件模式

模式 1:成本控制

typescript 复制代码
import { createMiddleware } from "langchain";

const costTracker = createMiddleware({
  name: "CostTracker",
  
  afterModel: async (response) => {
    // 计算成本
    const cost = calculateCost(response.usage, "gpt-4o");
    
    // 记录到数据库
    await saveCostRecord({ 
      cost, 
      timestamp: new Date(),
      userId: getCurrentUserId()
    });
    
    // 检查预算
    if (exceedsBudget(cost)) {
      throw new Error("超出预算限制");
    }
    
    return response;
  },
});

function calculateCost(usage: any, model: string): number {
  const pricing = {
    "gpt-4o": { input: 0.005, output: 0.015 },  // 每 1K tokens
  };
  
  const price = pricing[model];
  return (
    (usage.prompt_tokens / 1000) * price.input +
    (usage.completion_tokens / 1000) * price.output
  );
}

模式 2:内容审核

typescript 复制代码
const contentFilter = createMiddleware({
  name: "ContentFilter",
  
  beforeModel: async (request) => {
    // 获取最新的用户消息
    const lastUserMessage = request.messages.findLast(
      m => m.role === "user"
    );
    
    if (lastUserMessage && containsViolation(lastUserMessage.content)) {
      throw new Error("内容违规,请遵守使用条款");
    }
    
    return request;
  },
});

function containsViolation(content: string): boolean {
  // 简单的关键词过滤(生产环境用专业的审核服务)
  const violations = ["暴力", "色情", "违法"];
  return violations.some(word => content.includes(word));
}

模式 3:限流保护

typescript 复制代码
import rateLimit from "express-rate-limit";

const rateLimiter = createMiddleware({
  name: "RateLimiter",
  
  beforeModel: async (request) => {
    const userId = getCurrentUserId();
    
    // 检查是否超限
    await rateLimitCheck(userId);
    
    return request;
  },
});

async function rateLimitCheck(userId: string) {
  // 实现限流逻辑
  // 例如:每分钟最多 10 次调用
}

模式 4:响应缓存

typescript 复制代码
const responseCache = createMiddleware({
  name: "ResponseCache",
  
  wrapModelCall: async (request, handler) => {
    // 生成缓存键
    const cacheKey = generateCacheKey(request.messages);
    
    // 检查缓存
    const cached = await cache.get(cacheKey);
    if (cached) {
      console.log("[Cache] 命中缓存");
      return cached;
    }
    
    // 执行调用
    const result = await handler(request);
    
    // 存入缓存(有效期 1 小时)
    await cache.set(cacheKey, result, { ttl: 3600 });
    
    return result;
  },
});

4、中间件的组合使用

可以同时注册多个中间件,它们会按顺序执行:

typescript 复制代码
const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [],
  middleware: [
    contentFilter,     // 1. 内容审核
    rateLimiter,       // 2. 限流检查
    loggingMiddleware, // 3. 日志记录
    costTracker,       // 4. 成本追踪
    responseCache,     // 5. 响应缓存
  ],
});

执行顺序:

  1. 内容审核(阻止违规请求)
  2. 限流检查(防止滥用)
  3. 日志记录(记录请求)
  4. 缓存检查(可能直接返回)
  5. 成本追踪(监控费用)

五、Human-in-the-loop:在关键节点引入人工确认

有些操作------比如删除数据、发送通知、执行付款------需要在执行前得到人工确认。LangGraph 的中断(Interrupt) 机制支持在任意节点暂停 Agent,等待外部输入。

1、为什么需要 Human-in-the-loop?

风险场景举例:

操作 风险 后果
删除数据 误删重要数据 数据丢失,无法恢复
发送邮件 发送给错误的收件人 信息泄露
执行付款 金额错误或重复支付 财务损失
部署代码 部署到有 Bug 的版本 服务中断

解决方案: 在关键操作前暂停,等待人工确认。

2、基本实现

第一步:定义需要确认的工具

typescript 复制代码
import { interrupt, tool } from "langchain";
import { z } from "zod";

const deleteData = tool(
  async ({ recordId }) => {
    // 发起中断,等待人工确认
    const confirmed = await interrupt({
      question: `确认删除记录 ${recordId}?此操作不可撤销。`,
      type: "confirm",
    });

    if (!confirmed) {
      return "操作已取消";
    }

    // 执行删除
    await db.delete(recordId);
    return `记录 ${recordId} 已删除`;
  },
  {
    name: "delete_data",
    description: "删除指定记录(需要人工确认)",
    schema: z.object({ 
      recordId: z.string().describe("要删除的记录 ID") 
    }),
  }
);

代码解读:

  • 第 6-9 行:调用 interrupt() 发起中断
    • question:向用户展示的确认问题
    • type:中断类型(confirm、input 等)
  • 第 11-13 行:根据用户选择决定是否执行
  • 第 16 行:只有确认后才会执行删除操作

第二步:创建 Agent

typescript 复制代码
import { createAgent } from "langchain";
import { MemorySaver } from "@langchain/langgraph";

const agent = createAgent({
  model: "openai:gpt-4o",
  tools: [deleteData],
  checkpointer: new MemorySaver(),  // ⚠️ Human-in-the-loop 需要 checkpointer
});

⚠️ 重要提示

  • Human-in-the-loop 必须 配置 checkpointer
  • 因为中断后需要恢复状态,checkpointer 负责保存和恢复

第三步:执行并处理中断

typescript 复制代码
const config = { 
  configurable: { thread_id: "session-001" } 
};

// 第一次调用:Agent 会在需要确认时暂停
const result1 = await agent.invoke(
  { messages: [{ role: "user", content: "删除 ID 为 123 的记录" }] },
  config
);

// 检查是否有中断
if (result1.interrupt) {
  console.log(result1.interrupt.question);
  // 输出:"确认删除记录 123?此操作不可撤销。"
  
  // 向用户展示确认请求,获取用户选择
  const userConfirmed = await askUserForConfirmation(
    result1.interrupt.question
  );
  
  // 第二次调用:传入用户的确认结果
  const result2 = await agent.invoke(
    { messages: [] },  // 不需要新消息
    {
      ...config,
      // 传入用户的确认结果
      interrupt: { answer: userConfirmed },  // true 或 false
    }
  );
  
  console.log(result2.messages.at(-1)?.content);
  // 如果确认:输出 "记录 123 已删除"
  // 如果取消:输出 "操作已取消"
}

执行流程:

sequenceDiagram participant U as 用户 participant A as Agent participant T as 删除工具 participant DB as 数据库 U->>A: "删除记录 123" A->>T: 调用 delete_data(123) T->>A: interrupt("确认删除?") A-->>U: 显示确认对话框 U->>A: 点击"确认" A->>T: resume(answer=true) T->>DB: 执行删除 DB-->>T: 删除成功 T-->>A: "记录 123 已删除" A-->>U: 返回结果

3、中断的类型

类型 1:确认型(confirm)

typescript 复制代码
const confirmed = await interrupt({
  question: "确认执行此操作?",
  type: "confirm",
});
// 返回:true 或 false

类型 2:输入型(input)

typescript 复制代码
const userInput = await interrupt({
  question: "请输入验证码:",
  type: "input",
});
// 返回:用户输入的字符串

类型 3:选择型(select)

typescript 复制代码
const choice = await interrupt({
  question: "请选择操作:",
  type: "select",
  options: ["继续", "暂停", "取消"],
});
// 返回:用户选择的选项

4、实际应用:审批工作流

typescript 复制代码
const submitForApproval = tool(
  async ({ documentId, approverId }) => {
    // 发起审批中断
    const approval = await interrupt({
      question: `文档 ${documentId} 待审批,请决定:`,
      type: "select",
      options: ["批准", "拒绝", "需要修改"],
    });

    // 记录审批结果
    await db.updateDocument(documentId, {
      status: approval,
      approvedBy: approverId,
      approvedAt: new Date(),
    });

    return `文档 ${documentId} 已${approval}`;
  },
  {
    name: "submit_for_approval",
    description: "提交文档进行审批",
    schema: z.object({
      documentId: z.string(),
      approverId: z.string(),
    }),
  }
);

六、本章小结

这一章深入了 Agent 的内部机制,从黑盒变成了白盒。

📝 核心知识点回顾

知识点 关键要点 应用场景
createAgent() 本质 LangGraph 上的标准化 Agent 图 理解底层机制
ReAct 模式 推理与行动交替执行的循环 需要多步推理的任务
LangGraph 核心 State / Node / Edge / Graph 自定义复杂流程
中间件系统 在执行各阶段注入自定义逻辑 日志、成本控制、限流
Human-in-the-loop 在关键操作前暂停等待人工确认 高风险操作

🎯 动手练习

尝试完成以下练习,巩固所学知识:

练习 1:追踪 ReAct 执行过程 创建一个使用搜索工具的 Agent,执行一个需要多步推理的任务:

  • 启用详细日志,观察每一轮的 Thought、Action、Observation
  • 统计总共执行了多少轮
  • 分析是否可以优化 Prompt 减少轮数

练习 2:手动构建 Agent 图 不使用 createAgent(),直接用 LangGraph API 构建一个等效的 Agent:

  • 定义 agent 节点和 tools 节点
  • 添加条件边
  • 测试功能是否与 createAgent() 一致

练习 3:编写成本控制中间件 实现一个成本追踪中间件:

  • 记录每次调用的 Token 用量和费用
  • 累计每日总成本
  • 当超过预算时抛出错误
  • 将成本数据保存到文件

练习 4:实现审批工作流 构建一个简单的文档审批系统:

  • 用户上传文档
  • Agent 分析文档内容
  • 调用 submit_for_approval 工具
  • 等待人工审批(批准/拒绝/修改)
  • 根据审批结果执行相应操作

📚 延伸阅读


下一章:《第八章 ------ RAG 检索增强生成》

相关推荐
Empty-Filled1 小时前
Claude Gateway 排查教程
网络·数据库·人工智能
暗夜猎手-大魔王1 小时前
转载--AI Agent 架构设计:单 Agent vs 多 Agent(OpenClaw、Claude Code、Hermes Agent 对比)
人工智能
changshuaihua0011 小时前
扣子开发指南
javascript·人工智能
DogDaoDao1 小时前
【GitHub】OpenClaw:开源个人AI助手的新标杆
人工智能·深度学习·开源·大模型·github·ai编程·opeclaw
byte轻骑兵1 小时前
【AVRCP】规范精讲[10]:链路管理器LM互操作规则与场景落地
人工智能·音视频·蓝牙·avrcp·音视频控制
70asunflower1 小时前
AI推理时代的逻辑重构
人工智能·重构
海兰1 小时前
【开篇】Spring AI、OpenClaw 和Hermes
java·人工智能·spring·spring ai
带娃的IT创业者1 小时前
Zig 项目反AI贡献政策:一场关于开源灵魂的保卫战
人工智能·开源·ai编程·代码质量·github copilot·zig
love530love1 小时前
如何在 Google Chrome 中强制开启 Gemini AI 侧边栏(完整图文教程)
前端·人工智能·chrome·windows