Cloudflare AI Search 生产级实战模式:从 search() 到多租户、流式与重排的完整指南
【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills
本篇指南以cloudflare-deploy技能库中 patterns.md 为骨架,系统讲解 Cloudflare AI Search(原 AutoRAG,托管式语义检索与 RAG 服务)在生产环境中的核心使用模式:search()与aiSearch()的方法选型、基于文件夹的多租户隔离、流式响应、评分阈值调优、System Prompt 模板、复合过滤与重排序。读完本文,你将能在 Cloudflare Workers 中独立搭建一套可用于文档问答、企业知识库与多租户 SaaS 场景的检索增强生成管线。
一、模式总览:何时用哪个方法
AI Search 的核心 API 通过 Workers 上的env.AI.autorag("实例名")暴露两种检索方法,二者返回内容与适用场景截然不同,是后续所有模式的基础:
| 适用场景 | 方法 | 返回值 | 典型延迟 |
|---|---|---|---|
| 自定义 UI、数据分析 | search() | 仅原始分块(Raw chunks) | 约 100–300ms |
| 聊天机器人、问答 | aiSearch() | AI 生成回答 + 检索分块 | 约 500–2000ms |
// 仅获取检索结果,自己渲染 UI 或做统计 const results = await env.AI.autorag("my-search-instance").search(options); // 直接获得 AI 回答(内部自动完成检索 + 生成) const answer = await env.AI.autorag("my-search-instance").aiSearch(options);选择建议:
- 需要最终答案(聊天、Q&A、客服助手)→ 用
aiSearch(),返回的response字段即为生成结果,data字段附带检索到的分块,可同时用于"回答 + 引用来源"; - 需要原始检索结果(自建结果页、埋点分析、对 chunk 二次加工)→ 用
search(),延迟更低、不消耗 LLM 生成。
从 api.md 可见,aiSearch()返回结构为{ search_query, response, data, has_more, next_page },其中search_query是实际用于检索的查询词(开启rewrite_query后可能是改写后的版本),data中每条SearchResult包含id、score、content以及metadata: { filename, folder, timestamp }。这正是"回答 + 证据"模式的数据基础。
二、查询改写:rewrite_query 的正确开关
rewrite_query控制是否让 LLM 先对用户查询做改写(纠错、补全、语义归一)再执行检索:
| 设置 | 使用时机 |
|---|---|
true | 用户输入(可能含拼写错误、含糊查询) |
false | LLM 生成的查询(已经过优化) |
const answer = await env.AI.autorag("docs").aiSearch({ query: "how do i configre cachign?", // 拼写错误场景 model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast", rewrite_query: true });关键注意点(结合 api.md):
- 默认值为
false,不是true。如果你的用户输入质量参差,务必显式开启; - 当你的上层 Agent 或 LLM 已经生成精确查询时,开启改写反而会引入额外延迟甚至改变语义,此时保持
false; - 开启后,响应中的
search_query字段会反映改写后的查询词,可用于日志与排障。
三、多租户隔离:基于文件夹的前缀过滤
AI Search 自动索引的内容会带上folder元数据(见 configuration.md 中"Auto-indexed metadata"说明)。多租户场景下,让每个租户的文档位于独立目录(如tenants/{tenantId}/),再用过滤器做"前缀匹配"即可实现逻辑隔离,无需为每个租户建实例:
const answer = await env.AI.autorag("saas-docs").aiSearch({ query: "refund policy", model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast", filters: { column: "folder", operator: "gte", // "starts with" pattern value: `tenants/${tenantId}/` } });这里有两个容易被忽略的实现细节(见 gotchas.md):
- 文件夹前缀匹配必须用
gte而非eq:gte(大于等于)在字符串比较语义下能命中tenants/abc/...的全部嵌套子路径,实现"以该前缀开头的所有文件";若用eq只能精确匹配单个路径; - 确保
tenantId来自可信来源:将租户 ID 直接拼进过滤器值前应做校验/转义,避免被构造出跨越租户目录边界的前缀。
可用过滤器操作符完整列表见 api.md:eq、ne、gt、gte、lt、lte,内置元数据字段为filename、folder、timestamp(Unix 秒)。
四、流式输出:SSE 实时返回
聊天型产品要求逐字返回,aiSearch()支持stream: true直接返回可读流,配合text/event-stream响应头即可完成 SSE 流式问答:
const stream = await env.AI.autorag("docs").aiSearch({ query, model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast", stream: true }); return new Response(stream, { headers: { "Content-Type": "text/event-stream" } });要点说明:
stream选项默认值为false(见 api.md),流式场景需显式开启;- 该模式与 Workers 的
Response天然契合,前端可用标准EventSource或fetch+ReadableStream消费; - 若需要在流式输出过程中再叠加自定义格式(如把 chunk 包装成
data: {...}\n\n),可参照 workers-ai/patterns.md 中 Stream → TransformStream 的写法,原理一致。
五、评分阈值:Score Threshold 的三档调优
score_threshold用于过滤低相关分块,取值 0.0–1.0,默认 0.3。它在召回率与精确度之间做权衡:
| 阈值 | 适用场景 |
|---|---|
| 0.3(默认) | 广泛召回(Broad recall),探索型查询 |
| 0.5 | 均衡(Balanced),生产环境推荐默认值 |
| 0.7 | 高精确度(High precision),关键准确性场景 |
const answer = await env.AI.autorag("docs").aiSearch({ query, model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast", ranking_options: { score_threshold: 0.5 } });调优路径(结合 gotchas.md):
- 检索结果为空时先降阈值:按"移除过滤器 → 阈值降到 0.1 → 检查索引是否已填充"三步排查,逐步定位是过滤条件、阈值还是索引的问题;
- 响应过慢(>3s)时提高阈值并限制数量:配合
max_num_results(默认 10)一起使用,减少送入 LLM 的分块数量,从而降低生成延迟与 token 成本; - 阈值调优本质上是在"宁可漏、不可错"与"宁滥勿缺"之间选择:法律、金融等高风险回答用 0.7,探索式问答用 0.3。
六、System Prompt 模板:约束生成行为
aiSearch()支持通过system_prompt传入系统提示词约束 LLM 的生成,这是控制幻觉、要求"仅基于检索内容回答"的关键手段:
const systemPrompt = `You are a documentation assistant. - Answer ONLY based on provided context - If context doesn't contain answer, say "I don't have information" - Include code examples from context`; const answer = await env.AI.autorag("docs").aiSearch({ query: "How do I configure caching?", model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast", system_prompt: systemPrompt });为什么这套模板有效:
- "仅基于上下文回答"直接约束 LLM 不引用检索范围之外的知识,是 RAG 管线控制幻觉的第一道防线;
- "无答案时明确表态"避免模型强行编造,输出更诚实、可审计;
- "包含上下文中的代码示例"对文档类问答尤为重要——用户问的是配置方法,回答应尽量附上真实代码片段而非泛泛描述。
system_prompt字段在 api.md 的AiSearchOptions接口中为可选参数。若你的业务有多个产品线,可将 prompt 模板做成配置文件按环境切换,与下文的多环境管理配合使用。
七、复合过滤器:OR / AND 的写法与限制
当单字段过滤不够时,AI Search 支持and/or复合过滤器,最多嵌套 2 层,每个复合过滤器内最多 10 个子过滤器(平台限制见 gotchas.md)。
OR:多个文件夹命中(例如文档站的多模块搜索)
filters: { operator: "or", filters: [ { column: "folder", operator: "gte", value: "docs/api/" }, { column: "folder", operator: "gte", value: "docs/auth/" } ] }AND:文件夹 + 时间范围(例如只检索最近一周的新文档)
filters: { operator: "and", filters: [ { column: "folder", operator: "gte", value: "docs/" }, { column: "timestamp", operator: "gte", value: oneWeekAgoSeconds } ] }⚠️ OR 操作符的硬性限制(务必注意,否则请求会报校验错误):
or只能用于同一列,且子过滤器的operator只能是eq;- 跨文件夹的 OR 用
eq+ 同列枚举即可,例如{ operator: "or", filters: [{column:"folder", operator:"eq", value:"docs/"}, {column:"folder", operator:"eq", value:"guides/"}] }是合法写法,而gt/gte混入 OR 则不合法; and组合没有该限制,可混合不同列、不同操作符。
时间戳精度陷阱:timestamp使用 Unix秒(10 位数字),不是毫秒。计算时务必用Math.floor(Date.now() / 1000)(见 gotchas.md),用毫秒值会导致时间过滤完全失效。
八、重排序:Reranking 提升高价值场景精度
默认检索按向量相似度排序,但"语义相关"未必等于"对当前问题最有用"。重排序(Reranking)让一个交叉编码器对初筛结果二次打分,显著提升答案质量,代价是额外约 300ms 延迟:
reranking: { enabled: true, model: "@cf/baai/bge-reranker-base" }适用决策:
- 启用:高价值场景(high-stakes),如法律、医疗、金融问答,或对回答准确性有硬性要求的客服系统——多花 300ms 换取更可靠的结果;
- 不启用:延迟敏感、探索型或大规模低价值流量场景,默认向量排序已足够。
reranking与score_threshold可组合使用:先用阈值粗滤掉低质量分块,再对保留项重排,兼顾成本与精度。
九、把模式组装起来:一个生产级 Worker 示例
将上述模式组合,可以得到一个同时具备多租户隔离、流式输出、阈值控制与重排的完整问答端点:
export default { async fetch(request: Request, env: Env): Promise<Response> { const { query, tenantId } = await request.json<{ query: string; tenantId: string }>(); const stream = await env.AI.autorag(env.AI_SEARCH_INSTANCE).aiSearch({ query, model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast", rewrite_query: true, // 用户输入场景开启改写 system_prompt: `You are a documentation assistant. - Answer ONLY based on provided context - If context doesn't contain answer, say "I don't have information" - Include code examples from context`, ranking_options: { score_threshold: 0.5 }, // 生产默认阈值 reranking: { enabled: true, model: "@cf/baai/bge-reranker-base" }, filters: { column: "folder", operator: "gte", value: `tenants/${tenantId}/` // 多租户前缀过滤 }, stream: true }); return new Response(stream, { headers: { "Content-Type": "text/event-stream" } }); } };配套的 Worker 绑定与环境配置见 configuration.md:
// wrangler.jsonc { "ai": { "binding": "AI" } }# wrangler.toml 多环境隔离 [env.production.vars] AI_SEARCH_INSTANCE = "prod-docs" [env.staging.vars] AI_SEARCH_INSTANCE = "staging-docs"生产级补充建议(源自 gotchas.md 的反模式清单):
- 实例名用环境变量而非硬编码:
env.AI.autorag(env.AI_SEARCH_INSTANCE),避免多环境误连; - 区分捕获错误类型:
AutoRAGNotFoundError(实例不存在,404 语义)与AutoRAGUnauthorizedError(Token 无效/缺失,401 语义)分别处理,不要笼统 catch; - 实例名拼写核对:
AutoRAGNotFoundError最常见根因是实例名与 Dashboard 中的不一致,先核对再排查其他; - 索引实时性认知:索引每 6 小时自动刷新(支持手动 Force Sync,30 秒限频),不适合秒级更新场景;需要实时内容的场景请评估 vectorize 手动向量化方案(详见 README.md 的 AI Search vs Vectorize 对比)。
十、附:本文涉及的完整参考文档
| 参考文档 | 内容 |
|---|---|
| ai-search/README.md | 产品定位、快速开始、平台限制(每账号 10 实例、每实例 10 万文件、单文件 4MB) |
| ai-search/api.md | aiSearch()/search()全参数、响应结构、操作符、REST API |
| ai-search/configuration.md | Worker 绑定、R2/网站数据源、路径过滤、多环境、监控 |
| ai-search/gotchas.md | 类型安全、过滤器限制、索引问题、性能与反模式 |
| ai-search/patterns.md | 本文骨架:方法选型、改写、多租户、流式、阈值、Prompt、复合过滤、重排 |
本文所有代码示例均可直接复制到 Cloudflare Workers 项目中使用;实际部署前请确认账号已开通 AI Search 服务,并按 configuration.md 完成 AI binding 与数据源配置。
【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考