Passa al contenuto principale

Callback

Le callback sono delle funzioni python che possono essere definite dentro i nodi in base alla loro tipologia. Tali funzioni consentono di personalizzare in maniera approfondita il comportamento dell'agente durante la sua esecuzione.

Ciascuna callback, in base alla sua tipologia ha una firma predefinita. In input gli argomenti passati sono:

  • self: un riferimento del componente comune a tutti i nodi in esso contenuti;
  • context: è il contesto dal quale è possibile accedere a diversi strumenti utili tra cui il session_state;
  • special: è un contesto specifico che è disponibile in alcuni nodi. Vedere il capitolo sui nodi per approfondire;
  • links: è disponibile solo nelle callback after e permette di navigare tra i nodi;
warning

Il self rimane visibile solo ai nodi che sono figli diretti del componente, di conseguenza, se ho dei componenti annidati, i nodi figli del componente interno non possono accedere al self del componente esterno e viceversa!

informazioni

links è un types.SimpleNamespace pertanto per accedere al suo contentuo richiede la nostazione con il punto, mentre la notazione con le [] non è supportata. Nel caso in cui si volesse accedere in modo dinamico ad una proprietà di links occorre usare il comando getattr(links, prop), con prop una variabile di tipo stringa che contiene il nome della proprietà richiesta.

suggerimento

Tutte le callback sono di default sincrone, tuttavia, in caso di necessità, inserendo il comando async prima della firma è possibile renderle asincrone.

Di seguito sono descritte, una per una, tutte le callback presenti:

Before

Nodi supportati: empty query open close llm switch

La callback before di un nodo viene lanciata nel relativo step, quindi sempre prima della sua esecuzione.

(self, context) => None

Visto che questa callback non produce alcun output, generalmente viene impiegata per fare chiamate API o interagire con il session_state

After

Nodi supportati: empty query open close llm

La callback after di un nodo viene lanciata durante lo step after, ovvero a seguito della sua esecuzione. Grazie all'oggetto BaseAfterOutput restituito da questa funzione, è possibile controllare il successivo svolgimento dell'interazione. In particolare, si può specificare il prossimo nodo e lo step da eseguire tramite node_target e step. Invece outcome permette di specificare un fallimento avvenuto durante l'esecuzione del nodo. Il lancio di un fallimento comporta l'esecuzione del meccanismo reach_anchor e consente di indicare una lista di nodi e chunk dovranno essere ignorati durante lo step di explore per il resto dell'interazine corrente. Il parametro resume permette di sfruttare la gestione multi agente del Tree Agent.

(self, context, special, links) => BaseAfterOutput

con

class BaseAfterOutput:
node_target: int | None = None # nodo che si intende eseguire dopo l'esecuzione della callback
step: Step = Step.EXPLORE # step che si vuole eseguire dopo l'esecuzione della callback
outcome: Outcome = Outcome.SUCCES # se impostato con Outcome.FAILURE vengono ignorati gli altri parametri, e si attiva il meccanismo di reach_anchor
resume: bool = False # viene recuperata l'esecuzione sull'agente indicato tramite node_target (se node_target non è un agent_node viene restituito un errore!)

con

class Outcome(Enum):
SUCCESS = "success"
FAILURE = "failure"
informazioni

Non è necessario che l'id del nodo indicato tramite node_target sia figlio o discendente del nodo attuale.

suggerimento

Sia per l'after che per il before_run:

  • è possibile abilitare il resume, questo comando è utile solo in caso di multi agenti;
  • se non si specifica il node_target, a meno che non si abilita is_failed (solo nel caso del after) si proseguirà con il normale step di explore
warning

Gli unici step ammessi sono: BEFORE e EXPLORE!

Extend Message

Nodi supportati: root

La callback extend_message restituisce il prompt che viene poi passato al LLM indicato nel quarto punto dell'esecuzione generale.

(self, context, special) => BaseExtendMessagePromptOutput

con

class BaseExtendMessagePromptOutput:
prompt: str # prompt da passare al LLM per inizializzare context.input.extended

Before run

Nodi supportati: root

Come indicato nel quinto punto dell'esecuzione generale, la callback before_run viene eseguita appena si riceve il messaggio dell'utente e prima di eseguire l'albero.

(self, context, links) => BaseBeforeRunOutput

con

class BaseBeforeRunOutput:
node_target: int | None # nodo che si intende eseguire dopo l'esecuzione della callback
step: Step | None # step che si vuole eseguire dopo l'esecuzione della callback
resume: bool | None # viene recuperata l'esecuzione sull'agente indicato tramite node_target (se node_target non è un agent_node viene restituito un errore!)

Questa callback è particolarmente utile in caso di multi agenti: si possono realizzare degli agenti che si occupano unicamente di analizzare la richiesta dell'utente e selezionano l'agente migliore che si deve occupare di rispondere. Grazie a questo nodo, tramite in node_target è possibile puntare a tali agenti. Se node_target viene lasciato a None, allora il resto degli argomenti vengono ignorati, e viene ripresa l'esecuzione a partire dalla callback after dell'ultimo nodo eseguito.

suggerimento

Ad esempio è possibile sviluppare un agente specializzato sull'analisi dei documenti che l'utente carica in chat e la successiva estrazione delle informazioni rilevanti nel session_state. Grazie a questa callback si possono deviare tutte le interazioni avviate partendo da un messaggio con file allegati.

informazioni

Per la prima interazione della sessione, se la before_run non specifica alcun nodo da eseguire, sarà avviato lo step di explore a partire dall'unico nodo figlio del root node che ha la proprietà is_primary = True

After run

Nodi supportati: root

La callback after_run viene eseguita appena si conclude l'esecuzione dell'albero.

(self, context, special) => None

Visto che questa callback non produce alcun output, generalmente viene impiegata per fare chiamate API o interagire con il session_state.

Fallback

Nodi supportati: agent

All'inizio di ogni interazione viene impostato un contatore fail_counter = 0. Tale contatore viene incrementato ogni volta che una callback after restituisce is_fail = True e più in generale ogni volta che si attiva il meccanismo di reach_anchor. La callback fallback viene eseguita se durante l'interazione avviene che fail_counter > 2, in tale circostanza, onde evitare possibili loop, tramite questa callback viene restituito l'id di un nodo che sarà immediatamente eseguito. Date le circostanze, il nodo da indicare tramite node_target NON deve avere proprietà is_mute = True, ma deve restituire immediatamente un output all'utente. Per questo motivo sono permessi solo nodi di tipo open o close, oppure nodi llm con proprietà is_mute = False.

(self, context, links) => BaseFallbackOutput

con

class BaseFallbackOutput:
node_target: int # nodo che si intende eseguire dopo l'esecuzione della callback

Prompt

Nodi supportati: llm

La callback prompt è disponibile ai nodi che devono richiamare un LLM per rispondere ad una richiesta. Questa callback consente di specificare il prompt che si intende inviare al LLM.

(self, context, special) => BasePromptOutput

con

class BasePromptOutput:
prompt: str | None = None # prompt da inviare al LLM
system_prompt: str | None = None # system prompt da inviare al LLM
files: List[FileMetadata] | None = None # eventuali file che si intende inviare al LLM
segments: List[Segment] | None = None # prompt composto da una sequenza di testi e file
assets: List[FileMetadata] | None = None # eventuali file che si intende rendere disponibili per il meccanismo {{}}
temperature: float = 0.1 # temperatura per il LLM
web_search: bool = False # abilita l'accesso del modello a Internet

con

class Segment:
type: Literal["text", "files"] # il tipo del segmento
content: str | List[FileMetadata] # il contenuto del segmento
informazioni

Come specificato nella sezione del File Agent il FileMetadata può essere ricavato dai precedenti file scambiati in chat, dai file estratti tramite RAG e da quelli generati direttamente in code

warning

Attualemente il parametro web_search è compatibile solo con i modelli offerti dai provider Azure e OpenAI

Query

Nodi supportati: query

La callback query permette di realizzare una ricerca tra i chunk con proprietà for_rag = True presenti sul vector store associato al nodo corrente.

(self, context) => BaseQueryOutput

con

class BaseQueryOutput:
query: str # stringa da cui estrarre l'embedding per fare la ricerca
filter: models.Filter | None = None # eventuali filtri da applicare prima della ricerca sfruttando i tag eventualmente associati a ciascun chunk
black_list: AiBlackList | None = None # eventuali chunk da escludere
chunk_qty: int = 3 # massimo numero di chunk estraibili
threshold: float = 0.25 # soglia minima di similarità richiesta per l'estrazione dei chunk

dove model.Filter è una classe implementata tramite libreria Qdrant. Fare riferimento alla loro documentazione per implementare la logica di filtri.

informazioni

Ad esempio, se nei chunk del nodo ho associato tramite extra la proprietà "category" ed in fase di estrazione voglio considerare solo i chunk della categoria "food", posso scrivere:

filter = models.Filter(
must=[
models.FieldCondition(
key="category",
match=models.MatchValue(value="food")
)
]
)

Question

Nodi supportati: open close

La callback question è disponibile per i nodi che restituiscono messaggi controllati (di tipo open e close). La funzione restituisce una stringa: ovvero il messaggio che sarà inviato all'utente. Tale messaggio se viene attivata anche la relativa callback translate, prima di essere restituito all'utente, viene passato ad un LLM per effettuare l'eventuale traduzione nella lingua della conversazione.

(self, context) => BaseQuestionOutput

con

class BaseQuestionOutput:
question: str # testo da inviare all'utente
files: List[FileMetadata] | None # eventuali file che si intende inviare al l'utente
assets: List[FileMetadata] | None # eventuali file che si intende rendere disponibili per il meccanismo {{}}
informazioni

Come specificato nella sezione del File Agent il FileMetadata può essere ricavato dai precedenti file scambiati in chat, dai file estratti tramite RAG e da quelli generati direttamente in code

Options

Nodi supportati: close

La callback options è disponibile per i nodi di tipo close per definire le opzioni mutualmente esclusive che si intende proporre all'utente. Tali opzioni saranno presentate all'utente in forma di bottoni sotto al messaggio impostato tramite la callback question dello stesso nodo. La funzione restituisce una lista di stringhe che corrisponde alla lista di opzioni. Tali opzioni se viene attivata anche la relativa callback translate, vengono prima passate ad un LLM per effettuare l'eventuale traduzione nella lingua della conversazione.

informazioni

Nel caso in cui si seleziona come skill Whatsapp, invece di mostrare le opzioni come bottoni selezionabili, appare un elenco puntato. Di conseguenza, l'utente potrà scrivere liberamente l'opzione che preferisce, ed il framework andrà a recuperare automaticamente, ammettendo un minimo di tolleranza in caso di errori di battitura, l'opzione corrispondente. La risposta libera è ammessa anche in caso di webchat, quindi va sempre previsto e gestito nella relativa callback after il caso in cui l'utente risponda un testo differente da ogni opzione.

(self, context) => BaseOptionsOutput

con

class BaseOptionsOutput:
options: List[str] # lista di opzioni che si intende mostrare all'utente

Translate

Nodi supportati: open close

La callback translate è disponibile per i nodi che dispongono della callback question (di tipo open e close). Infatti, lo scopo di questa funzione è quello di restituisce prompt da passare ad LLM per eseguire la traduzione.

(self, context, special) => BaseTranslateOutput

con

class BaseTranslateOutput:
prompt: str # prompt per la traduzione