Vai al contenuto

Guide

Utenti simulati

Una conversazione con script mette alla prova il tuo assistente con un utente che non reagisce mai. Un utente simulato reagisce: un modello interpreta una persona descritta da ogni caso, scrive ogni messaggio successivo a partire da ciò che il tuo assistente ha appena detto, e si ferma quando il suo obiettivo è raggiunto o quando rinuncia. Oloproof registra ciò che è passato tra i due, lo misura come qualsiasi conversazione, e lascia che un gate decida su di esso solo dopo che delle persone hanno trovato realistico l'utente simulato. Il tutorial percorre un servizio di assistenza che parla con clienti simulati.

Personaggi

L'input di ogni caso contiene un personaggio (persona): chi è l'utente, che cosa vuole e che cosa sa.

{"id": "c25", "input": {"persona": {
  "description": "A retired teacher who ordered a cookbook last week. Writes short, polite messages.",
  "goal": "Have the order of a cookbook delivered to my new address.",
  "facts": {"order": "B-35", "postcode": "10275"}
}}}
  • description e goal sono obbligatori. Scrivi un obiettivo che un lettore possa verificare dalla sola conversazione: "far avviare un rimborso al negozio" si può decidere da ciò che dice l'assistente, "ottenere un rimborso" no, perché il denaro arriva più tardi.
  • facts è ciò che l'utente sa e condivide solo quando la conversazione ne ha bisogno, come un numero d'ordine. Il tuo assistente non vede mai il personaggio.
  • opening è il primo messaggio dell'utente, parola per parola, quando ogni sistema deve essere accolto allo stesso modo.
  • max_turns limita i messaggi di questo utente, sostituendo quello del progetto.

Un personaggio è contenuto del dataset: è coperto dal digest della suite ed è lo stesso per ogni sistema misurato su di esso.

Dichiarare l'utente simulato

Il modello che interpreta ogni personaggio si dichiara sul sistema, come un giudice:

system:
  name: support-desk
  callable: desk:talk
  simulated_user:
    provider: openai_compatible
    base_url: http://localhost:11434/v1
    model: qwen2.5vl
    max_turns: 6

Ogni campo è nel riferimento della configurazione. Un modello locale non costa nulla; uno ospitato fattura ogni messaggio che scrive, e i suoi token sono registrati accanto alla conversazione e mai contati come costo del tuo sistema.

Il tuo sistema mantiene il suo ciclo

Oloproof non guida la conversazione. Il tuo sistema chiede il primo messaggio dell'utente, gli risponde nel modo in cui risponde agli utenti, e restituisce ogni risposta per ottenere il messaggio successivo:

from oloproof import current_case

def talk(case):
    user = current_case().simulated_user()
    message = user.opening()
    while message is not None:
        message = user.reply(my_assistant.answer(message))
    return {}

reply restituisce None quando l'utente si ferma. Il tuo sistema può chiudere da sé la conversazione con user.end(answer), come farebbe un passaggio a una persona; un sistema async def attende aopening(), areply(answer) e aend(answer). Oloproof registra ciò che è passato attraverso l'handle come conversation/v1 e come è terminata come simulated_user/v1, e rifiuta l'uno e l'altro se provengono dal tuo sistema (Riferimento dell'SDK).

Come termina una conversazione

Dopo ogni risposta del tuo sistema, al modello dell'utente simulato viene chiesto, con una domanda separata a temperatura 0 e senza il gioco di ruolo che la circonda, se quella risposta ha realizzato l'obiettivo. Se sì, la conversazione termina goal_reached. Altrimenti l'utente scrive il suo messaggio successivo, oppure se ne va (user_left), finché non ha inviato max_turns messaggi (turn_limit). Un sistema che si ferma senza rispondere all'ultimo messaggio lascia la conversazione unanswered e troncata.

È chiedere a parte che rende utilizzabile un piccolo modello locale: interpretare un personaggio e decidere se un obiettivo è stato raggiunto sono compiti diversi, e un modello a cui si chiedono entrambi in un'unica risposta tende a continuare a chiacchierare dopo che il suo obiettivo è stato raggiunto, o a dire che se ne va quando è soddisfatto.

Misurare le conversazioni

La conversazione è l'unità: ogni valutatore dà un verdetto per conversazione, quindi ogni intervallo, confronto e gate si applica senza modifiche.

TipoPassa quando
conversation_completedil tuo sistema ha risposto a ogni messaggio
goal_reachedil controllo dell'obiettivo ha trovato l'obiettivo raggiunto
turns_to_goalciò è avvenuto entro max_turns dei messaggi dell'utente
every_turnogni risposta soddisfa le condizioni dichiarate: parole che deve contenere o non deve contenere, un pattern, una lunghezza
conversation_judgeun giudice a modello dell'intera trascrizione la fa passare, una volta validato rispetto alle etichette delle persone

Le repliche (replicates:) incontrano utenti con seed diversi, quindi un personaggio diventa più conversazioni. La versione dell'utente simulato (il suo modello, prompt, temperatura e budget) fa parte della chiave di cache di ogni esecuzione, quindi un utente simulato diverso misura di nuovo il tuo sistema.

Validare l'utente simulato

Un risultato su utenti simulati vale per gli utenti reali solo nella misura in cui l'utente simulato somiglia a loro. Quindi ogni regola su un'esecuzione i cui utenti erano simulati è INSUFFICIENT_EVIDENCE con simulated_user_not_validated finché delle persone non hanno trovato realistiche le sue conversazioni:

oloproof labels export RUN_ID --criterion simulated_user_realistic --sample 30 --local --out realism.csv
oloproof labels import realism.csv
oloproof simulated-users RUN_ID

Il foglio mostra ogni conversazione estratta con il personaggio e come è terminata. Una persona segna passed sì quando un cliente reale avrebbe potuto scrivere il lato dell'utente e chiuderlo a quel punto, in quel modo, il che copre anche il controllo dell'obiettivo: una conversazione terminata goal_reached quando l'obiettivo non era raggiunto non è realistica. L'utente simulato è validato sulla suite quando il limite inferiore esatto della quota realistica supera minimum_simulated_user_realism in release.yaml. Una conversazione estratta rimasta senza etichetta conta come non realistica, e una è realistica solo quando tutti quelli che l'hanno etichettata lo dicono.

Una validazione copre una versione di un utente simulato su una suite, con qualunque sistema abbia parlato, quindi un candidato misurato sugli stessi personaggi viene deciso sulle etichette della baseline. Un nuovo modello, una nuova impostazione del prompt o un nuovo insieme di personaggi richiede nuove etichette. Impostare require_validated_evaluators: false decide su utenti simulati senza di esse, consapevolmente.

Simulato accanto al reale

oloproof simulated-users RUN_ID --real REAL_RUN_ID mette la forma delle conversazioni simulate accanto a un'esecuzione di conversazioni reali (chat registrate e rigiocate come conversation/v1): quanti messaggi ha inviato l'utente, quanto erano lunghi, quanto erano lunghe le risposte, quanto spesso una conversazione è stata interrotta, e come sono terminate quelle simulate. È descrittivo e non decide mai: confrontare due campioni non appaiati richiede un metodo che Oloproof non ha ammesso. Leggilo per ciò che le etichette di realismo non colgono, come utenti simulati che scrivono in una frase ordinata ciò che quelli reali distribuiscono su tre.

Non supportato

  • Decidere su utenti simulati in uno spazio di lavoro ospitato: le sue decisioni restano trattenute finché la sua coda di revisione non può estrarre e sigillare da sé le etichette di realismo.
  • Un gate su come le conversazioni simulate si confrontano con quelle reali.
  • Tassi a livello di turno all'interno di una conversazione, e rigiocare una conversazione a partire da un turno.
  • Utenti simulati per un sistema HTTP: è il codice del tuo sistema a eseguire il ciclo, quindi deve essere un callable.