指导和见解

兼容 OpenAI 的 API 网关背后的多租户 RAG

用于在多模型 API 网关后面构建检索增强生成的实用参考架构:租户范围索引、提供商中立检索适配器、规范化引用、生命周期控制和成本归因。

面向客户的 AI 助手需要检索增强生成,但当请求流经 OpenAI 兼容的 API 网关而不是某个模型提供商的本机堆栈时,RAG 会变得更加困难。网关必须保持租户数据隔离,保留模型提供者之间的引用,按计划删除索引内容,并将嵌入、检索和生成成本归因于正确的客户。

实际的答案是将检索视为一流的网关子系统。不要将其隐藏在一个提供商集成中。将检索与生成分开,为每个请求提供租户范围的检索上下文,在返回引用之前对其进行标准化,并在分类帐中记录每个计费步骤。

读者问题

为许多客户构建人工智能助手的团队通常从一个简单的流程开始:上传文档、嵌入块、检索最匹配的内容、将这些片段放入提示中,然后要求模型回答。直到产品需要多个模型提供商、客户级计费、下架和可审核性之前,这种方法才有效。

风险不仅仅是不准确的答案。更大的运营风险是租户命名空间错误、无法验证的引用、文档删除后过时的索引,以及由于检索成本消失在通用基础设施支出中而无法解释的利润。

本文将事实、建议和预测分开。事实是当前提供商和矢量数据库 API 记录的实现能力。这些建议是网关产品的架构选择。据预测,随着提供商检索功能的不断变化,该架构可能需要灵活性。

参考架构

网关级 RAG 设计应包含五个组件:

  • 租户解析器:将传入的 API 密钥、工作区、客户帐户或合作伙伴 API 客户映射到规范的tenant_id。
  • 检索配置文件:定义哪个语料库搜索、要使用的嵌入模型、结果计数、过滤器、重新排名选项、引文要求和后备行为。
  • 检索适配器层:通过一个内部接口调用本机提供程序检索、外部矢量数据库或自定义搜索服务。
  • 提示组装和生成适配器:将检索到的上下文传递给所选模型提供程序,而不向其公开矢量后端详细信息调用者。
  • 使用和审计账本:记录嵌入、索引、检索、提示令牌、完成令牌、租户、模型、提供商和跟踪标识符。

最小请求合约可以保持提供商中立:

{
  “tenant_id”:“tenant_123”,
  "model": "gpt 兼容或克劳德兼容模型",
  "retrieval_profile": "support_docs_v2",
  “引用要求”:正确,
  “消息”:[
    {"role": "user", "content": "我们的包年套餐退款政策是什么?"}
  ]
}

响应也应该是提供商中立的:

{
  "answer": "年度计划可以在配置的政策窗口内退款...",
  “引用”:[
    {
      “source_id”:“doc_789”,
      "title": "计费政策",
      "url_or_internal_ref": "kb://billing-policy",
      "chunk_id": "chunk_044",
      “偏移量”:{“页面”:3},
      “分数”:0.82,
      "retrieval_provider": "向量_db",
      "model_provider": "openai_兼容",
      “provider_payload”:{}
    }
  ],
  “retrieval_trace_id”:“rt_456”,
  “bilable_tenant”:“tenant_123”,
  “embedding_usage”:空,
  “retrieval_usage”:{“查询”:1,“结果”:6},
  “model_usage”:{“input_tokens”:1920,“output_tokens”:180}}

事实:提供程序检索功能并不相同

OpenAI 的矢量存储 API 支持可以创建、搜索、使用分块策略配置、与文件元数据关联以及删除的矢量存储。矢量存储搜索支持查询、过滤器、最大结果计数、排名选项、分数阈值和查询重写控件。这些控件为网关作者提供了延迟、相关性和成本方面的有用旋钮。

OpenAI 平台数据控件还使生命周期设计变得重要:矢量存储中的客户内容将保留直至删除。如果租户离职,或者临时项目到期,网关不能假设提供商会根据产品的业务计划自动删除索引内容。

Anthropic 公开了不同的引用模式。应用程序可以提供带有源和标题元数据的搜索结果内容块,并且当启用引用时,模型可以将引用引用附加到生成的文本。存在实际限制:搜索结果引用设置在请求中是全有或全无,搜索结果块支持文本内容,引用粒度取决于内容如何分割成块。

含义很直接:网关不应将某个提供者的检索形状公开为其公共合同,除非它打算使该提供者成为永久检索机构。

建议:使用检索适配器,而不是检索锁定

创建内部检索适配器接口。网关可以支持其背后的多个后端:

  • 本地提供商检索:当客户希望以最快的路径进入某个提供商的文件搜索或矢量存储功能时有用。
  • 外部矢量数据库:当产品必须支持具有一致租户隔离和生命周期控制的多个模型提供商时有用。
  • 预取搜索结果块:当网关组装检索到的文本并传递时有用。将其发送给支持显式引用感知上下文的提供者。

无论后端如何,适配器都应返回相同的内部结构:

interface RetrievalResult {
  检索TraceId:字符串;
  租户ID:字符串;
  语料库ID:字符串;
  块:数组<{
    源ID:字符串;
    标题:字符串;
    文本:字符串;
    urlOrInternalRef?:字符串;
    块ID:字符串;
    偏移量?:{ 页数?:数量;字节开始?:数字;字节结束?:数字;令牌开始?:数字; tokenEnd?: 数字 };
    分数?: 数量;
    元数据:记录<字符串,字符串|数量 |布尔值>;
    提供商有效负载?:未知;
  }>;
  检索用法:{
    提供者:字符串;
    查询计数:数量;
    结果计数:数量;
    可计费单位?:数量;
  };}

这使得生成层可以接收上下文,而无需知道它是否来自 OpenAI 矢量存储、Pinecone、Weaviate、数据库全文搜索索引或内部混合检索器。

租户隔离在向量查询之前开始

租户隔离不得依赖于提示指令。它必须在检索之前在存储边界和查询边界强制执行。

对于 Pinecone 风格的系统,记录的多租户模式是无服务器索引中每个租户一个命名空间。数据平面操作以命名空间为目标,这简化了租户隔离和卸载,因为删除命名空间会删除该租户的记录。 Pinecone 还记录了命名空间和元数据过滤之间的权衡:在大型共享命名空间内进行过滤可以扫描更多数据,成本更高,并且比命名空间范围内的查询执行速度更慢。

对于 Weaviate 风格的系统,多租户将每个租户存储在单独的分片上,因此一个租户的数据对另一个租户不可见。租户删除会删除关联的分片。 Weaviate 还支持活动、非活动和卸载等租户状态,这为很少使用的租户创建了生命周期选项。

实施清单

  • 从经过身份验证的网关身份解析租户_id,而不是仅从用户提供的正文字段。
  • 通过服务器端将租户_id 映射到向量命名空间、分片或提供商向量存储标识符注册表。
  • 拒绝 API 密钥租户与请求的语料库租户不匹配的请求。
  • 将共享公共语料库与私有租户语料库分开。
  • 在选择租户边界后,对文档类型、语言、产品区域或日期范围使用元数据过滤。
  • 记录以下内容的命名空间、分片、corpus_id、retrieve_profile 和检索trace_id:可审计性。

通过单独的授权、单独的索引或受控的聚合路径保留显式管理工作流程的跨租户搜索。不要使跨租户搜索成为元数据过滤器的意外副作用。

将引用规范化为网关对象

引用是产品合同,而不仅仅是装饰。客户支持助理、法律起草工具或内部知识助理需要说明生成答案的原因以及支持文本的来源。

网关应将引文数据标准化为自己的架构:

{
  “source_id”:“doc_123”,
  "title": "退款条款",
  "url_or_internal_ref": "kb://退款条款",
  "chunk_id": "chunk_006",
  “偏移量”:{“页”:2,“byte_start”:4410,“byte_end”:5020},
  “分数”:0.79,
  "retrieval_provider": "weaviate",
  "model_provider": "人类",
  “model_provider_itation_payload”:{}
}

保持规范化字段稳定并允许特定于提供者的扩展。 一些提供商会比其他提供商公开更丰富的引用详细信息。 有些人会引用搜索结果块。 有些会引用上传的文件。 有些不会提供您的应用程序所需的确切偏移格式。 网关应该保留现有的内容,而不是假装每个提供者都具有相同的引用语义。

严格引用模式

当 itation_required 为 true 时,预先定义失败行为。 严格模式可以要求每个事实段落至少包含一次引用,或者最终答案包含来自高于最低分数阈值的检索块的引用。 如果所选的模型提供程序无法满足引用合同,则网关应快速失败,使用兼容的提供程序,或返回结构化拒绝。

这是建议,而不是通用规则。 严格的引用模式可以提高信任度,但也会增加拒绝、重试和回退的复杂性。 对于低风险的创意工作流程,引用可能是可选的。 对于面向客户的支持或受监管的内部工作流程,引用_required 通常应成为检索配置文件的一部分。

索引生命周期是一项产品功能

RAG 系统会积累数据。 临时上传意外地变成永久上传。 以前的客户留下了嵌入物。 产品团队更改分块策略并忘记重建旧索引。网关应明确生命周期控制。

建议的生命周期控制包括:

  • 临时语料库过期:为短期会话上传的文档应具有过期时间戳和删除作业。
  • 租户卸载:删除租户应将命名空间、分片、提供者向量存储和相关文件的删除排入队列对象。
  • 冷租户处理:在受支持的情况下,可以将非活动租户标记为非活动或卸载,以减少资源使用。
  • 重新索引版本控制:存储每个块的嵌入模型、分块策略、解析器版本和 indexed_at。
  • 删除状态公开:合作伙伴 API 工作流程应显示是否文档删除、向量删除和提供者端删除已完成。

重要的事实是,某些矢量存储内容会保留直至删除。 架构建议是使删除可见且可测试,而不是将其埋藏在没有面向客户状态的异步作业中。

跟踪三个成本账本

单个代币账本对于 RAG 来说是不够的。 网关至少需要三个账本:

  • 嵌入和索引成本:文档解析、分块、嵌入调用、文件存储、索引写入和重新索引。
  • 检索成本:向量数据库读取、本机向量存储搜索、重新排名、查询重写和结果扩展。
  • 生成成本:输入令牌来自用户消息和检索到的上下文、输出令牌、工具调用、重试和回退。

这对于转售或分配人工智能成本的机构、SaaS 供应商和内部平台团队尤其重要。 如果没有单独的账本,RAG 利润就很难解释。 对于小代使用的租户,如果不断上传文档、重新索引大型语料库或运行广泛的检索查询,其成本可能仍然很高。

每个账本事件应包括tenant_id、customer_id(如果不同)、API 密钥 ID、检索配置文件、corpus_id、模型、提供商、trace_id 和计费单位。 这让使用分析可以回答实际问题:哪些租户拥有昂贵的检索配置文件、哪些语料库过时、哪些模型产生引用失败以及哪些客户由于检索返回太多上下文而生成过大的提示。

要测试的故障模式

网关 RAG 子系统应该对造成客户可见损坏的故障模式进行测试:

  • 缺少引用: itation_required 是true,但提供者响应不包含可用的引用引用。
  • 过时索引:文档已更新或删除,但旧块仍出现在检索结果中。
  • 租户不匹配:请求解析为租户 A,而语料库或命名空间属于租户 B。
  • 过度检索:配置文件返回太多块,增加成本并稀释答案质量。
  • 块大小不匹配:块太大以至于引用不精确,或者太小以至于上下文失去意义。
  • 提供者功能不匹配:一个模型可以以所需的形式发出引用,而另一个则不能。
  • 生命周期失败:请求删除,但提供者端存储仍然处于活动状态或未经验证。

这些测试应该在网关合约级别运行,而不仅仅是在一个提供商适配器内运行。 目标是证明当检索后端或生成提供程序发生变化时,公共行为保持稳定。

权衡

本地提供程序检索可以减少应用程序代码并加速第一个版本。 权衡是存储生命周期、引文格式、查询控制和功能可用性可能会与一个提供商联系在一起。

外部矢量数据库增加了操作范围。 这样做的好处是跨 OpenAI 兼容模型、人类模型和未来提供商的可移植性更强。 它们还使租户范围的命名空间或分片更容易推理网关何时负责计费和卸载。

细粒度的块提高了引用精度和可审计性。 它们还增加了索引大小、检索量和提示组装复杂性。 粗略的块更简单,但它们可能会产生指向宽泛的页面或部分的引用,而不是精确的支持段落。

严格的引用要求模式可以提高用户信任度。它还迫使网关处理无法生成所需引文格式的模型,这可能意味着拒绝请求、更改模型或返回置信度较低的答案。

预测:检索将变得更加原生,但网关仍然需要自己的合同

提供商原生检索功能可能会变得更加强大。 更多模型将接受带有结构化源元数据的检索上下文。 更多 API 将公开排名控制、查询重写和引文设置。 这并没有消除对网关合同的需求。

网关仍然拥有租户身份、密钥管理、支出限制、使用分析、合作伙伴 API 工作流程和面向客户的删除承诺。 提供程序功能可以在适配器层后面使用,但产品不应强制每个租户、模型和计费工作流程进入一个提供程序的检索抽象。

可操作的结论

将多租户 RAG 构建为具有明确边界的网关子系统。 在检索之前解析租户身份。 使用租户范围的命名空间、分片或向量存储。 将检索保留在适配器后面。 将引用标准化为网关拥有的模式。 添加生命周期状态和删除验证。 分别跟踪嵌入、检索和生成成本。

这种架构使 RAG 保持稳定,而无需将产品锁定到一个检索提供商。 当人工智能助手从原型转向面向客户的系统时,它还为团队提供了所需的操作控制:隔离、引用、可移植性、生命周期管理和成本归因。

相关阅读

FAQ

常见问题

多模型网关应该使用本地提供商检索还是外部矢量数据库?
当实施速度很重要并且一个提供程序的生命周期和引用行为可以接受时,请使用本机提供程序检索。当可移植性、租户隔离、卸载和跨提供商的一致计费更为重要时,请使用外部矢量数据库。
元数据过滤是否足以实现 RAG 中的租户隔离?
元数据过滤在选择租户边界后很有用,但它不应该是私有租户数据的主要隔离机制。默认情况下,首选每个租户的命名空间、每个租户的分片或租户范围的向量存储。
规范化的引用对象应该包括什么?
包括 source_id、标题、URL 或内部引用、chunk_id、可用偏移量、检索分数、检索提供者、模型提供者以及提供者特定引文有效负载的扩展字段。
为什么要分开嵌入、检索和生成账本?
RAG 成本不仅仅来自模型输出代币。上传、嵌入、重新索引、矢量搜索、重新排名和快速扩展都可以改变租户成本。单独的分类账使利润和客户账单变得可以解释。