手把手教你从0到1用 gpt-5.6-sol 搭建一个 AI Agent(智能体)—— Node.js 版
大家好,我是 JavaPub。
上一篇我们使用 Python,从 0 开始手写了一个 AI Agent。
这次换一个很多 Web 开发者更加熟悉的技术栈:
Node.js
+
gpt-5.6-sol
+
OpenAI Compatible API
+
Tool Calling
我们不使用 LangChain,不使用 LangGraph,也不引入一堆 Agent Framework。
直接手写一个最小可用的 AI Agent。
本文使用的 API 地址:
https://api.chongplus.plus
模型:
gpt-5.6-sol
最终,我们要实现这样的效果:
你:
帮我计算 12345 * 6789,然后把计算结果保存成笔记。
Agent:
我需要先计算。
[Agent] 调用工具:calculator
[Agent] 参数:{"expression":"12345 * 6789"}
[Tool] 返回:
83810205
Agent:
接下来需要保存计算结果。
[Agent] 调用工具:save_note
[Agent] 参数:
{"content":"12345 × 6789 = 83810205"}
[Tool] 返回:
笔记保存成功
Agent:
计算完成,12345 × 6789 = 83810205,并且已经保存到笔记。
注意:
这里并不是我们在 JavaScript 里面提前写好了:
calculator();
saveNote();
而是:
gpt-5.6-sol 自己判断应该调用什么工具、传什么参数,以及下一步应该继续干什么。
这就是今天最核心的内容。
一、什么才算 AI Agent?
我们先把概念说清楚。
普通的大模型应用一般是:
用户
↓
LLM
↓
回答
例如:
用户:
12345 × 6789 是多少?
模型直接返回一个答案。
而 Agent 的运行过程更接近:
用户提出目标
↓
gpt-5.6-sol
↓
判断下一步应该做什么
↓
调用工具
↓
获得工具返回值
↓
继续交给 gpt-5.6-sol
↓
再次判断
↓
调用其他工具
↓
最终完成任务
所以我们可以先记住一个公式:
AI Agent
=
LLM
+
Prompt
+
Tools
+
Memory
+
Agent Loop
其中:
LLM
负责思考和决策
Prompt
负责告诉 Agent 身份和规则
Tools
负责真正执行操作
Memory
负责保存上下文
Agent Loop
负责让 Agent 连续执行多个步骤
今天我们就把这五个部分全部写出来。
二、准备 Node.js 环境
推荐:
Node.js 18+
查看版本:
node -v
例如:
v22.18.0
创建项目:
mkdir node-agent
cd node-agent
初始化:
npm init -y
安装 OpenAI SDK:
npm install openai
项目结构非常简单:
node-agent/
├── package.json
└── agent.js
三、配置 ES Module
为了直接使用:
import OpenAI from "openai";
在:
package.json
增加:
{
"type": "module"
}
完整一点可以是:
{
"name": "node-agent",
"version": "1.0.0",
"type": "module",
"main": "agent.js",
"scripts": {
"start": "node agent.js"
},
"dependencies": {
"openai": "^5.0.0"
}
}
之后就可以运行:
npm start
四、连接 gpt-5.6-sol
首先创建:
agent.js
写入:
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "sk-xxxxxxxxxxxxxxxx",
baseURL: "https://api.chongplus.plus/v1",
});
const response = await client.chat.completions.create({
model: "gpt-5.6-sol",
messages: [
{
role: "user",
content: "你好,请介绍一下你自己。",
},
],
});
console.log(response.choices[0].message.content);
运行:
node agent.js
可能返回:
你好!我是一个 AI 助手,可以帮助你进行编程、分析、写作、信息整理以及完成各种任务。
到这里其实只是最普通的:
ChatBot
还不是 Agent。
因为模型目前只能:
输入文字
↓
生成文字
还无法真正执行操作。
五、System Prompt
接下来,我们先给 Agent 定义身份。
例如:
const SYSTEM_PROMPT = `
你是一个 AI Agent。
你的任务是帮助用户完成任务。
你可以根据实际情况调用提供给你的工具。
规则:
1. 如果能够直接回答,则直接回答。
2. 如果任务需要使用工具,则调用对应工具。
3. 不允许伪造工具执行结果。
4. 工具执行完成以后,根据返回结果继续判断下一步。
5. 一个任务允许连续调用多个工具。
6. 当任务真正完成以后,再向用户返回最终答案。
`;
请求:
const messages = [
{
role: "system",
content: SYSTEM_PROMPT,
},
{
role: "user",
content: "你好",
},
];
但是只有 Prompt 还不够。
虽然我们告诉模型:
你可以使用工具
但模型根本不知道:
有哪些工具?
所以接下来就要进入 AI Agent 最核心的一部分:
Tool Calling
六、什么是 Tool Calling?
Tool Calling,也经常被叫做:
Function Calling
你可以简单理解为:
我们把 JavaScript 函数的“使用说明书”告诉 gpt-5.6-sol,然后让模型自己决定什么时候需要调用。
例如我们有一个函数:
function calculator(expression) {
// ...
}
它可以计算:
123 * 456
但是模型本身并不会直接运行这个 JavaScript 函数。
我们需要告诉模型:
这里有一个工具:
名称:
calculator
作用:
执行数学计算
参数:
expression
当用户说:
帮我算一下 123 * 456
gpt-5.6-sol 可能不会直接回答。
而是返回类似:
{
"name": "calculator",
"arguments": {
"expression": "123 * 456"
}
}
意思就是:
AI:
我认为这里应该调用 calculator。
参数是:
123 * 456
然后真正执行 JavaScript 函数的是:
我们的 Node.js 程序
所以:
LLM 决定做什么
Node.js 负责真正执行
整个流程是:
用户
│
▼
┌──────────────┐
│ gpt-5.6-sol │
└──────┬───────┘
│
Tool Call
│
▼
┌──────────────┐
│ Node.js │
│ Tools │
└──────┬───────┘
│
Tool Result
│
▼
┌──────────────┐
│ gpt-5.6-sol │
└──────┬───────┘
│
▼
最终回答
理解这个流程之后,Agent 基本就理解一半了。
七、第一个工具:Calculator
先实现一个简单计算器。
这里为了方便演示,我们写:
function calculator(expression) {
try {
const result = Function(
`"use strict"; return (${expression})`
)();
return String(result);
} catch (error) {
return `计算失败:${error.message}`;
}
}
测试:
console.log(
calculator("12345 * 6789")
);
输出:
83810205
注意:
这种动态执行表达式的方式主要用于教程演示。
生产环境不要直接让不可信用户输入进入 Function() 或类似动态执行环境。
后面我们再讲安全问题。
八、告诉 gpt-5.6-sol 有这个工具
JavaScript 函数写好了,但模型现在还不知道。
因此需要定义:
const tools = [
{
type: "function",
function: {
name: "calculator",
description:
"执行数学计算。当用户需要进行数学运算时调用。",
parameters: {
type: "object",
properties: {
expression: {
type: "string",
description:
"需要执行的数学表达式,例如:123 * 456",
},
},
required: ["expression"],
},
},
},
];
这一段实际上就是:
Tool Schema
你可以把它理解成:
写给大模型看的 API 文档。
它告诉模型:
工具叫什么?
这个工具是干什么的?
有哪些参数?
参数是什么类型?
哪些参数必须传?
九、让模型自己决定是否调用 Calculator
现在写:
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "sk-xxxxxxxxxxxxxxxx",
baseURL: "https://api.chongplus.plus/v1",
});
const tools = [
{
type: "function",
function: {
name: "calculator",
description: "执行数学计算。",
parameters: {
type: "object",
properties: {
expression: {
type: "string",
description: "数学表达式",
},
},
required: ["expression"],
},
},
},
];
const messages = [
{
role: "system",
content:
"你是一个 AI Agent,可以根据任务需要调用工具。",
},
{
role: "user",
content:
"帮我计算 12345 * 6789",
},
];
const response =
await client.chat.completions.create({
model: "gpt-5.6-sol",
messages,
tools,
tool_choice: "auto",
});
console.dir(
response.choices[0].message,
{
depth: null,
}
);
这里最重要的是:
tool_choice: "auto"
意思就是:
让模型自己判断:
到底需不需要调用工具。
运行之后,可能返回:
{
role: 'assistant',
content: null,
tool_calls: [
{
id: 'call_q8F7G23',
type: 'function',
function: {
name: 'calculator',
arguments: '{"expression":"12345 * 6789"}'
}
}
]
}
重点看:
tool_calls
模型告诉我们的程序:
我要调用:
calculator
参数:
12345 * 6789
这时候:
content: null
也很正常。
因为模型现在不是准备直接回答用户。
而是在:
请求执行工具
十、解析 Tool Call
获得:
const message =
response.choices[0].message;
然后:
const toolCall =
message.tool_calls[0];
const functionName =
toolCall.function.name;
const args = JSON.parse(
toolCall.function.arguments
);
console.log(functionName);
console.log(args);
输出:
calculator
以及:
{
expression: '12345 * 6789'
}
然后真正执行:
const result = calculator(
args.expression
);
console.log(result);
返回:
83810205
现在 JavaScript 已经算出结果。
但是:
gpt-5.6-sol 并不知道结果是什么。
所以还要继续。
十一、把 Tool Result 返回给模型
首先把模型刚才的消息放进上下文:
messages.push(message);
然后加入:
messages.push({
role: "tool",
tool_call_id: toolCall.id,
content: result,
});
现在对话实际上变成:
System:
你是一个 AI Agent。
User:
帮我计算 12345 * 6789
Assistant:
我要调用 calculator。
Tool:
83810205
接着再次调用 gpt-5.6-sol:
const finalResponse =
await client.chat.completions.create({
model: "gpt-5.6-sol",
messages,
tools,
});
console.log(
finalResponse.choices[0].message.content
);
可能输出:
12345 × 6789 = 83810205。
到这里,第一个真正意义上的:
Node.js AI Agent
已经出现了。
十二、完整 Calculator Agent
我们整理一下代码。
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "sk-xxxxxxxxxxxxxxxx",
baseURL:
"https://api.chongplus.plus/v1",
});
function calculator(expression) {
try {
const result = Function(
`"use strict"; return (${expression})`
)();
return String(result);
} catch (error) {
return `计算失败:${error.message}`;
}
}
const tools = [
{
type: "function",
function: {
name: "calculator",
description:
"执行数学计算。",
parameters: {
type: "object",
properties: {
expression: {
type: "string",
description:
"需要执行的数学表达式",
},
},
required: [
"expression",
],
},
},
},
];
const messages = [
{
role: "system",
content:
"你是一个 AI Agent,可以调用工具帮助用户完成任务。",
},
{
role: "user",
content:
"帮我计算 12345 * 6789",
},
];
const response =
await client.chat.completions.create({
model: "gpt-5.6-sol",
messages,
tools,
tool_choice: "auto",
});
const message =
response.choices[0].message;
messages.push(message);
if (
message.tool_calls &&
message.tool_calls.length > 0
) {
for (
const toolCall
of message.tool_calls
) {
const name =
toolCall.function.name;
const args =
JSON.parse(
toolCall.function.arguments
);
let result;
if (
name === "calculator"
) {
result =
calculator(
args.expression
);
}
messages.push({
role: "tool",
tool_call_id:
toolCall.id,
content:
String(result),
});
}
const finalResponse =
await client.chat.completions.create({
model: "gpt-5.6-sol",
messages,
tools,
});
console.log(
finalResponse
.choices[0]
.message
.content
);
} else {
console.log(
message.content
);
}
运行:
node agent.js
返回:
12345 × 6789 = 83810205。
十三、再增加一个时间工具
Agent 真正有意思的地方在于:
一个 Agent 可以拥有很多工具。
我们再增加:
get_current_time
Node.js:
function getCurrentTime() {
return new Date()
.toLocaleString(
"zh-CN",
{
timeZone:
"Asia/Shanghai",
}
);
}
测试:
console.log(
getCurrentTime()
);
例如输出:
2026/8/14 12:38:21
Tool Schema:
{
type: "function",
function: {
name: "get_current_time",
description:
"获取当前北京时间。",
parameters: {
type: "object",
properties: {},
},
},
}
现在:
const tools = [
{
type: "function",
function: {
name: "calculator",
description:
"执行数学计算。",
parameters: {
type: "object",
properties: {
expression: {
type: "string",
},
},
required: [
"expression",
],
},
},
},
{
type: "function",
function: {
name:
"get_current_time",
description:
"获取当前北京时间。",
parameters: {
type: "object",
properties: {},
},
},
},
];
用户:
现在几点?
模型可能返回:
{
"tool_calls": [
{
"type": "function",
"function": {
"name": "get_current_time",
"arguments": "{}"
}
}
]
}
Node.js 执行:
2026/8/14 12:38:21
然后模型根据真正的 Tool Result 回答:
当前北京时间是 2026 年 8 月 14 日 12:38 左右。
十四、增加第三个工具:保存笔记
接下来增加:
save_note
这个工具已经开始让 Agent:
真正影响外部世界
首先:
import fs from "node:fs";
然后:
function saveNote(content) {
fs.appendFileSync(
"notes.txt",
content + "\n",
"utf8"
);
return "笔记保存成功";
}
例如执行:
console.log(
saveNote(
"今天开始学习 AI Agent"
)
);
返回:
笔记保存成功
同时生成:
notes.txt
内容:
今天开始学习 AI Agent
Tool Schema:
{
type: "function",
function: {
name: "save_note",
description:
"将指定内容保存到本地笔记。",
parameters: {
type: "object",
properties: {
content: {
type: "string",
description:
"需要保存的笔记内容",
},
},
required: [
"content",
],
},
},
}
现在 Agent 拥有三个工具:
calculator
get_current_time
save_note
十五、真正的 Agent 不能只调用一次工具
现在问题来了。
用户如果说:
帮我计算 12345 * 6789,然后把结果保存到笔记。
这其实不是一步。
而是:
第一步
calculator
拿到:
83810205
然后:
第二步
save_note
最后才:
回答用户
因此整个过程应该是:
User
↓
gpt-5.6-sol
↓
calculator
↓
Tool Result
↓
gpt-5.6-sol
↓
save_note
↓
Tool Result
↓
gpt-5.6-sol
↓
Final Answer
如果我们只写:
if (message.tool_calls) {
}
执行一次就结束。
那么严格来说还不够。
一个真正的 Agent 需要:
Agent Loop
十六、Agent Loop 是整个 Agent 最核心的东西
最核心的代码其实就是:
while (true) {
}
大概逻辑:
while (true) {
const response =
await callLLM();
if (
response.tool_calls
) {
await executeTools();
continue;
}
return response.content;
}
什么意思?
就是:
让 AI 思考
如果想调用工具
执行工具
把结果告诉 AI
再让 AI 思考
如果还要调用工具
继续执行
直到 AI 不再调用工具
这就是:
Agent Loop
十七、实现 Tool Executor
随着工具越来越多,我们显然不能把所有判断都写在主逻辑里面。
所以创建:
async function executeTool(
name,
args
) {
switch (name) {
case "calculator":
return calculator(
args.expression
);
case "get_current_time":
return getCurrentTime();
case "save_note":
return saveNote(
args.content
);
default:
return `未知工具:${name}`;
}
}
以后新增工具,只需要继续:
case "search_web":
case "read_file":
case "send_email":
即可。
十八、完整 Agent Loop
现在进入整篇文章最重要的代码。
async function runAgent(
userInput
) {
const messages = [
{
role: "system",
content: `
你是一个 AI Agent。
你可以调用工具帮助用户完成任务。
当前拥有:
1. calculator
数学计算。
2. get_current_time
获取当前北京时间。
3. save_note
保存笔记。
规则:
- 如果能够直接回答,则直接回答。
- 如果需要工具,必须调用工具。
- 不允许伪造工具执行结果。
- 一个任务允许调用多个工具。
- 每次工具执行结束以后,根据工具返回值继续完成任务。
- 当任务完全完成以后,再向用户返回最终答案。
`,
},
{
role: "user",
content:
userInput,
},
];
while (true) {
const response =
await client
.chat
.completions
.create({
model:
"gpt-5.6-sol",
messages,
tools,
tool_choice:
"auto",
});
const message =
response
.choices[0]
.message;
messages.push(
message
);
if (
!message.tool_calls ||
message.tool_calls.length === 0
) {
return message.content;
}
for (
const toolCall
of message.tool_calls
) {
const name =
toolCall
.function
.name;
const args =
JSON.parse(
toolCall
.function
.arguments
);
console.log(
`\n[Agent] 调用工具:${name}`
);
console.log(
`[Agent] 参数:${JSON.stringify(args)}`
);
const result =
await executeTool(
name,
args
);
console.log(
`[Tool] 返回:${result}`
);
messages.push({
role:
"tool",
tool_call_id:
toolCall.id,
content:
String(result),
});
}
}
}
这段代码其实已经是:
一个完整的最小 AI Agent Runtime
十九、第一次执行多步骤任务
调用:
const result =
await runAgent(
"帮我计算 12345 * 6789,然后把计算结果保存成笔记。"
);
console.log(
"\nAgent:"
);
console.log(result);
运行:
node agent.js
第一次:
[Agent] 调用工具:calculator
参数:
[Agent] 参数:
{"expression":"12345 * 6789"}
工具:
[Tool] 返回:
83810205
注意。
程序现在没有结束。
因为:
while (true)
会再次把:
Tool Result
交给 gpt-5.6-sol。
模型发现:
用户还要求保存结果。
所以继续:
[Agent] 调用工具:save_note
参数:
{
"content": "12345 × 6789 = 83810205"
}
工具执行:
[Tool] 返回:
笔记保存成功
再次进入:
Agent Loop
这一次模型发现:
任务已经全部完成。
所以不再产生:
tool_calls
而是正常返回:
Agent:
计算完成。
12345 × 6789 = 83810205
计算结果已经保存到笔记。
同时项目目录出现:
notes.txt
里面:
12345 × 6789 = 83810205
这时候,一个完整的:
Node.js + gpt-5.6-sol AI Agent
已经跑起来了。
二十、完整可运行代码
下面直接给出完整版本。
文件:
agent.js
代码:
import OpenAI from "openai";
import fs from "node:fs";
/**
* =========================
* 基础配置
* =========================
*/
const API_KEY =
"sk-xxxxxxxxxxxxxxxx";
const BASE_URL =
"https://api.chongplus.plus/v1";
const MODEL =
"gpt-5.6-sol";
const client =
new OpenAI({
apiKey: API_KEY,
baseURL:
BASE_URL,
});
/**
* =========================
* System Prompt
* =========================
*/
const SYSTEM_PROMPT = `
你是一个 AI Agent。
你的目标是帮助用户完成任务,而不只是回答问题。
你拥有以下工具:
1. calculator
用于数学计算。
2. get_current_time
用于获取当前北京时间。
3. save_note
用于保存笔记。
工作规则:
1. 首先理解用户真正想完成的任务。
2. 如果能够直接回答,则直接回答。
3. 如果需要使用工具,则调用对应工具。
4. 不允许伪造工具执行结果。
5. 一个任务允许连续调用多个工具。
6. 每次工具执行完成以后,需要根据结果继续判断下一步。
7. 当任务真正全部完成以后,再向用户返回最终结果。
`;
/**
* =========================
* Tool 1
* Calculator
* =========================
*/
function calculator(
expression
) {
try {
const result =
Function(
`"use strict"; return (${expression})`
)();
return String(
result
);
} catch (error) {
return (
`计算失败:${error.message}`
);
}
}
/**
* =========================
* Tool 2
* Current Time
* =========================
*/
function getCurrentTime() {
return new Date()
.toLocaleString(
"zh-CN",
{
timeZone:
"Asia/Shanghai",
hour12:
false,
}
);
}
/**
* =========================
* Tool 3
* Save Note
* =========================
*/
function saveNote(
content
) {
fs.appendFileSync(
"notes.txt",
content + "\n",
"utf8"
);
return (
"笔记保存成功"
);
}
/**
* =========================
* Tool Schema
* =========================
*/
const tools = [
{
type: "function",
function: {
name:
"calculator",
description:
"执行数学计算。当用户需要数学运算时使用。",
parameters: {
type:
"object",
properties: {
expression: {
type:
"string",
description:
"需要执行的数学表达式,例如 123 * 456",
},
},
required: [
"expression",
],
},
},
},
{
type: "function",
function: {
name:
"get_current_time",
description:
"获取当前北京时间。",
parameters: {
type:
"object",
properties: {},
},
},
},
{
type: "function",
function: {
name:
"save_note",
description:
"将指定内容保存到本地笔记文件。",
parameters: {
type:
"object",
properties: {
content: {
type:
"string",
description:
"需要保存的笔记内容",
},
},
required: [
"content",
],
},
},
},
];
/**
* =========================
* Tool Executor
* =========================
*/
async function executeTool(
name,
args
) {
switch (name) {
case "calculator":
return calculator(
args.expression
);
case "get_current_time":
return getCurrentTime();
case "save_note":
return saveNote(
args.content
);
default:
return (
`未知工具:${name}`
);
}
}
/**
* =========================
* Conversation Memory
* =========================
*/
const messages = [
{
role:
"system",
content:
SYSTEM_PROMPT,
},
];
/**
* =========================
* Agent
* =========================
*/
async function runAgent(
userInput
) {
messages.push({
role:
"user",
content:
userInput,
});
while (true) {
const response =
await client
.chat
.completions
.create({
model:
MODEL,
messages,
tools,
tool_choice:
"auto",
});
const message =
response
.choices[0]
.message;
messages.push(
message
);
/**
* 没有 Tool Call
*
* 说明 Agent
* 认为任务已经完成
*/
if (
!message.tool_calls ||
message.tool_calls.length === 0
) {
return (
message.content
);
}
/**
* 执行所有 Tool Call
*/
for (
const toolCall
of message.tool_calls
) {
const name =
toolCall
.function
.name;
let args = {};
try {
args =
JSON.parse(
toolCall
.function
.arguments
);
} catch {
args = {};
}
console.log(
`\n[Agent] 调用工具:${name}`
);
console.log(
`[Agent] 参数:${JSON.stringify(args)}`
);
let result;
try {
result =
await executeTool(
name,
args
);
} catch (error) {
result =
`工具执行失败:${error.message}`;
}
console.log(
`[Tool] 返回:${result}`
);
messages.push({
role:
"tool",
tool_call_id:
toolCall.id,
content:
String(result),
});
}
}
}
/**
* =========================
* CLI
* =========================
*/
console.log(
"=============================="
);
console.log(
"gpt-5.6-sol AI Agent"
);
console.log(
"输入 exit / quit 退出"
);
console.log(
"=============================="
);
process.stdin.setEncoding(
"utf8"
);
process.stdout.write(
"\n你:"
);
process.stdin.on(
"data",
async (data) => {
const input =
data.trim();
if (
!input
) {
process.stdout.write(
"\n你:"
);
return;
}
if (
input === "exit" ||
input === "quit"
) {
console.log(
"\nAgent 已退出。"
);
process.exit(0);
}
try {
const result =
await runAgent(
input
);
console.log(
`\nAgent:${result}`
);
} catch (error) {
console.error(
"\nAgent 执行失败:",
error.message
);
}
process.stdout.write(
"\n你:"
);
}
);
二十一、启动 Agent
执行:
node agent.js
或者:
npm start
输出:
==============================
gpt-5.6-sol AI Agent
输入 exit / quit 退出
==============================
你:
现在输入:
你:帮我计算 99876 * 6677
Agent:
[Agent] 调用工具:calculator
[Agent] 参数:
{"expression":"99876 * 6677"}
[Tool] 返回:
666472052
最终:
Agent:
99876 × 6677 = 666472052。
二十二、测试多工具任务
再输入:
计算 123456 * 789,然后把结果保存下来。
可能运行:
[Agent] 调用工具:calculator
[Agent] 参数:
{"expression":"123456 * 789"}
[Tool] 返回:
97406784
接着:
[Agent] 调用工具:save_note
[Agent] 参数:
{"content":"123456 × 789 = 97406784"}
[Tool] 返回:
笔记保存成功
最终:
Agent:
计算完成:
123456 × 789 = 97406784
结果已经保存到笔记。
看到这里就应该能理解:
我们没有提前规定:
calculator
↓
save_note
而是 gpt-5.6-sol 根据:
用户目标
+
当前上下文
+
工具列表
+
工具执行结果
自己决定下一步。
二十三、我们已经给 Agent 加了 Memory
注意完整代码里:
const messages = [];
是在:
runAgent()
外面的。
也就是说:
messages
不会随着一次请求结束而销毁。
所以:
你:
我叫 JavaPub。
Agent:
好的。
你:
我叫什么?
Agent:
你叫 JavaPub。
模型能够根据前面的:
Conversation History
继续回答。
这就是最简单的:
Short-Term Memory
也就是:
短期记忆
二十四、为什么 messages 就是 Memory?
因为一次完整请求实际上是:
messages = [
{
role: "system",
content: "..."
},
{
role: "user",
content: "我叫 JavaPub"
},
{
role: "assistant",
content: "好的"
},
{
role: "user",
content: "我叫什么?"
}
];
gpt-5.6-sol 可以看到:
完整历史上下文
所以知道:
JavaPub
但是这种方式有一个问题。
如果用户连续聊:
100 次
1000 次
10000 次
messages 会越来越大。
因此真正的 Agent 系统一般还需要:
Context Window 管理
历史消息截断
Conversation Summary
Redis
MySQL
PostgreSQL
Vector Database
RAG
Long-Term Memory
也就是:
长期记忆
二十五、Tool 可以干什么?
今天只有:
calculator
get_current_time
save_note
看起来比较简单。
但是只要理解了 Tool Calling,你就可以无限扩展。
比如:
search_web
让 AI 搜索互联网。
比如:
read_file
读取文件。
比如:
write_file
创建或者修改文件。
比如:
run_shell
执行:
npm install
git status
git pull
docker ps
比如:
query_database
让 Agent 查询:
MySQL
PostgreSQL
MongoDB
Redis
比如:
github_create_issue
让 Agent 自动:
创建 Issue
比如:
send_email
发送邮件。
比如:
generate_image
调用图片模型。
比如:
generate_video
调用视频生成模型。
甚至:
deploy_application
让 Agent:
拉取 GitHub
↓
npm install
↓
build
↓
Docker 构建
↓
发布
↓
健康检查
这个时候,它就已经开始向:
Coding Agent
DevOps Agent
发展了。
二十六、Agent 到底是谁在控制程序?
这是理解 Agent 最重要的地方。
传统程序:
const result =
calculator();
saveNote(result);
执行顺序由:
程序员
决定。
而 Agent:
User
↓
LLM
↓
选择 Tool
↓
执行
↓
观察结果
↓
LLM
↓
决定下一步
也就是说:
模型开始参与程序流程控制。
这是 Agent 和传统自动化一个很大的区别。
二十七、Agent 和 Workflow 的区别
例如:
const data =
await search();
const article =
await writeArticle(data);
const image =
await generateImage(article);
await publish(
article,
image
);
这是:
Workflow
因为流程是固定的:
搜索
↓
写文章
↓
生成图片
↓
发布
但是 Agent 是:
用户:
帮我写一篇 DeepSeek 最新进展的文章并准备配图。
然后 AI 自己决定:
我要不要搜索?
搜索几个关键词?
资料够不够?
需不需要继续搜索?
什么时候开始写文章?
需不需要生成图片?
生成几张?
什么时候结束?
所以可以简单理解:
Workflow:
代码决定执行流程。
而:
Agent:
模型参与决定执行流程。
不过真正生产环境最常见的并不是:
Agent VS Workflow
而是:
Agent
+
Workflow
确定性的流程交给代码。
模糊决策交给模型。
这样通常更加稳定。
二十八、Agent Loop 到底解决了什么?
来看最核心的一段:
while (true) {
const response =
await llm();
if (
response.tool_calls
) {
await executeTool();
continue;
}
return response.content;
}
它实现的实际上是:
Think
↓
Act
↓
Observe
↓
Think
↓
Act
↓
Observe
↓
Answer
也就是很多 Agent 文章里经常提到的:
Thought
Action
Observation
只不过现代 Tool Calling 已经把很多过程标准化了。
你不一定需要让模型真的输出:
Thought:
我现在应该……
真正重要的是:
模型能够获得工具结果
然后:
继续决策
二十九、为什么很多 Agent Framework 看起来特别复杂?
当你去看:
LangChain
LangGraph
AutoGen
CrewAI
OpenAI Agents SDK
经常会遇到:
Agent
Node
Graph
State
Checkpoint
Tool
Memory
Chain
Workflow
Tracing
第一次学非常容易懵。
但是当你手写完今天这个 Agent 以后,再回头看它们就容易很多。
因为框架实际上主要是在帮助我们解决:
Agent Loop
Tool Registry
State 管理
Memory
异常重试
任务恢复
多 Agent
Human in the Loop
Tracing
日志
持久化
权限
并发
底层基本思想并没有变。
所以如果第一次学习 AI Agent,我建议:
先不要急着学框架,先自己手写一个最小 Agent。
几十到几百行 Node.js 已经足够。
三十、生产环境一定不能这样裸奔
教程为了方便理解,我们使用了:
Function(
`"use strict"; return (${expression})`
)();
这只是演示。
不要直接把不可信用户输入拿去动态执行。
更不要直接给 Agent:
root SSH
rm -rf 权限
数据库 DROP 权限
支付权限
转账权限
因为 Agent 仍然可能:
理解错误
生成错误参数
选错工具
出现 Prompt Injection
被恶意输入诱导
真正上线至少需要:
Tool 白名单
参数校验
权限控制
超时
重试
并发控制
调用次数限制
审计日志
Sandbox
敏感操作确认
三十一、敏感操作加入 Human in the Loop
例如 Agent 想执行:
delete_database
不要马上执行。
可以变成:
Agent:
准备执行:
DROP DATABASE production
这是一个高风险操作。
是否确认?
用户:
确认
程序才真正执行。
这就是:
Human in the Loop
也就是:
人在回路
AI 负责:
分析和建议
但高风险操作:
必须由人确认。
这是生产级 Agent 非常重要的设计。
三十二、再进一步:把 Tool 做成统一注册表
现在我们是:
switch (name) {
case "calculator":
case "save_note":
}
工具少的时候没问题。
但是如果以后有:
50 个 Tool
就会很难维护。
我们可以改成:
const toolHandlers = {
calculator:
async ({
expression
}) => {
return calculator(
expression
);
},
get_current_time:
async () => {
return getCurrentTime();
},
save_note:
async ({
content
}) => {
return saveNote(
content
);
},
};
执行:
async function executeTool(
name,
args
) {
const handler =
toolHandlers[name];
if (!handler) {
return (
`未知工具:${name}`
);
}
return await handler(
args
);
}
这样以后新增:
search_web
read_file
write_file
send_email
只要注册进去即可。
这就开始有一点:
Tool Registry
的味道了。
三十三、给 Agent 增加最大循环次数
还有一个生产环境问题。
现在:
while (true)
理论上可以无限执行。
万一模型一直:
调用 Tool
↓
调用 Tool
↓
调用 Tool
就有可能导致:
无限循环
因此增加:
const MAX_STEPS =
20;
改成:
for (
let step = 0;
step < MAX_STEPS;
step++
) {
// Agent Loop
}
最后:
throw new Error(
"Agent 超过最大执行步骤"
);
这样最多:
20 Steps
避免失控。
三十四、更加完整的 Agent Loop
生产一点的写法:
async function runAgent(
userInput
) {
messages.push({
role:
"user",
content:
userInput,
});
const MAX_STEPS =
20;
for (
let step = 1;
step <= MAX_STEPS;
step++
) {
console.log(
`\n========== Step ${step} ==========`
);
const response =
await client
.chat
.completions
.create({
model:
MODEL,
messages,
tools,
tool_choice:
"auto",
});
const message =
response
.choices[0]
.message;
messages.push(
message
);
if (
!message.tool_calls ||
message.tool_calls.length === 0
) {
return (
message.content
);
}
for (
const toolCall
of message.tool_calls
) {
const name =
toolCall
.function
.name;
const args =
JSON.parse(
toolCall
.function
.arguments || "{}"
);
console.log(
`[Agent] Tool:${name}`
);
console.log(
`[Agent] Args:${JSON.stringify(args)}`
);
let result;
try {
result =
await executeTool(
name,
args
);
} catch (error) {
result =
`Tool Error:${error.message}`;
}
console.log(
`[Tool] Result:${result}`
);
messages.push({
role:
"tool",
tool_call_id:
toolCall.id,
content:
String(result),
});
}
}
throw new Error(
"Agent 达到最大执行步骤,任务终止。"
);
}
例如:
========== Step 1 ==========
[Agent] Tool:calculator
[Agent] Args:
{"expression":"12345 * 6789"}
[Tool] Result:
83810205
========== Step 2 ==========
[Agent] Tool:save_note
[Agent] Args:
{"content":"12345 × 6789 = 83810205"}
[Tool] Result:
笔记保存成功
========== Step 3 ==========
Agent:
计算完成并已保存笔记。
现在整个 Agent 的运行过程已经非常清楚了。
三十五、一个真正 Agent 的五大部分
到这里重新看:
Agent
=
LLM
+
Prompt
+
Tools
+
Memory
+
Loop
基本就完全理解了。
1. LLM
这里就是:
gpt-5.6-sol
负责:
理解目标
分析问题
选择工具
生成参数
判断下一步
组织最终答案
可以把它理解成:
Agent 的大脑
2. Prompt
我们写的:
SYSTEM_PROMPT
负责规定:
身份
目标
规则
工具使用方式
行为边界
类似:
Agent 操作系统里的系统规则
3. Tools
今天:
calculator
get_current_time
save_note
相当于:
Agent 的手和脚
没有工具:
Agent 只能说。
有工具:
Agent 可以做。
这是两者非常重要的区别。
4. Memory
今天:
messages
就是最简单的 Memory。
让 Agent 知道:
前面聊过什么
执行过什么 Tool
工具返回过什么
用户之前要求了什么
5. Agent Loop
今天:
while (true)
或者:
for (...)
负责:
让 AI 不断:
思考
↓
行动
↓
观察
↓
继续思考
直到:
任务完成
三十六、从 Mini Agent 到真正产品
今天我们写的 Agent:
大概几百行以内
但是继续发展之后,就可以变成:
AI Coding Agent
例如给它:
read_file
write_file
list_files
run_shell
git_diff
git_commit
它就可以:
读取项目
↓
分析 Bug
↓
修改代码
↓
运行测试
↓
发现错误
↓
继续修改
↓
再次测试
这已经很接近:
Coding Agent
的核心运行模式了。
还可以做:
运维 Agent
给它:
ssh_command
docker_ps
docker_logs
restart_container
read_nginx_config
用户:
为什么我的 API 返回 502?
Agent:
查看 Docker
↓
查看 Nginx
↓
查看 upstream
↓
读取日志
↓
定位异常
↓
建议修复
甚至在有权限的情况下:
执行修复
还可以做:
内容 Agent
提供:
search_web
write_article
generate_image
publish_wordpress
用户:
写一篇今天 AI 行业最重要的新闻并发布。
Agent:
搜索新闻
↓
筛选信息
↓
交叉验证
↓
写文章
↓
生成配图
↓
发布
三十七、MCP 其实也可以看成 Tool 的升级
现在 AI Agent 领域经常看到:
MCP
很多人第一次看觉得又是一个非常新的东西。
但是如果已经理解今天的:
Tools
就很好理解。
今天我们的 Tool 是:
const tools = [...]
全部硬编码在 Node.js 里面。
而 MCP 想解决的问题之一就是:
让 Tool 的提供方式更加标准化。
以后 Agent 可以连接:
GitHub MCP
Database MCP
Browser MCP
Filesystem MCP
而不是每一个 Agent 都重新写一遍 Tool 接口。
所以理解:
Tool Calling
之后,再学习 MCP 会容易很多。
三十八、最后再看一次完整工作流程
假设用户说:
帮我计算 98765 × 4321,
把结果保存起来,
然后告诉我现在几点。
整个 Agent 可能执行:
User
│
▼
gpt-5.6-sol
│
│ Tool Call
▼
calculator
│
▼
426741565
│
▼
gpt-5.6-sol
│
│ Tool Call
▼
save_note
│
▼
保存成功
│
▼
gpt-5.6-sol
│
│ Tool Call
▼
get_current_time
│
▼
2026/8/14 12:38:21
│
▼
gpt-5.6-sol
│
▼
Final Answer
整个过程中:
Node.js
负责:
运行工具
维护上下文
控制 Agent Loop
而:
gpt-5.6-sol
负责:
理解目标
选择 Tool
生成 Tool 参数
判断下一步
最终回答
这就是一个最基础,但是完整的:
AI Agent Runtime
三十九、真正理解 AI Agent
如果只记住今天一件事情,我建议记住:
while (true) {
const response =
await llm(messages);
if (
response.tool_calls
) {
const result =
await executeTool();
messages.push(
result
);
continue;
}
return (
response.content
);
}
不要小看这几十行逻辑。
它实际上就是:
模型
↓
行动
↓
环境
↓
反馈
↓
模型
↓
行动
这也是今天很多 AI Agent 的核心思想。
框架可能不断换:
LangChain
LangGraph
AutoGen
CrewAI
Agents SDK
模型也可能不断更新。
但是:
Model
Prompt
Tool
Memory
Loop
这几个东西短时间内不会消失。
四十、总结
今天我们完全没有使用任何复杂 Agent Framework。
只使用:
Node.js
OpenAI SDK
gpt-5.6-sol
OpenAI Compatible API
Tool Calling
就实现了一个真正可以运行的:
AI Agent
API:
https://api.chongplus.plus
模型:
gpt-5.6-sol
安装:
npm install openai
整个 Agent 最核心的公式:
AI Agent
=
LLM
+
Prompt
+
Tools
+
Memory
+
Agent Loop
普通 AI 是:
你问它一个问题。
它给你一个回答。
而 Agent 更重要的变化是:
你给它一个目标。
它自己判断:
下一步做什么?
需要什么工具?
工具结果是什么?
接下来还需要干什么?
什么时候任务才算真正完成?
这就是为什么我一直觉得:
学习 Agent 最好的方式,不是第一天就安装 LangChain,而是亲手写一次 Agent Loop。
当你第一次看到终端里出现:
[Agent] 调用工具:calculator
紧接着:
[Tool] 返回:83810205
然后模型不是停止,而是继续:
[Agent] 调用工具:save_note
你就会真正理解:
AI Agent 到底是什么。
而当我们继续给它增加:
浏览器
搜索
文件系统
Shell
数据库
GitHub
图片生成
视频生成
邮件
服务器
这个几十到几百行代码的 Mini Agent,就可以逐渐成长为真正的:
Coding Agent
Browser Agent
DevOps Agent
Research Agent
Content Agent
Enterprise Agent
真正困难的,也会从:
怎么让 AI 调一次 Tool?
慢慢变成:
怎么让 Agent
长期、
稳定、
安全、
低成本地
完成复杂任务?
到了这里,才是真正的 Agent 工程。
一起成为勇猛精进的人类。
更多推荐



所有评论(0)