# Adicionar funcionalidades de IA a aplicações existentes

Uma equipe de produto quer funcionalidades de IA, como resumo, classificação, moderação ou compreensão de imagens, em uma aplicação que ela já executa, sem operar infraestrutura de GPU. A aplicação já fica atrás da Azion, e a equipe quer mais uma rota de API que possa chamar a partir do seu código como qualquer outra. Esta página adiciona uma rota de resumo a essa aplicação: uma function valida a requisição, chama um modelo do catálogo do AI Inference, armazena o resultado em cache para textos idênticos e retorna o resumo. O resultado é medido pela latência de inferência por requisição, pelo consumo a cada mil requisições e pela precisão da tarefa em um conjunto de teste.

Este caso de uso não cobre assistentes conversacionais fundamentados em conteúdo da empresa nem o treinamento de modelos do zero. Para assistentes, consulte [Criar e executar assistentes de IA para suporte ao cliente](/pt-br/documentacao/casos-de-uso/construir-e-executar-workloads-de-ai/criar-e-executar-assistentes-de-ia-para-suporte-ao-cliente/).

## Pré-requisitos

- Uma aplicação e um workload que já servem a sua aplicação, com o **Application Accelerator** ativado, que o behavior **Run Function** exige. Para criá-los, consulte [Primeiros passos com Applications](/pt-br/documentacao/plataforma/applications/primeiros-passos/).
- Um personal token, para as etapas de API. Para criar um, consulte [Gerencie personal tokens](/pt-br/documentacao/guias/plataforma/conta-e-billing/personal-tokens/).
- Os valores da sua própria configuração. Esta página usa `/api/summarize` para a rota, `ai-summarize` para a function e a sua instância e `www.example.com` para o domínio em que a sua aplicação responde. Substitua cada valor pelo seu em todas as etapas.

---

## Produtos necessários

| A funcionalidade precisa de                                  | O que significa                                                                    | Produto                 | Documentado em                                                                                                                                                                                             |
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Um modelo que resume, sem servidor de inferência para operar | Um modelo do catálogo chamado com `Azion.AI.run`                                   | AI Inference            | [Chame um modelo no AI Inference a partir de uma function](/pt-br/documentacao/guias/ai/inferencia/chamar-um-modelo-no-ai-inference-a-partir-de-uma-function/)                                             |
| Uma rota de API que valida a entrada e formata a saída       | Uma function que a aplicação executa em `/api/summarize`                           | Functions               | [Primeiros passos com Functions](/pt-br/documentacao/plataforma/functions/primeiros-passos/)                                                                                                               |
| O mesmo texto resumido uma vez, não a cada requisição        | Resultados armazenados e encontrados com a Cache API, pela key de um hash do texto | Cache                   | [Armazene em cache a resposta de uma function com a Cache API](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/functions-e-runtime/armazenar-em-cache-a-resposta-de-uma-function-com-a-cache-api/) |
| Uma visão da frequência com que a rota é executada           | O dashboard **Invocations** da aba **Functions**                                   | Real-Time Metrics       | [Crie dashboards](/pt-br/documentacao/plataforma/real-time-metrics/dashboards-build/#functions)                                                                                                            |
| Uma regra que executa a function na rota                     | O behavior **Run Function**, que exige o Application Accelerator na aplicação      | Application Accelerator | [Execute uma função em uma aplicação](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/functions-e-runtime/funcoes-serverless/)                                                                     |

---

## Arquitetura de referência

Esta página constrói o *Catalog-model inference API*: o modelo é usado como o AI Inference o publica, atrás de uma function que a sua aplicação chama.

```mermaid
%%{init: {"layout": "dagre", "themeVariables": {"fontSize": "13px"}, "flowchart": {"nodeSpacing": 12, "rankSpacing": 12, "padding": 6, "wrappingWidth": 70, "minNodeWidth": 40, "useMaxWidth": true}}}%%
flowchart TD
  AppCode["Código da sua aplicação"] -->|"POST /api/summarize"| App["regra da aplicação em /api/summarize"]
  App -->|"Run Function"| Fn["function ai-summarize"]
  Fn -->|"entrada inválida: 400 ou 413"| AppCode
  Fn -->|"SHA-256 do texto"| Cache["Cache API"]
  Cache -->|"hit: resumo armazenado"| Fn
  Fn -->|"miss: Azion.AI.run"| Model["AI Inference: Qwen3 30B A3B Instruct"]
  Model -->|"resumo"| Fn
  Fn -->|"resumo e status do cache"| AppCode
```

Leia o diagrama a partir da function. As setas que chegam à function vêm de uma rota de uma aplicação que já serve o seu tráfego, então o código da sua aplicação alcança o modelo por mais um caminho em um domínio que ele já chama. As setas que saem da function são uma única execução: a function mantém a requisição aberta enquanto o modelo gera, e nenhuma seta leva a um servidor de inferência, porque a function indica um id de modelo e a Azion executa o modelo. O modelo é usado como publicado, então o design não tem etapa de treinamento nem versão de modelo para escolher além do id.

### Fluxo de dados

1. O código da sua aplicação envia `POST /api/summarize` com o texto a resumir, e a regra da aplicação executa a function `ai-summarize`. Todos os outros caminhos mantêm as suas próprias regras.
2. A function valida o corpo antes de qualquer chamada ao modelo e recusa um texto ausente com `400` e um texto com mais de 20.000 caracteres com `413`.
3. A function calcula o hash do texto e procura esse hash no cache. Uma correspondência retorna o resumo armazenado sem chamar o modelo.
4. Em um miss, a function envia o texto ao modelo do catálogo com `Azion.AI.run`, com uma instrução para resumi-lo, e o AI Inference executa o modelo e retorna o resumo.
5. A function armazena o resumo no cache sob o hash, por um dia.
6. A function retorna o resumo e se ele veio do cache.

### Componentes

- **aplicação**: o Platform Resource que encaminha `/api/summarize` para a function. A rota é uma regra na aplicação que já serve o seu tráfego, então o domínio, o certificado TLS e qualquer autenticação na frente dela são os que a aplicação já tem. A Azion não emite credencial para uma chamada de modelo, então uma rota sem verificação própria responde a qualquer um que a alcance.
- **Functions**: trata cada requisição. A function `ai-summarize` guarda o prompt, o id do modelo, os limites de entrada e o formato da resposta, então cada decisão sobre o que o modelo recebe é código que a sua equipe controla.
- **AI Inference**: executa o modelo do catálogo, `Qwen/Qwen3-30B-A3B-Instruct-2507-FP8`. A sua equipe não carrega nenhum modelo nem dimensiona nenhum cluster, e o id da página do modelo é o único endereço de que a function precisa.
- **Cache**: armazena resultados para entradas repetidas, uma opção de design. A function usa como key de um resultado um hash da sua entrada pela Cache API, e só o usa para tarefas cuja saída é a mesma para toda entrada idêntica.
- **Real-Time Metrics**: mostra a latência e o volume da rota. Um design sem servidor de inferência próprio ainda precisa de uma visão do que a rota transportou.

### Outros designs para este caso de uso

- *Fine-tuned inference API with LoRA adapters*: para equipes cuja tarefa precisa de um modelo especializado. A equipe treina um adaptador LoRA com o seu próprio conjunto de dados no LoRA Fine-Tune, avalia o adaptador e serve o modelo base com ele no AI Inference atrás do mesmo tipo de API em uma function, o que acrescenta um fluxo de controle de treinamento e avaliação e uma decisão de versão de modelo antes de servir.

---

## Configure a function de resumo

A function é a funcionalidade inteira: ela decide o que é pedido ao modelo, o que ele pode receber e o que quem chama recebe de volta.

- **O modelo é `Qwen/Qwen3-30B-A3B-Instruct-2507-FP8`.** A página dele lista o resumo entre os seus usos, ele serve uma janela de contexto de 64k tokens e é o modelo que o AI Inference Starter Kit chama. A function o chama como [Chame um modelo no AI Inference a partir de uma function](/pt-br/documentacao/guias/ai/inferencia/chamar-um-modelo-no-ai-inference-a-partir-de-uma-function/) descreve, com `stream` definido como `false` e a instrução de resumo como a mensagem `system`.
- **Um texto tem no máximo 20.000 caracteres.** O modelo lê cada caractere que recebe, e a function espera enquanto ele lê, então um limite na entrada é um limite na espera. O campo `usage.prompt_tokens` da resposta mostra quanto um texto consumiu, que é como ajustar o limite.
- **`max_tokens` é `300`.** Um resumo é curto por definição, e o limite encerra uma geração que se estende demais.
- **Um resultado fica em cache por um dia sob o SHA-256 do texto.** O mesmo texto gera um resumo que quem chama pode reutilizar, então um texto repetido não custa nenhuma chamada ao modelo. A function armazena em cache como [Armazene em cache a resposta de uma function com a Cache API](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/functions-e-runtime/armazenar-em-cache-a-resposta-de-uma-function-com-a-cache-api/) descreve, com o cache `ai-summarize`, a key `https://ai-summarize.cache/<sha-256 of the text>` e `max-age=86400`.
- **O texto do modelo é lido com optional chaining.** Uma resposta sem um dos níveis gera um resumo vazio, que a function informa como `502`, em vez de uma exceção.

Crie uma function chamada `ai-summarize` com este código:

```javascript
const MODEL = "Qwen/Qwen3-30B-A3B-Instruct-2507-FP8";
const MAX_CHARS = 20000;
const CACHE_SECONDS = 86400;

async function sha256(text) {
  const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(text));
  return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, "0")).join("");
}

export default {
  async fetch(request, env, ctx) {
    if (request.method !== "POST") {
      return new Response("Method not allowed", { status: 405 });
    }
    const { text } = await request.json();
    if (typeof text !== "string" || text.trim() === "") {
      return Response.json({ error: "text is required" }, { status: 400 });
    }
    if (text.length > MAX_CHARS) {
      return Response.json({ error: `text is longer than ${MAX_CHARS} characters` }, { status: 413 });
    }

    const cache = await caches.open("ai-summarize");
    const cacheKey = `https://ai-summarize.cache/${await sha256(text)}`;
    const hit = await cache.match(cacheKey);
    if (hit) {
      return new Response(await hit.text(), {
        headers: { "Content-Type": "application/json", "x-summary-cache": "hit" }
      });
    }

    const modelResponse = await Azion.AI.run(MODEL, {
      "stream": false,
      "max_tokens": 300,
      "messages": [
        { "role": "system", "content": "Summarize the user's text in at most three sentences. Use only facts the text states." },
        { "role": "user", "content": text }
      ]
    });
    const summary = modelResponse?.choices?.[0]?.message?.content?.trim();
    if (!summary) {
      return Response.json({ error: "the model returned no summary" }, { status: 502 });
    }

    const body = JSON.stringify({ summary });
    await cache.put(cacheKey, new Response(body, {
      headers: { "Content-Type": "application/json", "cache-control": `max-age=${CACHE_SECONDS}` }
    }));
    return new Response(body, {
      headers: { "Content-Type": "application/json", "x-summary-cache": "miss" }
    });
  },
};
```

Para criar a function e a sua instância, siga [Primeiros passos com Functions](/pt-br/documentacao/plataforma/functions/primeiros-passos/) com o nome `ai-summarize` e dê à instância na sua aplicação o nome `ai-summarize`, sem Args. A Cache API não é definida no `azion dev`, então teste a function depois que ela estiver em execução na aplicação.

A aplicação tem uma instância `ai-summarize` que retorna o resumo de um texto, a partir do cache quando o mesmo texto foi resumido no último dia.

---

## Configure a rota de API

A rota é uma regra na aplicação que já serve a sua aplicação. Ela corresponde exatamente a `/api/summarize`, então nenhum outro caminho da sua aplicação executa a function, e é executada na Request Phase, porque a function produz a resposta inteira.

**Console**

Para criar a regra:

1. **Abra a aplicação**

   Acesse [Azion Console](https://console.azion.com/) > **Applications** > **sua aplicação**.

2. **Na aba Rules Engine, selecione + Rule**

3. **Dê um nome à regra**

   Digite `ai - summarize`.

4. **Selecione Request Phase**

5. **Faça a correspondência com a rota**

   Na seção **Criteria**, selecione a variável `${uri}`, o operador *is equal* e `/api/summarize` como argumento.

6. **Na seção Behaviors, selecione Run Function**

7. **Selecione a instância ai-summarize**

8. **Selecione Save**

**API**

Para criar a regra, envie-a às request rules da aplicação, com o ID da instância `ai-summarize`:

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/applications/<application-id>/request_rules \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "ai - summarize",
  "active": true,
  "criteria": [
    [
      { "variable": "${uri}", "conditional": "if", "operator": "is_equal", "argument": "/api/summarize" }
    ]
  ],
  "behaviors": [{ "type": "run_function", "attributes": { "value": <function-instance-id> } }]
}'
```

A API responde com um `state` de `pending` e a regra como foi armazenada.

Um `POST` para `/api/summarize` no seu domínio executa a function, e todos os outros caminhos mantêm as regras que tinham. Uma regra nova leva alguns minutos para se propagar.

---

## Verifique a configuração

- **A rota retorna um resumo.** Envie um texto:

  ```bash
  curl -s -i -X POST https://www.example.com/api/summarize \
    -H 'Content-Type: application/json' \
    -d '{"text":"<a paragraph of your own content>"}'
  ```

  A resposta traz `x-summary-cache: miss` e um corpo JSON com `summary`.

- **O mesmo texto é respondido a partir do cache.** Envie a mesma requisição de novo. A resposta traz `x-summary-cache: hit` e o mesmo `summary`.

- **Uma entrada inválida nunca chega ao modelo.** Envie `{"text":""}`. A resposta é `400` com `text is required`, que a function retorna antes da chamada ao modelo.

- **A rota é executada apenas no seu caminho.** Faça uma requisição a qualquer outro caminho da sua aplicação. Ele responde como respondia antes de a regra existir.

Quando a rota responde com a página da sua própria aplicação em vez de JSON, a regra ainda pode estar se propagando. Quando isso persistir depois de alguns minutos, leia as linhas de log da function na fonte de dados **Functions Console** do [Real-Time Events](/pt-br/documentacao/plataforma/real-time-events/primeiros-passos/).

---

## Medindo resultados

| Métrica                                    | Onde ler                                                                                                                                                                                                                                                                                                                                                      | Como é quando funciona                                                                                                               |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Latência de inferência por requisição      | O **Request Time** das requisições para `/api/summarize`, na fonte de dados **HTTP Requests** do [Real-Time Events](/pt-br/documentacao/plataforma/real-time-events/fontes-de-dados/#http-requests)                                                                                                                                                           | As requisições respondidas a partir do cache são mais rápidas que os misses, e os misses ficam estáveis à medida que o volume cresce |
| Volume de requisições                      | **Total Invocations** no dashboard **Invocations** da aba **Functions** no [Real-Time Metrics](/pt-br/documentacao/plataforma/real-time-metrics/dashboards-build/#functions)                                                                                                                                                                                  | Acompanha o próprio tráfego da sua aplicação para a funcionalidade                                                                   |
| Consumo a cada mil requisições             | `compute_time` sobre `invocations`, vezes 1.000, a partir do dataset de consumo em [Consulte dados de uso de Functions](/pt-br/documentacao/guias/plataforma/observabilidade/consultar-dados-de-uso-edge-functions-com-graphql/). Functions e AI Inference são cobrados cada um pela sua própria tarifa, em [Preços](/pt-br/documentacao/fundamentos/precos/) | Cai à medida que a parcela de respostas em cache sobe                                                                                |
| Precisão da tarefa em um conjunto de teste | Um conjunto fixo de textos com resumos de referência, enviado para `/api/summarize` depois de cada mudança no prompt ou no modelo                                                                                                                                                                                                                             | Se mantém ou sobe de uma execução para a outra                                                                                       |

---

## Boas práticas

- **Valide na function, antes da chamada ao modelo.** A function é o único lugar em que uma requisição pode ser recusada antes de um modelo ser executado, e cada chamada ao modelo consome Compute Time. Para o raciocínio, consulte [Boas práticas do AI Inference](/pt-br/documentacao/plataforma/ai-inference/boas-praticas/).
- **Armazene em cache apenas tarefas cuja saída pode ser reutilizada.** Um resumo de um texto idêntico pode valer para toda requisição que o envia. Uma tarefa cuja resposta precisa ser diferente por usuário ou por momento, como uma que lê a hora atual, não pode passar pelo cache.
- **Copie o id do modelo da página dele.** Os ids de modelo não seguem um único formato, então um id derivado do nome do modelo pode estar errado para outro modelo. Para mudar o modelo, copie o id de [Modelos de AI](/pt-br/documentacao/plataforma/ai-inference/modelos/) e mude o nome do cache, para que resumos do modelo antigo não sejam retornados para o novo.
- **Adicione autenticação quando a rota for pública.** A rota responde a qualquer um que alcance o seu domínio, e cada miss executa um modelo. Quando a sua aplicação tem uma sessão ou uma API key, verifique-a na function antes da busca no cache.

---

## Guias deste caso de uso

- [Armazene em cache a resposta de uma function com a Cache API](/pt-br/documentacao/guias/desenvolvimento-de-aplicacoes/functions-e-runtime/armazenar-em-cache-a-resposta-de-uma-function-com-a-cache-api.md): Armazena cada resumo sob o hash do seu texto e o retorna para o mesmo texto.
- [Chame um modelo no AI Inference a partir de uma function](/pt-br/documentacao/guias/ai/inferencia/chamar-um-modelo-no-ai-inference-a-partir-de-uma-function.md): Envia o texto ao modelo do catálogo com Azion.AI.run e lê o resumo na resposta.
