時系列とビッグデータフレームを処理するためのAIエージェント

Python と Ollama だけを使ってゼロから構築します (GPU や API キーは不要)

はじめに

エージェントは大規模言語モデル (LLM) を搭載した AI システムであり、目標について推論し、最終目標を達成するためのアクションを実行できます。クエリに応答するだけでなく、データフレームや時系列などのデータの処理を含む一連の操作を整理するように設計されています。この機能により、レポートの自動化、コード不要のクエリ、データのクリーニングと処理のサポートなど、多くの実際のアプリケーションでデータ分析へのアクセスを民主化できます。

エージェントは、次の 2 つの方法でデータフレームと対話できます。

  • عنطريق 自然言語 – 大規模言語モデル (LLM) は、テーブルをテキストの文字列として読み取り、知識ベースに基づいて理解しようとします。
  • عنطريق コードを作成して実行する – エージェントはデータセットをオブジェクトとして処理するためのツールをアクティブ化します。

AI エージェントは、自然言語処理 (NLP) の能力とコード実行の精度を組み合わせることで、より幅広いユーザーが複雑なデータセットを操作し、貴重な洞察を抽出できるようにします。

このチュートリアルでは、 AIエージェントを使用したデータフレームと時系列の処理。他の同様の状況に簡単に適用できる (コピー、貼り付け、実行するだけ) 便利な Python コードをいくつか提供し、この例を再現できるように各コード行をコメント付きで説明します (完全なコードへのリンクは記事の最後にあります)。

 

準備

準備を始めましょう オラマ (pip install ollama==0.4.7) は、クラウド サービスを必要とせずに大規模なオープンソース言語モデルをローカルで実行できるライブラリであり、データのプライバシーとパフォーマンスをより細かく制御できます。ローカルで実行されるため、チャット データはデバイスから送信されません。

まず、ダウンロードする必要があります オラマ ウェブサイトより。

次に、コマンド プロンプトで、コマンドを使用して、選択した大規模言語モデル (LLM) をダウンロードします。私は使います クウェン スマートかつ軽量なので、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()

次に、データ型を変更する必要があります。 データフレームから辞書へ.

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 コードを実行し、インターネットを検索する機能を備えた汎用 AI が、利用可能なすべての知識にアクセスし、データに基づいた意思決定を行えるようになります。

Python で Web 検索ツールを作成する最も簡単な方法は、一般的なプライベート ブラウザを使用することです。 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}

プロンプトに完全なデータフレームを追加することはできないため、LLM がデータセットの全体的なコンテキストを理解できるように、最初の 10 行のみを入力します。さらに、完全なデータセットがどこにあるかを指定します。

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

このやり取りでは、エージェントはコーディング ツールを正しく使用しました。今度は、他のツールも使ってもらいたいと思っています。

最後に、エージェントにこのチャットからこれまでに得られたすべての情報をまとめてもらう必要があります。

 

結論

この記事は、以下のことを説明するためのチュートリアルとして作成されました。 時系列や大規模なデータフレームを処理するエージェントをゼロから構築する方法。モデルがデータと対話する 2 つの方法について説明しました。1 つは自然言語による方法で、大規模言語モデル (LLM) が知識ベースを使用してテーブルを文字列として解釈します。もう 1 つはコードを生成して実行し、ツールを使用してデータセットをオブジェクトとして操作します。

この記事の完全なコード: GitHub

楽しんでいただけたら幸いです!ご質問やご意見、また興味深いプロジェクトを共有していただく場合は、お気軽にご連絡ください。

 

コメントは締め切りました。