Agenci AI do przetwarzania szeregów czasowych i ramek dużych danych
Zbuduj od podstaw, używając tylko Pythona i Ollama (bez GPU, bez klucza API)
wstęp
Agenci to systemy sztucznej inteligencji oparte na dużych modelach językowych (LLM), które potrafią wnioskować o swoich celach i podejmować działania w celu ich osiągnięcia. Są one zaprojektowane nie tylko do odpowiadania na zapytania, ale także do koordynowania szeregu operacji, w tym przetwarzania danych (takich jak ramki danych i szeregi czasowe). Ta możliwość umożliwia wielu aplikacjom w świecie rzeczywistym demokratyzację dostępu do analizy danych, na przykład poprzez automatyzację raportów, zapytania bezkodowe oraz obsługę czyszczenia i przetwarzania danych.

Agenci mogą wchodzić w interakcje z ramkami danych na dwa różne sposoby:
- przez język naturalny – Model dużego języka (LLM) odczytuje tabelę jako ciąg tekstowy i próbuje go zrozumieć na podstawie swojej bazy wiedzy.
- przez Utwórz i wykonaj kod – Agent aktywuje narzędzia do przetwarzania zbioru danych jako obiektu.
Łącząc możliwości przetwarzania języka naturalnego (NLP) z precyzją wykonywania kodu, agenci AI umożliwiają szerszemu gronu użytkowników interakcję ze złożonymi zbiorami danych i wyciąganie z nich cennych wniosków.
W tym samouczku pokażę Ci, jak Przetwarzanie ramek danych i szeregów czasowych przy użyciu agentów AIPrzedstawię przydatny kod Pythona, który można łatwo zastosować w innych podobnych sytuacjach (wystarczy skopiować, wkleić i uruchomić). Wyjaśnię każdą linijkę kodu za pomocą komentarzy, dzięki czemu będziesz mógł powtórzyć ten przykład (link do pełnego kodu znajduje się na końcu artykułu).
przygotowanie
Zacznijmy przygotowania Ollama (pip install ollama==0.4.7), biblioteka umożliwiająca użytkownikom uruchamianie dużych, otwartych modeli językowych lokalnie, bez potrzeby korzystania z usług w chmurze, zapewniając większą kontrolę nad prywatnością danych i wydajnością. Ponieważ działa lokalnie, żadne dane konwersacji nie opuszczają Twojego urządzenia.
Najpierw musisz pobrać Ollama Ze strony internetowej.
Następnie w wierszu poleceń użyj polecenia, aby pobrać wybrany model dużego języka (LLM). Użyję Qwen Własność Alibaby, ponieważ jest inteligentna i lekka.
Po zakończeniu pobierania możesz przełączyć się na Pythona i zacząć pisać kod.
import ollama
llm = "qwen2.5"
Wypróbujmy model dużego języka:
stream = ollama.generate(model=llm, prompt='''what time is it?''', stream=True)
for chunk in stream:
print(chunk['response'], end='', flush=True)
Szeregi czasowe
Szereg czasowy to sekwencja punktów danych mierzonych w określonym czasie, często wykorzystywana do analiz i prognozowania. Pozwala ona obserwować zmiany zmiennych w czasie i służy do identyfikacji trendów i wzorców sezonowych. Szeregi czasowe Potężne narzędzie do analizy statystycznej i prognozowania.
Utworzę zbiór danych. szereg czasowy Fałszywe, jako przykład.
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')
Zazwyczaj zestawy danych zawierają Szeregi czasowe W naprawdę prostej strukturze, w której główną zmienną jest kolumna, a czasem indeks.
Zanim przekonwertuję go na ciąg znaków, chcę mieć pewność, że wszystko znajduje się w kolumnie, dzięki czemu nie utracimy żadnych informacji.
dtf = ts.reset_index().rename(columns={"index":"date"})
dtf.head()
Następnie należy zmienić typ danych. Od DataFrame do słownika.
data = dtf.to_dict(orient='records')
data[0:5]
Wreszcie, Ze słownika do ciągu tekstowego.
str_data = "\n".join([str(row) for row in data])
str_data
Teraz, gdy mamy ciąg znaków, możemy Dodaj to do monitu Każdy model językowy może to przetworzyć. Po wklejeniu zestawu danych do monitu, wyświetli się komunikat Duży model językowy (LLM) Dane mają postać zwykłego tekstu, ale nadal można je interpretować jako strukturę i znaczenie na podstawie wzorców zaobserwowanych podczas szkolenia.
prompt = f'''
Analyze this dataset, it contains monthly sales data of an online retail product:
{str_data}
'''
Możemy łatwo rozpocząć rozmowę z Duży model językowy (LLM)Należy pamiętać, że na razie nie jest to agent, ponieważ nie posiada żadnych narzędzi; korzystamy jedynie z modelu językowego. Chociaż nie przetwarza on liczb jak komputer, to jednak to robi. Duży model językowy (LLM) Potrafi rozpoznawać nazwy kolumn, wzorce czasowe, trendy i wartości odstające, zwłaszcza w przypadku mniejszych zbiorów danych. Potrafi symulować analizę i objaśniać wyniki, ale nie wykona dokładnych obliczeń samodzielnie, ponieważ nie wykonuje kodu jak agent.
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} )
rozpoznać Duży model językowy (LLM) na liczbach i rozumie ogólny kontekst, w taki sam sposób, w jaki rozumie przepis lub linię kodu.
Jak widać, użycie Duże modele językowe (LLM) لتحليل Szeregi czasowe Doskonałe do szybkich spostrzeżeń i rozmów.
Agent
Modele dużego języka (LLM) doskonale radzą sobie z generowaniem pomysłów i eksploracją wstępnych koncepcji, podczas gdy agenci potrafią wykonywać kod. Dzięki temu mogą obsługiwać bardziej złożone zadania, takie jak tworzenie wykresów, prognozowanie i wykrywanie anomalii. Zatem, stwórzmy te narzędzia.
Czasami, mając do czynienia z „„Ostateczna odpowiedź” jako narzędzie Większa efektywność. Na przykład, jeśli agent wykonuje wiele działań, aby wygenerować wyniki pośrednie, ostateczną odpowiedź można postrzegać jako narzędzie integrujące wszystkie te informacje w spójną odpowiedź. Projektując ją w ten sposób, można uzyskać większą personalizację i kontrolę nad wynikami.
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")
Następnie, Narzędzie do kodowania.
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'))")
Ponadto dodam kilka funkcje narzędziowe Aby użyć narzędzia i uruchomić agenta.
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}
Kiedy agent próbuje rozwiązać zadanie, chcę, aby śledził użyte narzędzia, wypróbowane dane wejściowe i uzyskane wyniki. Proces powinien zostać zatrzymany dopiero wtedy, gdy model będzie gotowy do udzielenia ostatecznej odpowiedzi.
Jeśli chodzi o narzędzie do kodowania, zauważyłem, że agenci mają tendencję do ponownego tworzenia ramki danych na każdym kroku. Dlatego użyję wzmocnienie pamięci Aby przypomnieć modelowi, że zbiór danych już istnieje. To częsty trik stosowany w celu osiągnięcia pożądanego zachowania. Ostatecznie, wzmacnianie pamięci pomaga w osiągnięciu bardziej znaczących i efektywnych interakcji.
# 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} )
Wygenerowanie wykresu to coś, czego nie jest w stanie zrobić sam model dużego języka (LLM). Należy jednak pamiętać, że nawet jeśli agenci potrafią generować obrazy, nie mogą ich zobaczyć, ponieważ silnik jest przecież modelem języka. Dlatego użytkownik jest jedyną osobą, która wizualizuje wykres.
Agent korzysta z biblioteki modele statystyk Aby wytrenować model i prognozować szeregi czasowe.
Praca z dużymi ramkami danych
Duże modele językowe (LLM) mają ograniczoną pamięć, co ogranicza ilość informacji, które mogą przetwarzać jednocześnie. Nawet najbardziej zaawansowane modele mają limity tokenów (kilkaset stron tekstu). Ponadto, LLM nie zachowują pamięci między sesjami, chyba że wdrożony jest system wyszukiwania. W praktyce, aby efektywnie pracować z dużymi zbiorami danych, programiści często stosują strategie takie jak grupowanie, generowanie wspomagane wyszukiwaniem (RAG), bazy danych wektorowych i podsumowywanie treści przed wprowadzeniem jej do modelu.
Utwórzmy duży zbiór danych, z którym będziemy mogli eksperymentować.
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()
Dodam Narzędzie do wyszukiwania w sieci, dzięki czemu sztuczna inteligencja ogólnego przeznaczenia, potrafiąca wykonywać kod w Pythonie i przeszukiwać internet, uzyskuje dostęp do całej dostępnej wiedzy i może podejmować decyzje w oparciu o dane.
Najprostszym sposobem utworzenia wyszukiwarki internetowej w Pythonie jest użycie popularnej przeglądarki prywatnej. DuckDuckGo (pip install duckduckgo-search==6.3.5). Możesz użyć oryginalnej biblioteki bezpośrednio lub zaimportować powłokę. 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")
Łącznie agent ma teraz 3 narzędzia.
dic_tools = {'final_answer':final_answer,
'search_web':search_web,
'code_exec':code_exec}
Ponieważ nie mogę dodać pełnej ramki danych w wierszu poleceń, podam tylko pierwsze 10 wierszy, aby LLM mógł zrozumieć ogólny kontekst zbioru danych. Dodatkowo określę, gdzie znaleźć pełny zbiór danych.
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}
'''
Na koniec możemy uruchomić agenta.
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} )
W tej interakcji agent poprawnie użył narzędzia do kodowania. Teraz chcę, żeby użył również innego narzędzia.
Na koniec chciałbym, aby agent zebrał wszystkie informacje uzyskane dotychczas podczas tej rozmowy.
Wniosek
Niniejszy artykuł miał służyć jako samouczek ilustrujący Jak tworzyć agentów od podstaw w celu przetwarzania szeregów czasowych i dużych ramek danychOmówiliśmy dwa sposoby, w jakie modele mogą wchodzić w interakcję z danymi: za pomocą języka naturalnego, gdzie duży model języka (LLM) interpretuje tabelę jako ciąg znaków, korzystając ze swojej bazy wiedzy, oraz poprzez generowanie i wykonywanie kodu, wykorzystując narzędzia do manipulowania zestawem danych jak obiektem.
Pełny kod tego artykułu: GitHub
Mam nadzieję, że Ci się podobało! Zachęcam do kontaktu z pytaniami i komentarzami lub do podzielenia się swoimi interesującymi projektami.
Możliwość dodawania komentarzy nie jest dostępna.