LoginSignup
5
4

AWS Lambda(Python)からOpenAIのGPT4のAPIを呼び出してみた

Posted at

Supershipの名畑です。スナックバス江は肩の力を抜いて見られるのでいいですね。年齢を重ねる毎にこういう作品が好きになっていきます。

はじめに

AWS(Amazon Web Services)でWebアプリを作ることがあるのですが、その過程で触れてきたものについて、せっかくなので要点だけを抽出して残しておくことにしました。

特に目新しい内容はありませんが、AWSOpenAIのアカウント作成も含めて一通りの流れを残すので、いい具合の備忘になればと。

今回はLambdaを経由してOpenAIAPIを叩くまでをまとめます。

Lambdaとは

AWS Lambda は、サーバーをプロビジョニングまたは管理せずにコードを実行できるようにするコンピューティングサービスです。

Lambda は可用性の高いコンピューティングインフラストラクチャでコードを実行し、コンピューティングリソースに関するすべての管理を行います。これには、サーバーおよびオペレーティングシステムのメンテナンス、容量のプロビジョニングおよび自動スケーリング、さらにログ記録などが含まれます。Lambda で必要なことは、サポートするいずれかの言語ランタイムにコードを与えることだけです。

参考:AWS Lambda の概要 - AWS Lambda

私の環境

OSやブラウザ依存の部分はそこまで多くないですが、一応残しておきます。

MacOS Ventureで、ブラウザはChromeです。

AWSのアカウントを作る

私はすでにAWSアカウント取得済みでしたが、初めての方は「AWS アカウント作成の流れ」に従ってアカウントを作成してください。

AWS CLIをインストールする

AWS CLI(AWS コマンドラインインターフェイス)を入れておきます。

今回の内容であればなくても完結させられはするのですが、私は手元のコードをコードアップロードする等がしたいので入れました。

リンク先から自環境に適したインストーラをダウンロードします。

CLIは動かすためにリージョン(ロケーションの単位、東京であればap-northeast-1)の登録などが必要なのですが、configureコマンドで設定するのが早いでしょうか。

詳しくは下記あたりをご覧ください。

OpenAIのアカウント作成とAPI Keyの取得

OpenAIのアカウント作成はOpenAI platformで行えます。

API呼び出しに用いるAPI keyの取得はサインイン後のAPI keysのページで行えます。Create new secret keyを押して、名前(optional)をつけるだけです。
API keyは作成時しか画面に表示されませんので気をつけてください。画面上から後で知る方法はありません。

OpenAIのSDKのダウンロード

後ほどLambdaOpenAIのAPI呼び出しを行います。
そのためにOpenAIのSDKをダウンロードしておきます。

ただし、普通にダウンロードして普通にアップロードをすると、Lambdaからの呼び出しのタイミングで下記のエラーが発生します。

{
  "errorMessage": "Unable to import module 'LambdaFunctionOverHttps': No module named 'pydantic_core._pydantic_core'",
  "errorType": "Runtime.ImportModuleError",
  "requestId": "略",
  "stackTrace": []
}

どうやらこちらのissueでやりとりされているもののようです。
AWS Lambda Layers + OpenAI でつまづいた件」という記事で同種のエラーを上げられている方もいらっしゃいました。

これを回避するため、今回はfastapiのバージョンを下げた上でダウンロードします。

まず、私の環境ではPythonは3.10です。今回は全環境を3.10で統一することとします。

$ python --version
Python 3.10.12

次にSDKのダウンロードです。fastapiのバージョンを指定した上で、あらかじめ用意しておいたpythonというフォルダにダウンロードします。

$ python -m pip install -t ./python fastapi==0.99.0 openai

これをzip形式でopenai.zipとして固めておきます。後ほど使います。

$ zip -r openai.zip ./python

Lambda関数の作成

ブラウザのコンソールでLambdaを開いて「関数の作成」をクリックします。

一から作成」を選び、関数名はopenai-sampleとしました。
ランタイムPython 3.10を選びました。

これで「関数の作成」をクリックするとLambda関数が作られます。

デフォルトでのコードは下記です。

import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

OpenAIのSDKのアップロード

Lambdaでサイドメニューからレイヤーを選んで「レイヤーの作成」をクリックします。
名前はopenaiとしておきます。

先ほど作成したopenai.zipをアップロードするファイルとして選びます。

互換性のあるアーキテクチャはx86_64arm64を選びます。
互換性のあるランタイムはpython3.10とします。

最後に作成をクリックします。

lambda_1.png

スクリーンショット上では私が色々といじったのでバージョンが8となっていますが、実際の初期値は1です。バージョン番号はレイヤーを更新する度にアップデートされていきます。

この状態で先ほどのコード編集画面に戻り「レイヤーの追加」でカスタムレイヤーからopenaiを選びます。

すると下記のスクリーンショットのように追加されます。

lambda_1b.png

環境変数の設定

lambda_2.png

API_KEYをコードに直接記述するのはよろしくないので、Lambda設定環境変数

  • キー:OPENAI_API_KEY
  • :OpenAIで取得したAPI-Key

を設定しておきます。スクリーンショットのhogeを実際の値にしましょう。

タイムアウトの変更

Lambdaの「設定」の「基本設定」で「タイムアウト値」を3秒から伸ばしておきます。
3秒だとレスポンスがほとんど返ってこないためです。

今回は60秒としておきました。

Pythonのコードを書く

import openai
import json
import os
from openai import OpenAI
openai.api_key = os.environ['OPENAI_API_KEY']  # 環境変数から取得

def lambda_handler(event, context):
    try:
        client = OpenAI()
        completion = client.chat.completions.create(
            model="gpt-4",
            messages=event
        )
    except Exception as e:
        raise e
    
    return {
        'statusCode': 200,
        'body': json.dumps(completion.choices[0].message.content)
    }

受け取った内容をそのままOpenAIGPT4に投げるだけのコードです。
実際は受け取った内容に応じて分岐するでしょうし、エラー処理もきちんと書く必要があるでしょう。今はExceptionをそのまま投げているだけなので無意味な処理です。

今回は本題ではないので深くは触れませんが、OpenAIのAPIについて詳しくはAPI referenceをご覧ください。

コンソール上で直接このコードを貼り付けても大丈夫ですが、今回はせっかくなのでローカルからアップロードします。

lambda_function.pyというファイル名でローカルで保存します。
ファイル名はLambdaでのデフォルトです。コードの画面で確認できます。

まず、zipで圧縮します。

$ zip function.zip ./lambda_function.py

次にアップロードします。

$ aws lambda update-function-code --function-name openai-sample --zip-file fileb://function.zip

Lambdaのコードが更新されていることがコンソールでわかります。

lambda_3.png

Lambda関数を呼び出してみる

下記の内容をinput.txtというファイル名で保存しておきます。OpenAIのAPIに渡す内容をそのまま書いたものです。

[
	{
		"role": "user",
		"content":"あなたはOpenAIのAPIですか?"
	}
]

ターミナルからコマンドを叩いてみます。input.txtの内容をLambdaに渡して、レスポンスをoutput.txtに出力するコマンドです。

$ aws lambda invoke --function-name openai-sample --payload file://input.txt output.txt --cli-binary-format raw-in-base64-out

しばらく待つとレスポンスがありました。

{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

output.txtの中身をcatで見てみます。

$ cat output.txt  
{"statusCode": 200, "body": "\"\\u306f\\u3044\\u3001\\u305d\\u306e\\u901a\\u308a\\u3067\\u3059\\u3002\\u79c1\\u306fOpenAI\\u306e\\u4eba\\u5de5\\u77e5\\u80fd\\u30a2\\u30b7\\u30b9\\u30bf\\u30f3\\u30c8\\u3067\\u3001\\u8c4a\\u5bcc\\u306a\\u77e5\\u8b58\\u3068\\u6a5f\\u68b0\\u5b66\\u7fd2\\u306e\\u529b\\u3092\\u4f7f\\u3063\\u3066\\u3001\\u30e6\\u30fc\\u30b6\\u30fc\\u304b\\u3089\\u306e\\u3055\\u307e\\u3056\\u307e\\u306a\\u8cea\\u554f\\u3084\\u8981\\u6c42\\u306b\\u5fdc\\u3048\\u308b\\u3053\\u3068\\u304c\\u3067\\u304d\\u307e\\u3059\\u3002\""}%  

Unicodeをデコードしないと読めないですね。
もっと楽な手もあるかもしれませんが、sednkfでデコードして出力します。

$ cat output.txt | sed 's/\\\\\u\(....\)/\&#x\1;/g' | nkf --numchar-input -w
{"statusCode": 200, "body": "\"はい、その通りです。私はOpenAIの人工知能アシスタントで、豊富な知識と機械学習の力を使って、ユーザーからのさまざまな質問や要求に応えることができます。\""}%       

bodyの中身が

はい、その通りです。私はOpenAIの人工知能アシスタントで、豊富な知識と機械学習の力を使って、ユーザーからのさまざまな質問や要求に応えることができます。

こうなっていますので、無事にOpenAIのAPIの呼び出しが行えていそうです。

デコードに用いたnkfはデフォルトだとインストールされていませんので、ご注意ください。もしも使うならbrew等でインストールしましょう。

$ brew install nkf 

最後に

AWSに触れる度、本当に便利な時代になったものだと実感します。

次回は今回作成したLambda関数API Gatewayを接続してみる予定です。

そうすることによってURLを指定してLambda関数を叩けますので。今はLambda関数URLがあるので、用途によってはこれだけで充分かもしれませんが。

宣伝

SupershipのQiita Organizationを合わせてご覧いただけますと嬉しいです。他のメンバーの記事も多数あります。

Supershipではプロダクト開発やサービス開発に関わる方を絶賛募集しております。
興味がある方はSupership株式会社 採用サイトよりご確認ください。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4