Assistants APIのベクターストアで大規模コード解析に挑戦! (original) (raw)

こんにちは。虎の穴ラボ エンジニアの古賀です!

今回は、OpenAIの『Assistants API』を業務(ソースコードの調査や工数の見積もり)に活用した事例を紹介します。

はじめに

これを試してみようと思った経緯としては、業務で大量のPHPのソースコードファイルについて、PHPのバージョンアップに伴う作業工数の見積もりを行うことになりました。

すべて人手で調査をするととても時間が掛かることが予想されたので、その際にPythonのプログラムとAssistants APIのFile Searchを使って、ソースコードファイルの仕様や概算の必要工数を出力するCLIのプログラムを作成し、ソースコードリーディングや見積もりに役立てることができるかどうかを検証してみました。

本記事では最初にAssistants APIについて紹介し、その後にサンプルプログラムを紹介します。

Assistants APIは、OpenAIが提供するベータ版APIの1つで、AIアシスタントの開発を行うためのAPIです。OpenAPIのChat Completions APIと比べると以下のような大きな特徴があります。

ちなみにサポートされているファイル形式はこのページに記載があります。

Assistants APIを使うとAIアシスタントの開発で手間がかかる機能があらかじめ用意されているため、開発を容易に行うことができます。ただし、UIは提供されていないため、必要な場合は以前のブログで紹介させていただいたサンプルコードの「openai-assistants-quickstart」を使うと開発を効率化できます。

(今回はCLIプログラムのみで、このサンプルコードは使用しません。)

Assistants APIの料金

Assistants APIの料金は、以下の要素によって決まります。

OpenAI APIの利用料にさらにセッションあたりとベクターストレージの料金が加算されるため、利用する際には必ず試算してください。本記事の手順の中にファイルサイズから簡易的に試算するPythonのコードも含んでいます。

0. 前提条件と事前準備

OpenAI APIキーは、.envファイルに以下のように記述してください。

OPENAI_API_KEY=sk-1234567890abcdef1234567890abcdef

1. 環境構築

最初にopenaiのPythonライブラリをインストールします。Assistants APIはこのライブラリを使って利用します。

$ pipenv install openai

2. ベクターストアの料金試算

次のプログラムを使って、ベクターストアの料金を簡易的に試算します。

import os

BASE_PATH = "/path/to/php/files"

def get_php_files_size(directory): total_size = 0 for root, _, files in os.walk(directory): for file in files: if file.endswith(".php"): file_path = os.path.join(root, file) total_size += os.path.getsize(file_path) return total_size

total_size_bytes = get_php_files_size(BASE_PATH) total_size_mb = total_size_bytes / (1024 * 1024)
total_size_gb = total_size_mb / 1024

print(f"Total size of PHP files: {total_size_bytes} bytes") print(f"Total size of PHP files: {total_size_mb:.2f} MB") print(f"Total size of PHP files: {total_size_gb:.2f} GB")

vector_store_cost_per_gb_day = 0.10
estimated_cost = total_size_gb * vector_store_cost_per_gb_day print(f"Estimated cost per day for storing PHP files: ${estimated_cost:.2f}")

このプログラムを実行すると、PHPファイルのサイズとベクターストアの料金が表示されます。

$ python check-vector-price.py Total size of PHP files: 26570404 bytes Total size of PHP files: 25.34 MB Total size of PHP files: 0.02 GB Estimated cost per day for storing PHP files: $0.00

今回は、PHPファイルのサイズが0.02GBであるため、ベクターストアの料金は0.00ドルとなりました。かなり大きいサイズのファイルを大量にアップロードしない限りはあまり料金がかからないようです。

3. ベクターストアへのアップロード

次にアプリケーション内に含まれるすべてのPHPファイルをPythonのプログラムで一括でベクターストアにアップロードし、アシスタントが必要に応じて参照できるようにします。また、アップロードに時間が掛かるため、途中で失敗しても再開できる仕組みを用意しました。(ネットワークの状況によってはアップロードに時間がかかることがあるため)

再開する場合は、RESUME_PATHに再開するファイルのパスとVECTOR_STORE_IDにベクターストアのIDを指定してください。(ベクターストアのIDはOpenAI APIのStorageコンソールをみると確認できます。)

import os from openai import OpenAI

client = OpenAI()

BASE_PATH = "/path/to/php/files"

RESUME_PATH = None

VECTOR_STORE_NAME = "php-files" VECTOR_STORE_ID = None

vector_store = None if VECTOR_STORE_ID: vector_store = client.beta.vector_stores.retrieve(vector_store_id=VECTOR_STORE_ID) print(f"Using existing vector store: {vector_store.name}") else:

vector_store = client.beta.vector_stores.create(name=VECTOR_STORE_NAME)

def find_php_files(directory): php_file_paths = [] for root, _, files in os.walk(directory): for file in files: if file.endswith(".php"): php_file_paths.append(os.path.join(root, file)) return php_file_paths

php_files = find_php_files(BASE_PATH)

uploaded_count = 0 total_files = len(php_files)

resume_upload = RESUME_PATH is None

for file_path in php_files: try:

    if not resume_upload:
        if file_path == RESUME_PATH:
            resume_upload = True
        else:
            uploaded_count += 1
            print(f"Skipping file: {file_path}")
            continue

    
    if os.path.getsize(file_path) == 0:
        uploaded_count += 1
        print(f"Skipping empty file: {file_path}")
        continue  

    
    with open(file_path, "rb") as file_stream:
        file_batch = client.beta.vector_stores.file_batches.upload_and_poll(
            vector_store_id=vector_store.id, files=[file_stream]
        )

    
    uploaded_count += 1
    progress_percentage = (uploaded_count / total_files) * 100
    print(f"Successfully uploaded {file_path} ({uploaded_count}/{total_files}, {progress_percentage:.2f}% complete)")

except Exception as e:
    print(f"Error uploading {file_path}: {str(e)}")

print("All files processed.")

try: print("File batch upload finished with status:", file_batch.status) print("Number of files successfully processed:", file_batch.file_counts) except NameError: print("No files were successfully uploaded.")

このプログラムを次のように実行すると、PHPファイルがベクターストアにアップロードされます。

$ pipenv run python upload-vectorstore.py

4. ソースコードの解析を行う

最後に、Assistants APIのFile Searchを使って指定したPHPファイルの解析を行います。解析したいPHPファイルの一覧はphplist.txtに改行区切りで指定し、解析結果はCSV(diagnosis_results.csv)として出力します。

より良い結果を得るためには、事前に調査した内容やアプリケーションの仕様をMarkdownで記載しておくと、AIアシスタントがより適切な回答を返してくれることがあります。また、出力されるCSVの例がないとCSVのフォーマットにしたがって回答をしてくれない可能性が高いので、事前にいくつかのPHPファイル(10個程度)で実行し、望ましい結果に近いCSVを綺麗に整形して指示文の例のところに貼り付けると精度が上がります。

(プロンプトエンジニアリングの「One-shot/Few-shot」と呼ばれる手法です)

import os from openai import OpenAI

client = OpenAI()

sys_prompt = """ あなたはPHPに関してとても詳しいプロフェッショナルのエンジニアです。PHPのバージョンアップ(xからy)に伴う作業について、以下のCSVフォーマットで日本語で回答をしてください。 [ファイルパス],[機能や役割の要約],[参照しているライブラリの一覧],[参照している他のPHPファイルとその関数の一覧],[不明なクラスや関数参照の一覧],[アップデートが必要なライブラリやコードの箇所とその修正方法の一覧],[修正難易度:低/中/高],[修正にかかる予測工数(時間)],[その他補足]

含まれるPHPファイルについて、事前に調査した内容は下記になります。 この内容も参考にして回答してください。 (事前に調査した内容やアプリケーションの仕様が分かれば、ここにMarkdownで記載しておく)

回答はCSVフォーマットのみでそれ以外の文章は絶対に含めないでください。含められると非常に困ります。 以下はCSVの例です。

(ここに望ましい結果に近いCSVを貼り付ける。CSVのエスケープがされてなかったらエスケープする。)

以上のことを必ず踏まえて、PHPファイルをチェックしてください。 """

BASE_PATH = "/path/to/php/files"

input_file_path = "phplist.txt"

output_csv_path = "diagnosis_results.csv"

vector_store_ids = ["vs_〜"]

with open(input_file_path, "r") as file: php_file_paths = file.read().splitlines()

assistant = client.beta.assistants.create( name="PHPファイルを解析するBot", instructions=sys_prompt, model="gpt-4o-2024-08-06", tools=[{"type": "file_search"}], tool_resources={"file_search": {"vector_store_ids": vector_store_ids}}, )

thread = client.beta.threads.create()

with open(output_csv_path, "wt", encoding="utf-8") as text_file:

for relative_path in php_file_paths: try:

  full_path = os.path.join(BASE_PATH, relative_path)

  
  with open(full_path, "r", encoding="utf-8") as php_file:
      php_content = php_file.read()
  
  
  content = f"ファイルパス:{relative_path} \n```php\n{php_content}\n```"

  
  message = client.beta.threads.messages.create(
      thread_id=thread.id,
      role="user",
      content=content
  )

  
  run = client.beta.threads.runs.create_and_poll(
    thread_id=thread.id,
    assistant_id=assistant.id,
  )
  
  if run.status == 'completed':
    messages = client.beta.threads.messages.list(
      thread_id=thread.id
    )
    print(messages.data[0].content[-1].text.value)
    text_file.write(messages.data[0].content[-1].text.value + "\n")
    text_file.flush()
except Exception as e:
  
  text_file.write(f"\nError: {str(e)}\n")
  print(f"\n\nError processing file {relative_path}: {str(e)}\n\n")

client.beta.assistants.delete(assistant_id=assistant.id) client.beta.threads.delete(thread_id=thread.id)

このプログラムを実行すると、指定したPHPファイルの解析結果がCSVファイルに出力されます。

$ pipenv run python check-code.py

以下は出力されたCSVファイルの例です

xxx.php,"画像情報を取得して表示するスクリプト。Imagickを利用して画像の幅、高さ、深度を取得しています。","Imagick","なし","なし","なし","Imagick関連の処理 → PHPが8.0以降でも有効であることを確認して、特に変更が必要ない場合はそのまま使用。 getImageDepth()の動作を確認し、必要であれば対応する方法に変更。例えば、Imagickがインストールされているか確認し、パフォーマンスへの影響がないかチェックする。",低,1,"このスクリプトはPHPのImagick拡張を利用しており、PHP 8.0に引き続き対応可能です。大きな変更やアップグレードの負担は少ないと予測されます。", yyy.php,"S3にファイルをアップロードするスクリプト。条件により異なるバケットやACLを設定してアップロードしています。","なし","./roles/home/files/viewer_batch/batch/converter.php73/common.phpで定義されているputS3Object関数","なし","なし","AWS関連の設定(AWS_S3_BUCKET、AWS_S3_ACL等) → PHP 8.0で動作を確認し、必要ならAWS SDK for PHPのアップデート。特に指定された定数の場所、計算方法、またはその使用方法が変更されていないか再確認。putS3Object関連の変更が必要な場合、AWS SDKの新しいバージョンを使用し、変更点に合わせた修正。",中,2,"AWS SDKのバージョンによっては、コードの一部を再確認し修正が必要です。最新のライブラリバージョンでの動作確認をお勧めします。"

まとめ

今回はAssistants APIのベクターストアを使って大量のPHPファイルの解析を行い、PHPのファイルの調査や工数の見積もりのサポートをAIにさせてみました。

出力された結果にはImageMagickやAWS SDKのバージョンアップに伴う作業がどのAPIにどの程度時間がかかるか、また、どのような修正が必要かが記載されていましたし、改修にかかる予測工数や参照している他のPHPファイルや関数の一覧、機能の概要もほぼ正確に出力されていました。

内容に関しての正確性は100%ではないですが、大量のPHPファイルの解析を行う際に機能ごとにどのファイルを見るべきかの目安がついたので、かなり効率的に作業を進めることができると感じました。

思わぬ副作用としては、作成したベクターストアを使ったチャットがAssitants APIのコンソール上で可能なので、調査の際に知りたい機能があるPHPファイルの場所や内容をチャットで確認することもでき、作ってみて良かったなと感じています。

採用情報

虎の穴ラボでは一緒に働く仲間を募集中です!
この記事を読んで、興味を持っていただけた方はぜひ弊社の採用情報をご覧ください。
toranoana-lab.co.jp