Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Come funzionano i Tool

Con i Tool on è più l'essere umano che decide quando chiamare una funzione ma è il modello che sa quando invocare un LLM
Con i Tool on è più l'essere umano che decide quando chiamare una funzione ma è il modello che sa quando invocare un LLM
Link copiato negli appunti

Rimanendo fedeli alla formula che abbiamo appreso nella lezione precedente per cui AGENTE = LLM+TOOLS dobbiamo per prima cosa imparare a scrivere Tool. Sfrutteremo come sempre la libreria Langchain che ci permette di costruire rapidamente architetture attorno agli LLM.

Partiamo da una definizione: un tool è una funzione che un LLM sa quando chiamare. Ciò pone un grande cambio di paradigma rispetto alla programmazione tradizionale. Non è più l'essere umano che decide quando chiamare una funzione ma è il modello che, in base alla descrizione che noi forniamo, sa quando invocare un LLM.

Costruire tool

Il nostro primo scopo sarà quello di vedere come definire un tool e provarlo creando una sorta di LLM espanso con il collegamento ad esso. Non ancora un agente quindi ma potremmo considerare questa operazione una sorta di creazione di modello con i muscoli.

Realizziamo un semplice esempio in cui un LLM deve suggerire nomi per bambini, sia maschi che femmine, ricevendo l'indicazione di fornire un nome lungo o corto.

Per vedere effettivamente al lavoro la soluzione:

  • creeremo un tool che fornisce solo nomi per maschietti;
  • lo collegheremo ad un modello che, nel nostro esempio, sarà un modello OpenAI;
  • testeremo il modello potenziato con il tool chiedendogli sia nomi per maschietti sia per femminucce;
  • considerato che il modello ha solo un tool per nomi di maschi quando ne chiederemo uno per femmine l'LLM lavorerà in autonomia senza chiedergli niente.

Lo scopo dell'esempio consiste nel vedere un tool al lavoro ma anche capire il meccanismo dell'invocazione da parte del modello.

Il tool

Il codice del nostro tool è questo

from langchain_core.tools import tool
from random import choice
@tool
def suggerisci_nome_maschietto(nome_lungo: bool) -> str:
    """
    Suggerisce nomi per bambini di sesso MASCHILE.
    Usa True se l'utente vuole un nome lungo, False per un nome corto.
    """
    if nome_lungo:
        return choice(['Alessandro', 'Francesco', 'Riccardo', 'Leonardo'])
    else:
        return choice(['Ivo', 'Luca', 'Leo', 'Enea'])

Notiamo che esso non è altro che una normale funzione, con l'apposizione del decorator @tool ed una grossa descrizione in un commento multiriga in cui indichiamo quando il modello deve usarlo.

Senza ancora usare un LLM possiamo invocare direttamente il tool in questo modo:

suggerisci_nome_maschietto.invoke({"nome_lungo": True})

da cui otteniamo Francesco e

suggerisci_nome_maschietto.invoke({"nome_lungo": False})

da cui otteniamo Leo.

L'esempio mostra che la funzione, anche sotto forma di tool, svolge il suo semplice lavoro e questo primo spunto è fondamentale per le attività di debug.

Potremo ora agganciarlo ad un LLM in questo modo:

llm = ChatOpenAI(model="gpt-4o", temperature=0, api_key=api_key)
llm_with_tools = llm.bind_tools(tools)

Avremo in questo modo un LLM potenziato. Consideriamo che non abbiamo ancora un agente ma questo piccolo costrutto ci permette di svolgere attività per comprendere come funzionano davvero i tool. Scopriamo infatti che:

  • un LLM "con tool" risponderà un oggetto di tipo AIMessage;
  • nell'AIMessage, se il tool è stato invocato ovvero se l'LLM ha trovato necessità (dalla descrizione che abbiamo inserito in esso) di invocarlo sarà presente il campo tool_calls=[{'name': 'suggerisci_nome_maschietto', 'args': {'nome_lungo': False}, 'id': 'call_37K1RXfoJLPtcJX1Wxby0DZq', 'type': 'tool_call'}] che dimostra l'invocazione;
  • se è presente una tool call nel messaggio la useremo noi per invocarlo.

quest'ultimo punto è un po' strano in effetti perché sa di invocazione manuale ma è importante per capire che, quando avremo un agente, sarà proprio lì che interverrà l'automazione che questo attuerà!

Esempio completo

Usiamo questi stralci di codice in un esempio più completo in cui chiederemo ad un modello potenziato di fornirci un nome per maschietto ed uno per femminuccia. Vorremo vedere che solo nel primo caso l'agente interviene perché ha tool solo per nomi di maschietto!

Ecco il codice:

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage, ToolMessage
from random import choice
# Creiamo il tool
@tool
def suggerisci_nome_maschietto(nome_lungo: bool) -> str:
    """
    Suggerisce nomi solo per bambini di sesso maschile.
    Usa True se l'utente vuole un nome lungo, False per un nome corto.
    """
    if nome_lungo:
        return choice(['Alessandro', 'Francesco', 'Riccardo', 'Leonardo'])
    else:
        return choice(['Ivo', 'Luca', 'Leo', 'Enea'])
# Definiamo una lista di tool: in questo caso solo uno!
tools = [suggerisci_nome_maschietto]
# Modello potenziato
# Inserire la propria API KEY
llm = ChatOpenAI(model="gpt-4o", temperature=0, api_key=api_key)
llm_with_tools = llm.bind_tools(tools)
# Prepariamo un test
def test_nomi(genere_neonato: str, vuole_nome_lungo: bool):
    # Prepariamo la richiesta dell'utente
    query = f"Devo scegliere un nome per un {genere_neonato}. Lo vorrei {'lungo' if vuole_nome_lungo else 'corto'}."
    print(f"Utente: {query}")
    # Il messaggio di sistema è fondamentale per far capire al modello che se non usa il tool deve rispondere "di testa sua"
    messages = [
        ("system", "Sei un esperto di nomi. Se hai un tool adatto usalo, altrimenti rispondi usando le tue conoscenze."),
        ("human", query)
    ]
    risposta_ai = llm_with_tools.invoke(messages)
    messages.append(risposta_ai)
    # Se TRUE, l'AI ha usato il tool (si vede che avevamo chiesto un nome di maschietto)
    if risposta_ai.tool_calls:
        tool_call = risposta_ai.tool_calls[0]
        # VERA ESECUZIONE DEL TOOL
        risposta_tool = suggerisci_nome_maschietto.invoke(tool_call["args"])
        print(f"Tool {tool_call['name']} invocato. Output: {risposta_tool}")
        # Viene creato un ToolMessage da inviare al modello
        messages.append(ToolMessage(
            content=str(risposta_tool),
            tool_call_id=tool_call["id"]
        ))
        # Risposta finale
        risposta_finale = llm_with_tools.invoke(messages)
        return risposta_finale.content
    # Questo return agisce SOLO SE non è stato usato il tool (non avevamo chiesto un nome per maschietto evidentemente)
    return risposta_ai.content
# PRIMA PROVA: chiediamo un nome di maschietto
print(f"AI: {test_nomi('maschietto', False)}")
print("\n" + "-"*20 + "\n")
# SECONDA PROVA: chiediamo nome per femminuccia
print(f"AI: {test_nomi('femminuccia', False)}")

L'output

L'output che otteniamo

Utente: Devo scegliere un nome per un maschietto. Lo vorrei corto.
Tool suggerisci_nome_maschietto invocato. Output: Leo
AI: Un nome corto e carino per un maschietto è "Leo".
--------------------
Utente: Devo scegliere un nome per un femminuccia. Lo vorrei corto.
AI: Ecco alcuni suggerimenti per nomi femminili corti:
1. Mia
2. Eva
3. Zoe
4. Lia
5. Ada
6. Noa
7. Pia
8. Lea
9. Gia
10. Isa
Spero che uno di questi nomi ti piaccia!

Notiamo la differenza tra le due risposte. La prima (caso "maschietto") dimostra proprio l'uso del tool infatti otteniamo una risposta sintetica, estratta dall'elenco di nomi che abbiamo dato ed estremamente mirata. La seconda, quella dell'LLM, mostra la classica discorsività di un modello AI generativo.

Ora che padroneggiamo questi costrutti ed il modo in cui questi dialogano con gli LLM siamo pronti per passare agli agenti!

Se vuoi aggiornamenti su Come funzionano i Tool inserisci la tua email nel box qui sotto:

Compilando il presente form acconsento a ricevere le informazioni relative ai servizi di cui alla presente pagina ai sensi dell'informativa sulla privacy.

Ti consigliamo anche