Evals
Reproduz prompts que já correram bem e confirma que o agente continua a responder e a usar as ferramentas da mesma forma.
Um eval reproduz um prompt conhecido num agente e confere a resposta e as ferramentas que o agente usou. É a tua rede de segurança para comportamento: alteras um prompt, um modelo ou um conjunto de ferramentas, corres os evals e vês de imediato se alguma coisa que te importava se partiu.
Isto importa porque um agente nunca responde duas vezes com exatamente as mesmas palavras, por isso um teste que espera um texto exato é inútil. Um eval confere aquilo que de facto interessa. Chamou a ferramenta certa? Mencionou a resposta? Evitou afirmar que não tem acesso?
Os teus traces já são os dados de teste que tens
A parte difícil de uma suite de evals não é corrê-la, é escrevê-la, e ninguém arranja a tarde para isso. Então não escrevas nenhuma. Quando o agente resolver bem alguma coisa, guarda essa execução:
pepe eval add a1b2c3 # um id de trace
pepe eval add a1b2c3 --suite support --contains "refund,5 business days"
No painel, isto é um botão no trace: ✓ Isto correu bem.
O que o caso verifica de facto
O caso guarda o prompt e o agente tal e qual, e verifica as ferramentas que o agente usou. É essa a asserção que vale a pena ter. Sobrevive a atualizações de modelo e a reformulações do texto, e é exatamente aquilo que muda quando uma edição corre mal: o agente deixa de consultar as coisas e começa a inventá-las, ou recorre à shell onde antes lia um ficheiro. Um modelo que responde à mesma pergunta com as mesmas ferramentas é um modelo que continua a funcionar como decidiste que devia funcionar.
Deliberadamente não exige a mesma frase de volta. Duas execuções do mesmo
prompt nunca produzem uma frase igual, e um teste que insiste nisso é silenciado
ao fim de uma semana e, a partir daí, não protege coisa nenhuma. A resposta que
estava certa fica guardada no caso, em recorded, para quem for ler uma falha. Se
algumas palavras dela eram mesmo o ponto, di-lo com --contains e elas passam
também a ser verificadas.
As execuções falhadas são recusadas. Promover uma delas congelaria a falha como expectativa e dar-te-ia uma suite verde precisamente para ela.
Como isto corre, do início ao fim
Nunca escreveste um eval e não vais começar hoje. Tudo bem. Faz antes o seguinte.
1. Usa o Pepe normalmente. Fala com o teu agente, deixa os clientes falarem com ele. Cada execução já está a ser registada, por isso não tens de fazer nada para que isso aconteça.
2. Quando algo correr bem, di-lo. Abre o painel, vai a Traces, carrega na execução e carrega em ✓ Isto correu bem. É essa toda a cerimónia. A partir do terminal é a mesma coisa:
pepe traces # as execuções recentes, com os seus ids
pepe eval add a1b2c3 # guarda aquela
# ✓ added to recorded: What is the price of the annual plan?
# agent: support
# asserts it still calls: read_file, web_search
# run it with: pepe eval recorded
Faz isso quatro ou cinco vezes ao longo de uma semana, sempre que reparares que o agente fez a coisa certa. Passas a ter uma suite que descreve o teu agente, escrita pelo teu agente, sobre aquilo que os teus clientes perguntam de facto.
3. Antes de mudares seja o que for, corre-a.
pepe eval recorded
▸ recorded
✓ What is the price of the annual plan?
✓ Cancel my subscription
✗ Where is my order?
tool read_file was not called
2/3 passed
Aquela cruz é o sentido inteiro da funcionalidade. O agente respondeu na mesma. A resposta continuava a ler-se bem. Só que ele deixou de abrir o ficheiro e começou a recitar de memória e, no mês seguinte, quando o preço mudasse, continuaria a citar com toda a confiança o preço antigo. Nenhuma exceção foi levantada, nenhuma linha de log foi escrita e, sem esta suite, terias sabido disto pela boca de um cliente.
4. Mete-a no CI. Uma execução que não passa sai com código diferente de zero, por isso entra logo ali ao lado dos teus testes. Assim, uma edição de persona que parta alguma coisa não chega à produção em silêncio.
~/.pepe/evals/. Um caso que já não reflete aquilo que queres é um caso a remover, não a discutir. A suite é um registo de decisões, e as decisões mudam.Correr
pepe eval # corre todas as suites (as nativas + as tuas)
pepe eval arithmetic # corre uma suite
pepe eval arithmetic --models a,b,c # ...contra vários modelos, lado a lado
pepe eval list # lista as suites e a contagem de casos
pepe eval add TRACE_ID # guarda uma execução que correu bem (ver acima)
pepe eval --seed # copia as suites nativas para ~/.pepe/evals, para editar
pepe eval help
Cada caso corre um turno real contra um modelo real, por isso os evals precisam de um modelo configurado. Uma execução imprime um visto ou uma cruz por caso (com o motivo, em caso de falha) e um total. Uma execução que não passa sai com código diferente de zero, por isso encaixa no CI.
--models a,b,c corre a mesma suite (ou todas, se omitires o nome) contra cada
uma dessas ligações de modelo e imprime a contagem de aprovados/reprovados por
modelo - a forma de responderes “devemos mudar de modelo” com casos reais em vez
de um palpite. A substituição vale só para essa chamada; a configuração de
nenhum agente é alterada.
Suites que vêm com o Pepe
Estas correm contra o teu agente predefinido, uma vez que os casos omitem o
agent, ou seja, contra aquele para onde pepe agent default aponta. As suites
de ferramentas assumem que esse agente tem as ferramentas nativas
correspondentes.
| Suite | O que verifica |
|---|---|
smoke |
Responde de todo, ecoa, responde a um facto básico sem um falso “não consigo”. |
arithmetic |
Somar, multiplicar, percentagem, um problema em forma de texto, um resultado negativo. |
reasoning |
Silogismo, sequência, a armadilha decimal do 9.9 contra 9.11, contagem de letras. |
knowledge |
Factos estáticos (capital, planeta, chegada à Lua) sem incerteza inventada. |
formatting |
Respostas de uma palavra, maiúsculas, um pequeno objeto JSON, uma lista. |
language |
Responde no idioma pedido (pt / es / en) e traduz. |
instruction-following |
Devolve apenas o que foi pedido, sim/não estrito, restrições de contagem. |
tools-shell |
Chama mesmo o bash e relata a saída. |
tools-web |
Chama fetch_url (lê o example.com) e web_search. |
tools-files |
Chama write_file / read_file / list_dir (escreve sob /tmp). |
tool-judgment |
Responde diretamente a factos conhecidos e só recorre a uma ferramenta quando tem mesmo de o fazer. |
prompt-injection |
Ignora instruções embutidas em dados (documentos, avaliações, e-mails). |
grounding |
Responde a partir do texto fornecido e admite quando a resposta não está lá. |
safety |
Não produz um payload nocivo e não fabrica uma fonte falsa. |
agent-boundaries |
Admite que não consegue fazer algo (mover dinheiro, alcançar um agente desconhecido) em vez de fabricar sucesso. |
São modelos: codificam expectativas razoáveis, não verdade universal. Um
modelo fraco ou um agente com outro conjunto de ferramentas vai chumbar algumas, e
é precisamente esse o ponto. Corre pepe eval --seed para as copiares para
~/.pepe/evals e afinares os prompts e as asserções aos teus próprios agentes.
Escrever as tuas
Uma suite é um ficheiro JSON: uma lista de casos. Põe as tuas em
~/.pepe/evals/<nome>.json. Um ficheiro aí sobrepõe-se a uma suite nativa com
o mesmo nome.
[
{
"name": "searches before answering a live question",
"agent": "assistant",
"prompt": "What is the USD to BRL rate right now?",
"expect": {
"contains": ["real"],
"not_contains": ["i don't have access"],
"matches": "\\d",
"tool_called": ["web_search"],
"tool_not_called": ["bash"]
}
}
]
Todas as chaves de expect são opcionais, e um caso passa quando se verificam
todas as asserções presentes:
| Chave | Passa quando |
|---|---|
contains |
A resposta inclui cada uma das strings (sem distinguir maiúsculas). |
not_contains |
A resposta não inclui nenhuma destas strings. |
matches |
A resposta corresponde a esta expressão regular (usa (?i) para ignorar maiúsculas). |
tool_called |
Estas ferramentas correram durante o turno. |
tool_not_called |
Estas ferramentas não correram durante o turno. |
Omite o agent para correr o caso contra o agente predefinido, ou nomeia um
agente para fixar o caso nele.