訂閱以接收新文章的通知:

AI Search:適用於智慧體的搜尋基元

2026-04-16

閱讀時間:7 分鐘
本貼文還提供以下語言版本:English日本語한국어简体中文

每個智慧體都需要搜尋功能:編碼智慧體需要在數百萬個儲存庫檔案中搜尋,客服智慧體則需要查找客戶工單與內部文件。使用情境各不相同,但根本問題是一樣的:在正確的時機將正確的資訊提供給模型。

如果您要自己打造搜尋功能,就需要向量索引、能夠剖析並切割文件的索引管線,還需要一套機制在資料變更時更新索引。若需關鍵字搜尋,則需額外建立獨立索引與融合邏輯。而如果您的每個智慧體都需要自己專屬的可搜尋脈絡,您就得為每個智慧體重複設定這一切。

AI Search(原名 AutoRAG)就是您所需的隨插即用搜尋基礎組件。您可以動態建立執行個體、輸入資料,然後開始搜尋——無論透過 Worker、Agents SDK 或 Wrangler CLI 皆可。以下是我們推出的功能:

  • 混合搜尋。單一查詢同時啟用語義與關鍵字比對。向量搜尋與 BM25 並行執行,結果自動融合。(本部落格的搜尋功能現在由 AI Search 驅動,請點擊右上方放大鏡圖示體驗。)

  • 內建儲存與索引。新的執行個體會自帶儲存空間與向量索引。您可以直接透過 API 上傳檔案到某個執行個體,系統就會自動建立索引。無需額外設定 R2 儲存桶,也不必先連接外部資料來源。新的 ai_search_namespaces 繫結讓您可以從 Worker 在執行期間動態建立、刪除執行個體,因此您可以為每個智慧體、每位客戶、每種語言分別建立一個執行個體,而無需重新部署。

現在,您還可以為文件附加中繼資料,並在查詢時用來提升排名,也能在單一呼叫中跨多個執行個體進行查詢。

接下來,讓我們透過實際案例,深入探討這些功能究竟意味著什麼。

實際應用:客戶支援智慧體

讓我們來看看客服智慧體,它需要搜尋兩種知識:一種是共用產品文件,另一種是每個客戶的歷程記錄(例如過去解決過的案例)。產品文件內容太多,無法全部塞進脈絡視窗,而每位客戶的歷程記錄會隨著每次解決問題而不斷累積,所以智慧體必須透過擷取來找出相關內容。

以下展示如何透過 AI Search 與 Agents SDK 實現此場景。首先,建立一個專案架構:

npm create cloudflare@latest -- --template cloudflare/agents-starter

首先,將 AI Search 命名空間繫結到您的 Worker:

// wrangler.jsonc 
{
  "ai_search_namespaces": [
    { "binding": "SUPPORT_KB", "namespace": "support" }
  ],
  "ai": { "binding": "AI" },
  "durable_objects": {
    "bindings": [
      { "name": "SupportAgent", "class_name": "SupportAgent" }
    ]
  }
}

假設您的共用產品文件存放在名為 product-doc 的 R2 儲存桶中。您可以在 Cloudflare 儀表板的 support 命名空間底下,建立以該儲存桶為基礎的一次性 AI Search 執行個體(命名為 product-knowledge):

BLOG-3240 2

這將成為所有智慧體皆可參照的共用知識庫。

當客戶回報新問題時,若知道之前已經嘗試過哪些解法,就能為每個人節省時間。您可以為每位客戶建立一個 AI Search 執行個體來記錄這些資訊。每次解決問題後,智慧體會把問題原因與解決方法儲存下來。隨著時間累積,就會形成可供搜尋的歷史解決紀錄。您可以透過命名空間繫結來動態建立執行個體:

// create a per-customer instance when they first show up 
await env.SUPPORT_KB.create({
  id: `customer-${customerId}`,
  index_method:{ keyword: true, vector: true }
});

每個執行個體都擁有自己的內建儲存空間與向量索引,由 R2Vectorize 提供支援。執行個體一開始是空的,然後隨著脈絡資訊不斷累積。下次該客戶再來詢問時,所有歷程記錄皆可供搜尋。

以下是在幾個客戶之後,命名空間的樣貌:

namespace: "support"
├── product-knowledge     (R2 as source, shared across all agents)
├── customer-abc123       (managed storage, per-customer)
├── customer-def456       (managed storage, per-customer)
└── customer-ghi789       (managed storage, per-customer)

接著是智慧體本身。其延伸自 Agents SDK 的 AIChatAgent 並定義兩種工具。我們透過 Workers AI,將 Kimi K2.5 用作 LLM,由模型根據對話內容判斷何時呼叫工具:

import { AIChatAgent, type OnChatMessageOptions } from "@cloudflare/ai-chat";
import { createWorkersAI } from "workers-ai-provider";
import { streamText, convertToModelMessages, tool, stepCountIs } from "ai";
import { routeAgentRequest } from "agents";
import { z } from "zod";

export class SupportAgent extends AIChatAgent<Env> {
  async onChatMessage(_onFinish: unknown, options?: OnChatMessageOptions) {
    // the client passes customerId in the request body
    // via the Agent SDK's sendMessage({ body: { customerId } })
    const customerId = options?.body?.customerId;

    // create a per-customer instance when they first show up.
    // each instance gets its own storage and vector index.
    if (customerId) {
      try {
        await this.env.SUPPORT_KB.create({
          id: `customer-${customerId}`,
          index_method: { keyword: true, vector: true }
        });
      } catch {
        // instance already exists
      }
    }

    const workersai = createWorkersAI({ binding: this.env.AI });

    const result = streamText({
      model: workersai("@cf/moonshotai/kimi-k2.5"),
      system: `You are a support agent. Use search_knowledge_base
        to find relevant docs before answering. Search results
        include both product docs and this customer's past
        resolutions — use them to avoid repeating failed fixes
        and to recognize recurring issues. When the issue is
        resolved, call save_resolution before responding.`,
      // this.messages is the full conversation history, automatically
      // persisted by AIChatAgent across reconnects
      messages: await convertToModelMessages(this.messages),
      tools: {
        // tool 1: search across shared product docs AND this
        // customer's past resolutions in a single call
        search_knowledge_base: tool({
          description: "Search product docs and customer history",
          inputSchema: z.object({
            query: z.string().describe("The search query"),
          }),
          execute: async ({ query }) => {
            // always search product docs;
            // include customer history if available
            const instances = ["product-knowledge"];
            if (customerId) {
              instances.push(`customer-${customerId}`);
            }
            return await this.env.SUPPORT_KB.search({
              query: query,
              ai_search_options: {
                // surface recent docs over older ones
                boost_by: [
                  { field: "timestamp", direction: "desc" }
                ],
                // search across both instances at once
                instance_ids: instances
              }
            });
          }
        }),

        // tool 2: after resolving an issue, the agent saves a
        // summary so future agents have full context
        save_resolution: tool({
          description:
            "Save a resolution summary after solving a customer's issue",
          inputSchema: z.object({
            filename: z.string().describe(
              "Short descriptive filename, e.g. 'billing-fix.md'"
            ),
            content: z.string().describe(
              "What the problem was, what caused it, and how it was resolved"
            ),
          }),
          execute: async ({ filename, content }) => {
            if (!customerId) return { error: "No customer ID" };
            const instance = this.env.SUPPORT_KB.get(
              `customer-${customerId}`
            );
            // uploadAndPoll waits until indexing is complete,
            // so the resolution is searchable before the next query
            const item = await instance.items.uploadAndPoll(
              filename, content
            );
            return { saved: true, filename, status: item.status };
          }
        }),
      },
      // cap agentic tool-use loops at 10 steps
      stopWhen: stepCountIs(10),
      abortSignal: options?.abortSignal,
    });

    return result.toUIMessageStreamResponse();
  }
}

// route requests to the SupportAgent durable object
export default {
  async fetch(request: Request, env: Env) {
    return (
      (await routeAgentRequest(request, env)) ||
      new Response("Not found", { status: 404 })
    );
  }
} satisfies ExportedHandler<Env>;

如此一來,模型將自主決定搜尋與儲存的時機。搜尋時,它會同時查詢 product-knowledge 與該客戶的歷史解決紀錄。當問題解決後,它會儲存一份摘要,這份摘要就會在未來對話中立即成為可搜尋的內容。

AI Search 如何精準定位您所需的資訊

在技術底層,AI Search 運作著一個可設定的多步驟擷取流程。

混合搜尋:同時理解意圖與比對詞彙

先前 AI Search 僅提供向量搜尋功能。向量搜尋擅長理解查詢意圖,但可能遺漏具體細節。以查詢「ERR_CONNECTION_REFUSED timeout」為例,嵌入向量能擷取「連線失敗」的廣泛概念,但使用者實際需要的是包含「ERR_CONNECTION_REFUSED」這一特定錯誤字串的文件。純向量搜尋可能傳回通用的疑難排解文件,卻錯失包含確切錯誤字串的頁面。

關鍵字搜尋正可彌補此缺口。AI Search 現已支援 BM25,這是業界最廣泛採用的擷取評分函式之一。BM25 根據查詢詞彙出現頻率、詞彙在整體文件集的稀有程度,以及文件長度進行評分。它能獎勵特定詞彙的比對結果,濾除常見虛詞,並根據文件長度正規化評分。當您搜尋「ERR_CONNECTION_REFUSED timeout」時,BM25 能準確找出包含該錯誤碼的文件。然而,BM25 演算法也可能遺漏某些關於「網路連線疑難排解」的頁面,儘管這些頁面所描述的問題可能與您的查詢內容完全一致。這正是向量搜尋的優勢所在,也彰顯兩者並用的必要性。

啟用混合搜尋後,系統將並行執行向量與 BM25,融合結果並可選擇性進行重新排序:

BLOG-3240 3

讓我們來看看 BM25 的新設定,以及它們是如何協同運作的。

  1. 分詞器 (Tokenizer) 控制在建立索引時,如何將您的文件切割成可被比對的詞彙。Porter 詞幹提取器(選項:porter)會將單詞還原為詞幹,使「running」與「run」相符。Trigram(選項:trigram)會比對字元子字串,使「conf」與「configuration」相符。您可以對文件等自然語言內容使用 porter,對需要部分比對的程式碼使用 trigram。

  2. 關鍵字比對模式 (Keyword match mode) 控制在查詢時,哪些文件會成為 BM25 評分的候選項目。AND 要求文件中必須出現所有查詢詞彙;OR 則會納入任何至少有一個詞彙相符的文件。

  3. 融合 (Fusion) 控制在查詢時,如何將向量結果與關鍵字結果合併成最終的結果清單。互補排名融合(選項:rrf)會根據排名位置而非分數來合併,避免比較兩種不相容的評分尺度;而最大值融合(選項:max)則會取較高的分數。

  4. (選用)重新排序 (Reranking) 會額外加入一個交叉編碼器步驟,將查詢與文件搭配成對來重新評分。這有助於捕捉那些結果雖然包含正確詞彙,但實際上並未回答問題的情況。

在使用者省略不填時,所有選項皆有合理的預設值。您可在建立新執行個體時,根據需求靈活設定重要參數:

const instance = await env.AI_SEARCH.create({
  id: "my-instance",
  index_method: { keyword: true, vector: true },
  indexing_options: {
    keyword_tokenizer: "porter"
  },
  retrieval_options: {
    keyword_match_mode: "or"
  },
  fusion_method: "rrf",
  reranking: true,
  reranking_model: "@cf/baai/bge-reranker-base"
});

提升相關性:揭示重要內容

擷取機制能獲取相關結果,但僅有關聯性往往不足。在新聞搜尋中,上週的文章和三年前的文章可能都與「選舉結果」語意相關,但大多數使用者可能想要的是最近的那一篇。透過提升功能,您可以在擷取結果之上疊加業務邏輯,根據文件的中繼資料來微調排名。

您可以根據時間戳記(內建於每個項目之中)或任何您自訂的中繼資料欄位來進行提升。

// boost high priority docs
const results = await instance.search({
  query: "deployment guide",
  ai_search_options: {
    boost_by: [
      { field: "timestamp", direction: "desc" }
    ]
  }
});

跨執行個體搜尋:突破邊界的查詢

在客服智慧體的範例中,產品文件與客戶歷史解決記錄是刻意存放在不同執行個體中的。但是當智慧體在回答問題時,它需要同時從兩個來源取得情境資訊。如果沒有跨執行個體搜尋,您就必須分別呼叫兩次,然後自己合併結果。

命名空間繫結提供了一個 search() 方法來為您處理這件事。傳入一個執行個體名稱的陣列,就能得到一份經過合併排名後的結果清單:

const results = await env.SUPPORT_KB.search({
  query: "billing error",
  ai_search_options: {
    instance_ids: ["product-knowledge", "customer-abc123"]
  }
});

結果會跨執行個體進行合併與排名。智慧體不需要知道(也不需要關心)共用文件與客戶歷史解決記錄存放在不同地方這件事。

AI Search 執行個體如何運作

我們前面已探討 AI Search 如何找到正確的結果。現在來看看您如何建立與管理自己的搜尋執行個體。

如果您在此次發布前就已經使用過 AI Search,您應該知道原本的設定方式:建立一個 R2 儲存桶、將它連結到 AI Search 執行個體,AI Search 會為您產生一組服務 API 權杖,然後您再管理系統為您佈建在帳戶中的 Vectorize 索引。上傳物件時,您需要先寫入 R2,然後等待同步工作執行,該物件才能成功編入索引。

現在新建立的執行個體運作方式已經不同。當您呼叫 create() 時,該執行個體會自帶內建的儲存空間與向量索引。您可以直接上傳檔案,檔案會立即被送入索引,而且您可以透過同一個 uploadAndPoll() API 來輪詢索引狀態。一旦完成,您就能立刻搜尋該執行個體,完全不需要再另外接線各種外部依賴項。

const instance = env.AI_SEARCH.get("my-instance");

// upload and wait for indexing to complete
const item = await instance.items.uploadAndPoll("faq.md", content, {
  metadata: { category: "onboarding" }
});
console.log(item.status); // "completed"

// immediately search after indexing is completed
const results = await instance.search({
  // alternative way to pass in users' query other than using parameter query 
  messages: [{ role: "user", content: "onboarding guide" }],
});

每個執行個體還可以連接到一個外部資料來源(例如一個 R2 儲存桶或一個網站),並依照排程進行同步。這項功能可以與內建儲存空間並存。在客服智慧體的範例中,product-knowledge 由 R2 儲存桶提供支援,用於存放共用文件;而每位客戶的執行個體則使用內建儲存空間,用於存放即時上傳的脈絡資訊。

名稱空間:在執行時期建立搜尋執行個體

ai_search_namespaces 是一種全新的繫結,您可以利用它在執行時期動態建立搜尋執行個體。它取代了先前的 env.AI.autorag() API(後者是透過 AI 繫結來存取 AI Search)。舊的繫結將透過 Workers 相容性日期設定繼續運作。

// wrangler.jsonc 
{
  "ai_search_namespaces": [
    { "binding": "AI_SEARCH", "namespace": "example" },
  ]
}

命名空間繫結提供了命名空間層級的 API,例如 create()delete()list()search()。如果您需要動態建立執行個體(例如為每個智慧體、每位客戶或每個租用戶分別建立),此即為適用方案。

// create an instance 
const instance = await env.AI_SEARCH.create({
  id: "my-instance"
});

// delete an instance and all its indexed data
await env.AI_SEARCH.delete("old-instance");

新執行個體的定價

即日起建立的新執行個體,會自動獲得內建儲存空間與向量索引。

在 AI Search 公開測試期間,這些執行個體可免費使用,並適用下列限制。當使用網站作為資料來源時,透過 Browser Run(原為 Browser Rendering)進行的網站爬取現已成為內建服務,代表不會另行計費。測試版結束後,我們的目標是為 AI Search 提供統一的單一服務定價,而不是針對底層各個元件分別計費。Workers AI 與 AI Gateway 的使用則會繼續維持分別計費。

在開始任何計費之前,我們會提前至少 30 天通知,並公布定價細節。

限制

Workers Free

Workers Paid

每個帳戶的 AI Search 執行個體數量

100

5,000

每個執行個體的檔案數

100,000

100 萬(混合搜尋為 50 萬)

檔案大小上限

4MB

4MB

每月查詢數

20,000

無限

每天爬取頁面數上限

500

無限

既有執行個體的處理方式

如果您在此次發布前就已經建立執行個體,這些執行個體會維持原本的運作方式,不受影響。您的 R2 儲存桶、Vectorize 索引及 Browser Run 用量仍然會留在您的帳戶中,並按照先前的方式計費。我們將會儘快提供現有執行個體的遷移細節。

立即開始使用

搜尋是智慧體最基礎的功能之一。有了 AI Search,您無需自行打造基礎架構。建立執行個體、輸入資料,即可讓您的智慧體開始進行搜尋。

立即執行以下指令建立您的第一個執行個體:

npx wrangler ai-search create my-search

歡迎查閱技術文件,並前往 Cloudflare 開發人員 Discord 社群分享您的建置成果。

BLOG-3240 4

我們保護整個企業網路,協助客戶有效地建置網際網路規模的應用程式,加速任何網站或網際網路應用程式抵禦 DDoS 攻擊,阻止駭客入侵,並且可以協助您實現 Zero Trust

從任何裝置造訪 1.1.1.1,即可開始使用我們的免費應用程式,讓您的網際網路更快速、更安全。

若要進一步瞭解我們協助打造更好的網際網路的使命,請從這裡開始。如果您正在尋找新的職業方向,請查看我們的職缺
Agents Week代理程式AI 搜尋AI

在 X 上進行關注

Anni Wang|/aninibread
Cloudflare|@cloudflare

相關貼文

2026年4月30日

Agents can now create Cloudflare accounts, buy domains, and deploy

Starting today, agents can now be Cloudflare customers. They can create a Cloudflare account, start a paid subscription, register a domain, and get back an API token to deploy code right away. Humans can be in the loop to grant permission, but there’s no need to go to the dashboard, copy and paste API tokens, or enter credit card details. ...

2026年4月20日

The AI engineering stack we built internally — on the platform we ship

We built our internal AI engineering stack on the same products we ship. That means 20 million requests routed through AI Gateway, 241 billion tokens processed, and inference running on Workers AI, serving more than 3,683 internal users. Here's how we did it. ...