Introduzione a RRSI
RRSI è un metodo che consente a un agente basato su modello di linguaggio (LLM) di riscrivere autonomamente il proprio harness – prompt, strumenti, memoria, flusso di controllo e sub‑agenti – attorno a un modello congelato. L’obiettivo è evitare che l’harness si adatti eccessivamente ai compiti su cui l’agente evolve, mantenendo così una capacità di generalizzazione più robusta.
Installazione del pacchetto RRSI
Il pacchetto non è disponibile su PyPI, perciò si installa direttamente dal repository GitHub di Google Research, fissando il commit utilizzato nella nota originale. L’unica dipendenza aggiuntiva è il client Anthropic, necessario solo per le chiamate a Claude (non usate nella parte di selezione che noi eseguiamo).
import osimport sys
import subprocess
subprocess.run([sys.executable, "-m", "pip", "install", "-q",
"git+https://github.com/google-research/rrsi.git@be50316e1db05914068a973f322770ef08ed7ba1"],
check=True)
Dopo l’installazione, il codice stampa le versioni dei componenti principali e una breve descrizione del ruolo di RRSI.
Mappatura dei simboli del paper alle funzioni del codice
Il repository fornisce una tabella che collega ogni simbolo teorico a una posizione concreta nel codice. La lista completa è:
- Ŝ, Ĉ – Eq. (estimate) →
rrsi.evaluate.aggregate - δ – noise band →
rrsi.calibrate.calibrate - Algorithm 2 – floor + cost rule →
rrsi.selection.judge / selectround - bₜ – Eq. (anneal) →
rrsi.schedule.editbudget - Critic – leakage screen →
rrsi.critic.precheck / review - Lₜ, gₜ, Bₜ – history, yield, prune →
rrsi.history.History - σₜ, Uₜ – stall + exploration →
rrsi.history.stall_flag / exploration - ν – structural novelty →
rrsi.components.novelty
Questa mappatura è fondamentale per capire dove intervenire quando si desidera modificare o analizzare una singola parte dell’algoritmo.
Configurazione dei parametri di default
RRSIConfig raggruppa tutti gli iper‑parametri riportati nel paper. Stampando l’oggetto otteniamo valori come T = numero di round, k = trial per task, m = candidati per round e gli intervalli di budget bₘᵢₙ, bₘₐₓ. Ecco un esempio di output:
CFG = RRSIConfig()print(f"paper defaults: T={CFG.T} round, k={CFG.k} trial/task, m={CFG.m} cand/round,
b in [{CFG.bmin},{CFG.bmax}]
beta0={CFG.beta0} beta1={CFG.beta1} ws={CFG.ws} wc={CFG.wc} wn={CFG.wn}
deltaz={CFG.deltaz}")
Questi valori non richiedono chiavi API, GPU o dataset esterni, il che rende la fase di sperimentazione accessibile a chiunque disponga di un ambiente Python standard.
Valutazione dell’harness: stima di reward (Ŝ) e costo (Ĉ)
La funzione aggregate calcola due metriche per ogni harness: Ŝ, la media di reward su tutti i trial di tutti i task, e Ĉ, il numero medio di token usati per trial. Il codice di esempio crea tre task con due trial ciascuno, mostrando come il risultato venga stampato.
@section("2. Evaluate(H): a score and a cost, and why a crash counts as zero")
def estimator():
base = {
"task_000": TaskResult(rewards=[1, 1], tokens=[11800, 12400]),
"task_001": TaskResult(rewards=[1, 0], tokens=[15100, 14600]),
"task_002": TaskResult(rewards=[0, 0], tokens=[21000, 19500]),
}
ev = aggregate("H0", 2, base)
print(f"three tasks x k=2 -> Ŝ = {ev.S:.3f} Ĉ = {ev.C:,.0f}")
# simulazione di un crash sul task più difficile
crashy = dict(base)
crashy["task_002"] = TaskResult(rewards=[0.0, 0.0], tokens=[None, None], missing=2)
ev_crash = aggregate("crashy", 2, crashy)
# confronto con un estimatore che ignora le prove mancanti
dropped = {t: r for t, r in crashy.items() if not r.missing}
naive = sum(sum(r.rewards) for r in dropped.values()) / sum(len(r.rewards) for r in dropped.values())
print(f"naive estimator: {naive:.3f} RRSI aggregate: {ev_crash.S:.3f}")
return f"crash scored {ev_crash.S:.3f} vs naive {naive:.3f}"
estimator()
Il risultato evidenzia due aspetti cruciali:
- RRSI tratta le prove mancanti (crash) come reward zero, impedendo a un agente di “imporre” miglioramenti artificiosi cancellando i trial più difficili.
- Il calcolo di Ĉ considera solo i token registrati, ignorando i valori nulli.
Un ulteriore esempio mostra come gestire rubriche ponderate, tipiche di sistemi di valutazione come Harvey LAB, dove il reward è la frazione di criteri soddisfatti su tutti i task.
Calibrazione del rumore (δ) e banda di incertezza
La funzione calibrate stima la varianza dei reward ottenuti da una serie di trial, fornendo un valore δ che funge da “banda di rumore”. Questo valore è poi usato per decidere se una modifica è statisticamente significativa rispetto al rumore di fondo.
from rrsi.calibrate import calibratedelta = calibrate(estimations=[0.45, 0.48, 0.44, 0.46])
print(f"Noise band δ = {delta:.4f}")
Un δ