Agentes de IA para processamento de séries temporais e big data frames

Crie do zero usando apenas Python e Ollama (sem GPU, sem chave de API)

uma introdução

Agentes são sistemas de IA alimentados por grandes modelos de linguagem (LLMs), capazes de raciocinar sobre seus objetivos e tomar ações para atingir um objetivo final. Ele foi projetado não apenas para responder a consultas, mas para organizar uma série de operações, incluindo o processamento de dados (como dataframes e séries temporais). Esse recurso permite que muitos aplicativos do mundo real democratizem o acesso à análise de dados, como automação de relatórios, consultas sem código e suporte para limpeza e processamento de dados.

Os agentes podem interagir com dataframes de duas maneiras diferentes:

  • por linguagem natural – O modelo de linguagem grande (LLM) lê a tabela como uma sequência de texto e tenta entendê-la com base em sua base de conhecimento.
  • por Criar e executar código – O agente ativa ferramentas para processar o conjunto de dados como um objeto.

Ao combinar o poder do processamento de linguagem natural (PLN) com a precisão da execução do código, os agentes de IA permitem que uma gama maior de usuários interaja com conjuntos de dados complexos e extraia insights valiosos.

Neste tutorial, mostrarei como Processamento de dataframes e séries temporais usando agentes de IA. Fornecerei algum código Python útil que pode ser facilmente aplicado em outras situações semelhantes (basta copiar, colar e executar) e explicarei cada linha de código com comentários para que você possa replicar este exemplo (link para o código completo no final do artigo).

 

preparação

Vamos começar a nos preparar Ollama (pip install ollama==0.4.7), uma biblioteca que permite aos usuários executar grandes modelos de linguagem de código aberto localmente, sem a necessidade de serviços de nuvem, dando mais controle sobre a privacidade e o desempenho dos dados. Como ele é executado localmente, nenhum dado de bate-papo sai do seu dispositivo.

Primeiro, você precisa baixar Ollama Do site.

Em seguida, no prompt de comando, use o comando para baixar o modelo de linguagem grande (LLM) de sua escolha. Eu vou usar Qwen O próprio Alibaba, porque é inteligente e leve.

Após a conclusão do download, você pode mudar para Python e começar a escrever código.

import ollama
llm = "qwen2.5"

Vamos tentar o grande modelo de linguagem:

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

Séries temporais

Uma série temporal é uma sequência de pontos de dados medidos ao longo de um período de tempo, frequentemente usada para análise e previsão. Ela nos permite ver como as variáveis ​​mudam ao longo do tempo e é usada para identificar tendências e padrões sazonais. É considerado Séries temporais Uma ferramenta poderosa para análise estatística e previsão.

Vou criar um conjunto de dados. séries temporais Falso para usar como exemplo.

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')

Normalmente, os conjuntos de dados contêm Séries temporais Em uma estrutura realmente simples com a variável principal como uma coluna e o tempo como um índice.

Antes de convertê-lo em uma string, quero ter certeza de que tudo esteja colocado em uma coluna, para que não percamos nenhuma informação.

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

Então, você deve alterar o tipo de dados. Do DataFrame ao Dicionário.

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

finalmente, Do dicionário para a sequência de texto.

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

Agora que temos uma string, podemos Incluir em um prompt Qualquer modelo de linguagem pode processá-lo. Quando você cola um conjunto de dados em um prompt, ele lê: Modelo de Linguagem Grande (LLM) Os dados são texto simples, mas ainda conseguem entender a estrutura e o significado com base nos padrões observados durante o treinamento.

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

Podemos facilmente iniciar uma conversa com Modelo de Linguagem Grande (LLM). Observe que, no momento, este não é um agente porque não possui nenhuma ferramenta, estamos usando apenas o modelo de linguagem. Embora não processe números como um computador, ele o faz. Modelo de Linguagem Grande (LLM) Ele pode reconhecer nomes de colunas, padrões baseados em tempo, tendências e outliers, especialmente com conjuntos de dados menores. Ele pode simular a análise e explicar os resultados, mas não realizará cálculos precisos de forma independente, porque não executa código como um 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} )

reconhecer Modelo de Linguagem Grande (LLM) em números e entende o contexto geral, da mesma forma que entenderia uma receita ou uma linha de código.

Como você pode ver, o uso de Grandes Modelos de Linguagem (LLMs) تحليل Séries temporais Ótimo para insights e conversas rápidas.

Agente

Grandes modelos de linguagem (LLMs) são excelentes para gerar ideias e explorar conceitos iniciais, enquanto um agente pode executar código. Portanto, ele pode lidar com tarefas mais complexas, como gráficos, previsões e detecção de anomalias. Então, vamos criar as ferramentas.

Às vezes, lidar com ““Resposta Final” como Ferramenta Mais eficaz. Por exemplo, se um agente executa várias ações para criar resultados intermediários, a resposta final pode ser considerada a ferramenta que integra todas essas informações em uma resposta coerente. Ao projetá-lo dessa maneira, você pode ter mais personalização e controle sobre os resultados.

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")

Então, Ferramenta de codificação.

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'))")

Além disso, acrescentarei algumas funções utils Para usar a ferramenta e executar o 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 um agente tenta resolver uma tarefa, quero que ele rastreie quais ferramentas foram usadas, quais entradas ele tentou e quais resultados obteve. O processo só deve parar quando o modelo estiver pronto para fornecer a resposta final.

Em relação à ferramenta de codificação, notei que os agentes tendem a recriar o dataframe em cada etapa. Então eu vou usar reforço de memória Para lembrar ao modelo que o conjunto de dados já existe. É um truque comum usado para obter o comportamento desejado. Em última análise, os reforços de memória ajudam você a ter interações mais significativas e eficazes.

# 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} )

Criar um enredo é algo que um grande modelo de linguagem (LLM) sozinho não consegue fazer. Mas tenha em mente que mesmo que os agentes possam gerar imagens, eles não podem vê-las, porque o mecanismo ainda é, em última análise, um modelo de linguagem. Portanto, o usuário é o único que visualiza o gráfico.

O agente usa uma biblioteca modelos estatísticos Para treinar um modelo e prever séries temporais.

Lidando com grandes dataframes

Grandes modelos de linguagem (LLMs) têm memória limitada, o que restringe a quantidade de informações que eles podem processar de uma só vez. Mesmo os modelos mais sofisticados têm limites simbólicos (algumas centenas de páginas de texto). Além disso, modelos de linguagem grandes (LLMs) não retêm memória entre sessões, a menos que um sistema de recuperação seja incorporado. Na prática, para trabalhar efetivamente com grandes quadros de dados, os desenvolvedores geralmente usam estratégias como fragmentação, geração aumentada de recuperação (RAG), bancos de dados vetoriais e resumo de conteúdo antes de inseri-lo no modelo.

Vamos criar um grande conjunto de dados para brincar.

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()

Eu vou adicionar Ferramenta de pesquisa na Web, para que a IA de propósito geral, com a capacidade de executar código Python e pesquisar na internet, tenha acesso a todo o conhecimento disponível e possa tomar decisões baseadas em dados.

Em Python, a maneira mais fácil de criar uma ferramenta de pesquisa na web é usando o popular navegador privado. DuckDuckGo (pip install duckduckgo-search==6.3.5). Você pode usar a biblioteca original diretamente ou importar um 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")

No total, o agente agora tem 3 ferramentas.

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

Como não posso adicionar o dataframe completo no prompt, alimentarei apenas as 10 primeiras linhas para que o LLM possa entender o contexto geral do conjunto de dados. Além disso, especificarei onde encontrar o conjunto de dados 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}
'''

Finalmente, podemos executar o 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} )

Nessa interação, o agente utilizou a ferramenta de codificação corretamente. Agora, quero fazê-lo usar a outra ferramenta também.

Por fim, preciso que o agente reúna todas as informações obtidas até agora neste bate-papo.

 

Conclusão

Este artigo foi concebido como um tutorial para ilustrar Como construir agentes do zero para processar séries temporais e grandes dataframes. Abordamos as duas maneiras pelas quais os modelos podem interagir com dados: por meio de linguagem natural, onde um modelo de linguagem grande (LLM) interpreta uma tabela como uma sequência de caracteres usando sua base de conhecimento, e gerando e executando código, aproveitando ferramentas para manipular o conjunto de dados como um objeto.

Código completo para este artigo: GitHub

Espero que tenham gostado! Sinta-se à vontade para entrar em contato comigo com perguntas e comentários ou para compartilhar seus projetos interessantes.

 

Comentários estão fechados.