青菜年糕汤

一箪一瓢,一期一会。以文会友,以友辅仁。

2026年3月31日

让 AI 读网页这件小事 — Claude Code 源码解析

作者:林涛(青菜年糕汤)

2026 年 3 月 31 日 Claude Code 的源码被泄露,给了我们一个难得的机会去看一个生产级 AI 编程工具的内部实现。本系列逐个拆解其中的核心模块,这是第一篇。

Claude Code 的能力来自它的工具系统——65 个以上的工具各司其职,从读文件、跑命令到派生子 Agent,撑起了整个流畅的编码体验。今天我们拆开其中一个看看:WebFetchTool,让 AI 读一个网页。

一个 curl 就能干的事,它写了 1,173 行、5 个文件。权限控制、重定向拦截、HTML 转换、版权约束、二级模型摘要——每一层拆开来看,都藏着不少有意思的设计决策。

90 个域名的白名单

默认情况下 WebFetchTool 访问任何域名都需要用户手动批准。但它维护了一份约 90 个域名的预批准白名单,访问这些站点时可以直接放行。

这份名单覆盖面很广:编程语言官方文档(docs.python.orgdoc.rust-lang.org、go.dev),主流框架(react.dev、nextjs.orgfastapi.tiangolo.comlaravel.com),云服务(docs.aws.amazon.comcloud.google.comkubernetes.io),还有 Anthropic 自家的文档站点。基本上开发者日常查文档会用到的站点都在里面。

服务端黑名单预检

即使用户批准了某个域名,WebFetchTool 在发起请求之前还会向 Anthropic 的 API 做一次域名检查。这是一个服务端维护的动态黑名单,可以实时拦截恶意域名。

缓存策略有个细节:检查通过的结果缓存 5 分钟,但失败的结果不缓存。如果某个域名因为网络抖动而检查失败,下次请求时应该重试而非直接拒绝。

重定向不能自动跟

大多数 HTTP 客户端默认自动跟随重定向。但对 AI 工具来说这是一个攻击面:攻击者可以利用受信任域名上的开放重定向漏洞,把请求导向恶意站点。用户批准了 trusted.com,实际请求打到了 evil.com

WebFetchTool 关闭了自动重定向。同域跳转(包括加减 www.)自动跟随,最多 10 跳。跨域跳转不跟随,而是让模型用新 URL 重新调用 WebFetch,重新走一遍权限检查。

不直接返回网页内容

相比安全防护,我对一个 AI 工具怎么提升能力和性能更感兴趣。这个部分就跟能力和性能直接相关:网页内容不是直接返回给主模型的。

WebFetchTool 在抓取和返回之间加了一层 Haiku(Anthropic 的小快模型)做摘要。用小模型做前置过滤本身是 RAG 系统里常见的思路,但它在工具层面的具体做法有些值得注意的地方。

首先是参数设计。用户调用 WebFetch 时要提供两个参数:URL 和 prompt。这个 prompt 不是给主模型的,而是给 Haiku 的,描述“你想从这个页面提取什么”。也就是说提取方向在工具调用时就确定了,Haiku 做的是定向摘要而非通用压缩。主模型在决定调用 WebFetch 的时候就要想清楚自己需要什么信息,这比拿到整个页面再慢慢找要高效得多。

然后是选择性跳过。并非所有请求都会过 Haiku。如果内容本身是 Markdown 格式,且小于 100K 字符,就直接返回原文。这个判断很务实——技术文档站点原生提供的 Markdown 已经是结构化内容了,再过一遍摘要反而可能丢信息,还白白多一次模型调用的延迟和开销。

工具描述也是设计

WebFetchTool 只能做匿名 GET 请求,碰到 Google Docs、Confluence、Jira 这类需要登录的页面一定会失败。怎么处理这个局限?不是在代码里写 fallback,而是在工具描述里直接告诉主模型:“WebFetch 访问认证页面一定会失败,请改用对应的 MCP 工具。”模型在决定调用哪个工具之前就能避开这条死路。能力边界不藏在运行时的错误处理里,而是前置到工具的自我描述中,让模型自己做分发决策。

这句警告还有一个细节。按理说它可以更优雅地动态显示——有 MCP 认证工具可用时才提示,没有时省掉。但源码里没有这么做。注释解释了原因:工具描述是 system prompt 的一部分,如果在两次 API 调用之间发生变化,会导致 Anthropic API 的 prompt cache 失效。每次切换意味着连续两次缓存未命中。为了保住缓存命中率,宁可永远带着这句话,哪怕有时候多余。

摘要中的版权约束

开篇提到的那份 90 个域名的白名单,其实不只用于访问权限的判定,还用于版权约束的分级。

对白名单内的域名,Haiku 可以自由引用原文、包含完整代码示例。但对白名单外的域名,Haiku 收到的指令包含严格约束:单次引用不超过 125 个字符,必须用引号标注原文,禁止复制歌词。

在一个主要服务于编程场景的 Agent 里看到”禁止复制歌词”,不禁让人好奇 Anthropic 的法务部门经历过什么。

我本以为这份白名单跟我无关——常年用 bypass permissions 模式,不管在不在白名单都会跳过权限确认直接访问。但版权约束不在权限层,而在内容处理层,bypass permissions 穿透不了它。白名单在这里仍然生效。

HTML 转换和缓存

抓回来的 HTML 用 Turndown 库转成 Markdown。Turndown 占 1.4MB 堆内存,所以做成了懒加载单例:第一次抓网页时才 import,之后复用同一个实例。毕竟不是每次对话都需要读网页,没必要启动就加载。

转换后的内容会被缓存。同一个 URL 在 15 分钟内再次请求就直接返回缓存结果,缓存总量上限 50MB。

还有一个内存管理的小细节:HTTP 响应体最大 10MB,而 Turndown 把 HTML 转成 DOM 树时,内存占用可能膨胀到原始大小的 3-5 倍。源码在拿到响应体之后、交给 Turndown 之前,会立即把 axios 持有的 ArrayBuffer 引用置为 null,让 GC 尽早回收这块内存,避免两份数据同时驻留导致峰值翻倍。

彩蛋:x402 微支付

源码中有一段对 HTTP 402 的处理:当目标网站返回 Payment Required 并携带 x402 协议头时,WebFetchTool 会尝试自动完成微支付并重试请求。这个功能目前通过 feature flag 控制,但它暗示了一个有趣的方向——AI 工具自主为获取信息付费。

想象一下,未来一个 Agent 在执行任务时碰到一篇标价 0.01 美元的付费技术文档,算了算觉得比自己花更多 token 去研究划算,就自动付费拿到内容。甚至可以做得更好:让 Agent 先读,读完确认有用再付费——像 Anthropic 这样的中心化大公司完全有能力做信用担保,让内容提供方接受这种“先看后买”的模式。

以上就是对 WebFetchTool 这 1,173 行代码的解析。Claude Code 的源码里还有很多值得聊的东西,下次再继续。