Prompts como código: versionamento, testes e boas práticas
Prompt engineering operacional: versionamento, A/B testing, regressão de prompts e avaliação automatizada.
Alienhub Team
AI Engineering

Prompt engineering mudou. Não é mais "escrever um texto legal pra colinha do LLM" e rezar pra funcionar. É prompt ops — versionamento, testes, avaliação, monitoramento.
Você vai versioná-lo em git, testá-lo contra um eval set, comparar resultados de prompt V1 vs V2, monitorar degradação de qualidade quando o modelo upstream muda. É código. Bem, é quase código.
Prompt engineering vs prompt ops
Prompt engineering é o trabalho criativo: descobrir como estruturar uma pergunta pra o LLM entender e responder bem.
Prompt ops é a infraestrutura que mantém isso funcionando em produção.
Diferença:
| Aspecto | Prompt eng | Prompt ops |
|---|---|---|
| Quem faz | Pessoa fazendo iteração manual | Time automatizando processos |
| Versioning | Copypaste em Notion | Git, tags, branches |
| Testes | "Parece certo" | Eval sets, LLM-as-judge |
| A/B testing | Rodar na mão, comparar | Framework automático |
| Monitoramento | Nenhum | Alerts em regressão |
| Rollback | Manual | Um comando |
A realidade é que você precisa de ambos. Alguém faz o work criativo. Depois você coloca em uma infraestrutura que torna isso reproduzível e testável.
Versionamento: prompts em git
Prompts não devem viver em código ou em um AI IDE. Devem viver em git como qualquer outro artifact.
Estrutura de repo que funciona:
prompts/
├── classification/
│ ├── PROMPT.yml
│ ├── examples.jsonl
│ └── eval_set.jsonl
│
├── extraction/
│ ├── PROMPT.yml
│ ├── examples.jsonl
│ └── eval_set.jsonl
│
└── README.md
PROMPT.yml:
name: "content_classifier"
version: "2.1"
model: "gpt-4o-mini"
temperature: 0.3
max_tokens: 500
system_prompt: |
Você é um assistente que classifica conteúdo...
user_template: |
Classifique este conteúdo:
{{content}}
output_schema:
type: "object"
properties:
categoria:
type: "string"
enum: ["urgente", "normal", "baixo"]
confiança:
type: "number"
minimum: 0
maximum: 1
Versionamento em git significa:
- Histórico completo — quem mudou o prompt, quando, por quê
- Branches para testar variações (prompt/v2-mais-conciso)
- Code review antes de mercar pra main
- Tags pra "essa versão foi pra produção em 21-04-2026"
Templates: separar lógica de prompt
Um prompt hardcodado é difícil de versionar e testar.
Use templates (Jinja2 é padrão):
# PROMPT.yml
system_prompt: |
Você é um assistente de suporte {{ empresa }}.
user_template: |
Contexto: {{ contexto }}
Histórico:
{% for msg in historico %}
- {{ msg.role }}: {{ msg.conteudo }}
{% endfor %}
Nova pergunta: {{ pergunta }}
Isso permite:
- Reusar o mesmo prompt pra empresas diferentes
- Injetar contexto dinâmico sem reescrever
- Testar com diferentes valores de variável
A/B testing: prompt v1 vs v2
Você mudou o prompt. Agora o quê? Rodar nas mãos? Não. A/B test.
Setup:
- Crie eval set com 100 queries (ou mais)
- Rode prompt V1 nelas, capture respostas
- Rode prompt V2 nelas, capture respostas
- Avalie ambas (LLM-as-judge ou humano)
- Compare resultados
Exemplo com Promptfoo:
# promptfoo.config.yml
prompts:
- file: prompts/classification/v1.yml
- file: prompts/classification/v2.yml
testCases:
- vars:
content: "CLIENTE FURIOSO. PRODUTO VEIO QUEBRADO."
assert:
- type: regex
value: "urgente"
- vars:
content: "Olá, qual é o horário de atendimento?"
assert:
- type: llm-rubric
value: "A resposta é educada e relevante"
providers:
- openai:gpt-4o-mini
- openai:gpt-4o
Rode promptfoo eval e você tem uma tabela:
Prompt | Pass Rate | Avg Latency | Avg Cost
v1 (4o-mini) | 82% | 450ms | $0.008
v2 (4o-mini) | 91% | 460ms | $0.009
v1 (4o) | 94% | 280ms | $0.025
v2 (4o) | 96% | 285ms | $0.027
Agora você sabe. V2 é melhor, mas custa um pouco mais. Vale? Depende.
Regressão de prompt: quando o modelo muda
OpenAI atualiza GPT-4o. Agora seu prompt quebrou em 5% das queries que funcionavam antes.
É surpresa? Não. Modelos mudam. Qualidade sobe, desce, shift de lado.
Mitigação:
- Eval set estável: mantenha um eval set de 50-100 queries com respostas esperadas
- CI/CD de prompts: quando atualiza modelo ou prompt, roda eval set automaticamente
- Regressão check: falha se pass rate cai mais de 2%
- Alertas: se model performance degrada em produção, notifica
Exemplo com GitHub Actions:
name: Prompt Regression Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run eval set
run: promptfoo eval --config prompts/eval.yml
- name: Check regression
run: |
pass_rate=$(jq '.passRate' results.json)
if (( $(echo "$pass_rate < 0.88" | bc -l) )); then
echo "FAIL: Pass rate dropped below 88%"
exit 1
fi
Agora, toda mudança de prompt é testada automaticamente. Regressões são descobertas em minutos, não quando usuário reclama.
Avaliação automatizada: LLM-as-judge
Como você avalia se uma resposta é "boa"? Regexes não escalam. Você precisa de semântica.
LLM-as-judge: use um LLM pra avaliar output de outro LLM.
query: "Qual é a melhor forma de aprender Python?"
resposta_do_seu_agente: "Python é fácil. Use loops."
avaliador: "Avalie a resposta acima em uma escala 1-5 para:
- Clareza
- Corretude técnica
- Utilidade prática
Formato JSON."
resultado: {
"clareza": 3,
"corretude": 2,
"utilidade": 2,
"score_geral": 2.3,
"feedback": "Resposta vaga, não fornece recursos ou exemplos"
}
Isso funciona porque avaliar é mais simples que gerar. Um modelo consegue ser um avaliador honesto mesmo que não seja criativo.
Tools que fazem isso:
- Braintrust: plataforma de eval com LLM-as-judge integrado
- Langfuse: tracking + evals
- Weights & Biases: MLOps tradicional estendido pra LLM
Estrutura de repo para prompts (exemplo real)
projeto_saas/
├── prompts/
│ ├── content_classification/
│ │ ├── PROMPT.yml # config + template
│ │ ├── examples.jsonl # few-shot examples
│ │ ├── eval_set.jsonl # 50 queries para testar
│ │ └── README.md # documentação
│ │
│ ├── customer_support/
│ │ ├── PROMPT.yml
│ │ ├── examples.jsonl
│ │ ├── eval_set.jsonl
│ │ └── README.md
│ │
│ └── README.md # guia geral
│
├── tests/
│ ├── test_classification_regression.py
│ ├── test_support_llm_judge.py
│ └── conftest.py
│
├── .github/workflows/
│ └── prompt_eval.yml # CI/CD
│
└── scripts/
└── eval_prompts.py # rodar evals localmente
Cada prompt tem seu próprio diretório com:
- PROMPT.yml: versão canônica do prompt (versionada em git)
- examples.jsonl: few-shot examples (versionado em git)
- eval_set.jsonl: eval test cases (idealmente, versionado em git)
- README.md: contexto, histórico de mudanças
Script prático para testar localmente
import json
import yaml
from openai import OpenAI
client = OpenAI()
def load_prompt(prompt_file):
with open(prompt_file) as f:
return yaml.safe_load(f)
def load_eval_set(eval_file):
cases = []
with open(eval_file) as f:
for line in f:
cases.append(json.loads(line))
return cases
def run_eval(prompt_config, eval_cases):
system = prompt_config['system_prompt']
user_template = prompt_config['user_template']
results = []
for case in eval_cases:
user = user_template.format(**case['vars'])
response = client.chat.completions.create(
model=prompt_config['model'],
messages=[
{'role': 'system', 'content': system},
{'role': 'user', 'content': user}
],
temperature=prompt_config.get('temperature', 0.7)
)
answer = response.choices[0].message.content
results.append({
'query': case['vars'],
'expected': case.get('expected'),
'actual': answer,
'passed': evaluate(answer, case.get('expected'))
})
pass_rate = sum(1 for r in results if r['passed']) / len(results)
print(f"Pass rate: {pass_rate:.1%}")
return results
def evaluate(answer, expected):
# Implementar lógica de avaliação
# Pode ser regex, LLM-as-judge, ou validação estruturada
if expected is None:
return True
return expected.lower() in answer.lower()
if __name__ == '__main__':
prompt = load_prompt('prompts/classification/PROMPT.yml')
eval_set = load_eval_set('prompts/classification/eval_set.jsonl')
run_eval(prompt, eval_set)
Rollback rápido
Prompt está causando problemas em produção?
git log prompts/classification/PROMPT.yml
# vê o histórico
git checkout HEAD~1 prompts/classification/PROMPT.yml
# volta pra versão anterior
git commit -m "Revert classification prompt to v2.0"
# aplica revert
# seu app recarrega a config e tá feito
Rollback em 30 segundos. Sem downtime.
Checklist: antes de por um prompt em produção
[ ] Prompt está em git com versionamento claro
[ ] Eval set de pelo menos 30 casos está definido
[ ] Pass rate >= 85% no eval set
[ ] A/B tested contra versão anterior
[ ] LLM-as-judge avaliou qualidade
[ ] Custo/latência está dentro do budget
[ ] Testes de regressão estão em CI/CD
[ ] Rollback plan documentado
[ ] Monitoramento de qualidade em produção
[ ] Documentação: por que esse prompt? o que faz?
Na prática
A gente trabalha com times que têm centenas de prompts. Sem prompt ops, é caos — ninguém sabe qual versão está em produção, mudanças quebram coisas de forma aleatória, custos explodem.
Com prompt ops? Agora é gerenciável. Mudança de prompt é como mudança de código: revisa, testa, mercia, monitorada.
Se você tem prompts que precisam ser robusto, testável e iterável em produção, a gente sabe como estruturar. Já fomos para o poço aqui também.
Construindo seu SaaS?
Receba insights semanais sobre produto, tecnologia e negócios para fundadores de SaaS e Micro-SaaS.
Continue Lendo
