E4 · Tres ciclos sin costo
10 minCorre el ensayo.
Listo cuando: tail -n +2 $E/sis/results.tsv | cut -f5 | sort | uniq -c → 1 keep y 2 discard; git -C $E/sis log --oneline | wc -l → 2.
Clase 2 · 20 min
El diseño más limpio de un loop que mejora solo es corto: el agente cambia una cosa, un comando da la nota, si mejoró se queda con commit, si no mejoró vuelve con git reset, y todo se vuelve una línea en un archivo. En esta clase ejecutas ese ciclo con agentes falsos y después con Claude Code de verdad.
Empezar la clase
Objetivo: ejecutar un experimento al estilo autoresearch: el agente cambia, una métrica decide, git commit si mejoró y git reset si no.
El diseño de autoresearch, descrito en fuentes secundarias. Haz clic en cada bloque.
En autoresearch el sistema es un script de entrenamiento y la métrica es la pérdida en validación; aquí, un clasificador de triaje con 40 casos sintéticos.
Cuatro ideas, una por ciclo. Una de ellas se rompe en la primera ejecución (el agente se queda sin respuesta). Ejecuta, interrumpe y retoma.
Simulación en el navegador. El ensayo de verdad está justo abajo.
El kit crea un repo de triaje (v1) y corre tres ciclos: un agente que mejora, uno que empeora y uno que no cambia la nota. No se llama a ningún modelo.
K=~/projetos/loop-r-eng-aprende-v72/kit
E=${TMPDIR:-/tmp}/ensaio-aprende/a2
bash $K/novo-sistema.sh $E/sis
for m in sinonimos estraga comenta; do
AGENTE="bash $K/agente-falso.sh $m" bash $K/experimento.sh $E/sis "$m"; echo "saída: $?"
done
echo "## results.tsv"; cut -f1,3- $E/sis/results.tsv
echo "## git log"; git -C $E/sis log --format=%ssistema criado em /tmp/ensaio-aprende/a2/sis (acerto: 0.700 (28/40)) ciclo 1 · keep · 0.700 → 0.800 · melhorou saída: 0 ciclo 2 · discard · 0.800 → 0.700 · não melhorou saída: 1 ciclo 3 · discard · 0.800 → 0.800 · não melhorou saída: 1 ## results.tsv ciclo base novo status descricao 1 0.700 0.800 keep sinonimos 2 0.800 0.700 discard estraga 3 0.800 0.800 discard comenta ## git log keep: sinonimos (0.700 → 0.800) v1: regras de base
La columna del hash del commit se omite (cambia en cada ejecución). El código de salida del experimento.sh dice lo que pasó: 0 keep, 1 discard, 2 error.
Tratar un agente sin respuesta como "no mejoró". Cuando la suscripción llega al límite, el agente devuelve vacío: el ciclo tiene que salir como error (código 2), si no la cola se convierte en una serie de discards falsos y nadie nota que nada corrió. El agente-claude.sh sale con 1 cuando la respuesta no tiene reglas, y el experimento.sh registra erro.
Una llamada por tu suscripción (sale de la cuota de tu suscripción): claude -p sin herramientas recibe las reglas y los casos errados y devuelve un regras.txt nuevo. Quien decide es la medida, no el modelo.
K=~/projetos/loop-r-eng-aprende-v72/kit
E=${TMPDIR:-/tmp}/ensaio-aprende/a2 # o repo do ensaio acima, já com o keep dos sinônimos
AGENTE="bash $K/agente-claude.sh" bash $K/experimento.sh $E/sis "claude: uma mudança"; echo "saída: $?"
echo "status da última linha: $(tail -1 $E/sis/results.tsv | cut -f5)"#!/usr/bin/env bash
# agente-claude.sh — el agente REAL del experimento: Claude Code (sin herramientas) propone un regras.txt nuevo.
# Se ejecuta en la carpeta del repo, llamado por experimento.sh. Sale de la cuota de tu suscripción (una llamada).
# Respuesta vacía (límite de la sesión, error) = ERRO, salida 1: nunca se convierte en "no cambió nada".
set -uo pipefail
K=$(cd "$(dirname "$0")" && pwd)
PEDIDO="Você melhora as regras de um classificador de mensagens de suporte. Formato de cada linha: 'categoria: palavra, palavra'; a primeira categoria cuja palavra aparece no texto vence; sem nenhuma, 'outros'.
Regras atuais:
$(cat regras.txt)
Casos que o classificador errou:
$(python3 "$K/medir.py" . --erros | tail -n +2)
Proponha UMA mudança que generalize (palavras que pessoas reais usariam), sem copiar frases inteiras dos casos.
Responda SÓ com o conteúdo completo do novo regras.txt, sem explicação e sem cercas de código."
J=$(mktemp)
echo "$PEDIDO" | claude -p --tools "" --output-format json > "$J" 2>/dev/null
python3 - "$J" <<'PY'
import json, os, sys
try:
d = json.load(open(sys.argv[1], encoding="utf-8"))
except Exception:
print("ERRO: resposta do claude não é JSON"); sys.exit(1)
r = (d.get("result") or "").strip()
linhas = [l for l in r.splitlines() if not l.startswith("```")]
if d.get("is_error") or not any(":" in l for l in linhas):
print("ERRO: sem regras na resposta (" + (r[:80] or "vazia") + ")"); sys.exit(1)
u = d.get("usage") or {}
ent = u.get("input_tokens", 0) + u.get("cache_read_input_tokens", 0) + u.get("cache_creation_input_tokens", 0)
if os.environ.get("TOKENS_ARQ"):
open(os.environ["TOKENS_ARQ"], "w").write(f"{ent} {u.get('output_tokens', 0)}\n")
open("regras.txt", "w", encoding="utf-8").write("\n".join(linhas).strip() + "\n")
print(f"regras.txt reescrito ({len(linhas)} linhas)")
PY
rc=$?; rm -f "$J"; exit $rcciclo 4 · keep · 0.800 → 0.900 · melhorou saída: 0 status da última linha: keep
Una ejecución. El modelo agregó palabras de entrega (pacote, encomenda, transportadora, frete…) y la nota visible pasó de 0.800 a 0.900. Tu ejecución puede dar keep o discard: el "listo cuando" solo comprueba que la línea quedó registrada. En la clase 6, este mismo cambio es reprobado por los casos ocultos.
El experimento.sh del kit mide el clasificador de triaje. En tu repo, dos variables cambian el medidor; el results.tsv se crea solo y queda fuera de git. Ensayo sin costo en un repo de práctica.
K=~/projetos/loop-r-eng-aprende-v72/kit
E=${TMPDIR:-/tmp}/ensaio-aprende/a2-adaptar; rm -rf $E; mkdir -p $E/repo; cd $E/repo
# um repo "seu": sem results.tsv, sem .gitignore, com o próprio medidor
printf 'def dobro(x):\n return x + 2\n' > calc.py
printf '1 2\n2 4\n5 10\n0 0\n' > casos.txt # entrada e esperado
cat > medir.sh <<'FIM'
# imprime "<acerto> <ok> <total>" (o experimento.sh lê o 1º número)
python3 -c "
import calc
c = [l.split() for l in open('casos.txt') if l.strip()]
ok = sum(calc.dobro(int(a)) == int(b) for a, b in c)
print(f'{ok / len(c):.3f} {ok} {len(c)}')"
FIM
git init -q -b main; git add -A; git -c user.name=treino -c user.email=treino@exemplo.invalid commit -qm "v1"
export MEDIR="bash medir.sh" MEDIDOR="casos.txt medir.sh" # as duas variáveis da adaptação
bash $K/experimento.sh --congelar . $E/medidor.sha256; export GUARDA=$E/medidor.sha256
AGENTE="echo '# revisado' >> calc.py" bash $K/experimento.sh . "comenta"; echo "saída: $?"
AGENTE="printf 'def dobro(x):\n return x * 2\n' > calc.py" bash $K/experimento.sh . "corrige"; echo "saída: $?"
AGENTE="echo '3 7' >> casos.txt" bash $K/experimento.sh . "mexe nos casos"; echo "saída: $?"
echo "## results.tsv (criado pelo experimento.sh)"; cut -f1,3- results.tsv
echo "## git status (vazio = limpo)"; git status --shortmedidor congelado em /tmp/ensaio-aprende/a2-adaptar/medidor.sha256 ciclo 1 · discard · 0.250 → 0.250 · não melhorou saída: 1 ciclo 2 · keep · 0.250 → 1.000 · melhorou saída: 0 ciclo 3 · discard · 1.000 → 1.000 · DESCARTADO: mexeu no medidor (casos.txt medir.sh) saída: 1 ## results.tsv (criado pelo experimento.sh) ciclo base novo status descricao 1 0.250 0.250 discard comenta 2 0.250 1.000 keep corrige 3 1.000 1.000 discard mexe nos casos ## git status (vazio = limpo)
Coluna do hash do commit omitida. O ciclo 3 mostra a guarda da aula 6 valendo também para o medidor seu.
1. La medida. MEDIR="[tu comando]" corre en la carpeta del repo e imprime el número primero, en una línea. Recibe --valor y, si usas ESCONDIDOS (clase 6), también --casos [archivo]: tu script tiene que medir ese archivo en lugar de los casos de siempre.
2. Qué congelar. MEDIDOR="[archivos]" lista lo que lee la medida (casos y el propio script). Es lo que --congelar graba en el manifiesto.
3. El registro. Si falta, el experimento.sh crea el results.tsv con encabezado y lo pone en .git/info/exclude, sin tocar tu .gitignore. Rastro y manifiesto quedan fuera del repo; un archivo nuevo no ignorado dentro de él hace que el ciclo siguiente salga con error 2 (repo sucio).
Ensayo, real y tu sistema.
Corre el ensayo.
Listo cuando: tail -n +2 $E/sis/results.tsv | cut -f5 | sort | uniq -c → 1 keep y 2 discard; git -C $E/sis log --oneline | wc -l → 2.
Corre el bloque real justo después del ensayo.
Listo cuando: wc -l < $E/sis/results.tsv → 5 (encabezado + 4 ciclos) y la última columna de estado es keep, discard o erro, nunca vacía.
En tu sistema, escribe el comando que imprime la métrica de tu hipótesis (clase 1) como número al comienzo de la línea, en el formato del medir.py --valor. Conéctalo al experimento.sh con las variables MEDIR y MEDIDOR, como en el bloque "Adaptar a tu repo" de arriba.
Listo cuando: tu comando de medida, corrido dos veces seguidas sin cambios, imprime el mismo número; y AGENTE="echo '# revisado' >> [un archivo del repo]" bash $K/experimento.sh . "comenta"; echo "saída: $?", con MEDIR y MEDIDOR exportados, termina en discard y saída: 1.
Pregunta 1 de 4
El cambio dio exactamente la misma nota que la base. ¿Qué hace el ciclo?competencia
Pregunta 2 de 4
¿Por qué el discard también va al results.tsv?
Pregunta 3 de 4
El agente se quedó sin respuesta (límite de la sesión). ¿Cómo debe terminar el ciclo?competencia
Pregunta 4 de 4
Sobre los números de autoresearch (experimentos por hora, ganancia en el entrenamiento), ¿qué dice este curso?
Elige una alternativa. La explicación aparece después de tu intento.