🔐

業務で使うためのChatGPTのAPI Wrapperを作った

2023/04/09に公開

こんにちは。
フロントエンジニアを主にやっている「てすら」です。
zennや技術ブログ系は初めてなので読みづらいところがありましたらすみません...

最近は生成AIやChatGPT周りについて調べることが増えました。
ChatGPTを使いたいものの、企業によっては情報漏洩の観点から使えないことがあると思います。

そこで特定の単語だけ暗号化して送信するAPIのWrapperを作成し、情報漏洩の可能性を最小限に抑えるようなものを作成しました。

この記事は誰向けか

ChatGPTなどのLLMを使用したいが、データの秘匿性の観点などから使用に踏み切れない方
(API側のオプトアウトだけでは不安な方)

記事要約

GPT-4のAPIにおけるデータ保護を強化するためにMaskedGPT-APIを作成しました。

MaskedGPT-APIは、GPT-4やGPT-3.5-TurboのAPIを叩く際に特定の単語を暗号化して送信するAPIのWrapperです。
csvファイルを読み込んで、csvにある特定の単語だけを暗号化することができるため、秘匿性の高いサービス名や情報などを暗号化することができます。

MaskedGPT-APIの最大の利点は、復号化されたレスポンスを返すため、人間が読む分には違和感がない点です。
ただし、使用するトークン量が暗号化の分だけ増加するため、必要な人のみ使用するようにしてください。

dict.csv
word,description
ChatGPT,チャットで指示するAIアプリケーション
OpenAI,チャットで指示するAIアプリケーションの会社
Microsoft,特定の会社名1
Bing,検索エンジンサービス
Google,特定の会社名2

入力

terminal
curl -X POST "http://localhost:8000/process_message" -H "Content-Type: application/json" -d 
'{"message": "以下の文章を元にし、OpenAIの求人広告のテキストを出力して下さい。ChatGPTは、OpenAIが開発したGPT-3.5アーキテクチャに基づく大規模な言語モデルです。OpenAIは、人工知能と機械学習の分野でリーディングカンパニーの1つです。Microsoftは、OpenAIとの提携を通じて、その技術を活用しています。Bingは、Microsoftが運営する検索エンジンであり、Googleと競合しています。"}'

今回のWrapperによる変換後(GPT-4のAPIに送っているものの一部)

下の文章を元にし、#{3944ec2e}の求人広告のテキストを出力して下さい。
#{3ae630b1}は、#{3944ec2e}が開発したGPT-3.5アーキテクチャに基づく大規模な言語モデルです。
#{3944ec2e}は、人工知能と機械学習の分野でリーディングカンパニーの1つです。
#{add1fa45}は、#{3944ec2e}との提携を通じて、その技術を活用しています。
#{4e86d472}は、#{add1fa45}が運営する検索エンジンであり、#{6b4f474d}と競合しています。

出力(GPT-4のAPIからの返答)

terminal
{"id":"XXX","object":"chat.completion","created":YYYYYYYY,"model":"gpt-4-0314","usage":{"prompt_tokens":389,"completion_tokens":671,"total_tokens":1060},
"choices":[{"message":{"role":"assistant","content":"
【AIデベロッパー募集! OpenAIで働こう】\n\nOpenAIは、画期的なChatGPTを開発しています。我々の技術はGPT-3.5アーキテクチャに基づく大規模な言語モデルを提供し、世界中の多くの企業から信頼されています。今回、我々はあなたの技術と熱意でチームを強化したいと考えています。
\n\n我々は、機械学習と人工知能の分野でリーディングカンパニーの1つです。我々の技術は、業界のトップクラス企業であるMicrosoftにも採用され、Bingにおいて、競合企業であるGoogleに対抗できる成果を上げています。
【求めるスキル・経験】\n- ニューラルネットワークや機械学習の基礎知識\n- GPT系アーキテクチャに関する経験\n- Pythonなどプログラミング言語のスキル\n\n
【募集背景】\nChatGPTの開発を加速させ、技術革新に貢献するため、新しいチームメンバーを募集します。\n\n
【仕事内容】\n- AIアプリケーションの開発と最適化\n- Bingなどの新しいサービス開発\n- GPT-3.5アーキテクチャの改善と実装\n\n
【提供するもの】\n- 競争力のある給与と豊富な福利厚生\n- プロフェッショナルなチームメンバーとの共同作業\n- 業界の最先端技術に触れる機会\n\nアプリケーションや推薦状は以下のメールアドレスにお送りください。\n[email@example.com]\n\nAI開発の最前線で成功を収めるチャンスがここにあります。是非この機会にOpenAIへの参加をお考えください。お待ちしておりす。"},"finish_reason":"stop","index":0}]}

リポジトリ

https://github.com/tesla0225/MaskedGPT-API

使い方

リポジトリをCloneして、dict.csvを編集
(例と同じものを使用

ルートディレクトリに.envファイルを作成

.env
OPENAI_API_KEY=APIキー
LANGUAGE_CODE=ja
MODEL_NAME=gpt-3.5-turbo

コンテナのビルド

terminal
docker build -t maskedgpt . 

実行

terminal
docker run -p 8000:8000 maskedgpt 

以下の形式でpost

terminal
curl -X POST "http://localhost:8000/process_message" -H "Content-Type: application/json" -d '{"message": "文章が入ります"}'

実装内容

主なポイントは以下になります
・暗号化されたpromptと暗号化された単語の説明を別々のRoleで送っている
・additional_system_messageの最初の一行にものすごく実験を必要とした
(なかなか暗号化されただけで送ってもらえず、勝手に説明を加えたりした)

main.py
import os
import openai
from fastapi import FastAPI, Request
from dotenv import load_dotenv
from .database import session
from .preprocessing import request_preprocessing
from .postprocessing import response_postprocessing

load_dotenv()

language_code = os.environ.get("LANGUAGE_CODE", "ja")
model_name = os.environ.get("MODEL_NAME", "gpt-3.5-turbo")
openai_api_key = os.environ.get("OPENAI_API_KEY", "")
openai.api_key = openai_api_key

language_type = {
    "ja": "Japanese",
    "en": "English",
}

system_message_sent = False

app = FastAPI()


@app.post("/process_message")
async def process_message(request: Request):
    global system_message_sent

    data = await request.json()
    message = data["message"]

    # 前処理
    processed_message, additional_system_message = await request_preprocessing(message)

    messages = [{"role": "user", "content": processed_message}]

    if not system_message_sent:
        messages.insert(
            0, {"role": "system", "content": f"ChatGPT is an OpenAI language model. Follow instructions, use markdown for responses, and Output in {language_type}."})
        system_message_sent = True

    messages.insert(
        0, {"role": "system", "content": additional_system_message})

    response = openai.ChatCompletion.create(
        model=model_name,
        messages=messages,
    )

    # 後処理
    final_message = await response_postprocessing(response.choices[0]["message"]["content"])
    response.choices[0]["message"]["content"] = final_message
    return response

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
preprocessing.py
from .database import session
from .models import Word


async def request_preprocessing(message: str):
    additional_system_message = "IMPORTANT: include a word and its description as (word): (description). Do NOT use (description) in the output.  "
    words = session.query(Word).all()
    for word in words:
        if word.word in message:
            message = message.replace(word.word, word.cryptoword)
            additional_system_message += f" {word.cryptoword}: {word.description}"
    print("message:", message)
    print("additional_system_message:", additional_system_message)
    return message, additional_system_message

感想など

読みやすさと取り込みやすさ重視でPythonとFastAPIを選択しました。
ただPythonはあまり得意ではないので、ほとんどGPT-4と仕様を揉んでコード書いてもらって...という感じで実装しました。

Discussion