🤖 从零造一个AI程序员:30行核心代码拆解Cursor背后的Agent原理

别再迷信黑盒了!手把手带你实现一个能自动创建React项目的AI编程助手

引言:AI编程助手真的会"思考"吗?

当你对Cursor说"帮我创建一个TodoList应用",它唰唰唰地创建文件、安装依赖、启动服务------这背后到底是魔法还是代码?

答案是:一套精心设计的Agent循环 + 几个核心工具函数

今天,我们不玩虚的,直接手写一个mini-cursor。用不到300行代码,复刻AI编程助手的核心能力。读完这篇,你将彻底看透:

  • AI如何"假装思考"实则调用工具
  • LangChain如何成为AI的"神经系统"
  • Node.js如何让AI"动手干活"
  • 一个完整的Agent项目应该如何组织

一、架构全景:AI的"大脑"与"手脚"如何配合

text

arduino 复制代码
┌──────────────────────────────────────────────────────┐
│              mini-cursor 核心架构                    │
│                                                    │
│  ┌────────────────────────────────────────────┐    │
│  │         Agent 主循环 (mini-cursor.mjs)     │    │
│  │   ┌─────────────────────────────────┐     │    │
│  │   │  ReAct Loop:                     │     │    │
│  │   │  Think → Act → Observe          │     │    │
│  │   │  (最多30次迭代)                  │     │    │
│  │   └─────────────────────────────────┘     │    │
│  └────────────────────────────────────────────┘    │
│                      │                             │
│                      ▼                             │
│  ┌────────────────────────────────────────────┐    │
│  │        工具层 (all-tools.mjs)              │    │
│  │  ┌──────┐ ┌──────┐ ┌──────┐ ┌────────┐  │    │
│  │  │读文件 │ │写文件 │ │列目录 │ │执行命令│  │    │
│  │  └──────┘ └──────┘ └──────┘ └────────┘  │    │
│  └────────────────────────────────────────────┘    │
│                      │                             │
│                      ▼                             │
│  ┌────────────────────────────────────────────┐    │
│  │       Node.js 子进程 (node-exec.mjs)       │    │
│  │   隔离执行 pnpm / vite 等耗时命令          │    │
│  └────────────────────────────────────────────┘    │
└──────────────────────────────────────────────────────┘

一句话概括:大模型负责"想",工具负责"做",子进程负责"跑"。


二、工具层深入解析:AI的"四肢"是怎样炼成的

所有工具都通过LangChain的tool()函数创建。这个函数做了三件事:

  1. 接收一个异步执行函数
  2. 接收工具元数据(名称、描述、参数Schema)
  3. 返回一个可被AI调用的标准工具对象

🔧 读文件工具 ------ AI的"眼睛"

javascript

php 复制代码
const readFileTool = tool(
    async({ filePath }) => {
        const content = await fs.readFile(filePath, 'utf-8');
        console.log(`[工具调用] 读取 ${filePath},共 ${content.length} 字符`);
        return content;
    },
    {
        name: 'read_file',
        description: '读取文件内容,用于查看代码、配置文件等',
        schema: z.object({
            filePath: z.string().describe('文件路径,支持相对或绝对路径')
        })
    }
);

设计要点

  • z.object() 定义了参数结构,AI调用时必须传入符合格式的参数
  • 异步读取,不阻塞主流程
  • 返回值会作为ToolMessage注入对话上下文

✍️ 写文件工具 ------ AI的"手"

javascript

csharp 复制代码
const writeFileTool = tool(
    async({ filePath, content }) => {
        try {
            const dir = path.dirname(filePath);
            await fs.mkdir(dir, { recursive: true });  // 自动创建父目录
            await fs.writeFile(filePath, content, 'utf-8');
            return `✅ 成功写入 ${filePath}`;
        } catch(err) {
            return `❌ 写入失败:${err.message}`;
        }
    },
    {
        name: 'write_file',
        description: '写入文件内容,不存在则创建,父目录不存在则自动创建',
        schema: z.object({
            filePath: z.string().describe('目标文件路径'),
            content: z.string().describe('要写入的内容')
        })
    }
);

工程智慧

  • recursive: true 让AI无需关心目录是否存在
  • 错误被捕获并返回友好信息,AI可以根据错误调整策略

📂 列目录工具 ------ AI的"导航"

javascript

php 复制代码
const listDirectoryTool = tool(
    async ({ directoryPath }) => {
        const files = await fs.readdir(directoryPath);
        return files.map(f => `📄 ${f}`).join('\n');
    },
    {
        name: 'list_directory',
        description: '列出目录内容,帮助AI了解项目结构',
        schema: z.object({
            directoryPath: z.string().describe('目录路径')
        })
    }
);

⚡ 执行命令工具 ------ AI的"超能力"

这是最复杂的工具,也是AI真正"干活"的关键:

javascript

javascript 复制代码
const executeCommandTool = tool(
    async ({ command, workingDirectory }) => {
        const cwd = workingDirectory || process.cwd();
        return new Promise((resolve) => {
            const [cmd, ...args] = command.split(' ');
            const child = spawn(cmd, args, {
                cwd,
                stdio: 'inherit',  // 实时输出到终端
                shell: true,
            });

            let errorMsg = '';
            child.on('error', (err) => { errorMsg = err.message });
            child.on('close', (code) => {
                if (code === 0) {
                    resolve(`✅ 命令执行成功: ${command}`);
                } else {
                    resolve(`❌ 命令失败 (退出码: ${code}): ${errorMsg}`);
                }
            });
        });
    },
    {
        name: 'execute_command',
        description: '执行系统命令,支持指定工作目录',
        schema: z.object({
            command: z.string().describe('要执行的命令'),
            workingDirectory: z.string().describe('工作目录')
        })
    }
);

关键设计决策

  • 使用spawn而非exec:流式输出,适合长时间运行的命令
  • stdio: 'inherit':用户能看到pnpm install的实时进度
  • 返回Promise,完美融入async/await体系

三、Agent主循环:AI的"大脑"如何做决策

3.1 模型绑定工具

javascript

ini 复制代码
const model = new ChatOpenAI({
    modelName: 'deepseek-v4-pro',
    temperature: 0,
});

const modelWithTools = model.bindTools([
    readFileTool,
    writeFileTool,
    listDirectoryTool,
    executeCommandTool
]);

bindTools()是LangChain的核心魔法:

  • 自动将工具签名转换成OpenAI的function calling格式
  • 让模型知道"我有这些能力"
  • 返回的响应中会包含tool_calls字段

3.2 System Prompt ------ 给AI立规矩

javascript

bash 复制代码
const messages = [
    new SystemMessage(`
        你是项目管理助手,可用工具:
        1. read_file: 读取文件
        2. write_file: 写入文件
        3. execute_command: 执行命令(支持 workingDirectory 参数)
        4. list_directory: 列出目录
        
        ⚠️ 重要规则:
        - 使用 execute_command 时,指定 workingDirectory 后,
          不要在 command 里再用 cd 切换目录
        - 正确: { command: "pnpm install", workingDirectory: "react-todo-app" }
        - 错误: { command: "cd react-todo-app && pnpm install", workingDirectory: "react-todo-app" }
    `),
    new HumanMessage(query)
];

Prompt Engineering的艺术

  • 明确告诉AI有哪些工具可用
  • 给出正确和错误的使用示例
  • 避免AI在命令中拼接cd导致路径错误

3.3 ReAct循环 ------ Agent的灵魂

javascript

javascript 复制代码
async function runAgentWithTools(query, maxIterations = 30) {
    const messages = [systemMessage, humanMessage];

    for (let i = 0; i < maxIterations; i++) {
        console.log(chalk.bgGreen(`🧠 第 ${i} 次思考...`));

        // 1. THINK: AI推理
        const response = await modelWithTools.invoke(messages);
        messages.push(response);

        // 2. 没有工具调用 → 任务完成
        if (!response.tool_calls?.length) {
            console.log(chalk.green(`✅ ${response.content}`));
            return response.content;
        }

        // 3. ACT: 执行工具
        for (const toolCall of response.tool_calls) {
            const tool = tools.find(t => t.name === toolCall.name);
            if (tool) {
                // 4. OBSERVE: 记录结果
                const result = await tool.invoke(toolCall.args);
                messages.push(new ToolMessage({
                    content: result,
                    tool_call_id: toolCall.id
                }));
            }
        }
        // 回到步骤1,继续循环
    }
}

ReAct循环的本质

text

scss 复制代码
用户提问 → 🤔 Think (AI决定用什么工具)
         → ⚡ Act  (执行工具)
         → 👀 Observe (把结果加入上下文)
         → 🤔 Think (根据结果决定下一步)
         → ⚡ Act  ...
         → ✅ 完成任务,输出最终答案

这个过程模拟了人类解决问题的思维链:看到问题→思考方案→动手操作→观察结果→调整方案→继续操作→完成。


四、任务执行实战:从提问到完成的全流程

当我们给Agent下达这个任务:

javascript

markdown 复制代码
const task = `
创建React TodoList应用:
1. 用Vite创建项目
2. 实现完整TodoList功能
3. 添加美观样式和动画
4. 安装依赖并启动服务
`;

Agent的决策轨迹是这样的:

text

php 复制代码
🧠 第 0 次思考...
   🤔 "我需要先创建项目,使用 create-vite 命令"
   ⚡ execute_command({
        command: "pnpm create vite react-todo-app --template react-ts",
        workingDirectory: process.cwd()
      })
   👀 "✅ 项目创建成功"

🧠 第 1 次思考...
   🤔 "现在需要写入完整的App.tsx代码"
   ⚡ write_file({
        filePath: "react-todo-app/src/App.tsx",
        content: "完整的TodoList组件代码..."
      })
   👀 "✅ 成功写入 2847 字节"

🧠 第 2 次思考...
   🤔 "需要安装依赖"
   ⚡ execute_command({
        command: "pnpm install",
        workingDirectory: "react-todo-app"
      })
   👀 "✅ 依赖安装完成,新增 342 个包"

🧠 第 3 次思考...
   🤔 "启动开发服务器"
   ⚡ execute_command({
        command: "pnpm run dev",
        workingDirectory: "react-todo-app"
      })
   👀 "✅ 服务启动在 http://localhost:5173"

🧠 第 4 次思考...
   🤔 "所有任务完成,可以汇报了"
   💬 "🎉 TodoList应用已创建!访问 http://localhost:5173 查看"

五、子进程隔离:为什么需要独立执行

Node.js主进程是单线程的,如果在主进程里执行pnpm install,整个Agent会被阻塞。解决方案:

javascript

arduino 复制代码
// node-exec.mjs
const [cmd, ...args] = command.split(' ');
const child = spawn(cmd, args, {
    cwd,
    stdio: 'inherit',  // 实时显示输出
    shell: true,       // 使用Shell执行
});

child.on('close', (code) => {
    if (code === 0) {
        console.log('✅ 子进程执行成功');
        process.exit(0);
    } else {
        console.log(`❌ 子进程失败,退出码:${code}`);
        process.exit(code);
    }
});

为什么这样设计

  • 隔离性:子进程崩溃不影响主Agent
  • 实时性stdio: 'inherit'让用户看到命令输出
  • 可监控 :通过close事件感知命令执行结果

六、完整的执行日志展示

bash

scss 复制代码
$ node mini-cursor.mjs

🧠 第 0 次思考...
[工具调用] execute_command(pnpm create vite react-todo-app --template react-ts)
工作目录:/Users/xxx/projects
✔ 项目创建成功

🧠 第 1 次思考...
[工具调用] write_file(react-todo-app/src/App.tsx)
✅ 成功写入 2847 字节

🧠 第 2 次思考...
[工具调用] execute_command(pnpm install)
工作目录:react-todo-app
✔ 依赖安装完成 (342 packages)

🧠 第 3 次思考...
[工具调用] execute_command(pnpm run dev)
工作目录:react-todo-app
  ➜  Local:   http://localhost:5173/

🧠 第 4 次思考...
✅ AI最终回复:
🎉 TodoList 应用已创建成功!
- 项目目录:react-todo-app
- 访问地址:http://localhost:5173
- 功能:添加/删除/标记完成/分类筛选/数据持久化
- 样式:渐变背景 + 卡片设计 + 过渡动画

七、核心设计模式总结

设计模式 实现方式 解决的问题
工具抽象 tool() + Zod Schema 让AI能调用任意函数
消息历史 维护messages数组 让AI有"记忆"能力
ReAct循环 Think→Act→Observe 让AI能自主完成任务
子进程隔离 child_process.spawn 避免耗时命令阻塞主线程
错误回传 ToolMessage携带错误信息 让AI能根据错误调整策略

八、扩展与优化方向

🚀 可以立即添加的新工具

  • search_code:在项目中搜索代码片段
  • git_commit:自动提交代码
  • run_tests:执行测试用例
  • browser_open:打开浏览器预览

🧠 可以优化的决策机制

  • 并行执行 :多个独立工具调用可以Promise.all并发
  • 中断机制:用户可随时打断无限循环
  • 记忆模块:使用向量数据库存储项目上下文
  • 安全确认:危险操作前询问用户

写在最后:AI编程的本质

通过手写这个mini-cursor,我们发现:

AI编程助手并不神秘,它就是一个精心设计的工具调用系统。

大模型负责"思考"下一步该做什么,而真正的"执行"都落在我们写的工具函数上。这就是为什么:

  • Cursor能创建项目 → 因为它调用了execute_command
  • Cursor能修改代码 → 因为它调用了write_file
  • Cursor能理解代码 → 因为它调用了read_file

掌握了这个核心原理,你就能:

  1. 定制自己的AI编程助手
  2. 给现有工具添加新的能力
  3. 理解Claude Code、Copilot等产品的底层逻辑

现在,拿起键盘,去创造属于你自己的AI助手吧!🚀


💬 互动话题:如果你来设计一个AI编程助手,你最想给它添加什么"超能力"?欢迎在评论区分享你的想法!

相关推荐
大鱼>1 小时前
AI+货物追踪:智能快递柜追踪系统
人工智能·深度学习·算法·机器学习
程序喵大人1 小时前
【AI专栏】图解Transformer - 第04章:LLM生成
人工智能·深度学习·llm·transformer
1234567890@world1 小时前
知识管理 | 数字化 | APQC
大数据·数据库·人工智能
千维百策6661 小时前
AI 编码智能体平台如何提升研发效能:从 CI 修复到工程工作流自动化
人工智能·ci/cd·自动化
以和为贵1 小时前
🔥前端也能搞懂流式输出:从 SSE 到打字机效果
前端·人工智能·架构
sunywz2 小时前
【AI RAG知识库】06.【导入】【Web服务集成】
人工智能
zeng_jun_yv2 小时前
测试 Agent 评测体系详细方案
人工智能
人工智能时代 准备好了吗2 小时前
AI回答内容进入率监测:引用识别、文本匹配与语义判断
开发语言·人工智能·python
LONGZETECH2 小时前
新能源汽车动力电池检测仿真教学系统:C/S 分层架构与数字化实训落地全解析
大数据·c语言·开发语言·人工智能·架构·系统架构·汽车