,

最简单的Agent

玩具版: 项目目录和文件内容如下:├── index.js├── tools.js├── package.js…

玩具版:

项目目录和文件内容如下:
├── index.js
├── tools.js
├── package.json
├── .env.example
├── README.md
├── node_modules\ (37 个依赖包)
└── package-lock.json

index.js — Agent 主循环:

import OpenAI from 'openai';
import readline from 'node:readline';
import { toOpenAITools, runTool } from './tools.js';

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: process.env.OPENAI_BASE_URL, // 可选,兼容 Kimi/DeepSeek 等
});

const MODEL = process.env.MODEL || 'gpt-4o-mini';
const MAX_ROUNDS = 10; // 单轮提问中最多允许的工具调用轮数,防止死循环

const systemPrompt = '你是一个乐于助人的智能助手,可以使用工具来回答用户问题。';

async function chat(history, userInput) {
  history.push({ role: 'user', content: userInput });

  for (let round = 0; round < MAX_ROUNDS; round++) {
    const resp = await client.chat.completions.create({
      model: MODEL,
      messages: history,
      tools: toOpenAITools(),
    });
    const msg = resp.choices[0].message;
    history.push(msg);

    // 没有工具调用 → 得到最终回答
    if (!msg.tool_calls?.length) {
      return msg.content;
    }

    // 执行所有工具调用,把结果塞回对话
    for (const call of msg.tool_calls) {
      const result = await runTool(call.function.name, call.function.arguments);
      console.log(`  [tool] ${call.function.name}(${call.function.arguments}) → ${result}`);
      history.push({ role: 'tool', tool_call_id: call.id, content: result });
    }
  }
  return '(工具调用次数过多,已停止)';
}

async function main() { /* 命令行交互循环,输入 exit 退出 */ }
main();

tools.js — 内置 3 个工具(截取关键部分):

export const tools = [ 
 { 
   name: 'get_current_time', 
   description: '获取当前日期和时间',    
   parameters: { type: 'object', properties: {} },    
async execute() { 
   return new Date().toLocaleString('zh-CN', ...); 
} 
},  
{ 
    name: 'calculator', description: '计算一个数学表达式',    
    parameters: { ..., properties: { expression: { type: 'string' } } },    
    async execute({ expression }) { ... } },  
   { name: 'read_file', description: '读取当前工作目录下某个文本文件的内容',     
    parameters: { ..., properties: { filePath: { type: 'string' } } },    
    async execute({ filePath }) { ... } },
];

Agent 的核心确实就是一个循环,这不是偷懒,这就是事实。业界把 Agent 定义为 “LLM + tools + loop”:模型决定下一步动作 → 执行 → 观察结果 → 再决定,直到任务完成。Claude Code、Cursor、Devin 这些看起来很强大的 Agent,骨架也都是这个循环。

真正的差距不在循环本身,而在围绕循环的那一层工程:

维度玩具版(现在这个项目)生产级 Agent
工具3 个本地函数几十个工具 + 权限控制 + 结果截断
记忆无限堆积的对话历史上下文压缩、长期记忆、向量检索
规划模型即兴发挥显式的 TODO/plan 步骤、子任务分解
健壮性try/catch 打日志重试、超时、token 预算、循环检测
输出等最终结果流式输出、可中断、人机协作确认
架构单 Agent多 Agent 分工(规划者/执行者/评审)

所以这个”简单”版本的价值在于:它已经是真 Agent 了,能真实完成”现在几点→查时间→回答”这种工具驱动的任务,只是没有上面那些增强。

Previous Post

Next Post

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Latest News

View All

About the Author

每个人都有自己得时区,在自己得时区里,一切都是准时的。

BlockSpare — News, Magazine and Blog Addons for (Gutenberg) Block Editor

You May Have Missed