从零实现 GeekAgent —— Day12 代码搜索与网页抓取
内容提要
本文介绍GeekAgent第12天开发:新增search和fetch两个工具。search在权限目录内按内容搜索代码,返回文件:行号:内容,跳过node_modules和二进制文件;fetch读取网页并转纯文本,访问前需确认URL。两者均注册到工具系统,search用safePath限制目录,fetch用authorize确认。实现采用Node内置glob和正则剥标签,不依赖额外库,适合小型仓库。
延伸解读
为何不用 ripgrep 和 HTML 解析库
作者选择 Node 内置的 glob 和正则而非 ripgrep、cheerio 等成熟工具,主要为了减少依赖和运行条件。ripgrep 虽快且功能强,但需额外安装;cheerio 和 turndown 能保留结构,但增加依赖。当前实现适合小型仓库和快速原型,代价是搜索能力弱、网页结构丢失。读者若用于大型项目,应考虑更专业的方案。
权限与安全设计
search 通过 safePath 限制在权限根目录内,避免越权访问;fetch 默认 ask 策略,访问前显示 URL 并请求确认,且仅支持 http/https。这种设计在工具层面嵌入安全控制,防止模型随意访问外部资源或读取敏感文件。对于构建 Agent 的开发者,权限确认机制是值得借鉴的实践。
当前实现的局限性
文章明确列出未实现的功能:search 不支持正则、文件类型过滤和 .gitignore,fetch 不保留页面结构、不支持登录和 JS 渲染,且两者均无缓存。这些限制意味着工具仅适用于简单场景,复杂需求需后续扩展。读者应评估自身需求,避免过度依赖当前简化实现。
Q&A
GeekAgent Day12 新增了哪两个工具?它们分别解决什么问题?
新增了 search 和 fetch 两个工具。search 用于在仓库内按内容搜索代码,解决只知道内容但不知道在哪个文件的问题;fetch 用于抓取网页并转为纯文本,解决模型无法直接读取仓库外文档、博客等网页的问题。
search 工具是如何实现代码搜索的?为什么不直接调用 ripgrep?
search 工具使用 Node 内置的 glob 枚举文件,再用 readFile 逐行匹配关键词,返回相对路径:行号:内容。不直接调用 ripgrep 是因为 ripgrep 需要系统安装,且权限接入需要额外约束进程路径;而使用 Node 内置方法代码更直接,不增加运行条件,适合小型仓库。
fetch 工具如何将网页转为纯文本?为什么不用 HTML 解析库?
fetch 工具使用 Node 内置的 fetch 获取网页,然后通过一个简短的 htmlToText 函数删除脚本、样式、注释和 HTML 标签,并解码常见实体,保留段落换行。不用 cheerio 或 turndown 等解析库是为了不增加依赖,快速让模型读到正文,适合当前 demo。
search 和 fetch 工具在权限控制上有什么不同?
search 通过 safePath 限制在权限根目录内搜索,默认直接执行;fetch 通过 authorize 请求确认,访问外部网页前会显示完整 URL 并询问,确认后才发起请求。
search 工具返回的结果格式是什么?有哪些限制?
search 返回格式为“相对路径:行号: 内容”,最多返回 50 行。它会跳过 node_modules、隐藏目录、二进制文件和大于 1MB 的文件。
fetch 工具支持哪些协议?超时时间是多少?
fetch 只支持 http 和 https 协议,超时时间为 15 秒(FETCH_TIMEOUT_MS = 15000)。
文章中提到 search 和 fetch 有哪些未实现的功能?
search 不支持正则、文件类型过滤、结果排序,也不读取 .gitignore;fetch 只返回纯文本,不保留标题层级、链接和代码块结构,不支持需要登录或 JavaScript 渲染的页面,且两个工具都没有缓存。