俺のPythonを使ってくれ！自分の環境の Python でOpenAIを使ったデータ分析をやってみる

2023年にOpenAI/Azure OpenAIで導入されたFunction Callingですが、皆さん使っていますか？あれから月日が流れ、APIも変更されて使い方も変わりましたね。また、Assistants APIも導入され、アプリケーションに組み込む方法もいろいろ選択できるようになりました。

AssistantsにはCode Interpreter機能があります。このAssistants Code Interpreterは、Assistants APIのサンドボックス実行環境でPythonコードを作成して実行できるようになります。Code Interpreterを有効にすると、アシスタントはコードを繰り返し実行して、より困難なコード、数学、データ分析の問題を解決できるのが特徴です。また、Assistantsは、実行に失敗したコードを作成した場合、コードの実行が成功するまで、別のコードを変更して実行することで、反復して処理するなど、人間がプログラムを書くように動作します。

ただ、このPythonコードは、OpenAIもしくはAzure OpenAIで動作するため、自分のPython環境ではPythonコードは実行されません。あと、Pythonコードで使用するファイルのアップロードサイズにも制限があります。

今回は、Assistants APIのCode Interpreterではなく、Chat Completions APIのFunction Callingを使用して、自分のPython環境でCode InterpreterのようにPythonコードを動かしてみたいと思います。

※ 今回の記事で使用するプログラムは、OpenAIによって生成されたコードを実行します。生成されたコードによっては、問題が起こる可能性があります。必ずご自身の責任において実行してください。

# まずは準備

まず、Function callingが使えるモデルを選びます。ご自身で使用しているOpenAIの環境にあわせて選んでください。

## OpenAIでFunction callingをサポートするモデル
Function callingは、2023年6月1日のリリースで導入されましたが、この日付以降にリリースされたすべてのモデルは、Function callingをサポートしているようです。

https://platform.openai.com/docs/guides/function-calling#models-supporting-function-calling

## Azure OpenAIでFunction callingをサポートするモデル
Azure のドキュメントには、サポートするモデルが細かく書かれていますね。

https://learn.microsoft.com/ja-jp/azure/ai-services/openai/how-to/function-calling

## 実行環境の準備
Azure Virtual Machine などで Ubuntu Server 24.04.1 LTSを作成します。

## Pythonのインストール
Anaconda か Minicoda を Ubuntu Serverにインストールします。

```
curl -O https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
```

インストールが完了してパスの設定も完了したら、Pythonの環境を作成してください。

```
conda create -n py312 python=3.12
conda activate py312
```

https://docs.anaconda.com/miniconda/install/

## githubからコードを取得する
今回使用するpython_code_interpreterのコードをgithubから取得します。

```
git clone https://github.com/KentaroAOKI/python_code_interpreter.git --recursive
```

## python_code_interpreterの設定

.envファイルにpython_code_interpreterの設定を行います。サンプルの.env.sampleを参考にします。

```sh
cd python_code_interpreter
cp .env.sample .env
```

OpenAIを使用している方は、以下の環境変数を設定します。
- DEPLOYMENT_NAME: モデル名
- OPENAI_API_KEY: APIキー

Azure OpenAIを使用している方は、以下の環境変数を設定します。
- DEPLOYMENT_NAME: モデル名
- AZURE_OPENAI_API_KEY: APIキー
- AZURE_OPENAI_ENDPOINT: エンドポイントURL
- OPENAI_API_VERSION: APIバージョン

```sh:.env
DEPLOYMENT_NAME='gpt-4o-mini'

# OpenAI
# If your environment is OpenAI, set the following
OPENAI_API_KEY='<your openai key>'

# Azure OpenAI
# If your environment is Azure OpenAI, set the following
AZURE_OPENAI_API_KEY='<your azure openai key>'
AZURE_OPENAI_ENDPOINT='https://<your endpoint>.openai.azure.com/'
OPENAI_API_VERSION='2024-10-01-preview'
```

## python_code_interpreter.pyの変更
OpenAIを使用している方は、python_code_interpreter.pyの上のほうの以下の箇所を修正してください。

### OpenAIを使用する場合
```python:python_code_interpreter.py
class PythonCodeInterpreter():
    def __init__(self, deployment_name: str):

        self.client = OpenAI()
        # self.client = AzureOpenAI()
```

### Azure OpenAI Serviceを使用する場合（変更の必要はありません）

```python:python_code_interpreter.py
class PythonCodeInterpreter():
    def __init__(self, deployment_name: str):

        # self.client = OpenAI()
        self.client = AzureOpenAI()
```

## /mnt/data の設定
Pythonコードから読み込むデータは /mnt/data に置きます。今回はsample_dataディレクトリを使用したいと思いますので、以下のようにリンクしました。Pythonを実行する権限で/mnt/dataにアクセスできることを確認してください。

```sh
sudo ln -s `pwd`/sample_data /mnt/data
```

## Pythonモジュールのインストール
動作確認に使用する最低限のPythonモジュールをインストールします。

```sh
pip install -r requirements.txt
```

生成されたコード内で未インストールのPythonモジュールが使用された場合は、ご自身で必要に応じてPythonモジュールをインストールしてください。

# 実行してみる

python:python_code_interpreter.pyの下のほうのmessage変数に、指示を書いてください。今回の指示は以下にしました。

- /mnt/data/diagnosis.csv のデータが悪性か良性か判断してください。判断は、scikit-learn から取得できる load_breast_cancer データで学習したモデルを使ってください。日本語で説明してください。

```python:python_code_interpreter.py
if __name__ == '__main__':
    # message = "Get the NVIDIA stock price from January to March 2023 from Yahoo and predict the stock price after April 2023." # sample_01
    # message = "Determine whether the data in /mnt/data/diagnosis.csv is malignant or benign. To make a decision, use the model learned using the load_breast_cancer data available from scikit-learn." # sample_02
    # message = "2023年の1月から3月のNVIDIA株価をYahooから取得して、2023年4月以降の株価を予測してください。" # sample_03
    message = "/mnt/data/diagnosis.csv のデータが悪性か良性か判断してください。判断は、scikit-learn から取得できる load_breast_cancer データで学習したモデルを使ってください。日本語で説明してください。" # sample_04

    pci = PythonCodeInterpreter(deployment_name)
    assistant_response = pci.run_conversation(message)
    print(json.dumps(assistant_response))
```

設定したらプログラムを実行してみます。

```sh
python python_code_interpreter.py
```

実行すると、コードが生成されますので実行する場合は、"yes"と入力してください。以下は、一回"yes"と入力した出力の様子。

```
[{'role': 'user', 'content': '/mnt/data/diagnosis.csv のデータが悪性か良性か判断してください。判断は、scikit-learn から取得できる load_breast_cancer データで学習したモデルを使ってください。日本語で説明してください。'}]
----------
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# データの読み込み
cancer_data = load_breast_cancer()
X = cancer_data.data
y = cancer_data.target

# データをトレーニングセットとテストセットに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# ランダムフォレストモデルの作成と学習
model = RandomForestClassifier(random_state=42)
model.fit(X_train, y_train)

# テストセットでの予測
y_pred = model.predict(X_test)

# 精度の評価
accuracy = accuracy_score(y_test, y_pred)
accuracy
----------
Do you want to continue running this program?(yes/no): yes
Executing: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 2/2 [00:05<00:00,  2.81s/cell]
{'text/plain': '0.9649122807017544'}
[ChatCompletionMessage(content='モデルの精度は約96.5%です。これは、学習したモデルがテストデータに対して非常に高い精度で悪性か良性かを判断できることを示しています。\n\n次に、指定されたファイル `/mnt/data/diagnosis.csv` のデータを読み込み、そのデータを使って悪性か良性かを判断します。ファイルの内容を確認してから、予測を行います。', refusal=None, role='assistant', audio=None, function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_IHr0xIVsYX1E4v01U1IATq1J', function=Function(arguments='{"python_code":"# CSVファイルの読み込み\\nfile_path = \'/mnt/data/diagnosis.csv\'\\ndiagnosis_data = pd.read_csv(file_path)\\n\\ndiagnosis_data.head()"}', name='python'), type='function')])]
----------
# CSVファイルの読み込み
file_path = '/mnt/data/diagnosis.csv'
diagnosis_data = pd.read_csv(file_path)

diagnosis_data.head()
----------
Do you want to continue running this program?(yes/no):
```

今回のプログラムは、Jupyter notebookがサーバとして立ち上げていません。そのため、Pythonの状態情報は維持しておらず、毎回初めから実行しています。

## 実行結果
繰り返して答えが出るとプログラムが終了します。resultsフォルダに回答のnotebookのファイルが作成されますので確認してください。  

以下のようなファイルが作成されます。

https://github.com/KentaroAOKI/python_code_interpreter/blob/main/sample_results/sample_04.ipynb

# さいごに
自分のPython環境でプログラムを動かせると、自分のデータベースからデータを取得するなど、いろいろ夢が広がりますね。  
AIによって生成されたプログラムを実行するため、問題にならないかご自身で確認しながら実行するようにしてください。ではー。