メインコンテンツへスキップ
見出し画像

OpenAI APIのログを簡単に管理する

    こんにちは、ニケです。
    皆さん、OpenAI APIは使用されてますでしょうか。

    2023年はGPT4の登場もあって様々なAIサービスがリリースされました。
    この記事を読んでいる方の中にも、大小の規模を問わずAIアプリを作ってみた経験がある方は多いのではないでしょうか?

    そして多くの方が利用しているのはOpenAIのAPIだと思います。一番メジャーですからね。

    ところで、アプリ開発で重要なことってなんでしょう?
    アプリ開発にはユーザーのニーズ理解、効率的なコーディング、セキュリティ対策、そしてユーザー体験の最適化など、様々な重要な要素があります。

    しかし、どれも大事ですが、私は特にログ管理が大事だと思っています。
    ログ管理により、アプリの不具合を早期に発見し改善することができ、そしてこれはアプリの安定性を保つだけでなく、最終的にユーザー満足度を高めるためにも不可欠です。

    …そんな皆さん、朗報ですよ。

    ということで今回は、OpenAI APIのリバース プロキシとして機能するPythonライブラリをうえぞうさんが公開してくれたので、その内のログ管理機能を試してみたという記事です。

    AIアプリ開発者のみんなー!ChatGPT用のリバースプロキシ作ったよ〜✨🦉
    ✅リクエスト・レスポンス全量記録
    ✅フィルタリング(上書き、利用制限、過去応答の再生etc)
    ✅Stream対応(ログもトークン数カウントも)https://t.co/D0mAUWC4x9 #aiproxy

    — うえぞう@うな技研代表 (@uezochan) December 3, 2023

    始め方

    READMEに載っているやり方をなぞります。

    インストール

    パッケージ化されているのでgitリポジトリをクローンする必要はありません。適当な環境で実行してください。

    pip install aiproxy-python

    サーバー起動

    このコマンドを実行したフォルダにDBファイルが出力されます。

    python -m aiproxy [--host host] [--port port] [--openai_api_key OPENAI_API_KEY]
     
    # 特に追加設定が必要ないなら下記のみでOK
    # デフォルトは、http://127.0.0.1:8000
     
    python -m aiproxy

    使用方法

    あとは自身のAIアプリ内で、OpenAI APIのClientの設定を下記のようにします。

    import openai
    
    client = openai.Client(base_url="http://127.0.0.1:8000/", api_key="YOUR_API_KEY")
    resp = client.chat.completions.create(
      model="gpt-3.5-turbo",
      messages=[{"role": "user", "content": "hello!"}]
    )
    
    print(resp)

    OpenAIクラスを使う場合はこちら

    from openai import OpenAI
    
    client = OpenAI(base_url="http://127.0.0.1:8000/", api_key="YOUR_API_KEY")
    resp = client.chat.completions.create(
      model="gpt-3.5-turbo",
      messages=[{"role": "user", "content": "hello!"}]
    )
    
    print(resp)

    これだけです。

    出力ログ確認

    上記のpythonスクリプトを実行すると、aproxy.db というファイルが作成されます。
    SQLiteのデータベースファイルなので、適切な方法で開きます。

    SQLiteファイルの開き方わからん、って人は aproxy.db ファイルと同じフォルダ内で下記のスクリプトを実行してください。

    import sqlite3
    import csv
    
    # データベースに接続
    conn = sqlite3.connect('tests/aiproxy.db')
    c = conn.cursor()
    
    # データベース内の全てのテーブル名を取得
    c.execute("SELECT name FROM sqlite_master WHERE type='table';")
    tables = c.fetchall()
    
    for table_name in tables:
        table_name = table_name[0]
        print(f"Processing Table: {table_name}")
        
        # テーブルのカラム名を取得
        c.execute(f"PRAGMA table_info({table_name});")
        columns = c.fetchall()
        column_names = [column[1] for column in columns]
    
        # 各テーブルから全てのデータを取得
        c.execute(f"SELECT * FROM {table_name};")
        rows = c.fetchall()
    
        # データをCSVファイルに出力
        with open(f'{table_name}.csv', 'w', newline='') as f:
            writer = csv.writer(f)
            writer.writerow(column_names)  # カラム名を出力
            writer.writerows(rows)  # データを出力
    
    # 接続を閉じる
    conn.close()

    accesslog.csv というcsvファイルが出力されるので中身を確認します。

    id,request_id,created_at,direction,content,function_call,tool_calls,raw_body,raw_headers,model,prompt_tokens,completion_tokens,request_time,request_time_api
    1,c049cdc5-9c55-4584-89ca-6ed42ab0b546,2023-12-09 21:35:26.500663,request,hello!,,,"{""messages"": [{""role"": ""user"", ""content"": ""hello!""}], ""model"": ""gpt-3.5-turbo""}","{""host"": ""127.0.0.1:8000"", ""accept-encoding"": ""gzip, deflate, br"", ""connection"": ""keep-alive"", ""accept"": ""application/json"", ""content-type"": ""application/json"", ""user-agent"": ""OpenAI/Python 1.3.8"", ""x-stainless-lang"": ""python"", ""x-stainless-package-version"": ""1.3.8"", ""x-stainless-os"": ""MacOS"", ""x-stainless-arch"": ""arm64"", ""x-stainless-runtime"": ""CPython"", ""x-stainless-runtime-version"": ""3.9.13"", ""authorization"": ""Bearer sk-Ko*****Qn"", ""x-stainless-async"": ""false"", ""content-length"": ""79""}",gpt-3.5-turbo,,,,
    2,c049cdc5-9c55-4584-89ca-6ed42ab0b546,2023-12-09 21:35:27.513504,response,Hello! How can I assist you today?,,,"{""id"": ""chatcmpl-8TzGoUOVkH6CN6MahttTkXOMhHRv5"", ""choices"": [{""finish_reason"": ""stop"", ""index"": 0, ""message"": {""content"": ""Hello! How can I assist you today?"", ""role"": ""assistant"", ""function_call"": null, ""tool_calls"": null}}], ""created"": 1702157726, ""model"": ""gpt-3.5-turbo-0613"", ""object"": ""chat.completion"", ""system_fingerprint"": null, ""usage"": {""completion_tokens"": 9, ""prompt_tokens"": 9, ""total_tokens"": 18}}",,gpt-3.5-turbo-0613,9,9,1.033057689666748,1.032876968383789
    

    ぱっと見でわかりやすいようにスクショも置いておきますね。
    Id: 1がユーザー入力、Id: 2がアシスタントの入力です。

    画像
    画像

    メッセージ内容、使用モデル、入出トークン数、リクエストにかかった時間などが保存されています。便利ですね。

    ちなみにstreamにも対応しています。
    下記のスクリプトを実行した結果も載せておきます。

    from openai import OpenAI
    
    client = OpenAI(base_url="http://127.0.0.1:8000/", api_key="YOUR_API_KEY")
    stream = client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": "Say this is a test"}],
        stream=True,
    )
    for chunk in stream:
        if chunk.choices[0].delta.content is not None:
            print(chunk.choices[0].delta.content, end="")
    id,request_id,created_at,direction,content,function_call,tool_calls,raw_body,raw_headers,model,prompt_tokens,completion_tokens,request_time,request_time_api
    1,256670c1-d3a5-42c7-aa3e-709db7ac759d,2023-12-09 22:10:16.561955,request,Say this is a test,,,"{""messages"": [{""role"": ""user"", ""content"": ""Say this is a test""}], ""model"": ""gpt-4"", ""stream"": true}","{""host"": ""127.0.0.1:8000"", ""accept-encoding"": ""gzip, deflate, br"", ""connection"": ""keep-alive"", ""accept"": ""application/json"", ""content-type"": ""application/json"", ""user-agent"": ""OpenAI/Python 1.3.8"", ""x-stainless-lang"": ""python"", ""x-stainless-package-version"": ""1.3.8"", ""x-stainless-os"": ""MacOS"", ""x-stainless-arch"": ""arm64"", ""x-stainless-runtime"": ""CPython"", ""x-stainless-runtime-version"": ""3.9.13"", ""authorization"": ""Bearer sk-Ko*****Qn"", ""x-stainless-async"": ""false"", ""content-length"": ""99""}",gpt-4,,,,
    2,256670c1-d3a5-42c7-aa3e-709db7ac759d,2023-12-09 22:10:18.082565,response,This is a test.,,,"[{""id"": ""chatcmpl-8TzoWLmZR43i2lCFFnPwyEBGcBZnk"", ""choices"": [{""delta"": {""content"": """", ""function_call"": null, ""role"": ""assistant"", ""tool_calls"": null}, ""finish_reason"": null, ""index"": 0}], ""created"": 1702159816, ""model"": ""gpt-4-0613"", ""object"": ""chat.completion.chunk"", ""system_fingerprint"": null}, {""id"": ""chatcmpl-8TzoWLmZR43i2lCFFnPwyEBGcBZnk"", ""choices"": [{""delta"": {""content"": ""This"", ""function_call"": null, ""role"": null, ""tool_calls"": null}, ""finish_reason"": null, ""index"": 0}], ""created"": 1702159816, ""model"": ""gpt-4-0613"", ""object"": ""chat.completion.chunk"", ""system_fingerprint"": null}, {""id"": ""chatcmpl-8TzoWLmZR43i2lCFFnPwyEBGcBZnk"", ""choices"": [{""delta"": {""content"": "" is"", ""function_call"": null, ""role"": null, ""tool_calls"": null}, ""finish_reason"": null, ""index"": 0}], ""created"": 1702159816, ""model"": ""gpt-4-0613"", ""object"": ""chat.completion.chunk"", ""system_fingerprint"": null}, {""id"": ""chatcmpl-8TzoWLmZR43i2lCFFnPwyEBGcBZnk"", ""choices"": [{""delta"": {""content"": "" a"", ""function_call"": null, ""role"": null, ""tool_calls"": null}, ""finish_reason"": null, ""index"": 0}], ""created"": 1702159816, ""model"": ""gpt-4-0613"", ""object"": ""chat.completion.chunk"", ""system_fingerprint"": null}, {""id"": ""chatcmpl-8TzoWLmZR43i2lCFFnPwyEBGcBZnk"", ""choices"": [{""delta"": {""content"": "" test"", ""function_call"": null, ""role"": null, ""tool_calls"": null}, ""finish_reason"": null, ""index"": 0}], ""created"": 1702159816, ""model"": ""gpt-4-0613"", ""object"": ""chat.completion.chunk"", ""system_fingerprint"": null}, {""id"": ""chatcmpl-8TzoWLmZR43i2lCFFnPwyEBGcBZnk"", ""choices"": [{""delta"": {""content"": ""."", ""function_call"": null, ""role"": null, ""tool_calls"": null}, ""finish_reason"": null, ""index"": 0}], ""created"": 1702159816, ""model"": ""gpt-4-0613"", ""object"": ""chat.completion.chunk"", ""system_fingerprint"": null}, {""id"": ""chatcmpl-8TzoWLmZR43i2lCFFnPwyEBGcBZnk"", ""choices"": [{""delta"": {""content"": null, ""function_call"": null, ""role"": null, ""tool_calls"": null}, ""finish_reason"": ""stop"", ""index"": 0}], ""created"": 1702159816, ""model"": ""gpt-4-0613"", ""object"": ""chat.completion.chunk"", ""system_fingerprint"": null}]",,gpt-4-0613,12,5,1.4459269046783447,1.444814920425415
    

    その他

    カスタマイズすることで下記のようなことができるようになります。

    • PostgreSQL などの他の RDBMS を使用

    • 出力カラムの追加

    今回はログ出力機能だけに絞って紹介しましたが、このライブラリの実態はリバースプロキシなので、特定のリクエストを検知し出力結果をコントロールしたりすることもできるようです。

    便利過ぎる…!!
    ここらへんの機能まだ手元で試せていないので、追々確認していきたいと思います。

    詳細な使用方法などはリポジトリに記載してあるのでこちらからどうぞ。

     
     
    ポーランド在住AI VTuber & Agent developer。 AIツールやAIキャラに関してのキャッチアップ多め。

    あなたへのおすすめ