使用专用 (Private Service Connect) 端点的语义缓存

本页面适用于 Apigee,但不适用于 Apigee Hybrid

查看 Apigee Edge 文档。

本页面介绍了如何配置和使用 Apigee 语义缓存政策,以根据语义相似度启用智能响应重用。在此示例中,政策针对部署在专用 (Private Service Connect) 端点上的 Vector Search 索引运行相似性搜索。在 Apigee API 代理中使用这些政策可最大限度地减少冗余的后端 API 调用,缩短延迟时间,并降低运营成本。

准备工作

在开始之前,请完成以下任务:

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  2. Verify that billing is enabled for your Google Cloud project.

  3. Enable the Compute Engine, AI Platform, and Cloud Storage APIs.

    Roles required to enable APIs

    To enable APIs, you need the serviceusage.services.enable permission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.

    Enable the APIs

  4. 在您的 Google Cloud 项目中启用并配置 Vertex AI Text embeddings API
  5. 创建(或有权访问)部署在专用 (Private Service Connect) 端点上的 Vector Search 搜索索引。本教程不会重复介绍 Vector Search 设置步骤;如需了解 SemanticCacheLookup 特有的要求以及 Vector Search 文档的链接,请参阅向量搜索索引前提条件
  6. 确认您的 Apigee 实例中有中级全面环境。语义缓存政策只能部署在中级全面环境中。
  7. 确认您有一个环境组,其中包含一个运行时主机名,您可以使用该主机名向 API 代理发送请求。

所需的角色

如需获得创建和使用语义缓存政策所需的权限,请让您的管理员为您授予用于部署 Apigee 代理的服务账号的 AI Platform User (roles/aiplatform.user) IAM 角色。 如需详细了解如何授予角色,请参阅管理对项目、文件夹和组织的访问权限

您也可以通过自定义角色或其他预定义角色来获取所需的权限。

设置环境变量

在包含 Apigee 实例的 Google Cloud 项目中,使用以下命令设置环境变量:

export PROJECT_ID=PROJECT_ID
export REGION=REGION
export RUNTIME_HOSTNAME=RUNTIME_HOSTNAME

其中:

  • PROJECT_ID 是包含 Apigee 实例的项目的 ID。
  • REGION 是 Apigee 实例的 Google Cloud 区域。
  • RUNTIME_HOSTNAME 是 Apigee 运行时的主机名。

如需确认环境变量设置正确,请运行以下命令并查看输出:

echo $PROJECT_ID $REGION $RUNTIME_HOSTNAME

设置项目

在开发环境中设置 Google Cloud 项目:

    gcloud auth login
    gcloud config set project $PROJECT_ID

Vector Search 索引前提条件

本教程假设您已拥有(或将创建)部署在专用 (Private Service Connect) 端点上的 Vector Search 搜索索引。有关创建、设置格式和部署 Vector Search 搜索索引的文档已在 Vector Search 指南中提供,因此本教程不会重复介绍这些步骤。请按照 Vector Search 文档执行以下操作:

创建索引时,该索引必须满足以下特定于 SemanticCacheLookup 的要求:

  • 索引必须使用 STREAM_UPDATE ("indexUpdateMethod": "STREAM_UPDATE"),这样 SemanticCachePopulate 政策的 upsertDatapoints 调用才能在近乎实时的时间内可查询。
  • 索引 dimensions 必须与您在 SemanticCacheLookup 政策中使用的嵌入模型的输出维度一致。本教程使用 gemini-embedding-001,默认情况下会生成 3072 维的嵌入。如果您将输出截断为较低的维度(例如 768 或 1536),请将 dimensions 设置为相同的值。
  • 使用与政策的 <DistanceMeasureType> 相匹配的距离衡量方式 (distanceMeasureType) 创建索引。SemanticCacheLookup 政策中的 <SimilaritySearch><VertexAI><DistanceMeasureType> 元素是可选的,默认值为 DOT_PRODUCT_DISTANCE;系统还支持 COSINE_DISTANCE。指数距离度量和政策 <DistanceMeasureType> 必须相同。

以下最简示例会创建一个兼容的索引。如需查看完整的请求正文和所有可用选项,请参阅创建和管理索引

ACCESS_TOKEN=$(gcloud auth print-access-token) && curl -X POST \
  "https://$REGION-aiplatform.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/indexes" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "displayName": "semantic-cache-index",
    "metadata": {
      "config": {
        "dimensions": 3072,
        "distanceMeasureType": "DOT_PRODUCT_DISTANCE"
      }
    },
    "indexUpdateMethod": "STREAM_UPDATE"
  }'

请注意响应中返回的数值 INDEX_ID;您将在 SemanticCachePopulate 政策中使用该数值。创建索引后,创建一个 Private Service Connect 索引端点,并将索引部署到该端点。

创建 Private Service Connect 索引端点时,该端点必须满足以下特定于 SemanticCacheLookup 的要求:

  • projectAllowlist 必须包含发起连接的 Apigee 项目
    • Apigee:使用 Apigee 租户项目。从 Organizations APIapigeeProjectId 字段)获取租户项目 ID。
    索引端点创建后,projectAllowlist 便无法修改。如果您将错误的项目列入许可名单,则必须删除并重新创建索引端点。

记下索引端点的数字 INDEX_ENDPOINT_ID

为 Apigee 代理配置服务账号

Apigee 代理使用服务账号进行 Vertex AI REST 调用:SemanticCacheLookup 政策中的 Embeddings API、SemanticCachePopulate 政策中的 upsertDatapoints 以及模型目标。向该服务账号授予 AI Platform User (roles/aiplatform.user) 角色:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:SERVICE_ACCOUNT" \
  --role="roles/aiplatform.user"

其中,SERVICE_ACCOUNT 是代理使用的服务账号的电子邮件地址。您将在第 4 步:导入和部署 API 代理中部署代理时引用此服务账号。

概览

借助语义缓存政策,Apigee 用户可以利用 LLM 模型智能高效地处理相同或语义相似的提示,从而最大限度地减少后端 API 调用并减少资源消耗。

SemanticCacheLookupSemanticCachePopulate 政策分别附加到 Apigee API 代理的请求流和响应流。当代理收到请求时,SemanticCacheLookup 政策会从请求中提取用户提示,并使用文本嵌入 API 将提示转换为数值表示形式。使用 Vector Search 执行语义相似度搜索,以查找相似的提示。如果找到相似的提示数据点,系统会执行缓存查找。如果找到缓存的数据,则将缓存的回答返回给客户端。

如果相似度搜索未返回类似的先前提示,LLM 模型会生成内容来回答用户提示,并使用该回答填充 Apigee 缓存。系统会创建一个反馈环,以更新 Vector Search 索引条目,为日后的请求做好准备。

在此场景中,Vector Search 搜索索引通过 gRPC 部署在专用 (Private Service Connect) 端点上。如需详细了解 Vector Search Private Service Connect 支持,请参阅查询专用服务访问通道或 Private Service Connect 索引

以下部分介绍了创建和配置语义缓存政策的步骤:

  1. 验证您的资源并获取 Apigee 所需的值。
  2. 连接到服务连接。
  3. 构建 API 代理软件包。
  4. 导入并部署 API 代理。
  5. 测试语义缓存政策。

第 1 步:验证您的资源并获取 Apigee 所需的值

在配置 Apigee 之前,请确认您的 Vector Search 搜索索引端点已启用 Private Service Connect,并且您的索引已部署。然后,读取 Apigee 代理使用的两个值:服务附件和 DEPLOYED_INDEX_ID

确认索引已部署,并且端点公开了 Private Service Connect 服务连接:

gcloud ai index-endpoints describe INDEX_ENDPOINT_ID \
  --project=$PROJECT_ID --region=$REGION \
  --format="value(deployedIndexes.privateEndpoints.serviceAttachment)"

该命令会返回格式为 projects/TENANT_PROJECT/regions/REGION/serviceAttachments/SERVICE_ATTACHMENT_NAME 的服务连接资源名称。 本指南将该值称为 SERVICE_ATTACHMENT。如果该命令返回空值,则表示索引尚未部署在 Private Service Connect 端点上。返回向量搜索索引前提条件,并在继续之前完成索引部署。

读取部署在端点上的索引的 DEPLOYED_INDEX_ID

gcloud ai index-endpoints describe INDEX_ENDPOINT_ID \
  --project=$PROJECT_ID --region=$REGION \
  --format="value(deployedIndexes.id)"

本指南将该值称为 DEPLOYED_INDEX_ID。您将在第 3 步:构建 API 代理软件包的 SemanticCacheLookup 政策中使用它。

如需详细了解如何部署和查询专用索引端点,请参阅将索引部署到 Private Service Connect 端点查询专用服务访问通道或 Private Service Connect 索引

第 2 步:连接到服务连接

此步骤会提供代理的 <GrpcEndpoint> 调用所针对的私有主机。 在 Apigee 上,创建 Apigee 端点连接。端点连接是 Apigee 的 Private Service Connect 使用方,它连接到 Vector Search 服务连接,并为您提供代理调用的专用主机。

curl -X POST \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "Content-Type: application/json" \
  -d '{
        "location": "'"$REGION"'",
        "serviceAttachment": "SERVICE_ATTACHMENT"
      }' \
  "https://apigee.googleapis.com/v1/organizations/$PROJECT_ID/endpointAttachments?endpointAttachmentId=ENDPOINT_ATTACHMENT"

轮询,直到附件的 stateACTIVEconnectionStateACCEPTED,然后记下主机:

curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  "https://apigee.googleapis.com/v1/organizations/$PROJECT_ID/endpointAttachments/ENDPOINT_ATTACHMENT"

响应包含 host 字段中的主机。本指南将该值称为 TARGET_HOST

如需从代理连接到 Vector Search 服务连接,您可以使用以下任一方法:

  • IP 地址:直接使用 host 字段中返回的 IP 地址作为 TARGET_HOST(例如 7.0.3.4)。
  • 专用 DNS 记录:如果您在 Google Cloud 项目中配置了专用 Cloud DNS 区域,并与 Apigee 建立了 DNS 对等互连,则可以在专用区域中创建指向端点连接 IP 地址的 A 记录,并使用该网域名称(例如 vectorsearch.example.com)作为 TARGET_HOST。如需了解详情,请参阅使用 DNS 记录通过专用 DNS 对等互连区域进行连接

第 3 步:构建 API 代理软件包

创建代理软件包

创建以下目录布局:

apiproxy/
├── PROXY_NAME.xml
├── proxies/default.xml
├── targets/default.xml
└── policies/
    ├── SCL-1.xml
    └── SCP-1.xml

policies/SCL-1.xml - SemanticCacheLookup 政策。<SimilaritySearch> 代码块使用 <PrivateServiceConnect><GrpcEndpoint>(不使用 <URL>)。

注意:<GrpcEndpoint> 规则:

  • 格式为 grpc://TARGET_HOST:PORT;方案必须为 grpc://。此版本支持 grpcs:// (TLS)。
  • Vector Search 的端口为 10000。Private Service Connect 数据平面端点在端口 10000 上提供 gRPC 服务,因此端点始终为 grpc://TARGET_HOST:10000
  • TARGET_HOST 可以是端点连接 IP 地址(来自第 2 步),也可以是在专用 DNS 区域中创建的自定义 DNS 记录。
  • gRPC 跳是明文且未经身份验证(通过网络隔离进行保护)。
<SemanticCacheLookup async="false" continueOnError="false" enabled="true" name="SCL-1">
  <DisplayName>SCL-1</DisplayName>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <UserPromptSource>{jsonPath('$.contents[-1].parts[-1].text',request.content,true)}</UserPromptSource>
  <Embeddings>
    <VertexAI>
      <URL>https://REGION-aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/REGION/publishers/google/models/gemini-embedding-001:predict</URL>
    </VertexAI>
  </Embeddings>
  <SimilaritySearch>
    <VertexAI>
      <PrivateServiceConnect>
        <GrpcEndpoint>grpc://TARGET_HOST:10000</GrpcEndpoint>
      </PrivateServiceConnect>
      <DeployedIndexID>DEPLOYED_INDEX_ID</DeployedIndexID>
      <Threshold>0.95</Threshold>
    </VertexAI>
  </SimilaritySearch>
</SemanticCacheLookup>

policies/SCP-1.xml - SemanticCachePopulate 政策。填充是仅限 REST 的操作,必须使用 <URL>(在部署时会拒绝 <PrivateServiceConnect>):

<SemanticCachePopulate async="false" continueOnError="true" enabled="true" name="SCP-1">
  <DisplayName>SCP-1</DisplayName>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
  <SimilaritySearch>
    <VertexAI>
      <URL>https://REGION-aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/REGION/indexes/INDEX_ID:upsertDatapoints</URL>
    </VertexAI>
  </SimilaritySearch>
  <TTLInSeconds>3600</TTLInSeconds>
</SemanticCachePopulate>

targets/default.xml - 模型目标。目标调用 Google API,因此需要令牌;<GoogleAccessToken> 使用部署的服务账号:

<TargetEndpoint name="default">
  <PreFlow name="PreFlow"><Request/><Response/></PreFlow>
  <PostFlow name="PostFlow"><Request/><Response/></PostFlow>
  <HTTPTargetConnection>
    <Authentication>
      <GoogleAccessToken>
        <Scopes>
          <Scope>https://www.googleapis.com/auth/cloud-platform</Scope>
        </Scopes>
      </GoogleAccessToken>
    </Authentication>
    <URL>https://REGION-aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/REGION/publishers/google/models/gemini-2.5-flash:generateContent</URL>
  </HTTPTargetConnection>
</TargetEndpoint>

proxies/default.xml - 在请求上运行 SemanticCacheLookup 政策,在响应上运行 SemanticCachePopulate 政策:

<ProxyEndpoint name="default">
  <PreFlow name="PreFlow">
    <Request><Step><Name>SCL-1</Name></Step></Request>
    <Response><Step><Name>SCP-1</Name></Step></Response>
  </PreFlow>
  <PostFlow name="PostFlow"><Request/><Response/></PostFlow>
  <HTTPProxyConnection>
    <BasePath>/PROXY_NAME</BasePath>
  </HTTPProxyConnection>
  <RouteRule name="default">
    <TargetEndpoint>default</TargetEndpoint>
  </RouteRule>
</ProxyEndpoint>

PROXY_NAME.xml - 软件包描述符:

<APIProxy name="PROXY_NAME">
  <BasePaths>/PROXY_NAME</BasePaths>
  <Policies><Policy>SCL-1</Policy><Policy>SCP-1</Policy></Policies>
  <ProxyEndpoints><ProxyEndpoint>default</ProxyEndpoint></ProxyEndpoints>
  <TargetEndpoints><TargetEndpoint>default</TargetEndpoint></TargetEndpoints>
</APIProxy>

第 4 步:导入和部署 API 代理

将该软件包压缩,导入该软件包以创建新修订版本,然后使用您的服务账号部署该修订版本:

TOKEN=$(gcloud auth print-access-token)
(cd BUNDLE_DIR && zip -r ../PROXY_NAME.zip apiproxy)
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -F "file=@PROXY_NAME.zip" \
  "https://apigee.googleapis.com/v1/organizations/$PROJECT_ID/apis?action=import&name=PROXY_NAME"
curl -X POST -H "Authorization: Bearer $TOKEN" \
  "https://apigee.googleapis.com/v1/organizations/$PROJECT_ID/environments/ENV/apis/PROXY_NAME/revisions/REVISION/deployments?override=true&serviceAccount=SERVICE_ACCOUNT"

其中:

  • BUNDLE_DIR 是包含 apiproxy/ 文件夹的目录。归档文件的根目录中必须包含 apiproxy/ 文件夹。
  • ENV 是您部署代理的 Apigee 环境。环境必须是中级综合环境。
  • REVISION 是导入调用返回的修订版本号。
  • SERVICE_ACCOUNT 是您用于部署代理的服务账号的电子邮件地址。

等待部署报告 READY

curl -s -H "Authorization: Bearer $TOKEN" \
  "https://apigee.googleapis.com/v1/organizations/$PROJECT_ID/environments/ENV/apis/PROXY_NAME/revisions/REVISION/deployments" | jq .state

第 5 步:测试语义缓存政策

发送提示。这是缓存未命中:系统会调用模型,并将回答缓存起来。

curl -X POST "https://$RUNTIME_HOSTNAME/PROXY_NAME" \
  -H "Content-Type: application/json" \
  -d '{"contents":[{"role":"user","parts":[{"text":"Explain in one sentence why the sky appears blue."}]}]}'

再次发送相同的提示。这是缓存命中:响应是从缓存中提供的,并且不会调用模型。

curl -i -X POST "https://$RUNTIME_HOSTNAME/PROXY_NAME" \
  -H "Content-Type: application/json" \
  -d '{"contents":[{"role":"user","parts":[{"text":"Explain in one sentence why the sky appears blue."}]}]}'

在命中时,响应包括 Cached-content: true 标头、相同的答案和明显更低的延迟时间。

您还可以通过调试会话验证缓存。如果命中,SemanticCacheLookup 政策会设置以下流变量:

变量 命中中的值
SemanticCacheLookup.SCL-1.dense_embeddings 提示的嵌入向量。
SemanticCacheLookup.SCL-1.is_nearest_neighbor_hit true
SemanticCacheLookup.SCL-1.cache_hit true
SemanticCacheLookup.SCL-1.cached_llm_response 缓存的回答。

如果命中,则不会调用模型目标,流程会短路并返回缓存的响应。

问题排查

如需查看完整的错误参考信息,请参阅 SemanticCacheLookup 政策

后续步骤