原文:AI Search: the search primitive for your agents
发布时间:2026 年 4 月 16 日
作者:Gabriel Massadas、Miguel Cardoso、Anni Wang
每个 Agent 都需要搜索,但自己搭很麻烦
编码 Agent 要检索数百万个文件,客服 Agent 要搜索工单历史和内部文档,知识库 Agent 要从海量文档里找相关段落。用例各不相同,底层问题是一个:在正确的时间,把正确的信息送到模型面前。
如果自己动手搭这套搜索系统,需要的东西不少:一个向量索引、一条把文档拆分和嵌入的索引管道、一套当数据变化时保持索引更新的机制。如果同时还需要关键词搜索,那就是另一个独立的索引,加上把两套结果融合在一起的逻辑。如果每个 Agent 还需要自己独立的搜索上下文,那这整套东西得为每个 Agent 分别搭一遍。
Cloudflare 把这套基础设施打包成了一个产品:AI Search(前身是 AutoRAG),一个开箱即用的搜索原语。这次更新带来了几项核心能力:混合检索(向量 + 关键词并行)、内置存储和向量索引、运行时动态创建实例、元数据 Boost 排序,以及跨多个实例的联合查询。
接下来逐一拆解。
一个完整的例子:客服 Agent
原文给了一个完整的落地示例,读完基本就能理解 AI Search 的设计思路,值得花时间看一下。
问题设定
场景是一个客服 Agent,需要访问两类知识:
- 共享产品文档:所有 Agent 都需要,但文档量太大,塞不进上下文窗口
- 每个客户的历史解决记录:记录这个客户以前遇到过什么问题、怎么解决的,避免反复尝试已知无效的方案
这两类数据的来源和更新频率完全不同,放在一起管理并不合适。
实例结构设计
AI Search 支持在一个命名空间(namespace)里创建多个实例(instance)。针对上面的需求,结构可以这样设计:
namespace: "support"
├── product-knowledge (关联 R2 存储桶,所有 Agent 共用)
├── customer-abc123 (内置存储,按客户单独创建)
├── customer-def456 (内置存储,按客户单独创建)
└── customer-ghi789 (内置存储,按客户单独创建)
product-knowledge 是一个一次性创建的共享实例,背后挂一个 R2 存储桶,产品文档放在里面。每次有客户发起会话,就动态创建一个以该客户 ID 命名的实例:
await env.SUPPORT_KB.create({
id: `customer-${customerId}`,
index_method: { keyword: true, vector: true }
});
每个实例自带存储和向量索引,从零开始积累这个客户的历史上下文。
Agent 的工具设计
Agent 定义了两个工具,由模型自主决定什么时候调用:
工具一:搜索知识库——同时搜索共享产品文档和当前客户的历史记录,一次调用返回融合排序后的结果:
search_knowledge_base: tool({
description: "Search product docs and customer history",
execute: async ({ query }) => {
const instances = ["product-knowledge"];
if (customerId) instances.push(`customer-${customerId}`);
return await this.env.SUPPORT_KB.search({
query: query,
ai_search_options: {
boost_by: [{ field: "timestamp", direction: "desc" }],
instance_ids: instances
}
});
}
})
工具二:保存解决记录——问题处理完之后,Agent 把"发生了什么、原因是什么、怎么解决的"写进这个客户的实例,立即可被下次检索:
save_resolution: tool({
description: "Save a resolution summary after solving a customer's issue",
execute: async ({ filename, content }) => {
const instance = this.env.SUPPORT_KB.get(`customer-${customerId}`);
// uploadAndPoll 会等待索引完成,保证下次查询前已可搜索
const item = await instance.items.uploadAndPoll(filename, content);
return { saved: true, filename, status: item.status };
}
})
模型在回答之前会搜索知识库,解决问题之后会写入记录。随着对话积累,这个客户的实例里的内容越来越丰富,后续处理这个客户的问题会越来越准确。
混合检索:向量搜索和关键词搜索为什么要同时用
这次更新最核心的技术变化是加入了关键词检索(BM25),和原有的向量检索并行运行。
两种检索各有盲区
向量检索擅长理解语义意图。查询"连接建立失败",它能找到描述"connection refused"的英文文档,即便关键词完全不重叠。但它有一个弱点:会丢失具体的词。如果用户查的是错误码 ERR_CONNECTION_REFUSED,向量检索可能返回一堆关于网络故障排查的通用文档,却把那篇正好包含这个精确错误码的文档排在很后面。
**关键词检索(BM25)**填补了这个空白。BM25 根据查询词在文档里出现的频率、该词在整个语料里的稀有程度、以及文档长度来打分。"ERR_CONNECTION_REFUSED"这样罕见且具体的词,在 BM25 里权重很高,包含它的文档会被优先召回。但 BM25 反过来又会错过那些语义相关、却用了不同措辞的文档。
两者加起来,才是一个完整的检索系统。
四个可调参数
AI Search 的混合检索流程里有四个配置项:
分词器(Tokenizer):控制文档在索引时怎么被拆成可匹配的词。porter 做词干提取,"running"和"run"会被当成同一个词匹配;trigram 按字符子串匹配,"conf"可以匹配"configuration"。处理自然语言文档用 porter,处理代码用 trigram,因为代码里经常需要前缀或子串匹配。
关键词匹配模式(keyword_match_mode):AND 要求查询词全部出现在候选文档里,OR 只要有一个词匹配就进入候选集。前者精确,后者召回率更高。
结果融合方式(fusion_method):向量检索和 BM25 分别产出一份排序列表,需要合并成一个最终结果。rrf(倒数排名融合)按排名位置合并,不直接比较两套评分——因为向量相似度和 BM25 分数的量纲本就不同,直接比较没有意义。max 则取两者的较高分。
重排序(reranking,可选):在融合结果之后,用一个 cross-encoder 模型把查询和每个候选文档作为一对重新打分。这能捕捉到"词汇相关但不回答问题"的情况,把真正回答用户问题的文档排到更前面。
这四个参数都有合理的默认值,创建实例时按需配置即可:
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:在检索结果上叠加业务逻辑
检索系统给出的是"相关性",但业务上需要的往往不只是相关性。
同样是关于"选举结果"的文章,上周发布的和三年前发布的在语义上可能同样相关,但用户大概率想看最近的。这类需求靠纯检索无法满足,需要在结果排序阶段注入业务逻辑。
AI Search 支持在查询时对结果进行 Boost:按内置的时间戳字段,或者任意你自己定义的元数据字段,来调整排序权重:
const results = await instance.search({
query: "deployment guide",
ai_search_options: {
boost_by: [
{ field: "timestamp", direction: "desc" } // 时间越近排越前
]
}
});
如果你的文档有"优先级"或"来源权威性"这类自定义属性,也可以在上传时附加元数据,再在查询时按这些字段 Boost。
跨实例联合查询
在客服 Agent 的例子里,产品文档和客户历史记录分开存在不同实例里。但 Agent 回答问题时需要同时参考两者。
如果没有跨实例查询,就得分别调用两次,自己合并排序结果。AI Search 的 namespace binding 直接提供了这个能力:传入一个实例 ID 列表,得到一个跨所有实例统一排序后的结果:
const results = await env.SUPPORT_KB.search({
query: "billing error",
ai_search_options: {
instance_ids: ["product-knowledge", "customer-abc123"]
}
});
结果跨实例合并排序,Agent 不需要知道数据分布在哪里。
实例管理:新的运行时 API
旧版 AI Search(AutoRAG)的使用流程比较繁琐:先创建 R2 存储桶,再把它关联到 AI Search 实例,系统生成 Service API Token,同时在账户下创建 Vectorize 索引。上传文件需要写入 R2,然后等待一个定时同步任务跑完,文件才能被检索到。
新版彻底简化了这个流程。调用 create() 创建实例时,存储和向量索引自动随实例一起创建,不需要任何外部依赖。上传文件、等待索引、立即搜索,三步都通过同一套 API 完成:
const instance = env.AI_SEARCH.get("my-instance");
// 上传并等待索引完成
const item = await instance.items.uploadAndPoll("faq.md", content, {
metadata: { category: "onboarding" }
});
console.log(item.status); // "completed"
// 索引完成后立即可以搜索
const results = await instance.search({
messages: [{ role: "user", content: "onboarding guide" }],
});
ai_search_namespaces 是这次新增的 binding 类型,替代了之前通过 env.AI.autorag() 访问 AI Search 的方式(旧方式会继续保持兼容)。配置一行,即可在 Worker 里动态创建和删除实例:
// wrangler.jsonc
{
"ai_search_namespaces": [
{ "binding": "AI_SEARCH", "namespace": "example" }
]
}
// 运行时创建实例
await env.AI_SEARCH.create({ id: "my-instance" });
// 运行时删除实例及其所有数据
await env.AI_SEARCH.delete("old-instance");
每个实例也支持连接一个外部数据源(R2 存储桶或一个网站),并按计划定时同步,和内置存储可以同时存在。
定价与限制
AI Search 目前处于公开测试阶段,期间免费使用。网站爬取功能(基于 Browser Run)已作为内置服务包含在内,不单独计费。
| 限制项 | Workers 免费套餐 | Workers 付费套餐 |
|---|---|---|
| 每账号实例数 | 100 | 5,000 |
| 每实例文件数 | 100,000 | 100 万(混合检索为 50 万) |
| 单文件最大 | 4MB | 4MB |
| 每月查询次数 | 20,000 | 无限制 |
| 每日最大爬取页面数 | 500 | 无限制 |
测试结束后,Cloudflare 计划把 AI Search 作为一个统一服务定价,不再分别向底层组件(Vectorize、R2、Browser Run)单独收费。会在正式收费前至少提前 30 天通知。
对于此前已有的旧版实例,不受影响,继续按原有方式运行,相关存储桶、Vectorize 索引、Browser Run 用量也照常计费。迁移方案后续会另行公布。
小结
AI Search 解决的核心问题,是把"给 Agent 用的搜索基础设施"从一件需要自己搭建的事情,变成一个可以直接调用的原语。
几个值得关注的设计决策:
混合检索不是新概念,但集成进来降低了门槛。 向量检索和 BM25 各自的局限在业界已经讨论了很久,但真正在生产环境里把两套索引搭在一起、配好融合逻辑,工程量并不小。AI Search 把这件事变成了一个配置项。
"每个 Agent 一个实例"的设计思路值得注意。 运行时动态创建实例意味着搜索上下文可以做到极细的粒度——每个用户、每个会话、每个租户,都可以有完全隔离的搜索空间,而不是所有 Agent 共享一个大索引。这对多租户产品的架构影响比较大。
跨实例查询是实际工程里常见的需求。 数据按业务逻辑分开存储(共享知识 vs 个人历史),但检索时需要合并,这个模式非常普遍。有了统一的跨实例查询 API,不用自己写合并逻辑了。
参考链接
- 官方文档:developers.cloudflare.com/ai-search/
- 快速上手:
npx wrangler ai-search create my-search - 原文博客:blog.cloudflare.com/ai-search-a…
- Cloudflare 开发者 Discord:discord.cloudflare.com/