10 月 2 日,Cloudflare 把 Web Search API 推进公开 beta。
Agent 发一个 POST 就能搜全网,不用再猜 URL 或吃训练截止日。
真正扎眼的是价格:同一个接口,三家引擎,价差 28 倍。
默认的 Ceramic.ai 每千次0.25 美元,Exa 每千次7 美元。
Linkup 夹在中间,每千次5 美元。
Hacker News 上 546 个赞、两百多条评论,吵的不是接口而是生意。
一边封别人的爬虫,一边卖别人的索引,闭环两个字被反复提起。
这篇拆解把账单、条款和文档矛盾逐条摆开。
数字全部来自 Cloudflare 官方文档与供应商条款原文。
读完你可以自己算清 Agent 搜索到底该花多少钱。
一个 POST 三家引擎:接口长什么样
端点挂在 Cloudflare 主 API 之下,路径是 /ai/websearch/。
完整地址带账户 ID,POST 加 Bearer 令牌即可调用。
令牌需要两个权限:Workers AI 的 Read 和 AI Gateway 的 Read。
请求体只有四个字段:query、provider、limit、options。
query 最长1024 字符,这是全文唯一的输入框。
provider 是枚举,ceramic、exa、linkup 三选一。
不写 provider 就默认走 Ceramic.ai。
limit 控制返回条数,1 到 10,默认 10。
options 里必须指定 AI Gateway 的 id,每账户自带 default。
所有请求都流经 AI Gateway,这是整个设计的轴心。
搜索调用和模型推理落在同一份日志里。
计费、限流、分析、访问控制全部复用网关那一套。
响应很薄:items 数组加一段 metadata。
每条 item 只有 url、title、description 三个字段。
metadata 带 query、requestId 和 latencyMs。
没有答案生成,没有摘要拼接,原始结果直出。
Worker 里更省事,env.AI.websearch 一行搞定。
绑定方法返回标准 Response,再调一次 json 就是结果。
wrangler 配置只要声明 ai binding,不必装任何 SDK。
BYOK 也支持,把供应商密钥托管到网关的 Provider Keys。
托管密钥经 Secrets Store 加密,请求里永不出现明文。
传了 byokAlias 而网关没配置,请求直接 400,绝不回落扣费。
不传且网关存在 default 别名密钥,就静默走你自己的 key。
文档还给出工具调用范式:模型声明 web_search 工具再回填结果。
二十八倍价差买什么:三份搜索哲学
三家的差别不是质量浮动,是底层资产完全不同。
Ceramic.ai 自己养着超过400 亿页的独立索引。
这个索引从第一天就服务模型,不服务人类搜索框。
它返回的每条 description 可以长到 8000 字符。
对 Agent 来说,这几乎等于把页面正文摘要直接塞过来。
0.25 美元千次的定价,明显冲着高频调用的 Agent 场景。
一个任务跑几十次搜索的 Agent,只有这个价位扛得住。
Exa 是关键词加嵌入向量的混合索引,auto 模式自动权衡。
它返回的 description 是与查询最相关的页面高亮片段。
7 美元千次,买的是精挑摘录而不是长篇描述。
Linkup 走 fast 深度加原始结果,明确不替你生成答案。
5 美元千次,卖点是带来源的快速可信片段。
Hacker News 评论区立刻有人拉出市价对比。
serper.dev 每千次 1 美元,还送 2500 次免费额度。
OpenRouter 的搜索接口背后就是 Exa,每千次 4 美元。
同一家 Exa,经 Cloudflare 过手反而比 OpenRouter 贵 3 美元。
也有人点破:Brave 是唯一允许付费存储结果的玩家。
存储权为什么敏感,后面的条款一节会看到。
价格表值得完整摆一次,数字自己会说话。
| Provider | 千次价格 | 索引资产 | 结果描述 | ZDR |
|---|---|---|---|---|
| Ceramic.ai(默认) | $0.25 | 自建 400 亿+ 页 | 长描述,至 8000 字符 | 是 |
| Linkup | $5.00 | 全网可信片段 | fast 深度原始结果 | 是 |
| Exa | $7.00 | 关键词+嵌入混合 | auto 模式高亮摘录 | 否(见下节) |
| serper.dev | $1.00 | Google 结果 | 2500 次免费额度 | — |
| OpenRouter | $4.00 | Exa 通道 | 同 Exa | — |
注意表里 Exa 的 ZDR 一栏,那是下一节的引子。
按刊例价算账,Agent 搜索成本可以差出一个数量级。
每天 200 次查询的 Agent,月查询量约 6000 次。
走 Ceramic 月成本1.5 美元,约等于一杯豆浆。
同样的查询量走 Exa,月成本42 美元。
28 倍就是这么来的:0.25 对 7,明晃晃写在官网。
选 provider 因此不是技术偏好,而是预算决策。
零数据保留的罗生门
changelog 原文写得漂亮:三家都为经 Cloudflare 的请求提供 ZDR。
翻到 providers 文档页,Exa 那一栏却印着 No。
Hacker News 读者把两处原文并排贴出来,矛盾无从遁形。
有评论替官方解围,猜测这只是文档笔误。
但另一条评论翻出 Exa 隐私政策,称其保留训练权利。
数日过去,官方页面仍未统一口径。
ZDR 不是合规装饰品,它保护的是查询本身。
Agent 的搜索词往往暴露业务方向和未公开计划。
检索某个竞品价格这件事本身,就是商业情报。
文档打架时,采购的稳妥姿势是按 No 假设。
涉密查询走 BYOK 加自建审计,而不是赌笔误。
Ceramic 和 Linkup 两家明确标了 Yes。
它们的承诺还附带 verified bot 爬取标准背书。
值得一提,ZDR 管的是供应商侧留存。
Cloudflare 网关侧的日志留存是另一本账。
网关日志里同样躺着完整 query,留存策略另算。
敏感场景要把两本账放在一起审。
这个细节在 changelog 里没有一个字的提示。
文档团队欠读者一个勘误。
在勘误落地之前,把 Exa 当非 ZDR 用。
服务条款里埋的存储禁令
Simon Willison 在评论区抛出他的头号问题。
搜索 API 到底允不允许存下结果再分发。
答案照例埋在条款深处,不在产品页。
他翻出 Ceramic 条款禁止清单里的第 n 条。
原文禁止收集、聚合、存储、编译 Output 去建任何库。
无论这个库是否用来和 Ceramic 竞争,一律禁止。
第 o 条再补一刀:禁止转售或作为独立组件分发。
例外条款写得极其狭窄。
只能展示给授权最终用户,且必须伴随实时查询。
并且结果不得被用户或第三方单独提取下载。
有读者跟帖:可见即可提取,这个例外自相矛盾。
另一处条款禁止超出合理必要地保留与缓存结果。
Simon 评价:合理必要四个字模糊得令人恼火。
长会话里保存搜索结果,很可能就越过这条线。
对 Agent 架构这是硬约束,不是法务噪音。
你不能给 Agent 建私有搜索结果缓存层。
每次检索都要重新向卖方付费。
这恰好解释了 0.25 美元的低价策略。
低价钓高频调用,条款锁死数据沉淀。
Brave 允许存结果,但要为此付更高的价格。
存储权本身就是定价维度,这是行业明规则。
架构结论:把搜索当实时流,别当资产。
封爬虫的手与卖索引的手
更大的争议在 Cloudflare 的角色。
过去一年它用 AI Crawl Control 给 AI 爬虫扎篱笆。
默认拦截加按域名授权,站长第一次有了开关。
现在它又把三家搜索引擎的索引卖给 Agent。
入口向爬虫收钱,出口向检索收钱。
codingdave 的评论点破了仲裁者角色。
谁来判定一个请求是人、授权 bot 还是非法 bot。
Cloudflare 想三方通吃:判定者、收费者、受益者。
OutOfHere 的评论更尖锐,直接扣上反垄断帽子。
先封掉别人的爬虫,再放行自己结盟的爬虫。
有人提到 pay-to-crawl 可能抽成三成的传闻。
这个数字没有官方确认,但方向符合商业逻辑。
也有用户站出来说好话。
bayesianbot 给自家 Agent 发带限额的 Cloudflare 令牌。
几分钟就接管了几十个服务的密钥与预算。
这和我们此前拆过的硬预算帽是同一逻辑。
默认断供比事后账单有人情味得多。
信任派的理由是 Cloudflare 已是既定中间人。
多用一项服务,并不增加新的数据暴露面。
反对派搬出 FISA 702 条款与元数据风险。
网关集中化让查询日志成为单点情报源。
这场争论没有标准答案。
但采购清单里必须有仲裁者风险这一行。
基础设施越顺手,锁定就越深。
动手:带预算帽的多引擎客户端
最后把价差固化成代码,写一个带预算帽的客户端。
纯标准库实现,连 requests 都不用装。
预算检查先于网络请求执行。
超支直接抛异常,Agent 主循环捕获后自行降级。
单价表硬编码三家刊例价,换 provider 即换单价。
账户 ID 与令牌走环境变量,不落盘。
响应解析兼容网关包装与裸结果两种形态。
每条结果打印标题、链接与前 160 字符描述。
metadata 里的 latencyMs 一并输出,便于对账。
代码如下,拿到令牌即可直接运行。
import json import os import urllib.request ACCOUNT_ID = os.environ["CLOUDFLARE_ACCOUNT_ID"] API_TOKEN = os.environ["CLOUDFLARE_API_TOKEN"] ENDPOINT = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/websearch/" PRICE_PER_1K = {"ceramic": 0.25, "linkup": 5.00, "exa": 7.00} def web_search(query, provider="ceramic", limit=5, gateway="default", budget_usd=0.50, spent_usd=0.0): unit_cost = PRICE_PER_1K[provider] / 1000 if spent_usd + unit_cost > budget_usd: raise RuntimeError( f"budget exceeded: {spent_usd + unit_cost:.4f} > {budget_usd:.2f}") payload = { "query": query, "provider": provider, "limit": limit, "options": {"gateway": {"id": gateway}}, } req = urllib.request.Request( ENDPOINT, data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {API_TOKEN}", "Content-Type": "application/json", }, method="POST", ) with urllib.request.urlopen(req, timeout=30) as resp: body = json.load(resp) result = body.get("result", body) for rank, item in enumerate(result.get("items", []), 1): print(f"[{rank}] {item.get('title', '')}") print(f" {item.get('url', '')}") print(f" {str(item.get('description', ''))[:160]}") meta = result.get("metadata", {}) print(f"latency={meta.get('latencyMs')}ms cost=${unit_cost:.4f} via {provider}") return result.get("items", []), spent_usd + unit_cost if __name__ == "__main__": web_search("Cloudflare Web Search API pricing", provider="ceramic", limit=5)跑之前先建令牌:Workers AI Read 加 AI Gateway Read。
账户里预存 AI Gateway credits 即可开调。
把 budget_usd 调小,就能立刻验证超支拦截路径。
生产环境建议把 spent_usd 持久化到网关之外的账本。
记住条款约束:打印展示可以,落库建索引不行。
这个边界不是技术问题,而是法务问题。
回看整场发布,最值得带走的不是端点地址。
而是搜索从免费基础设施变成按次计费资源这件事。
28 倍价差逼着每个 Agent 团队建立自己的账本。
读条款和读接口文档,从此同等重要。