LoginSignup
9
6
新規開発や新技術の検証、導入にまつわる記事を投稿しよう!

chatGPT function callで遊んでみた〜戦闘システム編〜

Posted at

はじめに

2023年の6月13日に、OpenAIのChat Comppletion APIに新機能、function callが追加されました。
関数を半自動で呼んでくれるのも頼もしいですが、前半処理の、argumentsを抽出する部分にフォーカスして何か作ってみようと思いました。
今まではchatGPTのレスポンスの文字列を抽出して、変数を取得していましたが、function callを使えば確実に変数を取得できそうです。
そこで、簡単な戦闘システムをpythonで作ってみました。

成果物

勇者(あなた)と魔王が戦闘するゲームを作りました。
勇者が攻撃する内容をターミナルで入力し、魔王を討伐します。
HPの管理を、function callで実装しました。

処理の流れ

  1. systemの定義
    1. chatGPTにあなたが魔王で、私が勇者である旨を設定する。
    2. この際、HP情報を言ってもらう旨も設定しておく。
  2. あなたに魔王を攻撃する手法を入力してもらう。
  3. 攻撃内容をchatGPTに送信。
    1. 攻撃前のHP情報も合わせて送信。
  4. 上記のレスポンスをfunction call付きでchatGPTに送信。
  5. function callで、HPを更新するローカル関数を実行。
  6. 以後どちらかが倒れるまで繰り返し2-5を繰り返し。

通常のfunction callの流れでは、関数実行の結果をさらにchatGPTに送信しますが、今回は必要が無いので、していません。

コード

battle.py
import openai
import json

devel_hp = 1000 #魔王の初期HP
brave_hp = 500 #勇者の初期HP
system_description = "あなたは異世界の魔王。私は魔王を討伐する勇者。あなたの一人称は「余」。私が攻撃したら反撃して。HPに変動があったら言って。戦闘描写を軽く実況して"
hp_description = ""
def hp_change(d_hp, b_hp):
    global devel_hp, brave_hp
    devel_hp = d_hp
    brave_hp = b_hp
    print("状況:魔王のHPは、"+str(devel_hp) + "。勇者のHPは、"+str(brave_hp))

def run_conversation():
    print("勇者の攻撃:",end='')
    content = input()
    hp_description = "魔王のHPは、"+str(devel_hp) + "勇者のHPは、"+str(brave_hp)# 毎回HPを更新し、systemに入れる。
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo-0613",
        messages=[
                    {"role": "system", "content": system_description + hp_description},
                    {"role": "user", "content": content}
                ]
    )
    print(response["choices"][0]["message"]["content"])
    # HP情報の抽出
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo-0613",
        messages=[{"role": "user", "content": response["choices"][0]["message"]["content"]}],
        functions=[
            {
                "name": "hp_change",
                "description": "HPを上書きする",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "devil_hp": {
                            "type": "number",
                            "description": "魔王のHP",
                        },
                        "brave_hp": {
                            "type": "number",
                            "description": "勇者のHP",
                        }
                    },
                },
            }
        ],
        function_call="auto",
    )
    message = response["choices"][0]["message"]
    function_call = message.get("function_call")

    if function_call:# 更新があれば、HP情報の更新処理
        arguments = json.loads(function_call["arguments"])
        hp_change(
            d_hp=arguments.get("devil_hp", devel_hp), b_hp=arguments.get("brave_hp", brave_hp)
        )
    else:
        print("(何もおきなかった)")

if __name__ == '__main__':
    print("余は、魔王だ。勇者よ、かかってこい!")
    while True:# どちらかのHPが0になるまで戦闘する。
        run_conversation()
        if brave_hp<=0:
            print("勇者の負け")
            break
        if devel_hp<=0:
            print("勇者の勝ち")
            break

実行結果

戦闘描写が長いので、途中までを貼り付けました。
お手元で実行する場合は、環境変数OPENAI_API_KEYを設定してください。(参考)

❯ python3 battle.py
余は、魔王だ。勇者よ、かかってこい!
勇者の攻撃:炎と氷の合体魔法
余は魔王の姿となり、勇者の攻撃を待っている。勇者が素早く手を組み、炎と氷の力を合わせた合体魔法を繰り出してきた!炎と氷が交差し、凄まじいエネルギーが放たれる!

炎と氷の嵐が余に襲いかかり、魔王の体は一瞬炎と氷に包まれる!しかし、魔王の力がその攻撃を凌いでいく。魔王の耐性と魔力が、炎と氷の攻撃を相殺している様子だ。

魔王のHP:1000
勇者のHP:500

魔王は今の攻撃によって傷つくことはありませんでした。次は勇者の行動に期待です!
(何もおきなかった)
勇者の攻撃:無限月詠
余「よし、いざ参ろう、勇者よ!我、魔王余、汝の挑戦を受ける覚悟を持って参ろうぞ!」

勇者「魔王よ、汝の悪逆なる力を討ち払い、この世界を救うのが我が使命だ!」

余「せいっ!」(魔王が勇者に向かって闇のエネルギーを放つ)

勇者「見切る!」(勇者が剣を振って魔王の攻撃を受け止める)

余「な!?」(魔王の攻撃が跳ね返され、100のダメージを受ける。魔王HP : 900, 勇者HP : 500)

勇者「これが私の剣技!魔王よ、諦めるが良い!」(勇者が剣を振り下ろし、魔王に攻撃)

余「くっ!」(魔王が身をかわし、勇者の攻撃を回避する)

余「余応える!」(魔王が闇の球を放ち、勇者に向かって飛ばす)

勇者「見えているぞ!」(勇者が瞬間的に身をかわし、魔王の攻撃を回避する)

余「何だと!?そんな技を持っているとはな!」(魔王が驚愕しながら勇者の動きを見つめる)

余「ならば、この技に対する答えを教えてやろう!」(魔王が闇の刃を振り下ろし、勇者に攻撃)

勇者「くっ!」(勇者がダメージを受け、100のダメージを受ける。魔王HP : 900, 勇者HP : 400)

勇者「まだまだ終わらん!決着をつけるまで立ち向かう!」(勇者が息を切らせながら魔王に再び攻撃を仕掛ける)

余「その覚悟、試してみようではないか!魔王余、全力で迎え撃つぞ!」
状況:魔王のHPは、900。勇者のHPは、400

終わりに

function callを使用して、chatGPTのレスポンスから変数部分を抽出し、簡易的な戦闘システムを構築することができました。
他にも面白いfunction callの使い方がありそうです。
今回で言うと、戦闘中の状態異常とかも取れたら面白そうですね。

9
6
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
9
6