Агенты ИИ для обработки временных рядов и больших массивов данных

Создание с нуля только с использованием Python и Ollama (без GPU, без API-ключа)

введение

Агенты — это системы искусственного интеллекта, работающие на основе больших языковых моделей (LLM), способные рассуждать о своих целях и предпринимать действия для достижения конечной цели. Он предназначен не только для ответа на запросы, но и для организации серии операций, включая обработку данных (таких как кадры данных и временные ряды). Эта возможность позволяет многим реальным приложениям демократизировать доступ к анализу данных, например, автоматизировать создание отчетов, запросы без кода и поддерживать очистку и обработку данных.

Агенты могут взаимодействовать с фреймами данных двумя различными способами:

  • от естественный язык – Большая языковая модель (LLM) считывает таблицу как строку текста и пытается понять ее на основе своей базы знаний.
  • от Создать и выполнить код – Агент активирует инструменты для обработки набора данных как объекта.

Объединяя мощь обработки естественного языка (NLP) с точностью выполнения кода, агенты ИИ позволяют более широкому кругу пользователей взаимодействовать со сложными наборами данных и извлекать ценную информацию.

В этом уроке я покажу вам, как Обработка кадров данных и временных рядов с использованием агентов ИИ. Я предоставлю полезный код Python, который можно легко применить в других подобных ситуациях (просто скопируйте, вставьте и запустите), и объясню каждую строку кода комментариями, чтобы вы могли повторить этот пример (ссылка на полный код в конце статьи).

 

подготовка

Давайте начнем подготовку Оллама (pip install ollama==0.4.7), библиотека, которая позволяет пользователям локально запускать большие языковые модели с открытым исходным кодом, без необходимости использования облачных сервисов, предоставляя больший контроль над конфиденциальностью данных и производительностью. Поскольку приложение работает локально, никакие данные чата не покидают ваше устройство.

Сначала вам нужно скачать Оллама С сайта.

Затем в командной строке используйте команду для загрузки большой языковой модели (LLM) по вашему выбору. Я буду использовать Qwen Собственный продукт Alibaba, потому что он одновременно умный и легкий.

После завершения загрузки вы можете переключиться на Python и начать писать код.

import ollama
llm = "qwen2.5"

Давайте попробуем большую языковую модель:

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

Временной ряд

Временной ряд — это последовательность точек данных, измеренных за определенный период времени, часто используемая для анализа и прогнозирования. Он позволяет нам увидеть, как переменные изменяются с течением времени, и используется для выявления тенденций и сезонных закономерностей. Это считается Временной ряд Мощный инструмент статистического анализа и прогнозирования.

Я создам набор данных. временной ряд Подделка для использования в качестве примера.

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

Обычно наборы данных содержат Временной ряд На очень простой структуре с основной переменной в качестве столбца и временем в качестве индекса.

Прежде чем преобразовывать его в строку, я хочу убедиться, что все размещено в столбце, чтобы не потерять никакую информацию.

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

Затем необходимо изменить тип данных. От DataFrame к словарю.

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

наконец, Из словаря в текстовую строку.

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

Теперь, когда у нас есть строка, мы можем Включите его в подсказку Любая языковая модель может это обработать. При вставке набора данных в командную строку отображается следующее: Модель большого языка (LLM) Данные представляют собой обычный текст, но его структуру и значение можно распознать на основе закономерностей, обнаруженных во время обучения.

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

Мы можем легко начать разговор с Модель большого языка (LLM). Обратите внимание, что на данный момент это не агент, поскольку у него нет никаких инструментов, мы используем только языковую модель. Хотя он и не обрабатывает числа, как компьютер, он это делает. Модель большого языка (LLM) Он может распознавать имена столбцов, временные закономерности, тенденции и выбросы, особенно при работе с небольшими наборами данных. Он может моделировать анализ и объяснять результаты, но не может выполнять точные вычисления самостоятельно, поскольку не выполняет код, как агент.

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

распознавать Модель большого языка (LLM) на числах и понимает общий контекст так же, как он мог бы понять рецепт или строку кода.

Как вы видите, использование Большие языковые модели (LLM) لتحليل Временной ряд Отлично подходит для быстрого получения информации и общения.

Агент

Большие языковые модели (LLM) отлично подходят для генерации идей и исследования начальных концепций, в то время как агент может выполнять код. Поэтому он может выполнять более сложные задачи, такие как построение графиков, прогнозирование и обнаружение аномалий. Итак, давайте создадим инструменты.

Иногда, имея дело с ««Окончательный ответ» как инструмент Более эффективно. Например, если агент выполняет несколько действий для создания промежуточных результатов, окончательный ответ можно рассматривать как инструмент, который объединяет всю эту информацию в последовательный ответ. Спроектировав его таким образом, вы получите больше возможностей для настройки и контроля над результатами.

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

Потом, Инструмент кодирования.

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

Кроме того, я добавлю несколько утилиты функции Использовать инструмент и запустить агент.

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}

Когда агент пытается решить задачу, я хочу, чтобы он отслеживал, какие инструменты были использованы, какие входные данные он попробовал и какие результаты получил. Процесс следует останавливать только тогда, когда модель будет готова предоставить окончательный ответ.

Что касается инструмента кодирования, я заметил, что агенты имеют тенденцию заново создавать фрейм данных на каждом этапе. Поэтому я буду использовать укрепление памяти Напомнить модели, что набор данных уже существует. Это распространенный трюк, используемый для получения желаемого поведения. В конечном итоге закрепление памяти помогает вам осуществлять более осмысленное и эффективное взаимодействие.

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

Создание сюжета — это то, чего не может сделать одна только большая языковая модель (LLM). Но имейте в виду, что даже если агенты могут генерировать изображения, они не могут их видеть, поскольку движок по сути все равно является языковой моделью. Таким образом, пользователь является единственным, кто визуализирует сюжет.

Агент использует библиотеку статистические модели Обучить модель и спрогнозировать временные ряды.

Работа с большими фреймами данных

Большие языковые модели (LLM) имеют ограниченный объем памяти, что ограничивает объем информации, которую они могут обрабатывать одновременно. Даже самые сложные модели имеют ограничения по объему (несколько сотен страниц текста). Кроме того, большие языковые модели (LLM) не сохраняют память между сеансами, если не включена система извлечения. На практике для эффективной работы с большими массивами данных разработчики часто используют такие стратегии, как фрагментация, расширенная генерация поиска (RAG), векторные базы данных и обобщение контента перед его передачей в модель.

Давайте создадим большой набор данных для экспериментов.

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

Я добавлю Инструмент веб-поиска, так что универсальный ИИ, способный выполнять код Python и выполнять поиск в Интернете, получает доступ ко всем имеющимся знаниям и может принимать решения на основе данных.

В Python самый простой способ создания инструмента веб-поиска — это использование популярного приватного браузера. DuckDuckGo (pip install duckduckgo-search==6.3.5). Вы можете использовать исходную библиотеку напрямую или импортировать оболочку. Лангчейн (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")

Всего у агента теперь 3 инструмента.

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

Поскольку я не могу добавить полный фрейм данных в приглашение, я передам только первые 10 строк, чтобы LLM мог понять общий контекст набора данных. Кроме того, я укажу, где найти полный набор данных.

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

Наконец, мы можем запустить агент.

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

В этом взаимодействии агент правильно использовал инструмент кодирования. Теперь я хочу, чтобы он использовал и другой инструмент.

Наконец, мне нужно, чтобы агент собрал воедино всю информацию, полученную из этого чата.

 

Заключение

Эта статья была задумана как учебное пособие для иллюстрации Как создавать агенты с нуля для обработки временных рядов и больших фреймов данных. Мы рассмотрели два способа взаимодействия моделей с данными: посредством естественного языка, где большая языковая модель (LLM) интерпретирует таблицу как строку, используя свою базу знаний, и посредством генерации и выполнения кода, используя инструменты для манипулирования набором данных как объектом.

Полный код для этой статьи: GitHub

Надеюсь, вам понравилось! Не стесняйтесь обращаться ко мне с вопросами и комментариями или делиться своими интересными проектами.

 

Комментарии закрыты.