解构 LangChain Tool Calling:从 Schema 定义到 Agent 执行循环的深度解析

摘要: 在 2026 年的今天,仅仅会调用 model.invoke 已经无法满足复杂的业务需求。本文将带你从零开始,通过对比"基础大模型调用"与"工具增强型智能体"的代码实现,深入剖析 AI Agent 的核心架构(LLM + Tools + Loop)。我们将手把手教你如何让 AI 拥抱"手脚",实现真正的自主行动。


🧠 引言:Prompt Engineering 已死,Agentic Engineering 当立

如果你还在通过简单的 console.log(await model.invoke("你好")) 来使用 AI,那么你可能正在浪费大模型的潜力。

回顾我们对 AI 应用的认知,已经发生了翻天覆地的变化:

  • 过去(LLM Era): 我们认为 AI 是一个超级大脑,通过精心设计的 Prompt(提示词)来获取答案。
  • 现在(Agent Era): 我们意识到 AI 应该是一个智能体(Agent) 。它不仅有大脑(LLM),还有记忆(Memory)、知识库(RAG)和手脚(Tools)。

正如我们在核心理念中所总结的:

AI Agent = LLM(思考) + Memory(记忆) + Tools(行动) + RAG(知识)

今天,我们将重点攻克 Tools(工具)Loop(循环) ,利用 Node.js 和 LangChain,打造一个能读取文件、分析代码的"Cursor"最小雏形。


🆚第一部分:冰与火之歌------基础模型 vs 智能体

为了让你直观感受两者的区别,我们准备了两段核心代码进行对比。

1. 基础版:单向的"传声筒"

这是最原始的 LLM 调用方式,对应我们代码库中的基础调用逻辑。

arduino 复制代码
import { ChatOpenAI } from '@langchain/openai';
import dotenv from 'dotenv';
dotenv.config();

// 1. 初始化模型
const model = new ChatOpenAI({
    modelName: process.env.MODEL_NAME,
    apiKey: process.env.OPENAI_API_KEY,
    configuration: {
        baseURL: process.env.OPENAI_API_BASE_URL
    }
});

// 2. 单次对话
const response = await model.invoke("介绍下高德地图");
console.log(response.content);

痛点分析:

这段代码只能进行单次、无状态的交互。它像一个被蒙上眼睛的天才,虽然知识渊博,但无法感知外部世界,也无法执行任何操作。如果让它写代码,它只能凭空想象,无法读取现有文件。

2. 进阶版:拥有"手脚"的智能体

这是我们今天的主角,一个具备文件读取能力的 Agent。

php 复制代码
// ... 导入必要的模块 (LangChain, fs, zod) ...

// 1. 定义工具 (Tools) - 给 AI 装上手脚
const readFileTool = tool(
  async ({ path }) => {
    const content = await fs.readFile(path, 'utf-8');
    return content; // 返回文件内容
  },
  {
    name: 'read_file',
    description: '当用户需要读取文件内容时调用此工具',
    schema: z.object({ path: z.string().describe('文件路径') })
  }
);

⚙️ 第二部分:核心架构解密------Agent 的"心跳"

让 AI 变得智能的关键,不在于工具本身,而在于 Agent Loop(智能体循环) 。这是 AI 思考、行动、观察的闭环。

1. 绑定工具

首先,我们将工具交给模型,让它知道"我能做什么"。

ini 复制代码
const modelWithTools = model.bindTools([readFileTool]);

2. 构建记忆(Message History)

Agent 需要记住刚才发生了什么,所以我们维护了一个 messages 数组。

arduino 复制代码
const messages = [
  new SystemMessage("你是一个代码助手..."), // 角色设定
  new HumanMessage('请读取当前文件并解释代码') // 用户指令
];

3. 核心循环 (The Loop)

这是最精彩的部分,也是 while 循环存在的意义。

javascript 复制代码
let response = await modelWithTools.invoke(messages);

// 【关键】Agent Loop:只要 AI 想调用工具,就一直循环
while (response.tool_calls && response.tool_calls.length > 0) {
  console.log(`[检测到工具调用]`);
  
  // Step 1: 并发执行工具 (Promise.all 提升效率)
  const toolResults = await Promise.all(
    response.tool_calls.map(async (toolCall) => {
      const tool = findToolByName(toolCall.name);
      return await tool.invoke(toolCall.args); // 执行工具
    })
  );

  // Step 2: 将工具执行结果(Observation)塞回给 AI
  response.tool_calls.forEach((toolCall, index) => {
    messages.push(
      new ToolMessage({
        content: toolResults[index], // 工具返回的数据
        tool_call_id: toolCall.id // 关联 ID
      })
    );
  });

  // Step 3: 让 AI 基于新信息进行下一轮思考
  response = await modelWithTools.invoke(messages);
}

// 循环结束,输出最终结果
console.log(response.content);

💡 第三部分:深度思考------为什么这样设计?

这种架构设计解决了传统 AI 开发的三大痛点:

1. 为什么用 while 循环?

大模型本质上是"短视"的,一次只能做一个决定。

  • 第一轮: 你让它解释代码,它想:"我得先读文件" -> 调用 read_file
  • 第二轮: 你把文件内容给它,它想:"哦,原来是这样" -> 生成解释。
    如果没有 while 循环,AI 就会在第一步卡住,无法完成任务。

2. 为什么用 Promise.all()

如果 AI 同时需要读取 10 个文件,你是让它一个一个读(串行),还是同时读(并行)?
Promise.all() 让 Agent 能够并发执行多个工具,这是实现高性能 Agent 的关键。

3. 从 Cursor 到 Manus

  • Cursor 的本质: 就是 LLM + File System Tools。它通过工具读写文件,通过循环不断修正代码。
  • Manus 的本质:LLM + Web Browsing Tools + Planning。它能拆解复杂任务,通过多步工具调用完成上网、搜索、下单等操作。

🚀 结语:拥抱 Agentic Engineering

2026 年,AI 开发的范式已经从 Prompt Engineering(提示词工程) 转向了 Agentic Engineering(智能体工程)

作为全栈开发者,我们不再仅仅是调用 API,而是构建 AI 的大脑(LLM)记忆(Memory)手脚(Tools)

下一步建议:

  1. 扩展工具箱: 尝试加入 write_file(写文件)和 execute_command(执行命令)工具。
  2. 引入记忆: 使用 ConversationBufferMemory 让 AI 记住上下文。
  3. 接入 RAG: 让 AI 能基于你的私有文档回答问题。

代码即智能,工具即力量。 现在,你已经拥有了构建属于自己的 AI 助手的钥匙。

相关推荐
YukiMori231 小时前
深入理解 JavaScript 执行机制:事件循环、执行栈、同步与异步彻底搞懂
前端·javascript·面试
卢叁2 小时前
Flutter之路由监听器
前端·flutter
三翼鸟数字化技术团队2 小时前
2025前端技术趋势:从智能到沉浸的新时代
前端·ai编程
恋猫de小郭2 小时前
Android 17 有什么需要适配的?2026 Android 禁止侧载又是什么?
android·前端·flutter
Never_Satisfied2 小时前
在HTML & CSS中,如何计算CSS特异性
前端·css·html
滕青山2 小时前
网页源代码查看在线工具 核心JS实现
前端·javascript·vue.js
www_stdio2 小时前
项目基础准备之Zustand:轻量级 React 状态管理的优雅之选
前端·react.js·typescript
躲在云朵里`2 小时前
同一账号在同一客户端类型只能登录一次
前端·spring·bootstrap
敲敲了个代码2 小时前
构建工具的第三次革命:从 Rollup 到 Rust Bundler,我是如何设计 robuild 的
开发语言·前端·javascript·后端·rust