用一支 Cloudflare Worker 打通 Agent Readiness 清單

上一篇講完 isitagentready.com 的評分項目 之後,剛好就在想:這一長串檢查項目裡,真的要手動一個一個改靜態檔案、改框架路由、改 CDN 設定嗎?

其實沒必要。這些東西幾乎清一色是「特定路徑回傳特定內容」或「對回應加點 header」,天生就是邊緣層該做的事。用一支 Cloudflare Worker 掛在網域前面,十分鐘就能把清單上大部分的項目補齊。

為什麼選 Worker

三個理由:

  • 邊緣執行:所有請求都會經過,不需要動到後端應用程式。
  • 一個檔案管全部:robots.txt、llms.txt、.well-known/* 的路由、回應的 Link header 都可以在同一支 Worker 處理。
  • 好部署好改wrangler deploy 一下就上線,改完不需要重新 build 網站。

如果你的網站已經在 Cloudflare 後面,新增一支 Worker 並綁到對應的 route(例如 example.com/*)就完事。

Worker 骨架

以下是可以直接複製的起點,邏輯分成三塊:靜態檔案路由Content NegotiationLink header 注入

// worker.js
const ROBOTS_TXT = `User-agent: *
Content-signal: search=yes, ai-input=yes, ai-train=no
Allow: /

User-agent: GPTBot
Allow: /

User-agent: ClaudeBot
Allow: /

User-agent: PerplexityBot
Allow: /

Sitemap: https://example.com/sitemap.xml
`;

const LLMS_TXT = `# Example Site

> 一句話說明這個站在做什麼。

## 重要頁面
- [關於](https://example.com/about): 網站主旨與聯絡方式
- [文章列表](https://example.com/blog): 所有文章索引
`;

const API_CATALOG = {
  linkset: [{
    anchor: "https://api.example.com/v1",
    "service-desc": [{
      href: "https://example.com/openapi.json",
      type: "application/vnd.oai.openapi+json",
    }],
    "service-doc": [{
      href: "https://example.com/docs",
      type: "text/html",
    }],
  }],
};

const MCP_SERVER_CARD = {
  name: "example-mcp",
  version: "1.0.0",
  protocolVersion: "2025-11-25",
  transports: [{ type: "streamable-http", url: "https://example.com/mcp" }],
  auth: { type: "oauth2", metadata: "/.well-known/oauth-authorization-server" },
};

export default {
  async fetch(request) {
    const url = new URL(request.url);

    // 1. 靜態路由
    switch (url.pathname) {
      case '/robots.txt':
        return text(ROBOTS_TXT);
      case '/llms.txt':
        return text(LLMS_TXT, 'text/markdown');
      case '/.well-known/api-catalog':
        return json(API_CATALOG, 'application/linkset+json; profile="https://www.rfc-editor.org/info/rfc9727"');
      case '/.well-known/mcp/server-card.json':
        return json(MCP_SERVER_CARD);
    }

    // 2. 一般請求:轉發到 origin,順便做 Content Negotiation
    const originResp = await fetch(request);
    const accept = request.headers.get('accept') || '';
    const isHtml = originResp.headers.get('content-type')?.includes('text/html');

    if (isHtml && accept.includes('text/markdown')) {
      const html = await originResp.text();
      return new Response(htmlToMarkdown(html), {
        headers: { 'content-type': 'text/markdown; charset=utf-8' },
      });
    }

    // 3. HTML 回應都附上 Link header
    if (isHtml) {
      const headers = new Headers(originResp.headers);
      headers.append('Link', '</sitemap.xml>; rel="sitemap"');
      headers.append('Link', '</llms.txt>; rel="service-doc"');
      headers.append('Link', '</.well-known/api-catalog>; rel="api-catalog"');
      headers.append('Link', '</.well-known/mcp/server-card.json>; rel="mcp-server-card"');
      return new Response(originResp.body, { status: originResp.status, headers });
    }

    return originResp;
  },
};

const text = (body, ct = 'text/plain') =>
  new Response(body, { headers: { 'content-type': `${ct}; charset=utf-8` } });

const json = (body, ct = 'application/json') =>
  new Response(JSON.stringify(body, null, 2), {
    headers: { 'content-type': `${ct}; charset=utf-8` },
  });

htmlToMarkdown 這個函式我留空——實務上可以用 turndown 之類的函式庫,或直接呼叫 Cloudflare AI Gateway / Browser Run 幫你轉。自己寫也可以,抓 <main><article> 清掉 script/style 就很夠用。

NOTE — API Catalog 較穩,MCP Server Card 還在變動

這兩個常數的穩定程度不一樣,實作時要分開看:

  • API_CATALOGRFC 9727 的 Linkset JSON 格式,回應 MIME 應該是 application/linkset+json
  • MCP_SERVER_CARDSEP-1649 草案;MCP 本身已有正式規格,但 server card discovery 還不是穩定標準

API_CATALOG 已經有 RFC 可以依循;MCP_SERVER_CARD 比較像是提前把 discoverability 的洞先補起來。正式上線前,建議用最新版規範與 isitagentready.com 各跑一次,確認機器真的讀得到。

NOTE — `.well-known/*` 其實放靜態檔就好

老實講,/.well-known/api-catalog/.well-known/mcp/server-card.json 是純靜態 JSON,丟到 public/.well-known/ 給 Pages / Vercel / Netlify 之類的靜態 host 直接送是更輕的做法。

放在 Worker 主要兩個理由:

  • Content-Type 控制/.well-known/api-catalog 依 RFC 9727 沒有副檔名,多數靜態 host 預設會回 application/octet-stream,得另外設 MIME 規則;Worker 可以直接回 application/linkset+json
  • 反正 Worker 也要做別的:Content Negotiation、Link header 注入本來就要 Worker,把這兩個 endpoint 順便集中管理,邏輯一目了然

如果你的網站完全不需要 Worker(例如純 Astro / Next.js 靜態站、又不在意 MIME 設定),那這兩個 endpoint 直接擺檔案就好,不用為它們開一支 Worker。

對應到評分項目

上面這支 Worker 覆蓋到的項目:

評分項目處理方式
robots.txt直接回傳,內含 AI bot 規則與 content-signals
sitemap.xml由 origin 產生,Worker 不動
Link header對 HTML 回應 append 四組 rel
Markdown 內容看到 Accept: text/markdown 就轉譯
llms.txt直接回傳
AI Bot 規則在 robots.txt 內
Content Signalsrobots.txt 的 Content-signal directive
API Catalog/.well-known/api-catalog
MCP Server Card/.well-known/mcp/server-card.json

剩下 Web Bot Auth、OAuth Discovery、WebMCP、x402、UCP、ACP、Agent Skills 這幾項,要嘛需要跟身分認證整合、要嘛涉及實際的業務能力(電商、付款),不是 Worker 塞個檔案就能解決——這些才是真的要評估「做不做」的部分。

補充:Web Bot Auth 不要自己在 Worker 刻

上面那串裡 Web Bot Auth 特別值得拉出來講。它的核心是讓 bot 用密碼學方式向網站驗證身分,不再依賴 User-Agent 或 IP 這種容易偽造的東西。技術細節依 draft-meunier-web-bot-auth-architecture-02 草案:

  • bot 用私鑰簽請求,header 帶 Signature-InputSignatureSignature-Agent
  • 簽名包含 created / expires 時戳跟 Key ID(JWK Thumbprint)
  • 驗證端依 Signature-Agent 指向的 key directory 取得公鑰並驗章

Worker 確實有 crypto.subtle.verify 可以實作,但強烈建議直接用 Cloudflare 平台層,原因:

自己在 Worker 寫用 Cloudflare 內建
公鑰存哪裡?KV / Secrets 都不理想在 dashboard 填 key directory URL,Cloudflare 自動拉
要自己處理 key rotation、JWKS cache平台幫你維護
Replay 防護要自己設計短效簽章、必要時另存 nonceCloudflare 目前建議用短 expires 降低 replay 風險
規格還在草案,改了要重寫Cloudflare 會跟著規格升

實際操作流程(官方文件):

  1. Manage Account → Configurations → Bot Submission Form
  2. Verification Method 選 Request Signature
  3. Validation Instructions 填你的 key directory URL(裡面放 Ed25519 公鑰)
  4. https://crawltest.com/cdn-cgi/web-bot-auth 測你的簽章——回 200 表示 key 認得且驗證通過、401 可能是 key 未登錄或已登錄但驗證失敗、400 表示格式錯

如果是反過來、你要讓自己的 bot 去簽請求給別人,Cloudflare 也有 web-bot-auth npm 套件

import { signatureHeadersSync } from 'web-bot-auth';
const headers = signatureHeadersSync(request, signer, { created, expires });
INFO — Worker 適合做什麼、不適合做什麼

簡單分一下:

  • Worker 適合:HMAC 對稱簽章驗證、固定公鑰的 Ed25519 驗證、靜態檔案路由、header 改寫
  • Worker 不適合:Web Bot Auth 完整流程、OAuth JWT + JWKS rotation、跨節點 replay 防護——這些有狀態、有金鑰管理需求,交給 Bot Management / Workers OAuth Provider 之類專屬服務更穩

偷懶版:robots.txt 直接交給 Cloudflare

如果你已經是 Cloudflare 的客戶,上面 Worker 裡的 ROBOTS_TXT 那段其實不用自己維護——Cloudflare 提供 Managed robots.txt,在 dashboard 點一點就好。

操作路徑(官方文件):

  1. 進入 Cloudflare dashboard,選對應網域
  2. Security Settings → Bot traffic
  3. 開啟 Instruct AI bot traffic with robots.txt

啟用後 Cloudflare 會自動:

  • 在你網域根目錄掛上一份 robots.txt(如果原本就有,會幫你合併)
  • 對主流 AI 爬蟲寫入 Disallow: /:ClaudeBot、GPTBot、Google-Extended、Applebot-Extended、Amazonbot、Bytespider、CCBot、meta-externalagent 等
  • 預設套用 Content Signals:Content-signal: search=yes, ai-train=no(允許搜尋、禁止訓練)
  • 持續維護這份清單,新的 AI 爬蟲冒出來時自動補進去

不想顯示 Content Signals 的政策說明註解,可以在 Control AI Crawlers 區塊取消勾選 Display Content Signals Policy。目前已經有超過 380 萬個網域在用這個服務。

TIP — 那 Worker 還寫不寫

如果只是要 robots.txt,啟用 Managed robots.txt 就完事,Worker 裡那段刪掉就好。Worker 的價值在於:Markdown Content Negotiation、Link header 注入、/.well-known/* 的 JSON 回應——這些 Cloudflare dashboard 還沒包成一鍵服務的部分。

NOTE — 真的要強制阻擋請走 AI Crawl Control

robots.txt 是「禮貌請求」,技術上沒有強制力,會不會遵守由爬蟲自己決定。如果你真的要擋(例如不想被白嫖),要搭配 Cloudflare 的 AI Crawl Control,那是在邊緣層執行阻擋或收費規則,不靠對方自律。

聊聊 Cloudflare 的一盤大棋

寫到這裡會發現一件事:整份 Agent Readiness 清單裡,Cloudflare 的影子無所不在

角色Cloudflare 做的事
標準制定者Content Signals、Web Bot Auth、Agent Skills Discovery RFC 都是 Cloudflare 主推
網站端執行環境Workers、Browser Run(內建 WebMCP)、Managed robots.txt
AI 端執行環境Workers AI(全球 GPU 推論)、Cloudflare Agents(agent 本體部署)、Remote MCP Server
評分裁判isitagentready.com 本身就是 Cloudflare 推出的
商業模式AI Crawl Control、Pay Per Crawl 把 AI 爬取變成可收費的資源

去年最關鍵的補刀,是把「AI 自己」也收進來。Workers AI 在 2025 年大幅擴張,把 GPU 推論服務鋪到全球 190 多個城市,serverless 計費,模型直接在邊緣跑;同年 Cloudflare Agents 平台上線,agent 本體也能直接在 Cloudflare 上部署;今年 Agents Week 又補上 Agent Cloud(Dynamic Workers、Artifacts、Remote MCP Server、Project Think),等於宣告:

你的 agent、agent 跑的程式碼、agent 用的工具、agent 拿的資料、agent 發出的網路請求,全部我家包辦。

以前 Cloudflare 是「把你的內容送到使用者面前」的 CDN;現在要做的是「把 AI 整條生產鏈收進自己平台」。從網站要被 agent 讀的那一端、到 agent 本身在哪裡跑、到 agent 出去爬別人網站的那條路,全部都是 Cloudflare 的地盤。

這個組合非常眼熟——早期 Google 用 PageRank、Sitemap 標準、Search Console、廣告網路,差不多就是這一套。只是這次換成了 AI Agent 的世界,玩家換成了 Cloudflare,而且野心更大:Google 當年只要做搜尋的中間人;Cloudflare 想當 AI 整段流程的中間人

這不是在酸。這套組合拳會成功,是因為每一步都解決了真實的問題:

  • 網站主不知道要為 AI Agent 做什麼 → 評分工具告訴你
  • 做了也沒人知道標準長怎樣 → Cloudflare 寫 RFC
  • 寫了不知道怎麼實作 → Workers / Managed 服務包好給你
  • AI 本身要跑在哪 → Workers AI、Agents 平台直接給你 GPU 跟 runtime
  • 實作了還被 AI 白嫖 → Pay Per Crawl 讓你收錢

對一般網站主跟開發者來說,其實頗順手。但站遠一點看,Cloudflare 正在把 AI 時代的 Web 基礎設施——標準、執行、算力、計費、稽核——五個層面全部納進自己的產品線。一統天下的味道很濃。

NOTE — 為什麼這件事重要

AI Agent 的 Web 比人類瀏覽的 Web 更吃「基礎設施的默契」:agent 要靠機器可讀的 manifest 找資源、靠 well-known 路徑做發現、靠簽章驗證身分。誰掌握這些預設慣例,誰就是新的守門人。

Cloudflare 的佈局看起來就是要當這個守門人。

我的看法

短期來看,Worker 這種解法很實用:一個檔案、一次部署、覆蓋大半項目,成本低到不做白不做。如果你網站還沒在 Cloudflare 後面,多數靜態部分(robots.txt、llms.txt、.well-known/*)其實放到你原本的靜態資源目錄裡就好,不必為這件事搬家。

長期來看,值得持續觀察的是 Cloudflare 到底把多少「提案」推成了事實標準、有多少會被其他大廠(Google UCP、Coinbase x402)搶走話語權。作為開發者,現在不用急著選邊站;作為網站主,把 robots.txt 跟 llms.txt 先弄好,其他的,讓子彈飛一下。


資料來源:

相關閱讀:

留言