为 Agent 提供 web_fetch tool 以读取 URL。Agents SDK 处理 HTTP 请求周边工作:将文档转换为可读文本、将长页面拆成更小的结果,并控制模型可以 fetch 的 URL。
将提供的 adapter 与 Pi Durable、AI SDK 或 TanStack AI 一起使用。对于其他 harness,使用 agents/webfetch 中公开的 fetch、分页和格式化函数。
研究型 Agent 可能需要读取网页、PDF 报告和 JSON feed。web_fetch 不会把每个响应体直接返回给模型,而是处理每种格式,并提供它所读取内容的上下文。
| 任务 | web_fetch 的做法 |
|---|---|
| 读取网页和文档 | 通过 Workers AI Markdown Conversion 将 HTML、PDF 和支持的 Office 文档转换为 Markdown。 |
| 优先使用 Markdown | 先请求 Markdown。支持 Markdown for Agents 的站点可直接返回 Markdown,无需转换。 |
| 读取结构化数据 | 美化打印 JSON,并原样传递 Markdown 和其他文本格式。 |
| 读取长页面 | 返回有界的内容窗口,并提供用于读取下一部分的 offset。 |
| 理解响应 | 包含最终 URL、HTTP 状态、内容类型、总字符数和续读信息。 |
| 控制请求 | 应用你的主机限制、重定向检查、字节上限和超时。遵循 harness 的取消。 |
| 从错误中恢复 | 指导模型修正输入、重试或改用其他来源,并为你的应用提供结构化错误。 |
这些示例需要 Agents SDK 0.28.0 或更高版本,以及已有的 harness。要新建 Pi Durable Agent,请从 Pi harness 指南开始。
-
在 Worker 项目中更新 Agents SDK:
npm i agents@latestyarn add agents@latestpnpm add agents@latestbun add agents@latest -
在 Wrangler 配置中添加 Workers AI 绑定(binding),用于 HTML 和文档转换:
{ "$schema": "./node_modules/wrangler/config-schema.json", "ai": { "binding": "AI", "remote": true } }[ai] binding = "AI" remote = true该 tool 使用 Worker 的
fetch检索 URL。Markdown、JSON 和纯文本会跳过 Workers AI 转换。本地开发期间的转换会针对你的 Cloudflare 账户远程运行。 -
使用后续示例之一,向 harness 注册该 tool。
在 Pi harness factory 中,在将其传给 Harness.open() 之前,把 tool 安装到 registry:
import { webFetchTool } from "agents/webfetch/pi";
// Inside the harness factory, before Harness.open():
this.registry.install({
name: "web-tools",
tools: [webFetchTool({ binding: this.env.AI })],
});import { webFetchTool } from "agents/webfetch/pi";
// Inside the harness factory, before Harness.open():
this.registry.install({
name: "web-tools",
tools: [webFetchTool({ binding: this.env.AI })],
});让 Agent 读取 URL,例如文档页面或 PDF 报告。模型可以用 url 调用 web_fetch,然后传入建议的续读 offset 以读取更多内容。
Pi tool 标记为 replay: "safe"。session 恢复时,Pi 会重新运行因 evict 而中断的 fetch。已完成的结果会保留存储,恢复期间不会再次 fetch。取消正在运行的调用时,该 tool 也会遵循 Pi 的 abort signal。
将 tool 添加到现有 streamText() 或 generateText() 调用的 tools 对象:
import { streamText } from "ai";
import { webFetchTool } from "agents/webfetch/ai-sdk";
const tools = {
web_fetch: webFetchTool({ binding: env.AI }),
};
const result = streamText({ model, messages, tools });import { streamText } from "ai";
import { webFetchTool } from "agents/webfetch/ai-sdk";
const tools = {
web_fetch: webFetchTool({ binding: env.AI }),
};
const result = streamText({ model, messages, tools });若你自行转换 UI messages,请将相同的 tools 传给 convertToModelMessages(messages, { tools })。这样模型在读取先前结果时会保留格式化的 header 和 untrusted-content wrapper。
将服务端 tool 添加到现有 chat() 调用:
import { chat } from "@tanstack/ai";
import { webFetchTool } from "agents/webfetch/tanstack-ai";
const stream = chat({
adapter,
messages,
tools: [webFetchTool({ binding: env.AI })],
});import { chat } from "@tanstack/ai";
import { webFetchTool } from "agents/webfetch/tanstack-ai";
const stream = chat({
adapter,
messages,
tools: [webFetchTool({ binding: env.AI })],
});在 harness 的 tool handler 内使用 fetchWeb()。它返回完整转换后的页面。使用 windowWebFetchPage() 和 renderWebFetchPage(),向模型提供与内置 adapter 相同的有界结果:
import {
fetchWeb,
renderWebFetchPage,
windowWebFetchPage,
} from "agents/webfetch";
// Register this handler with your harness's tool interface.
// Forward the harness's cancellation signal when it provides one.
async function readUrl(input, env, signal) {
const page = await fetchWeb(
{ url: input.url, format: input.format },
{ binding: env.AI, signal },
);
const output = windowWebFetchPage(page, {
offset: input.offset,
pageChars: 20_000,
});
return renderWebFetchPage(output);
}import {
fetchWeb,
renderWebFetchPage,
windowWebFetchPage,
type WebFetchToolInput,
} from "agents/webfetch";
// Register this handler with your harness's tool interface.
// Forward the harness's cancellation signal when it provides one.
async function readUrl(
input: WebFetchToolInput,
env: { AI: Ai },
signal?: AbortSignal,
) {
const page = await fetchWeb(
{ url: input.url, format: input.format },
{ binding: env.AI, signal },
);
const output = windowWebFetchPage(page, {
offset: input.offset,
pageChars: 20_000,
});
return renderWebFetchPage(output);
}用必填的 url、可选的非负整数 offset,以及可选的 "auto" 或 "raw" format 定义 tool 的输入 schema。将 WebFetchError 映射到 harness 的错误结果。这些函数不需要 Durable Object、浏览器或 Worker Loader 绑定。
默认情况下,模型每次调用最多收到 20,000 个字符。每个结果包含 header,并将内容包在 untrusted_web_content 标签中:
web_fetch: https://example.com/report · 200 · text/html → markdown · chars 0–19873 of 81200 · continue with offset=19873
<untrusted_web_content>
# Report
...
</untrusted_web_content>模型使用结果中的 offset 继续读取,该 offset 可能停在换行处。你的应用会在结构化输出中收到 nextOffset,到达末尾时为 null。Pi 将该输出存储在 details.output 中;AI SDK 从 execute 返回它。TanStack AI 返回格式化文本。
内置 source 会为每次 tool 调用再次 fetch URL。读取五个窗口就会进行五次 fetch,两次调用之间内容可能变化。要复用已 fetch 的页面,请保留 fetchWeb() 返回的 WebFetchPage,再用下一个 offset 调用 windowWebFetchPage()。
wrapper 将外部内容标记为数据而非指令。它不能保证抵御 prompt injection。
模型选择 url、offset 和 format。你的应用在创建 tool 时选择请求策略和限制:
import { webFetchTool } from "agents/webfetch/pi";
const readDocs = webFetchTool({
binding: env.AI,
allowedHosts: ["developers.cloudflare.com"],
pageChars: 10_000,
maxBytes: 1_000_000,
timeoutMs: 15_000,
maxRedirects: 3,
});import { webFetchTool } from "agents/webfetch/pi";
const readDocs = webFetchTool({
binding: env.AI,
allowedHosts: ["developers.cloudflare.com"],
pageChars: 10_000,
maxBytes: 1_000_000,
timeoutMs: 15_000,
maxRedirects: 3,
});| 选项 | 默认值 | 效果 |
|---|---|---|
pageChars |
20000 |
一次 tool 结果内容窗口的最大字符数。 |
maxBytes |
5000000 |
拒绝前读取的最大响应体字节数。 |
timeoutMs |
30000 |
以毫秒计的截止时间,包括重定向和转换。 |
maxRedirects |
5 |
最多跟随的重定向次数。接受 0 到 20 的整数。 |
allowedHosts |
任何公开主机 | tool 可以 fetch 的主机名。*.example.com 匹配子域,但不匹配 example.com 本身。 |
blockedHosts |
无 | tool 必须拒绝的主机名,在 allowedHosts 之前检查。 |
allowPrivateHosts |
false |
设为 true 时允许本地和私有主机,用于本地开发。 |
内置 source 会检查每个 URL 和重定向目标。它会拒绝非 HTTP scheme、URL 中的凭据、超过 2,000 个字符的 URL,以及 HTTPS 到 HTTP 的重定向。默认会阻止私有 IP 字面量和本地主机名,但不会通过 DNS 解析来检查公开主机名背后的地址。
要添加缓存或使用不同的检索服务,请通过 source 选项提供 WebFetchSource,而不是 binding。自定义 source 负责 URL 验证、主机限制、字节上限和重定向处理。tool 仍会应用 pageChars 和 timeoutMs。你可以包装 createDirectWebFetch() 以保留内置请求策略。
可读的 HTTP 错误页面会随其状态一起返回。Fetch 失败使用 WebFetchError 代码,例如 web_fetch_timeout、web_fetch_too_large 和 web_fetch_unsupported_content_type,并带有 retryable 字段。Pi 在 details 中以 ok: false 返回失败;AI SDK 和 TanStack AI adapter 会抛出 WebFetchError。取消会作为 abort 传播,而不是 fetch 失败。
使用 format: "raw" 可在不转换的情况下读取文本响应体。raw 模式无法返回 PDF 或其他二进制文档内容。不支持图片、音频和视频。
当 Agent 需要 JavaScript 渲染的内容、登录 session、屏幕截图或交互时,使用 Browser。Web fetch 会发出不带浏览器 cookie、凭据或自定义请求标头的 GET 请求。检测到 bot 挑战时会返回 web_fetch_blocked,并建议模型使用浏览器或其他来源。