使用扩展处理器配置 Apigee 政策

本页面适用于 ApigeeApigee Hybrid

查看 Apigee Edge 文档。

借助 Apigee 扩展处理器,您可以将 Apigee 的 AI 网关功能应用于未通过 Apigee 代理的流量。例如,在 Google Kubernetes Engine 上运行的服务、由其他网关管理的 API 或 AI 智能体的 MCP 服务器。由于流量路径与标准 API 代理不同,因此某些政策配置特定于扩展处理器。本页介绍了这些注意事项,并提供了配置示例。每个政策部分都链接到相应政策的完整教程。

无论扩展处理器附加到何处,本页面上的政策都以相同的方式应用:

主要注意事项

将任何政策附加到扩展处理器代理时,请注意以下事项。如需了解将它们附加到何处,请参阅快速入门中的将政策与扩展处理器搭配使用

将示例与模型 API 相匹配

本页面上的示例使用 Gemini 请求和响应格式。其他模型提供商的工作方式相同:UserPromptSourceLLMTokenUsageSourceLLMModelSource 是消息模板,因此您需要将它们设置为相应 API 的载荷中的等效位置。政策本身没有变化。

确定您处理的流量范围

使用标准 API 代理时,您需要分配一个基本路径,然后客户端会调用该特定网址,因此代理只会接收发给它的流量。扩展处理器没有基本路径,因此您可以在两个位置限定其流量范围:在扩展中(决定哪些流量会到达 Apigee),以及在代理中(决定哪些流量会到达并运行)。同时使用

先在扩展程序中进行过滤,这样您不打算管理的流量就不会发送到 Apigee:

  • 在流量扩展程序上,为扩展程序链设置 CEL 匹配条件,例如 matchCondition.celExpression: 'request.host == "example.com"'
  • 在授权扩展程序中,匹配授权政策httpRules.to.operations 下的主机和路径前缀。

然后,在代理中确定各个政策的范围。单个扩展处理器代理会接收扩展程序选择的所有内容,这些内容仍然可以混合在一起:AI 代理的模型调用、会话和状态调用以及遥测调用可以共享一个宿主。如果某项政策会检查模型载荷,但某次调用未携带载荷,则该政策会失败,而失败的政策会阻止相应请求。附加每项政策,并使用可将其范围限定为预期流量的条件

<!-- Run only on the model (generateContent) call -->
<Step>
  <Name>My-Policy</Name>
  <Condition>(request.uri Like "*generateContent*")</Condition>
</Step>

<!-- Or scope by backend host -->
<Step>
  <Name>My-Policy</Name>
  <Condition>(request.header.host = "backend.example.com")</Condition>
</Step>

使用无目标代理

扩展处理器代理会处理拦截的流量,但没有目标端点。 将它们部署为可扩展代理。扩展处理器环境中的所有代理都必须属于同一代理类型。

读取拦截的通话内容

检查载荷的政策会处理在线路上传输的消息。对于模型调用,这是模型的请求和响应。例如,用户提示位于 $.contents[-1].parts[-1].text,模型回答位于 $.candidates[-1].content.parts[-1].text

为调用 Google 服务的政策授予服务账号

调用 Google 服务的政策(例如 Model Armor 或语义缓存使用的嵌入和索引查找)需要部署服务账号。使用 serviceAccount 参数部署代理。

使用 Model Armor 确保 AI 安全

附加 SanitizeUserPromptSanitizeModelResponse 政策,并将其范围限定为模型调用。如需了解模板设置,请参阅 Model Armor 使用入门

<SanitizeUserPrompt name="SUP-sanitize" continueOnError="false">
  <ModelArmor>
    <TemplateName>projects/PROJECT/locations/LOCATION/templates/TEMPLATE</TemplateName>
  </ModelArmor>
  <UserPromptSource>{jsonPath('$.contents[-1].parts[-1].text',request.content,true)}</UserPromptSource>
</SanitizeUserPrompt>

在请求流程中附加 SUP-sanitize,并设置条件 (request.uri Like "*generateContent*")。如果提示与 Model Armor 模板匹配,政策会拒绝该请求,因此提示永远不会到达模型。

语义缓存

在请求流程中附加 SemanticCacheLookup 政策,在响应流程中附加 SemanticCachePopulate 政策,两者都限定为模型调用。如需了解索引和嵌入设置,请参阅语义缓存使用入门。 当请求与缓存的提示匹配时,系统会从缓存中提供回答,而无需调用模型。

模型调用的 token 数量上限

有两项政策会限制模型调用时的大语言模型 (LLM) token 使用量。将两者都限定为具有条件 (request.uri Like "*generateContent*") 的模型调用。如需了解设置,请参阅 LLM 令牌政策使用入门

限制提示 token 数

PromptTokenLimit 政策会根据用户提示来限制 token,相当于针对提示的流量突增防护。将其附加在请求流程中;它会从拦截的请求中读取提示,并在超出速率时拒绝调用,因此过大的提示永远不会到达模型。以下示例将提示限制为每分钟 1,000 个令牌:

<PromptTokenLimit continueOnError="false" enabled="true" name="PTL-limit-prompt">
  <Rate>1000pm</Rate>
  <UserPromptSource>{jsonPath('$.contents[-1].parts[-1].text',request.content,true)}</UserPromptSource>
</PromptTokenLimit>

限制回答 token 消耗量

LLMTokenQuota 政策会在时间间隔内强制执行 token 消耗配额,并统计模型响应中返回的 token 数量。在请求流中附加 EnforceOnly 实例,以便在超出配额时拒绝调用;在响应流中附加 CountOnly 实例,以便统计所用的 token(从 $.usageMetadata.candidatesTokenCount 中读取)。为这两个实例提供相同的 SharedName,以便它们更新单个计数器。此政策需要可扩展的代理。 以下配对强制执行每 30 分钟 15,000 个令牌的限制:

<!-- Request flow: reject when the token quota is exceeded -->
<LLMTokenQuota name="LTQ-enforce" type="rollingwindow">
  <SharedName>llm-token-counter</SharedName>
  <EnforceOnly>true</EnforceOnly>
  <Allow count="15000"/>
  <Interval>30</Interval>
  <TimeUnit>minute</TimeUnit>
  <Distributed>true</Distributed>
</LLMTokenQuota>

<!-- Response flow: count the tokens used in the model response -->
<LLMTokenQuota name="LTQ-count" type="rollingwindow">
  <SharedName>llm-token-counter</SharedName>
  <CountOnly>true</CountOnly>
  <Allow count="15000"/>
  <Interval>30</Interval>
  <TimeUnit>minute</TimeUnit>
  <Distributed>true</Distributed>
  <LLMTokenUsageSource>{jsonPath('$.usageMetadata.candidatesTokenCount',response.content,true)}</LLMTokenUsageSource>
</LLMTokenQuota>

流量治理:配额、授权和突峰阻止

这些政策通过扩展处理器对任何后端(包括未托管在 Apigee 上的后端,例如 GKE 托管的 API 或 AI 智能体调用的工具或 MCP 服务器)强制执行。将每项政策的范围限定为要保护的后端:

<Step><Name>Verify-API-Key</Name><Condition>(request.header.host = "backend.example.com")</Condition></Step>
<Step><Name>Quota-Limit</Name><Condition>(request.header.host = "backend.example.com")</Condition></Step>
<Step><Name>Spike-Arrest</Name><Condition>(request.header.host = "backend.example.com")</Condition></Step>
  • 授权:使用 VerifyAPIKeyOAuthV2 政策。 未经授权的调用会在到达后端之前被拒绝。
  • Quota:使用Quota政策来强制执行精确的调用次数限制。将政策配置为分布式和同步,以便在整个运行时强制执行该限制,作为单个共享计数。
  • 流量突增抑制:使用 SpikeArrest 政策来平滑流量突增。SpikeArrest 政策是按消息处理器强制执行的,不保证确切的全局速率;如果您需要精确的限制,请使用 Quota 政策。

转换消息和提取变量

使用 AssignMessage 政策添加、更改或移除消息的各个部分(标头、查询参数或载荷),并使用 ExtractVariables 政策从消息中读取值到变量中,以便后续政策可以使用这些变量。借助扩展处理器,这两个政策都可以在请求流中运行,对拦截的请求进行操作;也可以在响应流中运行,对后端响应进行操作。与任何扩展处理器政策一样,请使用条件限定每个附件的范围,以便仅在预期流量上运行。

以下示例使用 ExtractVariables 从请求正文中读取字段,并在响应流程中从响应正文中读取字段:

<!-- Request flow: read a field from the intercepted request -->
<ExtractVariables name="EV-from-request">
  <Source>request</Source>
  <JSONPayload>
    <Variable name="user.prompt">
      <JSONPath>$.contents[-1].parts[-1].text</JSONPath>
    </Variable>
  </JSONPayload>
</ExtractVariables>

<!-- Response flow: read a field from the backend response -->
<ExtractVariables name="EV-from-response">
  <Source>response</Source>
  <JSONPayload>
    <Variable name="model.answer">
      <JSONPath>$.candidates[-1].content.parts[-1].text</JSONPath>
    </Variable>
  </JSONPayload>
</ExtractVariables>

以下示例使用 AssignMessage 在请求到达后端之前以及在响应返回给调用方之前设置请求和响应的标头:

<!-- Request flow: add a header to the intercepted request -->
<AssignMessage name="AM-set-request-header">
  <Set>
    <Headers>
      <Header name="X-Apigee-Processed">true</Header>
    </Headers>
  </Set>
  <AssignTo createNew="false" type="request"/>
</AssignMessage>

<!-- Response flow: add a header to the backend response -->
<AssignMessage name="AM-set-response-header">
  <Set>
    <Headers>
      <Header name="X-Apigee-Cache">miss</Header>
    </Headers>
  </Set>
  <AssignTo createNew="false" type="response"/>
</AssignMessage>

后续步骤