☰
手把手给AI装上13个工具:claude-code-from-scratch工具系统设计与edit_file防坑实战
2026/10/1 8:44:56 网站建设 项目流程

手把手给AI装上13个工具:claude-code-from-scratch工具系统设计与edit_file防坑实战

【免费下载链接】claude-code-from-scratchBuild your own Claude Code from scratch. 🔍 Claude Code 开源了 50 万行代码,读不动?用 ~5000 行 TypeScript / Python 从零复现核心架构,11 章分步教程带你理解 coding agent 精髓项目地址: https://gitcode.com/gh_mirrors/cl/claude-code-from-scratch

Claude Code 开源了 50 万行代码,读不动?claude-code-from-scratch用约 5000 行 TypeScript / Python 代码从零复现了它的核心架构,而工具系统(Tool System)正是让 AI 从"只会聊天"进化为"能干活的 coding agent"的关键一步。本文带你手把手拆解这个开源项目如何给 AI 装上 13 个工具:一个静态数组 + 一个 switch 分发器就搭起了完整工具系统,再深入edit_file工具,看清"改错地方"、"引号不匹配"、"覆盖用户修改"三大坑是如何被逐一堵上的。

为什么 AI 需要工具:一个工具只有三样东西

大模型本身只能"说话",它不能读文件、不能跑测试。工具就是 AI 的"手":模型决定调什么工具、传什么参数,真正干活的函数由你的代码执行。

在 src/tools.ts 中,每个工具只需要三样东西:

组成说明作用
名字如read_file、edit_file模型调用时用的标识
给模型看的说明description + input_schema让模型知道工具能干什么、传什么参数
干活的函数一个普通函数真正执行文件读写、搜索等操作

这个设计极简但威力巨大——模型通过 schema "理解"工具,函数负责落地执行,两者之间只差一层 JSON 参数。

13 个工具全家福:6 核心 + 7 扩展

项目共定义 13 个工具,全部集中在一个 toolDefinitions 静态数组里:

分类工具能力
📄 文件读写read_file读取文件(带行号)
write_file新建 / 覆盖文件(自动创建父目录)
edit_file精确字符串替换(本章重点 ⭐)
🔍 探索代码list_filesglob 模式列文件
grep_search正则搜索(优先系统 grep)
⚡ 执行命令run_shell跑测试、git、装依赖
🧩 扩展能力skill调用.claude/skills/里的技能模板
web_fetch抓取 URL 并去 HTML 标签
enter_plan_mode/exit_plan_modePlan 模式进出(deferred 延迟加载)
agent派生子 Agent 隔离干活
tool_search按需激活延迟加载的工具

Python 版功能完全一致,实现在 python/mini_claude/tools.py,两版可对照阅读。

工具系统核心设计:数组 + switch,拒绝过度工程

Claude Code 的 66+ 工具用类体系管理(继承、多态、独立测试),但教程项目里 13 个工具完全够用更简单的方案:

  1. 定义层:toolDefinitions 静态数组,格式与 Anthropic API 的tools参数完全一致,零转换直接发送;
  2. 执行层:executeTool 分发器 用一个switch把工具名分派到对应函数。
// src/tools.ts — 工具执行分发 switch (name) { case "read_file": result = readFile(input); break; case "write_file": result = writeFile(input); break; case "edit_file": result = editFile(input); break; // ... list_files, grep_search, run_shell, web_fetch, tool_search default: return `Unknown tool: ${name}`; }

💡设计哲学:错误是数据,不是异常。未知工具返回Unknown tool: xxx字符串而非抛异常——这段文字会回到模型手里,让它自己发现"我幻觉出了一个不存在的工具名"并纠正。

edit_file 防坑实战:这个工具藏着 3 个真实的坑

edit_file是 13 个工具里唯一"有坑"的。它的工作方式很简单:给一段old_string和一段new_string,把文件里精确匹配到的旧字符串替换掉。听起来没问题?实际运行会撞上三个坑。

坑 1:改错地方 —— 唯一性检查

如果old_string在文件里出现 3 次,静默替换第一个匹配项就是灾难。editFile 实现 先数出现次数,不唯一就直接拒绝:

const count = content.split(actual).length - 1; if (count > 1) return `Error: old_string found ${count} times. Must be unique.`;

出现 0 次说明模型"记错了"文件内容(幻觉检测);出现 >1 次则要求模型提供更多信息来唯一定位。宁可失败也不猜测——错误信息会喂回给模型,它会带上更多上下文重试。

坑 2:引号不匹配 —— 引号容错

LLM 的 tokenization 可能把文件里的直引号"生成成弯引号",没有容错的话这类编辑会 100% 失败。项目用 normalizeQuotes + findActualString 解决:先尝试精确匹配,失败后把两边的弯引号统一归一化再找,匹配成功后返回文件中的原始字符串去替换,保持文件原有字符风格不被改写。

细节彩蛋:替换用content.split(actual).join(new_string)而不是String.replace——后者的$有替换符语义,遇到含$的代码会被悄悄改写。

坑 3:覆盖用户正在改的东西 —— read-before-edit + mtime 防护

这是整个工具系统最有价值的防护(executeTool 中的检查逻辑):

场景系统行为
AI 没读过就直接改已有文件❌ 拒绝:You must read this file before editing
AI 读完后,你在 IDE 里手动改了它⚠️ 警告:modified externally, read_file again
新建文件✅ 跳过检查(新文件无需先读)

原理:Agent 用一个 Map 记录每个文件读取时的mtime(修改时间戳),写入前再比对一次。时间戳变了 = 文件在 AI 读取后被外部动过。这与 Claude Code 的readFileTimestamps机制对齐——编辑必须基于已知状态,不能"盲写"。

编辑成功还送一份 diff

编辑完成后,工具会生成一段带行号的简易 diff 返回(generateDiff),模型和人都能立刻确认改对了哪几行。

为什么选"字符串替换"而不是行号或 diff?

项目文档 docs/02-tools.md 里有张精彩的方案对比表,值得新手记住:

备选方案致命缺陷
行号编辑插入 3 行后所有后续行号偏移,多步编辑要复杂重算
AST 编辑语法错误的文件恰恰最需要编辑,AST 解析器直接报错
Unified diffLLM 生成严格格式很差,一个+/-前缀错就废
全文件重写大文件烧 Token,还可能静默丢掉没改的代码
字符串替换✅ 且自带"幻觉安全":字符串不存在就直接失败,逼模型重读纠正

另外 3 个值得抄作业的工具设计

  1. 结果截断保头尾:超过 50K 字符时,truncateResult 保留开头和结尾各一半——因为编译错误摘要、测试统计往往在末尾,只砍中间并明确标注"truncated N chars";
  2. 只读工具并行跑:read_file、grep_search等无副作用的工具标记为 CONCURRENCY_SAFE_TOOLS,可并发执行,2-3 倍加速;
  3. deferred 延迟加载:不常用的工具(如 plan mode)只把名字发给模型,需要时模型调tool_search激活完整 schema——工具一多起来,这是省 token 的关键。

动手跑起来:一条命令验证工具系统

仓库是只读的,先 clone 到本地再运行:

git clone https://gitcode.com/gh_mirrors/cl/claude-code-from-scratch cd claude-code-from-scratch npm install node steps/run.mjs 2 # 跑第 2 章工具系统,无需 API key node steps/run.mjs 2 --diff # 看这一章比上一章多了什么 node steps/run.mjs 2 --py # 换 Python 版

第 2 章的可运行最小实现位于 steps/canonical/ts/tools.ts,文档与代码由同一真源生成,保证"文档说的和代码对得上"。完整 13 项工具行为可用 test/TEST-GUIDE.md 逐一手动验证。

总结:~5000 行看懂工具系统的精髓

要点一句话总结
工具结构名字 + 说明 + 函数,静态数组定义、switch 分发执行
错误处理错误是数据:失败信息回喂模型,让它自我纠正
edit_file 三坑唯一性检查 / 引号容错 / read-before-edit + mtime
防上下文爆炸50K 截断保头尾、大结果持久化到磁盘

工具定义了 agent 的能力,下一篇可以顺着 docs/03-system-prompt.md 看 System Prompt 如何定义它的行为——什么时候该小心、优先用哪个工具。

💬 想交流 AI Agent 开发心得?可以加入AI Agent 工坊交流群(群号 1090526244),扫码进群一起讨论 coding agent 的实现细节。

【免费下载链接】claude-code-from-scratchBuild your own Claude Code from scratch. 🔍 Claude Code 开源了 50 万行代码,读不动?用 ~5000 行 TypeScript / Python 从零复现核心架构,11 章分步教程带你理解 coding agent 精髓项目地址: https://gitcode.com/gh_mirrors/cl/claude-code-from-scratch

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询