Configurar políticas do Apigee com o processador de extensão

Esta página se aplica à Apigee e à Apigee híbrida.

Confira a documentação da Apigee Edge.

O processador de extensão da Apigee permite aplicar recursos do gateway de IA da Apigee ao tráfego que não flui por um proxy da Apigee. Por exemplo, um serviço executado no Google Kubernetes Engine, uma API gerenciada por outro gateway ou um servidor MCP para um agente de IA. Como o caminho de tráfego é diferente de um proxy de API padrão, algumas configurações de política são específicas do processador de extensão. Nesta página, descrevemos essas considerações e fornecemos exemplos de configurações. Cada seção de política tem um link para o tutorial completo dela.

As políticas nesta página se aplicam da mesma forma em qualquer lugar em que o processador de extensão esteja anexado:

Principais considerações

As seguintes considerações se aplicam ao anexar uma política a um proxy de processador de extensão. Para saber onde anexá-las, consulte Usar políticas com o processador de extensão no guia de início rápido.

Correlacione os exemplos à API do modelo

Os exemplos nesta página usam o formato de solicitação e resposta do Gemini. Outros provedores de modelos funcionam da mesma forma: UserPromptSource, LLMTokenUsageSource e LLMModelSource são modelos de mensagens. Portanto, defina-os para o local equivalente no payload dessa API. As políticas em si não mudaram.

Definir o escopo do tráfego processado

Com um proxy de API padrão, você atribui um caminho base e os clientes chamam esse URL específico. Assim, o proxy recebe apenas o tráfego destinado a ele. O processador de extensão não tem um caminho de base. Portanto, você define o escopo do tráfego em dois lugares: na extensão, que decide o que chega ao Apigee e no proxy, que decide o que é executado no tráfego que chega. Use os dois

Filtre primeiro na extensão para que o tráfego que você não pretende governar nunca seja enviado ao Apigee:

Em seguida, defina o escopo das políticas individuais dentro do proxy. Um único proxy de processador de extensão recebe tudo o que a extensão seleciona, e isso ainda pode ser uma mistura: chamadas de modelo de um agente de IA, chamadas de sessão e estado e chamadas de telemetria podem compartilhar um host. Uma política que inspeciona uma carga útil de modelo falha em uma chamada que não tem uma, e uma política com falha bloqueia a solicitação. Anexe cada política com uma condição que a escopo para o tráfego pretendido:

<!-- 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>

Usar um proxy sem destino

Os proxies do processador de extensão processam o tráfego interceptado e não têm um endpoint de destino. Implante-os como proxies extensíveis. Todos os proxies em um ambiente de processador de extensão precisam ser do mesmo tipo.

Ler o conteúdo da chamada interceptada

As políticas que inspecionam o payload operam na mensagem conforme ela aparece na rede. Para uma chamada de modelo, essa é a solicitação e a resposta do modelo. Por exemplo, o comando do usuário está em $.contents[-1].parts[-1].text e a resposta do modelo está em $.candidates[-1].content.parts[-1].text.

Conceder uma conta de serviço para políticas que chamam os Serviços do Google

As políticas que chamam um serviço do Google, como o Model Armor ou as pesquisas de incorporações e índices usadas pelo cache semântico, exigem uma conta de serviço de implantação. Implante o proxy com o parâmetro serviceAccount.

Segurança de IA com o Model Armor

Anexe as políticas SanitizeUserPrompt e SanitizeModelResponse, com escopo para a chamada do modelo. Para configurar modelos, consulte Começar a usar o 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>

Anexe SUP-sanitize no fluxo de solicitação com a condição (request.uri Like "*generateContent*"). Quando o comando corresponde ao modelo do Model Armor, a política rejeita a solicitação, para que o comando nunca chegue ao modelo.

Armazenamento em cache semântico

Anexe a política SemanticCacheLookup no fluxo de solicitação e a política SemanticCachePopulate no fluxo de resposta, ambos no escopo da chamada do modelo. Para configurar o índice e os embeddings, consulte Começar a usar o cache semântico. Quando uma solicitação corresponde a um comando em cache, a resposta é veiculada do cache sem chamar o modelo.

Limites de tokens para chamadas de modelo

Duas políticas limitam o uso de tokens de modelos de linguagem grandes (LLMs) na chamada do modelo. Escopo para a chamada de modelo com a condição (request.uri Like "*generateContent*"). Para instruções de configuração, consulte Começar a usar políticas de tokens de LLM.

Limitar tokens de comando

A política PromptTokenLimit limita os tokens com base no comando do usuário, ou seja, uma proteção contra picos para comandos. Anexe-o ao fluxo de solicitação. Ele lê o comando da solicitação interceptada e rejeita a chamada quando a taxa é excedida. Assim, um comando muito grande nunca chega ao modelo. O exemplo a seguir limita os comandos a 1.000 tokens por minuto:

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

Limitar o consumo de tokens de resposta

A política LLMTokenQuota impõe uma cota de consumo de tokens em um intervalo de tempo, contando os tokens retornados na resposta do modelo. Anexe uma instância EnforceOnly no fluxo de solicitação para rejeitar chamadas quando a cota for excedida e uma instância CountOnly no fluxo de resposta para contar os tokens usados, lidos de $.usageMetadata.candidatesTokenCount. Dê às duas instâncias o mesmo SharedName para que elas atualizem um único contador. Essa política exige um proxy extensível. O par a seguir aplica 15.000 tokens a cada 30 minutos:

<!-- 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>

Governança de tráfego: cota, autorização e interrupção de picos

Essas políticas são aplicadas ao tráfego pelo processador de extensão para qualquer back-end, incluindo back-ends não hospedados na Apigee, como uma API hospedada no GKE ou um servidor de ferramenta ou servidor MCP que um agente de IA chama. Defina o escopo de cada política para o back-end que você quer proteger:

<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>
  • Autorização: use a política VerifyAPIKey ou OAuthV2. As chamadas não autorizadas são rejeitadas antes de chegarem ao back-end.
  • Quota: use a política de Quota para aplicar um limite preciso de chamadas. Configure a política como distribuída e síncrona para que o limite seja aplicado como uma única contagem compartilhada em todo o tempo de execução.
  • SpikeArrest: use a política SpikeArrest para suavizar picos de tráfego. O controle de picos é aplicado por processador de mensagens e não garante uma taxa global exata. Quando você precisa de um limite preciso, use a política de cota.

Transformar mensagens e extrair variáveis

Use a política AssignMessage para adicionar, mudar ou remover partes de uma mensagem (cabeçalhos, parâmetros de consulta ou o payload) e a política ExtractVariables para ler valores de uma mensagem em variáveis que políticas posteriores podem usar. Com o processador de extensão, as duas políticas funcionam no fluxo de solicitação, operando na solicitação interceptada, e no fluxo de resposta, operando na resposta do back-end. Como em qualquer política de processador de extensão, defina o escopo de cada anexo com uma condição para que ele seja executado apenas no tráfego pretendido.

O exemplo a seguir usa ExtractVariables para ler um campo do corpo da solicitação e, no fluxo de resposta, para ler um campo do corpo da resposta:

<!-- 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>

O exemplo a seguir usa AssignMessage para definir um cabeçalho na solicitação antes que ela chegue ao back-end e na resposta antes que ela retorne ao autor da chamada:

<!-- 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>

A seguir