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 os

import 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 calibrate

delta = calibrate(estimations=[0.45, 0.48, 0.44, 0.46])

print(f"Noise band δ = {delta:.4f}")

Un δ