Agenti di intelligenza artificiale per l'elaborazione di serie temporali e frame di big data

Crea da zero usando solo Python e Ollama (nessuna GPU, nessuna chiave API)

un introduzione

Gli agenti sono sistemi di intelligenza artificiale basati su modelli linguistici di grandi dimensioni (LLM) in grado di ragionare sui propri obiettivi e di intraprendere azioni per raggiungerli. Sono progettati non solo per rispondere alle query, ma anche per orchestrare una serie di operazioni, inclusa l'elaborazione dei dati (come dataframe e serie temporali). Questa capacità consente a molte applicazioni del mondo reale di democratizzare l'accesso all'analisi dei dati, ad esempio tramite l'automazione dei report, le query senza codice e il supporto per la pulizia e l'elaborazione dei dati.

Gli agenti possono interagire con i dataframe in due modi diversi:

  • di linguaggio naturale – Il modello di linguaggio di grandi dimensioni (LLM) legge la tabella come una stringa di testo e cerca di comprenderla in base alla sua base di conoscenza.
  • di Creare ed eseguire codice – L’agente attiva gli strumenti per elaborare il set di dati come un oggetto.

Combinando la potenza dell'elaborazione del linguaggio naturale (NLP) con la precisione dell'esecuzione del codice, gli agenti di intelligenza artificiale consentono a una gamma più ampia di utenti di interagire con set di dati complessi ed estrarre informazioni preziose.

In questo tutorial ti mostrerò come Elaborazione di dataframe e serie temporali mediante agenti di intelligenza artificialeFornirò del codice Python utile che può essere facilmente applicato ad altre situazioni simili (basta copiare, incollare ed eseguire) e spiegherò ogni riga di codice con commenti in modo che possiate replicare questo esempio (link al codice completo alla fine dell'articolo).

 

preparazione

Iniziamo a prepararci Ollama (pip install ollama==0.4.7), una libreria che consente agli utenti di eseguire localmente modelli linguistici open source di grandi dimensioni, senza la necessità di servizi cloud, offrendo agli utenti un maggiore controllo sulla privacy dei dati e sulle prestazioni. Poiché viene eseguita localmente, nessun dato di conversazione lascia mai il dispositivo.

Per prima cosa devi scaricare Ollama Dal sito web.

Quindi, al prompt dei comandi, usa il comando per scaricare il modello linguistico di grandi dimensioni (LLM) di tua scelta. Io userò Qwen Di proprietà di Alibaba, perché è intelligente e leggero.

Una volta completato il download, puoi passare a Python e iniziare a scrivere il codice.

import ollama
llm = "qwen2.5"

Proviamo il modello del linguaggio più ampio:

stream = ollama.generate(model=llm, prompt='''what time is it?''', stream=True)
for chunk in stream:
    print(chunk['response'], end='', flush=True)

Serie temporali

Una serie temporale è una sequenza di punti dati misurati in un determinato periodo di tempo, spesso utilizzata per analisi e previsioni. Ci consente di osservare come le variabili cambiano nel tempo e viene utilizzata per identificare tendenze e andamenti stagionali. Serie temporali Uno strumento potente per l'analisi statistica e le previsioni.

Creerò un set di dati. serie temporali Falso da usare come esempio.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

## create data
np.random.seed(1) #<--for reproducibility
length = 30
ts = pd.DataFrame(data=np.random.randint(low=0, high=15, size=length),
                  columns=['y'],
                  index=pd.date_range(start='2023-01-01', freq='MS', periods=length).strftime('%Y-%m'))

## plot
ts.plot(kind="bar", figsize=(10,3), legend=False, color="black").grid(axis='y')

In genere, i set di dati contengono Serie temporali Su una struttura molto semplice con la variabile principale come colonna e il tempo come indice.

Prima di convertirlo in una stringa, voglio assicurarmi che tutto sia posizionato sotto una colonna, in modo da non perdere alcuna informazione.

dtf = ts.reset_index().rename(columns={"index":"date"})
dtf.head()

Quindi, è necessario modificare il tipo di dati. Da DataFrame a Dizionario.

data = dtf.to_dict(orient='records')
data[0:5]

finalmente, Dal dizionario alla stringa di testo.

str_data = "\n".join([str(row) for row in data])
str_data

Ora che abbiamo una stringa, possiamo Includilo in un prompt Qualsiasi modello linguistico può elaborarlo. Quando si incolla un set di dati in un prompt, si legge Modello linguistico di grandi dimensioni (LLM) I dati sono in formato testo normale, ma è comunque possibile comprenderne la struttura e il significato in base ai modelli osservati durante l'addestramento.

prompt = f'''
Analyze this dataset, it contains monthly sales data of an online retail product:
{str_data}
'''

Possiamo facilmente iniziare una conversazione con Modello linguistico di grandi dimensioni (LLM)Si prega di notare che al momento non si tratta di un agente, perché non dispone di alcuno strumento; utilizziamo solo il modello linguistico. Sebbene non elabori numeri come un computer, lo fa. Modello linguistico di grandi dimensioni (LLM) È in grado di riconoscere nomi di colonne, modelli basati sul tempo, tendenze e valori anomali, soprattutto con set di dati più piccoli. Può simulare analisi e spiegare i risultati, ma non eseguirà calcoli accurati in modo indipendente perché non esegue codice come un agente.

messages = [{"role":"system", "content":prompt}]

while True:
    ## User
    q = input('🙂 >')
    if q == "quit":
        break
    messages.append( {"role":"user", "content":q} )
   
    ## Model
    agent_res = ollama.chat(model=llm, messages=messages, tools=[])
    res = agent_res["message"]["content"]
   
    ## Response
    print("👽 >", f"\x1b[1;30m{res}\x1b[0m")
    messages.append( {"role":"assistant", "content":res} )

riconoscere Modello linguistico di grandi dimensioni (LLM) sui numeri e comprende il contesto generale, nello stesso modo in cui potrebbe comprendere una ricetta o una riga di codice.

Come puoi vedere, l'uso di Modelli linguistici di grandi dimensioni (LLM) Per analizzare Serie temporali Ottimo per approfondimenti e conversazioni rapide.

Agente

I modelli linguistici di grandi dimensioni (LLM) eccellono nel generare idee ed esplorare concetti iniziali, mentre gli agenti possono eseguire codice. Pertanto, possono gestire attività più complesse come la creazione di grafici, le previsioni e il rilevamento di anomalie. Quindi, costruiamo gli strumenti.

A volte, avere a che fare con ““Risposta finale” come strumento Più efficace. Ad esempio, se un agente esegue più azioni per generare risultati intermedi, la risposta finale può essere vista come lo strumento che integra tutte queste informazioni in una risposta coerente. Progettandola in questo modo, è possibile ottenere maggiore personalizzazione e controllo sui risultati.

def final_answer(text:str) -> str:
    return text

tool_final_answer = {'type':'function', 'function':{
  'name': 'final_answer',
  'description': 'Returns a natural language response to the user',
  'parameters': {'type': 'object',
                'required': ['text'],
                'properties': {'text': {'type':'str', 'description':'natural language response'}}
}}}

final_answer(text="hi")

Quindi, Strumento di codifica.

import io
import contextlib

def code_exec(code:str) -> str:
    output = io.StringIO()
    with contextlib.redirect_stdout(output):
        try:
            exec(code)
        except Exception as e:
            print(f"Error: {e}")
    return output.getvalue()

tool_code_exec = {'type':'function', 'function':{
  'name': 'code_exec',
  'description': 'Execute python code. Use always the function print() to get the output.',
  'parameters': {'type': 'object',
                'required': ['code'],
                'properties': {
                    'code': {'type':'str', 'description':'code to execute'},
}}}}

code_exec("from datetime import datetime; print(datetime.now().strftime('%H:%M'))")

Inoltre, aggiungerò alcuni funzioni di utilità Per utilizzare lo strumento ed eseguire l'agente.

dic_tools = {"final_answer":final_answer, "code_exec":code_exec}

# Utils
def use_tool(agent_res:dict, dic_tools:dict) -> dict:
    ## use tool
    if "tool_calls" in agent_res["message"].keys():
        for tool in agent_res["message"]["tool_calls"]:
            t_name, t_inputs = tool["function"]["name"], tool["function"]["arguments"]
            if f := dic_tools.get(t_name):
                ### calling tool
                print('🔧 >', f"\x1b[1;31m{t_name} -> Inputs: {t_inputs}\x1b[0m")
                ### tool output
                t_output = f(**tool["function"]["arguments"])
                print(t_output)
                ### final res
                res = t_output
            else:
                print('🤬 >', f"\x1b[1;31m{t_name} -> NotFound\x1b[0m")
    ## don't use tool
    if agent_res['message']['content'] != '':
        res = agent_res["message"]["content"]
        t_name, t_inputs = '', ''
    return {'res':res, 'tool_used':t_name, 'inputs_used':t_inputs}

Quando un agente tenta di risolvere un compito, voglio che tenga traccia degli strumenti utilizzati, degli input provati e dei risultati ottenuti. Il processo dovrebbe interrompersi solo quando il modello è pronto a fornire la risposta finale.

Per quanto riguarda lo strumento di codifica, ho notato che gli agenti tendono a ricreare il dataframe ad ogni passaggio. Quindi userò rinforzo della memoria Ricordare al modello che il set di dati esiste già. Questo è un trucco comune utilizzato per ottenere il comportamento desiderato. In definitiva, i rinforzi della memoria aiutano a ottenere interazioni più significative ed efficienti.

# Start a chat
messages = [{"role":"system", "content":prompt}]
memory = '''
The dataset already exists and it's called 'dtf', don't create a new one.
'''
while True:
    ## User
    q = input('🙂 >')
    if q == "quit":
        break
    messages.append( {"role":"user", "content":q} )

    ## Memory
    messages.append( {"role":"user", "content":memory} )     
   
    ## Model
    available_tools = {"final_answer":tool_final_answer, "code_exec":tool_code_exec}
    res = run_agent(llm, messages, available_tools)
   
    ## Response
    print("👽 >", f"\x1b[1;30m{res}\x1b[0m")
    messages.append( {"role":"assistant", "content":res} )

Generare un grafico è un'attività che un modello linguistico di grandi dimensioni (LLM) non è in grado di svolgere da solo. Tuttavia, è importante tenere presente che, anche se gli agenti possono generare immagini, non possono visualizzarle, perché il motore è pur sempre un modello linguistico. Pertanto, l'utente è l'unico a visualizzare il grafico.

L'agente utilizza una libreria modelli di statistiche Per addestrare un modello e prevedere serie temporali.

Gestione di grandi dataframe

I modelli linguistici di grandi dimensioni (LLM) hanno una memoria limitata, che limita la quantità di informazioni che possono elaborare contemporaneamente. Anche i modelli più sofisticati hanno limiti di token (alcune centinaia di pagine di testo). Inoltre, gli LLM non mantengono la memoria tra le sessioni, a meno che non sia incorporato un sistema di recupero. In pratica, per lavorare efficacemente con set di dati di grandi dimensioni, gli sviluppatori utilizzano spesso strategie come il chunking, la generazione aumentata dal recupero (RAG), i database vettoriali e la sintesi dei contenuti prima di inserirli nel modello.

Creiamo un ampio set di dati con cui giocare.

import random
import string

length = 1000

dtf = pd.DataFrame(data={
    'Id': [''.join(random.choices(string.ascii_letters, k=5)) for _ in range(length)],
    'Age': np.random.randint(low=18, high=80, size=length),
    'Score': np.random.uniform(low=50, high=100, size=length).round(1),
    'Status': np.random.choice(['Active','Inactive','Pending'], size=length)
})

dtf.tail()

Aggiungerò Strumento di ricerca sul Web, in modo che l'intelligenza artificiale generica, con la capacità di eseguire codice Python e di effettuare ricerche su Internet, abbia accesso a tutte le conoscenze disponibili e possa prendere decisioni basate sui dati.

In Python, il modo più semplice per creare uno strumento di ricerca sul web è utilizzare il popolare browser privato. DuckDuckGo (pip install duckduckgo-search==6.3.5). È possibile utilizzare direttamente la libreria originale oppure importare una shell. LangChain (pip install langchain-community==0.3.17).

from langchain_community.tools import DuckDuckGoSearchResults

def search_web(query:str) -> str:
  return DuckDuckGoSearchResults(backend="news").run(query)

tool_search_web = {'type':'function', 'function':{
  'name': 'search_web',
  'description': 'Search the web',
  'parameters': {'type': 'object',
                'required': ['query'],
                'properties': {
                    'query': {'type':'str', 'description':'the topic or subject to search on the web'},
}}}}

search_web(query="nvidia")

In totale, l'agente ora ha 3 strumenti.

dic_tools = {'final_answer':final_answer,
             'search_web':search_web,
             'code_exec':code_exec}

Poiché non posso aggiungere l'intero dataframe nel prompt, inserirò solo le prime 10 righe in modo che l'LLM possa comprendere il contesto generale del dataset. Inoltre, specificherò dove trovare il dataset completo.

str_data = "\n".join([str(row) for row in dtf.head(10).to_dict(orient='records')])

prompt = f'''
You are a Data Analyst, you will be given a task to solve as best you can.
You have access to the following tools:
- tool 'final_answer' to return a text response.
- tool 'code_exec' to execute Python code.
- tool 'search_web' to search for information on the internet.

If you use the 'code_exec' tool, remember to always use the function print() to get the output.
The dataset already exists and it's called 'dtf', don't create a new one.

This dataset contains credit score for each customer of the bank. Here's the first rows:
{str_data}
'''

Infine, possiamo eseguire l'agente.

messages = [{"role":"system", "content":prompt}]
memory = '''
The dataset already exists and it's called 'dtf', don't create a new one.
'''
while True:
    ## User
    q = input('🙂 >')
    if q == "quit":
        break
    messages.append( {"role":"user", "content":q} )

    ## Memory
    messages.append( {"role":"user", "content":memory} )     
   
    ## Model
    available_tools = {"final_answer":tool_final_answer, "code_exec":tool_code_exec, "search_web":tool_search_web}
    res = run_agent(llm, messages, available_tools)
   
    ## Response
    print("👽 >", f"\x1b[1;30m{res}\x1b[0m")
    messages.append( {"role":"assistant", "content":res} )

In questa interazione, l'agente ha utilizzato correttamente lo strumento di codifica. Ora voglio che utilizzi anche l'altro strumento.

Infine, ho bisogno che l'agente metta insieme tutte le informazioni ottenute finora da questa chat.

 

Conclusione

Questo articolo è stato concepito come un tutorial per illustrare Come creare agenti da zero per elaborare serie temporali e grandi dataframeAbbiamo esaminato i due modi in cui i modelli possono interagire con i dati: tramite il linguaggio naturale, in cui un modello di linguaggio di grandi dimensioni (LLM) interpreta una tabella come una stringa utilizzando la sua base di conoscenza, e tramite la generazione e l'esecuzione di codice, sfruttando strumenti per elaborare il set di dati come un oggetto.

Codice completo per questo articolo: GitHub

Spero che vi sia piaciuto! Non esitate a contattarmi per domande e commenti, o per condividere i vostri progetti interessanti.

 

I commenti sono chiusi.