Engenharia de prompt no Bedrock: o que muda entre Nova, Claude e Llama
- ⬜🗂️ O catálogo de modelos: qual escolher para cada caso(AWS Bedrock — GenAI em Produção)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
O problema que só aparece no Bedrock
Engenharia de prompt com um provedor de modelo único é um problema de escrita: você aprende as manias de uma família e escreve para ela. No Bedrock o problema muda de natureza, porque o modelo é uma variável de configuração. O mesmo prompt roda em Nova, Claude, Llama e Mistral, e o resultado não é o mesmo — nem em qualidade, nem em formato, nem em custo.
Isso não é defeito da plataforma: é a consequência direta do que o Bedrock existe para dar, que é a liberdade de trocar de modelo sem reescrever a aplicação. Mas essa liberdade só é real se o prompt sobreviver à troca. Prompt que só funciona num modelo transforma a escolha de modelo numa decisão irreversível — exatamente o que você queria evitar ao entrar num serviço multi-modelo.
A pergunta que organiza este módulo
Não é "qual é o melhor prompt?". É "quanto do meu prompt é conhecimento sobre a TAREFA e quanto é conhecimento sobre o MODELO?". A primeira parte migra; a segunda apodrece na próxima troca de modelo. Todo o resto aqui é a prática de manter as duas separadas.
O que a Converse API padroniza — e o que ela deliberadamente não padroniza
A Converse API dá uma forma única de requisição para todos os modelos do catálogo. O que ela padroniza é a ESTRUTURA: onde vai a instrução de sistema, onde vai o histórico de turnos, onde vão os parâmetros de inferência e onde vai a declaração de ferramentas. Você deixa de escrever um corpo de requisição por família de modelo.
| Campo | O que carrega | Padronizado? |
|---|---|---|
| system | Instrução persistente — papel, regras, formato de saída | Sim — todo modelo recebe no lugar certo |
| messages | Turnos de user e assistant, com blocos de texto, imagem ou documento | Sim — a Converse traduz para o template de cada família |
| inferenceConfig | maxTokens, temperature, topP, stopSequences | Sim, mas o EFEITO de cada valor varia por modelo |
| toolConfig | Declaração das ferramentas em JSON Schema | Sim — a mesma declaração serve a qualquer modelo com suporte |
| additionalModelRequestFields | Parâmetros que só uma família entende | Não, e é esse o propósito dele |
O último campo é o mais importante para entender o desenho. `additionalModelRequestFields` é a válvula de escape declarada: tudo que é específico de um modelo entra ali, separado do resto. Isso não é um detalhe de implementação — é o lugar do código onde mora a sua dependência de fornecedor, e mantê-la concentrada num campo é o que torna a troca de modelo uma mudança pequena.
import boto3
brt = boto3.client("bedrock-runtime", region_name="us-east-1")
resposta = brt.converse(
modelId="us.amazon.nova-pro-v1:0",
system=[{"text": "Você classifica chamados de suporte. Responda apenas com a categoria."}],
messages=[{"role": "user", "content": [{"text": "Não consigo emitir a segunda via do boleto."}]}],
inferenceConfig={"maxTokens": 64, "temperature": 0.0},
)
print(resposta["output"]["message"]["content"][0]["text"])
print(resposta["usage"]) # inputTokens, outputTokens, totalTokensPor que o prefixo do modelId importa
O `us.` em `us.amazon.nova-pro-v1:0` indica um perfil de inferência entre regiões: a AWS roteia a chamada para a região com capacidade dentro daquela geografia. Sem o prefixo, você fala com uma região só e passa a competir por cota nela. É a diferença entre uma carga que absorve pico e uma que recebe throttling no pico — e não custa nada mudar.
Você quer trocar de modelo no Bedrock sem reescrever a aplicação. Onde a dependência de um modelo específico deve ficar concentrada?
As quatro alavancas que valem em qualquer modelo
Antes de tratar as diferenças entre famílias, vale fixar o que não muda. Estas quatro alavancas melhoram a saída de praticamente qualquer modelo do catálogo, e são a parte do prompt que migra intacta na troca:
- Instrução no system, não no turno do usuário. O que é regra permanente — papel, formato, restrições — pertence ao campo `system`. Enfiar regra permanente dentro da mensagem do usuário funciona por acidente e quebra quando o histórico cresce, porque a regra fica cada vez mais longe do fim do contexto.
- Estrutura explícita em vez de parágrafo corrido. Delimitar seções — com marcação XML, com títulos de markdown, com rótulos maiúsculos — dá ao modelo endereços para navegar. Um prompt de mil palavras sem estrutura é um prompt onde o modelo escolhe sozinho o que é importante.
- Exemplo em vez de adjetivo. "Responda de forma concisa" é uma instrução que cada modelo interpreta na sua régua. Dois exemplos de entrada e saída definem a régua sem ambiguidade, e é o recurso mais barato que existe para alinhar formato.
- Critério de parada explícito. Diga o que fazer quando a informação não está disponível. Sem isso, o comportamento padrão de todo modelo de linguagem é preencher a lacuna — que é a definição operacional de alucinação.
A quarta é a que mais se esquece, e é a que mais dói em produção
Um prompt de extração sem critério de parada devolve um CNPJ inventado quando o documento não tem CNPJ. O modelo não está mentindo: você pediu um CNPJ e não disse o que fazer se não houvesse. A instrução que resolve é literal — "se o campo não estiver presente no documento, devolva null e não infira" — e ela custa uma linha.
O que muda entre as famílias do catálogo
Com as quatro alavancas no lugar, as diferenças entre famílias deixam de ser sobre qualidade e passam a ser sobre convenção. Nenhuma das linhas abaixo é regra absoluta — são tendências que valem como ponto de partida e que você deve confirmar medindo no seu caso.
| Família | Convenção que costuma render | Onde tropeça |
|---|---|---|
| Amazon Nova | Seção nomeada e explícita no system; instrução direta sobre o formato de saída | Prompt longo sem seções — a estrutura é o que mais rende aqui |
| Anthropic Claude | Marcação XML para delimitar contexto e instrução; pedir raciocínio antes da resposta | Instrução no fim de um contexto muito longo perde peso — repita a tarefa depois do material |
| Meta Llama | Instrução curta e imperativa; poucos exemplos, bem escolhidos | Prompt com muitas regras simultâneas — tende a cumprir umas e ignorar outras |
| Mistral | Formato de saída declarado literalmente, com exemplo do formato | Saída livre — sem exemplo, o formato varia entre chamadas |
Não escreva isto na sua base de código como verdade permanente
Estas convenções mudam a cada versão de modelo. O que deve ficar permanente na sua base é o mecanismo de MEDIR — um conjunto de casos com resposta esperada, que roda contra qualquer modelo. Com ele, trocar de modelo é rodar a suíte e ler o número. Sem ele, é trocar e torcer, e a decisão volta a depender de quem tem a opinião mais confiante na reunião.
Prompt caching muda o desenho do prompt, não só o custo
O Bedrock permite marcar pontos de cache no prompt com blocos `cachePoint`. O que fica ANTES do ponto marcado é reaproveitado entre chamadas, e é cobrado de forma diferente do que é processado do zero. A consequência prática não é financeira, é de arquitetura do prompt: ela dita a ORDEM em que você monta as partes.
Para o cache servir, o prefixo precisa ser idêntico byte a byte entre chamadas. Isso inverte a intuição de quem monta prompt por concatenação: o que varia por requisição — a pergunta do usuário, o carimbo de data, o identificador da sessão — tem de ir depois do ponto de cache, nunca antes. Um carimbo de data no início do system prompt invalida o cache de todas as chamadas e não produz nenhum erro para você notar.
# Instrução e material de referência ficam ANTES do ponto de cache:
# são estáveis entre chamadas e é isso que se reaproveita.
system = [
{"text": INSTRUCAO_ESTAVEL + MANUAL_DE_POLITICAS},
{"cachePoint": {"type": "default"}},
]
# O que varia por requisição vem depois — jamais antes.
messages = [{"role": "user", "content": [{"text": pergunta_do_usuario}]}]
r = brt.converse(modelId=MODELO, system=system, messages=messages)
# A leitura que prova que funcionou:
u = r["usage"]
print(u.get("cacheReadInputTokens"), u.get("cacheWriteInputTokens"))Cache que não funciona falha em silêncio
Não há erro quando o prefixo muda: a chamada simplesmente processa tudo do zero e cobra por isso. O único sinal é `cacheReadInputTokens` vindo zerado em requisição que deveria ter acertado. Instrumente esse campo desde o primeiro dia — é a diferença entre descobrir na hora e descobrir na fatura. Há também um mínimo de tokens por modelo abaixo do qual o ponto de cache é ignorado, então prompt curto não se beneficia.
Sua aplicação monta o system prompt assim: data e hora atuais, depois o manual de políticas de 8 mil tokens, depois um `cachePoint`. O cache nunca acerta. Por quê?
Medir, e não acreditar
Toda afirmação deste módulo é uma hipótese sobre o seu caso até você medir. O ciclo mínimo que torna engenharia de prompt uma disciplina, e não um exercício de intuição, tem três peças e cabe numa tarde:
- Um conjunto de casos com resposta esperada — vinte a cinquenta entradas reais, com o que uma boa saída seria. Sai do seu histórico de produção, não da sua imaginação.
- Um critério de acerto que uma máquina consiga aplicar — igualdade exata para classificação, contém-o-campo para extração, ou um modelo julgando com rubrica escrita quando a saída é texto livre.
- Um registro por execução: modelo, versão do prompt, taxa de acerto, tokens de entrada e de saída. Sem a última coluna você compara qualidade ignorando custo, e escolhe o modelo caro por uma diferença que não paga.
Com isso montado, a pergunta "Nova ou Claude para esta tarefa?" deixa de ser debate e vira uma linha de tabela. E, mais importante, a resposta passa a ser reaproveitável: quando sair um modelo novo no catálogo, avaliar custa rodar a suíte.
Anti-padrões
| Anti-padrão | Por que parece boa ideia | O que quebra |
|---|---|---|
| Pedir "seja conciso" e esperar um tamanho | É o que se diria a uma pessoa | Cada modelo tem uma régua. Dê um limite numérico ou um exemplo |
| Empilhar dez regras num parágrafo | Todas são importantes | Modelos cumprem as primeiras e as últimas melhor que as do meio. Use lista e ordene por criticidade |
| Colar o documento inteiro e perguntar no fim | O contexto é grande, cabe | Instrução distante do fim perde peso. Repita a tarefa depois do material |
| Prompt afinado num modelo, sem suíte de avaliação | Funcionou nos testes manuais | A troca de modelo vira risco desconhecido, e a plataforma multi-modelo perde a razão de existir |
| Carimbo de data ou ID no início do system | Dá contexto ao modelo | Invalida o cache em toda chamada, sem erro visível |
Um prompt de extração de dados de nota fiscal devolve, ocasionalmente, um número de CNPJ que não está no documento. Qual correção ataca a causa?
Próximo passo
Com o prompt estável e medido, o passo seguinte é dar ferramentas ao modelo: é o que transforma uma chamada de texto numa ação sobre o seu sistema. O contrato entre modelo e aplicação é o assunto de tool use, e as mesmas quatro alavancas valem lá — a descrição de uma ferramenta é um prompt.
Perguntas frequentes
❓ Preciso reescrever o prompt ao trocar de modelo no Bedrock?
❓ Por que o prompt caching do Bedrock não está reduzindo meu custo?
❓ Qual modelo do Bedrock é melhor para engenharia de prompt?
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…