摘要: 在 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) 。
下一步建议:
- 扩展工具箱: 尝试加入
write_file(写文件)和execute_command(执行命令)工具。 - 引入记忆: 使用
ConversationBufferMemory让 AI 记住上下文。 - 接入 RAG: 让 AI 能基于你的私有文档回答问题。
代码即智能,工具即力量。 现在,你已经拥有了构建属于自己的 AI 助手的钥匙。