Passa al contenuto principale

Step

Il ciclo di vita dell'esecuzione dell'albero si articola sempre in 4 step principali:

Step di esecuzione dell'albero

Explore

Lo step explore ha il compito di determinare automaticamente il prossimo nodo da eseguire. Si attiva in tre specifiche casistiche:

  1. quando l'ultimo nodo eseguto non ha nessuna callback after associata;
  2. quando la callback after restituisce un oggetto BaseAfterOutput privo di node_target;
  3. quando la callback after restituisce un oggetto BaseAfterOutput con step step = Step.EXPLORE;

I chunk nei nodi

I chunk svolgono un ruolo centrale durante lo step explore. Durante questa fase, la navigazione si sposta verso il nodo discendente (rispetto all'ultimo eseguito) che contiene il chunk con similarità maggiore rispetto alla direction.

informazioni

Di default, la direzione, accessibile tramite l'explore_strategy corrisponde alla richiesta dell'utente.

Per questo motivo, i chunk non sono limitati ai soli nodi query, ma possono essere inseriti in tutte le altre tipologie di nodi impostando la proprietà for_rag = False. A differenza dei chunk con for_rag = True (riservati ai soli nodi query per essere aggiunti al prompt da passare al LLM), tutti gli altri chunk fungono da veri e propri "cartelli stradali" per guidare la direzione dell'esplorazione.

Step di esecuzione dell'albero

Questo meccaniscmo permette di esplorare l'albero sfruttando la correlazione semantica tra la query dell'utente ed i chunk, senza dover puntare esplicitamente a un nodo tramite la callback after. Sostituire il routing semantico con l'abuso di riferimenti espliciti ottentui tramite l'esecuzione di un LLM comporta due grandi svantaggi:

  • prestazioni: ogni chiamata ad un LLM ha un costo, e richiede tempo;
  • affidabilità: l'affidabilità di una soluzione che si basa su LLM si abbassa tanti più llm node vengono concatenati prima di arrivare ed eseguire il nodo effettivo. Spesso in questi casi si ha un problema di propagaizone dell'errore!

Funzionamento

In questa fase emerge il criterio di collegamento tra i nodi che compone il grafo, infatti la ricerca si articola in questo modo:

  1. Si verifica la proprietà is_blocking del nodo corrente:

    1. Se uguale a True si rimane nel nodo attuale e si passa allo step before, quindi la ricerca è conclusa;
    2. Se uguale a False la ricerca prosegue con la fase successiva;
  2. Se il nodo corrente non ha figli, allora:

    1. Se il nodo attuale è anche l'ultimo ad essere stato eseguito, allora si incrementa il fail_counter di 1 e si raggiunge il nodo ascendente con proprietà is_anchor = True più prossimo;
    2. Altrimenti si rimane nel nodo attuale e si passa allo step before, quindi la ricerca è conclusa;
  3. Viene recuperato il chunk appartenente all'albero sottostante al nodo corrente con la maggiore similarity rispetto all'embedding della stringa inserita dentro l'explore_strategy:

    1. Se la similarity è maggiore della similarity_threshold specificata nelle proprietà del nodo, allora ci si sposta nel nodo figlio il cui sottoalbero contiene il chunk individuato e si lascia lo step explore, il flusso di ricerca si ripete;
    2. Se la similarity è minore della soglia allora:
      1. Se il nodo attuale è anche l'ultimo ad essere stato eseguito, allora si incrementa il fail_counter di 1 e si raggiunge il nodo ascendente con proprietà is_anchor = True più prossimo. Viene anche aggiunto automaticamente il nodo attuale nella black_list dell'explore_strategy;
      2. Altrimenti si rimane nel nodo attuale e si passa allo step before, quindi la ricerca è conclusa;
informazioni

Il punto 1 si salta all'inizio dello step, altrimenti un nodo bloccante appena eseguito interromperebbe subito la ricerca.

informazioni

La similarity è un numero calcolato confrontando l'embedding della query con l'embedding di un singolo chunk. Nell'albero, come misura si utilizza la cosine similarity.

informazioni

L'explore_strategy permette di personalizzare la logica con cui viene individuato il nodo da eseguire durante lo step explore. Questo oggetto, accessibile tramite il context, contiene sia la direction ovvero il testo che viene embeddato per calcolare la similarity sia dei vincoli che possono escludere dei chunk del grafo.

Before

Lo step before segue sempre explore, oppure può essere manualmente impostato a seguito di una callback after. Lo scopo di questo step è quello di consentire l'esecuzione dell'omonima callback eventualmente associata al nodo corrente.

Execute

Durante questo step viene eseguita la funzione execute del nodo individuato tramite esplorazione, oppure esplicitamente richiesto tramite la proprietà node_target nell'output della callback after. Durante questo step, in base alla tipologia del nodo corrente posso essere eseguite azioni distinte: ad esempio nel nodo query viene fatta una ricerca nel vector store associato, oppure nel nodo llm viene fatta una richiesta al modello indicato, oppure nel nodo empty non viene fatto nulla!

informazioni

A differenza delle callback, l'esecuzione del nodo non è direttamente personalizzabile. In particolare, durante lo step execute vengono eseguite la maggior parte delle callback associate al nodo, ma l'ordine di esecuzione, ed il modo con cui vengono utilizzati i relativi output non può essere modificato.

After

Lo step after viene eseguito in due momenti distinti:

  • immediatamente dopo l'esecuzione dello stesso nodo, se questo non ha interrotto il flusso con un output verso l'utente;
  • dopo la risposta dell'utente, se il nodo ha inviato un messaggio (nodo emit) o un avviso (nodo guardrail). In questo caso l'esecuzione dell'after viene sospesa in attesa del successivo input. Questo è particolarmente utile per i nodi emit con opzioni: la callback after riceve nel campo selected_option l'opzione scelta dall'utente.

Durante questo step viene solamente lanciata la callback after del nodo se definita.