当前位置: 首页 > news >正文

做 Agent 会用到的 Node API(1):路径与文件

本系列讲实现 Agent harness 时脚下的 Node API,按场景拆篇,不当成 Node 全手册。
示例仓库:react-agent-mini
若还不熟「Agent 主循环长什么样」,可先看同仓库前作:150 行搞懂 Agent 主循环
本篇相关:代码库工具 Read/Write · Agent Memory


场景:工具的手脚落在磁盘上

Agent 要「读仓库、改文件、记偏好」,最后都会碰到两件事:

  1. 路径怎么拼、怎么防逃出工作区
  2. 文件怎么读、怎么写、写前要不要建目录

在 Node 里,这对应两个模块:

模块管什么
node:path字符串层面的路径:拼接、解析绝对路径、算相对关系
node:fs/promises真正碰磁盘:stat/readFile/writeFile/mkdir

本篇只讲 Agent 里高频的那一小撮,对照react-agent-mini的 Read / Write / Memory。


1.path:先把字符串变成「可信绝对路径」

常用三个:

import{isAbsolute,relative,resolve,join,dirname}from'node:path'resolve(cwd,inputPath)// 相对 → 绝对;处理 `.` / `..`relative(cwd,absolute)// 绝对相对 cwd 的相对串join(cwd,'.agents','memory','MEMORY.md')// 纯拼接片段dirname(filePath)// 父目录,给 mkdir 用

Agent 里最关键的一招:cwd 沙箱

模型可能传../../etc/passwd。只靠「拼一下」不够,要校验结果仍在工作区子树内:

export function resolvePathUnderCwd( inputPath: string, cwd = process.cwd(), ): string { const absolute = resolve(cwd, inputPath) const rel = relative(cwd, absolute) if (rel.startsWith('..') || isAbsolute(rel)) { throw new Error('拒绝访问:路径必须在当前工作目录内') } return absolute }

要点:

  • resolve会消掉..,所以必须再看relative结果
  • rel.startsWith('..'):还在往上爬
  • isAbsolute(rel):Windows 上相对结果有时是另一盘符绝对路径,也要拦

Read / Write / Edit / Glob / Grep 都复用这一函数——路径规则写一次,所有文件工具共用。

Memory 则用join钉死约定路径,不接受模型乱指:

join(cwd,'.agents/memory/MEMORY.md')

2.fs/promises:异步读盘,别阻塞事件循环

Agent 一轮里可能连读多个文件;用 Promise 版,方便awaitTool.call

import{readFile,writeFile,stat,mkdir}from'node:fs/promises'

stat:先问「是不是文件、有多大」

constfileStat=awaitstat(filePath)if(!fileStat.isFile())thrownewError('不是普通文件')if(fileStat.size>MAX_READ_BYTES)thrownewError('文件过大')

Read 在readFile之前做这件事,避免把巨型二进制整份读进内存再报错。

ENOENT(不存在)要转成对模型友好的文案,而不是把堆栈塞进tool_result

try{fileStat=awaitstat(filePath)}catch(err){if(err&&typeoferr==='object'&&'code'inerr&&err.code==='ENOENT'){thrownewError(`文件不存在:${args.file_path}`)}throwerr}

readFile:拿正文

constcontent=awaitreadFile(filePath,'utf-8')

指定'utf-8',得到string。Agent 文本工具几乎总是这么读;二进制另议(你们 MCP Resource 对 blob 是占位,不塞 base64)。

writeFile+mkdir:写入与建父目录

Write 的典型顺序:

awaitmkdir(dirname(filePath),{recursive:true})awaitwriteFile(filePath,args.content,'utf-8')
  • recursive: true:父目录多层一次性建好
  • Memory 启动时的ensureMemoryDirExists也是同一个mkdir(..., { recursive: true }),方便模型直接 Write,少一轮「先建目录」

也可用stat判断「创建还是覆盖」,给模型不同成功文案——但仍是覆盖写语义。


3. 字节预算:Buffer.byteLength

截断「最多 32KB / 100KB」时,不要用string.length(那是 UTF-16 码元数)。Memory 用的是:

Buffer.byteLength(content,'utf-8')

readFile/writeFile的字节语义一致,避免中文多字节把预算算爆。


一张对照表

Agent 需求Node API仓库里
相对路径 → 绝对 + 防穿越resolve+relative+isAbsoluteresolvePathUnderCwd
约定死路径joinMemory / hooks / skills 发现
父目录dirnameWrite 前 mkdir
元信息 / 大小statRead 上限、mtime 刷新
读文本readFile(..., 'utf-8')Read、加载 AGENTS/MEMORY
写文本writeFileWrite、Edit 落盘
建目录mkdir({ recursive: true })Write、ensure memory dir

常见坑

建议
resolve不校验模型可逃出 cwd;必须relative检查
existsSync再读有竞态;stat/readFile捕获ENOENT更干净
同步fs.readFileSync塞进热路径拖住整条 Agent 事件循环;工具里优先 promises
length当字节预算多字节字符不准;用Buffer.byteLength
Windows 路径分隔符尽量交给path;少手写/\拼接

和主循环的关系

主循环(query())不关心磁盘;工具层才碰path/fs

query → tool_use: Read → resolvePathUnderCwd → stat / readFile → tool_result 文本回模型

所以学 Node 文件 API,是在学Agent 的效应器,不是在学 ReAct 本身。主循环仍是前作那 150 行;本篇补的是「手脚怎么落地」。


本系列下一篇预告

(2)子进程:Bash 与 Hooks 的壳——spawn、stdout/stderr、超时杀掉、跨平台 shell。


你可以带走什么?

  1. 路径先沙箱,再读写——resolve+relative是文件类工具的安全带。
  2. promises 版 fs——和async call()同一套心智。
  3. stat再读——类型、大小、是否存在,一次问清。
  4. 写入常配mkdir(recursive)——少让模型多走一轮建目录。
  5. 预算按字节——Buffer.byteLength,不是string.length

仓库与延伸

  • GitHub:react-agent-mini
  • 本系列定位:Agent 实现向的 Node API 笔记(与 harness 设计系列分开)
  • 前作主循环:150 行搞懂 Agent 主循环
  • 相关实现:ReadTool.ts · WriteTool.ts · memory/load.ts

欢迎 Star、Issue 和 PR。


本文为「做 Agent 会用到的 Node API」系列第 1 篇;示例基于 react-agent-mini。

http://www.jsqmd.com/news/1328275/

相关文章:

  • 字符串操作实战:翻转、旋转、匹配与重复模式解析
  • Cesium瓦片方案与天地图服务对接实战指南
  • 【2026年成都全屋定制收纳实力榜】深度拆解5大品牌,避开隐形坑选出真高配 - 官方资讯
  • 2026年8月长春代理记账优选推荐|易金财务合规做账高口碑靠谱省心 - 品牌优企推荐
  • 从迷茫到精通:网安新人从零搭建属于自己的「个人知识体系」,彻底告别瞎学
  • 终极解决方案:如何免费解锁WeMod Pro功能的完整指南
  • ChatGPT Plus和Pro用户注意:Codex从GPT-5.4迁移到GPT-5.6完整教程
  • AI辅助数学证明:构建可验证的GPT推理工作流实践
  • 香港本科申英研最大的隐性优势不是英语——是推荐信文化 - 科技焦点
  • StarRailAssistant:崩坏星穹铁道自动化工具的终极指南
  • 大厂Java面试深度解析:核心、并发与Spring Boot实战
  • C++约数算法精解:从质因数分解到欧拉函数与性能优化
  • Unity帧率上限设置:从原理到实战的性能优化指南
  • 劲牌公司行业地位为何稳固?多维优势铸就酒业健康赛道领军者 - 资讯在线
  • 2026马鞍山婚纱照避坑帖!4家高口碑本土店,新人优选附地址 - 商业信息快查
  • 8月南京闲置首饰思考,入手价格高变现折价问题根源到底在哪里 - 每日生活报
  • 2026 抖店无货源合规运营指南:抖大侠违规风险预警与避坑教程 - 抖大侠
  • SRWE窗口编辑器:实时调整Windows应用程序窗口的完整指南
  • 163MusicLyrics:免费歌词获取工具全攻略
  • 网安新人快速突破瓶颈指南:学不动、没成果、想放弃?全套解决方案
  • 如何5分钟打造你的专属Obsidian个性化首页:新手快速上手指南
  • 2026 上海包包回收,全品类闲置奢包标准化变现渠道详解 - 讯息早知道
  • 2026年7月|广东劳动关系托管服务**推荐 - 资讯在线
  • 看懂黄金大盘实时行情,帮你杭州卖黄金不吃亏 - 日常比对手册
  • 基于Godot引擎的跨设备分布式3D渲染架构设计与工程实践
  • Unity回合制战斗系统开发:状态机、ScriptableObject与伤害计算实战
  • 不用复杂家庭 nas 机架运维,搭建浏览器私有云共享存储
  • League Akari:英雄联盟玩家如何通过本地化工具提升300%游戏效率
  • 不同岗位的人用本体语义平台到底能得到什么:老板、业务、一线、IT各自的实际收益
  • Pinegrow可视化建站:源码可控的响应式网页设计实战指南