La Potenza della Chiamata di Funzioni di OpenAI nei Modelli di Apprendimento Linguistico Una Guida Completa

OpenAI Function Call Power in Language Learning Models A Complete Guide

Trasformazione dei Data Pipelines con la Funzione di Chiamata delle Funzioni di OpenAI: Implementazione di un Flusso di Lavoro per l’Invio di E-mail Utilizzando PostgreSQL e FastAPI

Introduzione

Il mondo emozionante dell’AI ha compiuto un altro passo avanti con l’introduzione della funzione di chiamata delle funzioni nei più recenti Large Language Models (LLM) di OpenAI. Questa nuova funzionalità migliora l’interazione tra esseri umani e AI, trasformandola da un semplice formato di domanda e risposta in un dialogo più dinamico e attivo.

Ma esattamente cosa sono queste funzionalità di chiamata delle funzioni? Nel loro nucleo, consentono all’LLM di chiamare funzioni predefinite durante una conversazione in base alle istruzioni di input. Questo potrebbe essere qualsiasi cosa, dall’invio di un’e-mail al recupero di dati da un database in base al contesto della conversazione. I benefici e le applicazioni dell’utilizzo delle funzionalità di chiamata delle funzioni sono vasti. Aumenta significativamente l’utilità dinamica dell’AI in varie applicazioni, dal servizio clienti a come costruiamo i data pipeline.

Immaginate un’AI per il servizio clienti che può rispondere alle domande e svolgere azioni come prenotare appuntamenti, inviare informazioni a un indirizzo e-mail o aggiornare i dettagli del cliente in tempo reale. Oppure considerate un data pipeline in cui l’agente LLM può recuperare, aggiornare e manipolare i dati su comando.

Nelle prossime sezioni, esploreremo queste applicazioni in modo più approfondito e forniremo una guida passo passo sull’utilizzo di questa nuova funzionalità costruendo un flusso di lavoro per l’invio di e-mail.

Figura 1: LLM sta diventando un agente intelligente con cui possiamo lavorare (fonte immagine)

Come sempre, il codice è disponibile sul mio Github.

Comprensione della Nuova Funzionalità di Chiamata delle Funzioni e Confronto con LangChain

Vogliamo capire cosa porta la nuova funzionalità di chiamata delle funzioni introdotta da OpenAI alla gara dell’AI. Per questo, cerchiamo di capire cosa la differenzia da altri strumenti e framework sul mercato, come LangChain. Abbiamo già presentato LangChain nel primo articolo di questa serie. È un framework popolare per lo sviluppo di applicazioni alimentate da AI. La funzione di chiamata delle funzioni e LangChain portano vantaggi e capacità uniche sul tavolo e sono costruiti per rendere l’AI più utilizzabile, versatile e dinamica.

Sappiamo già che la funzione di chiamata delle funzioni aggiunge uno strato extra di interattività alle applicazioni di AI. Consente al modello di chiamare funzioni predefinite all’interno di una conversazione, migliorando la dinamicità e la reattività dell’LLM. Questa nuova funzionalità può semplificare potenzialmente il processo di aggiunta di funzionalità alle applicazioni di AI. Gli sviluppatori dovrebbero definire queste funzioni e il modello potrebbe quindi eseguirle come parte della conversazione, a seconda del contesto. Il vantaggio principale qui è la sua integrazione diretta con i modelli OpenAI, che facilita l’uso, la configurazione rapida e una curva di apprendimento più bassa per gli sviluppatori familiari con l’ecosistema OpenAI.

D’altra parte, LangChain offre un framework completo e versatile progettato per lo sviluppo di applicazioni AI complesse, consapevoli dei dati e agenti. Consente a un modello di linguaggio di interagire con il proprio ambiente e di prendere decisioni basate su direttive di alto livello. I suoi moduli forniscono astrazioni e interfacce standard per la costruzione di applicazioni, inclusi modelli, prompt, memoria, indici, catene, agenti e callback.

L’approccio di LangChain facilita la creazione di applicazioni in cui un LLM può persistere il proprio stato attraverso diverse interazioni, sequenze e chiamate a diverse utility, e persino interagire con fonti di dati esterne. Possiamo vedere queste come funzionalità di chiamata di funzioni su steroide. Pertanto, è particolarmente utile per gli sviluppatori che creano applicazioni complesse a più fasi che sfruttano i modelli di linguaggio. Lo svantaggio della complessità aggiunta è che crea una curva di apprendimento più ripida per usarla completamente.

Caso d’uso – Trasformazione dei Data Pipelines

Dal mio punto di vista, i data pipeline sono tra le aree di applicazione più interessanti per le nuove funzionalità di chiamata delle funzioni negli LLM. I data pipeline sono un componente critico di qualsiasi organizzazione basata sui dati che raccoglie, elabora e distribuisce dati. Tipicamente, questi processi sono statici, predefiniti e richiedono l’intervento manuale per eventuali modifiche o aggiornamenti. Qui la comportamento dinamico di un LLM che abbiamo discusso sopra crea un’opportunità.

Tradizionalmente, il recupero di dati dal database richiede una conoscenza specifica di linguaggi di query come SQL. Con la capacità degli LLM di chiamare funzioni, servizi e database direttamente, gli utenti possono recuperare i dati conversazionalmente senza la necessità di formulare esplicitamente la query. Un LLM potrebbe tradurre la richiesta dell’utente in una query del database, recuperare i dati e restituirli in un formato amichevole per l’utente, tutto in tempo reale. Questa funzione potrebbe democratizzare l’accesso ai dati in diversi ruoli all’interno di un’organizzazione.

Un altro aspetto che potrebbe cambiare è la trasformazione dei dati. Spesso richiede passaggi di pulizia e elaborazione dati separati prima dell’analisi. Un LLM potrebbe semplificare questo processo eseguendo attività di pulizia e manipolazione dei dati in modo interattivo in base alle istruzioni dell’utente. Inoltre, la manipolazione dei dati in tempo reale durante una conversazione consente un’analisi dei dati più esplorativa e iterativa.

Un terzo caso d’uso è il monitoraggio dei dati. Questo implica controlli regolari per garantire l’accuratezza e la coerenza dei dati in un flusso di dati. Con gli LLM, le attività di monitoraggio possono diventare più interattive ed efficienti. Ad esempio, un LLM può avvisare gli utenti delle incongruenze dei dati durante le conversazioni e intervenire immediatamente.

Infine, gli LLM possono anche automatizzare la creazione e la distribuzione di report sui dati. Gli utenti possono istruire l’LLM per generare un rapporto in base a criteri specifici e l’LLM può recuperare i dati, creare il rapporto e persino inviarlo ai destinatari pertinenti.

Costruzione di una pipeline di invio email con le funzionalità di chiamata di funzioni OpenAI

Aimiamo a creare una pipeline che invia un’email a un utente. Sebbene possa sembrare semplice, la bellezza di questo processo risiede nell’interazione dei diversi componenti controllati dall’LLM. Il modello di intelligenza artificiale non genera solo il corpo dell’email; interagisce dinamicamente con un database per recuperare le informazioni dell’utente, compone un’email appropriata in base al contesto e quindi istruisce un servizio per inviarla.

La nostra pipeline è composta da tre componenti principali: PostgreSQL, FastAPI e l’LLM di OpenAI. Usiamo PostgreSQL per archiviare i nostri dati utente. Questi dati includono i nomi degli utenti e i loro indirizzi email associati. Serve come nostra fonte di verità per le informazioni dell’utente. FastAPI è un moderno framework web ad alte prestazioni per la creazione di API con Python. Usiamo un servizio FastAPI per simulare il processo di invio di un’email. Quando il servizio riceve una richiesta di invio di un’email, restituisce una risposta che conferma l’invio dell’email. L’LLM serve da orchestratore dell’intero processo. Controlla la conversazione, determina le azioni necessarie in base al contesto, interagisce con il database PostgreSQL per recuperare le informazioni dell’utente, crea un messaggio email e istruisce il servizio FastAPI per inviare l’email.

Implementazione del database PostgreSQL

Il primo componente della nostra pipeline è il database PostgreSQL in cui archiviamo i nostri dati utente. La configurazione di un’istanza PostgreSQL è resa facile e riproducibile con Docker, una piattaforma che consente di containerizzare e isolare il nostro ambiente del database.

Per configurare un contenitore Docker PostgreSQL, è necessario prima installare Docker. Una volta installato, è possibile scaricare l’immagine PostgreSQL e eseguirla come contenitore. Mappiamo la porta 5432 del contenitore alla porta 5432 dell’host per accedere al database. In un ambiente di produzione, impostare la password come variabile d’ambiente e non impostarle direttamente in un comando come indicato di seguito. Lo stiamo facendo in questo modo per velocizzare il processo.

docker run --name user_db -e POSTGRES_PASSWORD=testpass -p 5432:5432 -d postgres

Con la nostra istanza PostgreSQL in esecuzione, possiamo ora creare un database e una tabella per archiviare i nostri dati utente. Utilizzeremo uno script di inizializzazione per creare una tabella users con le colonne username e email e popolarla con alcuni dati fittizi. Questo script è posizionato in una directory che viene quindi mappata nella directory /docker-entrypoint-initdb.d nel contenitore. PostgreSQL esegue gli script trovati in questa directory all’avvio. Ecco a cosa assomiglia lo script (user_init.sql):

CREATE DATABASE user_database;\c user_database;CREATE TABLE users (    username VARCHAR(50),    email VARCHAR(50));INSERT INTO users (username, email) VALUES    ('user1', '[email protected]'),    ('user2', '[email protected]'),    ('user3', '[email protected]'),    ...    ('user10', '[email protected]');

LLM è in grado di comprendere i comandi SQL e può essere utilizzato per interrogare il database PostgreSQL. Quando l’LLM riceve una richiesta che comporta il recupero dei dati utente, può formulare una query SQL per recuperare i dati necessari dal database.

Ad esempio, se chiedi all’LLM di inviare un’email a user10, l’LLM può formulare la query:

SELECT email FROM users WHERE username='user10';

Ciò consente di recuperare l’indirizzo email di user10 dalla tabella users. L’LLM può quindi utilizzare questo indirizzo email per istruire il servizio FastAPI per inviare l’email.

Nella prossima sezione, ti guideremo nell’implementazione del servizio FastAPI che invia le email.

Creazione del servizio email FastAPI

Il nostro secondo componente è un servizio FastAPI. Questo servizio simulerà il processo di invio di email. È un’API semplice che riceve una richiesta POST contenente il nome del destinatario, l’email e il corpo dell’email. Restituirà una risposta che conferma l’invio dell’email. Utilizzeremo nuovamente Docker per garantire che il nostro servizio sia isolato e riproducibile.

Prima di tutto, devi installare Docker (se non è già installato). Quindi, crea una nuova directory per il tuo servizio FastAPI e spostati al suo interno. Qui, crea un nuovo file Python (ad esempio, main.py) e aggiungi il seguente codice:

from fastapi import FastAPIfrom pydantic import BaseModelapp = FastAPI()class User(BaseModel):    name: str    email: str    body: [email protected]("/send_email")async def send_email(user: User):    return {        "message": f"Email inviata con successo a {user.name} con l'email {user.email}. Corpo dell'email:\n\n{user.body}"    }

Questo codice definisce un’applicazione FastAPI con un unico endpoint /send_email/. Questo endpoint accetta richieste POST e si aspetta un corpo JSON contenente il nome del destinatario, l’email e il corpo dell’email.

Successivamente, crea un Dockerfile nella stessa directory con il seguente contenuto:

FROM python:3.9-slim-busterWORKDIR /appADD . /appRUN pip install --no-cache-dir fastapi uvicornEXPOSE 1000CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "1000"]

Questo Dockerfile istruisce Docker a creare un’immagine basata sull’immagine python:3.9-slim-buster, un’immagine leggera ideale per eseguire efficientemente le applicazioni Python. Successivamente, copia il nostro file main.py nella directory /app/ dell’immagine.

Puoi creare l’immagine Docker utilizzando il comando:

docker build -t fastapi_email_service .

E quindi eseguirlo con:

docker run -d -p 1000:1000 fastapi_email_service

LLM interagisce con il servizio FastAPI utilizzando una richiesta POST. Quando LLM decide di inviare un’email, genera una chiamata di funzione alla funzione send_email. Gli argomenti di questa chiamata di funzione contengono il nome, l’email e il corpo dell’email.

La chiamata di funzione viene elaborata dal nostro script Python, che estrae gli argomenti della funzione e li utilizza per inviare una richiesta POST al nostro servizio FastAPI. Il servizio FastAPI risponde con un messaggio che indica che l’email è stata inviata con successo.

Ora abbiamo tutti i componenti della nostra pipeline. La prossima sezione li unirà, spiegando come LLM orchestrerà l’interazione tra il database PostgreSQL e il servizio FastAPI per inviare un’email.

Integrazione con OpenAI LLM

L’ultimo pezzo della nostra pipeline è l’integrazione con OpenAI LLM. LLM funge da orchestratore, interpretando i nostri comandi, interrogando il database per le informazioni dell’utente e istruendo il servizio FastAPI ad inviare email.

Il nostro script utilizza l’API di OpenAI per effettuare completamenti basati su chat con LLM. Ogni richiesta di completamento consiste in una serie di messaggi e, facoltativamente, una lista di specifiche di funzioni che il modello potrebbe chiamare. Iniziamo la conversazione con un messaggio dell’utente, che fornisce un prompt all’assistente.

Ecco la funzione chat_completion_request che utilizziamo per inviare una richiesta all’API:

@retry(wait=wait_random_exponential(min=1, max=40), stop=stop_after_attempt(3))def chat_completion_request(messages, functions=None, model=GPT_MODEL):    headers = {        "Content-Type": "application/json",        "Authorization": "Bearer " + openai.api_key,    }    json_data = {"model": model, "messages": messages}    if functions is not None:        json_data.update({"functions": functions})    response = requests.post(        "https://api.openai.com/v1/chat/completions",        headers=headers,        json=json_data,    )    return response

Utilizziamo la classe Chat per gestire la cronologia delle conversazioni. Ha metodi per aggiungere un nuovo messaggio alla cronologia e visualizzare l’intera conversazione:

class Chat:
    def __init__(self):
        self.conversation_history = []
    
    def add_prompt(self, role, content):
        message = {"role": role, "content": content}
        self.conversation_history.append(message)

    def display_conversation(self):
        for message in self.conversation_history:
            print(f"{message['role']}: {message['content']}")

Nel nostro caso d’uso, LLM deve interagire con il nostro database PostgreSQL e il servizio FastAPI. Definiamo queste funzioni e le includiamo nella nostra richiesta di completamento. Ecco come definiamo le nostre funzioni sql_query_email e send_email:

functions = [
    {
        "name": "send_email",
        "description": "Invia una nuova email",
        "parameters": {
            "type": "object",
            "properties": {
                "to": {
                    "type": "string",
                    "description": "L'email di destinazione.",
                },
                "name": {
                    "type": "string",
                    "description": "Il nome della persona che riceverà l'email.",
                },
                "body": {
                    "type": "string",
                    "description": "Il corpo dell'email.",
                },
            },
            "required": ["to", "name", "body"],
        },
    },
    {
        "name": "sql_query_email",
        "description": "Query SQL per ottenere le email degli utenti",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "La query per ottenere le email degli utenti.",
                },
            },
            "required": ["query"],
        },
    },
]

Quando facciamo una richiesta di completamento, LLM risponde con le sue azioni intenzionate. Se la risposta include una chiamata di funzione, il nostro script esegue quella funzione. Ad esempio, se LLM decide di chiamare la funzione sql_query_email, il nostro script recupera l’email dell’utente dal database e poi aggiunge il risultato alla cronologia della conversazione. Quando viene chiamata la funzione send_email, il nostro script invia una email utilizzando il servizio FastAPI.

Il ciclo principale del nostro script controlla le chiamate di funzione nella risposta di LLM e agisce di conseguenza:

chat = Chat()
chat.add_prompt("user", "Invia un'email all'utente10 dicendo che deve pagare la quota mensile.")
result_query = ''
for i in range(2):
    chat_response = chat_completion_request(
        chat.conversation_history,
        functions=functions
    )
    response_content = chat_response.json()['choices'][0]['message']
    if 'function_call' in response_content:
        if response_content['function_call']['name'] == 'send_email':
            res = json.loads(response_content['function_call']['arguments'])
            send_email(res['name'], res['to'], res['body'])
            break
        elif response_content['function_call']['name'] == 'sql_query_email':
            result_query = query_db(json.loads(response_content['function_call']['arguments'])['query'])
            chat.add_prompt('user', str(result_query))
    else:
        chat.add_prompt('assistant', response_content['content'])

Quando eseguiamo lo script, otteniamo il seguente output:

{  "message": "Email inviata con successo all'utente 10 con l'email [email protected].",  "Corpo email": "\n\nGentile utente 10, \n\nQuesta è una promemoria che la tua quota mensile è scaduta. Si prega di effettuare il pagamento il prima possibile per garantire un servizio ininterrotto. Grazie per la collaborazione. \n\nCordiali saluti, \nIl tuo team di servizio abbonamento"}

Suddividiamo ciò che è successo per ottenere questo output. Il nostro prompt era “Invia un’email all’utente10 dicendo che deve pagare la quota mensile.”. Notare che non ci sono informazioni sull’email dell’utente10 nel nostro messaggio. LLM ha identificato le informazioni mancanti e ha capito che la nostra funzione query_email gli avrebbe permesso di interrogare il database per ottenere l’email di quell’utente. Dopo aver ottenuto l’email, ha ottenuto ancora una volta due cose giuste: prima, dovrebbe generare il corpo dell’email, e seconda, dovrebbe chiamare la funzione send_email per attivare l’email utilizzando il servizio di posta elettronica FastAPI.

Conclusione

Questo articolo ha esplorato la funzione di chiamata di funzione implementando uno studio di caso in cui LLM coordina una pipeline che coinvolge un database PostgreSQL e un servizio email FastAPI. LLM ha navigato con successo il compito di recuperare l’email di un utente dal database e di istruire il servizio email a inviare un messaggio personalizzato, tutto in risposta a un singolo prompt.

Le implicazioni della chiamata di funzioni nei modelli di intelligenza artificiale potrebbero essere enormi, aprendo nuove possibilità per l’automatizzazione e il razionalizzazione dei processi. Le pipeline dei dati potrebbero passare da entità statiche e pesanti in termini di ingegnerizzazione a entità dinamiche, consentendo agli utenti non tecnici di mettere rapidamente le mani sui dati più recenti utilizzando il linguaggio naturale.

Cronache dei grandi modelli linguistici: navigare la frontiera dell’elaborazione del linguaggio naturale

Questo articolo appartiene alle “Cronache dei grandi modelli linguistici: navigare la frontiera dell’elaborazione del linguaggio naturale”, una nuova serie settimanale di articoli che esplorerà come sfruttare la potenza dei grandi modelli per varie attività di elaborazione del linguaggio naturale. Approfondendo queste tecnologie all’avanguardia, miriamo ad abilitare sviluppatori, ricercatori e appassionati ad utilizzare il potenziale dell’elaborazione del linguaggio naturale e sbloccare nuove possibilità.

Articoli finora pubblicati:

  1. Sommario delle ultime uscite di Spotify con ChatGPT
  2. Migliora la ricerca semantica su larga scala: indicizza milioni di documenti con tempi di inferenza estremamente veloci utilizzando FAISS e Sentence Transformers
  3. Sfrutta la potenza dei dati audio: trascrizione avanzata e diarizzazione con Whisper, WhisperX e PyAnnotate
  4. Whisper JAX vs PyTorch: scoprire la verità sulle prestazioni dell’ASR sulle GPU
  5. Vosk per un riconoscimento vocale efficiente a livello aziendale: una guida per valutazione e implementazione
  6. Test del modello di linguaggio massivamente multilingue (MMS) che supporta 1162 lingue
  7. Sfruttare il modello Falcon 40B, il più potente modello LLM open source

Rimani in contatto: LinkedIn