社内イベント「ThanksDay」にありがとう!〜GIFTechでの開発記録〜


こんにちは、GIFTechエンジニアの佐藤です。
これから、私自身もGIFTechなエンジニア(= [仲間と共創し価値あるモノ創りができるエンジニア])を目指して、日々の発見や学びをテックブログにて共有していきます🙇‍♀️
今回は、先日開催された社内ファミリーデーイベント「ThanksDay」にて、事業紹介ブースで展開した、制作中のアプリ体験に関する開発エピソードです!

ThanksDay2024_GIFTech_booth
ThanksDay2024_GIFTech_booth

GIFTechエンジニアは何をしているの?

私が現在取り組んでいるのは、生成AIを活用したアプリ開発です。このアプリは、英単語を入力することで、AIがそれに関連するイラストとストーリーを生成し、ユーザーが面白く生成AIを使って英単語を覚えられるコンテンツです。このコンテンツを通して、GIFTechが手掛けるハッカソンなどの次なるテーマやリファレンスとなるように取り組んでいます。

ThanksDay当日

ThanksDay当日は、家族を招待し、私たちが開発している技術やサービスを実際に体験してもらうことができました。予想以上に多くの方が興味を持ってブースに足を運んでくれたことは、とても励みになりました。特に印象的だったのは、生成AIが一般の方にとっても「こんなことができるんだ!」と新鮮なリアクションを与えるほどで、私たちがこのアプリを通して伝えたいことを体験してくれたことです。
AIによるイラストやストーリー生成の体験は、技術がどのように日常生活に結びつくのか、直感的に理解してもらえたのではないかと思います。また、「AIをもっとこう使えたら面白いんじゃないか」といったアイデアもいただき、プロジェクトの可能性がさらに広がるヒントにもなりました。

ThanksDay2024_GIFTech_app_experience
ThanksDay2024_GIFTech_アプリ体験様子

準備中、実は・・・

このイベントでより楽しんでもらえるように、アプリをThanksDay仕様に変更しました。

この作業中の出来事です。

イベントを迎える1週間ほど前から突然エラーが発生するようになりました。原因を辿ると、GPTちゃんが応えられないよ〜〜と嘆いていました。 今まではちゃんと応えてくれたのに、突然突き放してくるように。6回に1回は成功するかな....くらいの確率になっていました。

実際のレスポンス

ChatCompletion(
    id='[REDACTED]',
    choices=[
        Choice(
            finish_reason='stop', 
            index=0, 
            logprobs=None, 
            message=ChatCompletionMessage(
                content=None, 
                refusal="I'm sorry, I can't assist with that request.",
                role='assistant', 
                audio=None, 
                function_call=None, 
                tool_calls=None
            )
        )
    ], 
    created=[REDACTED], 
    model='gpt-4o-2024-08-06', 
    object='chat.completion', 
    service_tier=None, 
    system_fingerprint='[REDACTED]', 
    usage=CompletionUsage(
        completion_tokens=[REDACTED], 
        prompt_tokens=[REDACTED], 
        total_tokens=[REDACTED], 
        completion_tokens_details=CompletionTokensDetails(
            audio_tokens=None, 
            reasoning_tokens=0
        ), 
        prompt_tokens_details=PromptTokensDetails(
            audio_tokens=None, 
            cached_tokens=0
        )
    )
)


ここです↓
refusal="I'm sorry, I can't assist with that request." ええええんん、、、、、

このままではThanksDayで体験してもらうのにUXが悪すぎる、、、全然ダメです。。。

この原因を調べると、プロンプトが複雑すぎたり何らかの制約に引っかかっている可能性があるそうで、プロンプトをめちゃくちゃ調整したり、出力形式を変えてコードでフォーマットするようにしたり....かなり試行錯誤しました。

徹夜して、なんとか修正を繰り返し気づけばThanksDay当日。。。。

それでも3回に1回くらいの成功確率でした。
確率は上がったものの、ブースに来てくださったお子様やご家族に体験してもらうとやはりエラーも出る。。。
ログを確認すると、当日2時間のイベント中だけで38.1%の確率でエラーになっていました。

せっかく体験してくれているユーザーがいるのに、これを作った私が恥ずかしく、悔しくていたたまれなかったです。
上司にも、改修は試みたけれど結果論では失敗だと言われてその通りだと反省しました。。。。

その後....

イベント終了後、私はこの問題について諦めずに改善を続けました。
途方に暮れながらも、めげずにいたある日....
ふと、モデルのアップデートがあったことを思い出しました。

モデルは目的に合わせながらですが基本は最新にしていたいので、最新モデルに切り替える準備中でした。
当時使用していたモデルはgpt-4oです。最新モデルはgpt-4o-2024-08-06というモデルでした。
最新モデルの情報はメールでも追っていて、価格が安くなるよーという内容のアプデでした。また、gpt-4oは、10/2にgpt-4o-2024-08-06に自動で切り替わることも知っていました。(気づけ....)

まて、、、時期的にあやしいぞと。

ーーこれか・・・・これの可能性しかないだろう・・・。

調べて見ると、リクエストのパラメータが変更されていました。
原因は構造化出力の精度が上がって指示できるようになったことでした。 プロンプトでフォーマットを指示していたのですが、response_formatを指定できるようになったのでより正確に、より安定して使えるようになりました。

また、β版のモデルの時は、client.chat.completions.create()のメソッドではなく client.beta.chat.completions.parse()のメソッドを使用すると特定のフォーマットや構造化された応答が求められる場合に安定して使えるそうです。

今回沼ってしまったポイントとしては、リクエストが成功する時もあるのがかなり厄介で気づくまでに時間がかかってしまいました。

gpt-4oのリクエスト(構造化出力はプロンプトで指示している)

completion = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {
            "role": "user",
            "content": "Write a haiku about recursion in programming."
        }
    ]
)

print(completion.choices[0].message)



gpt-4o-2024-08-06のリクエスト(構造化出力をリクエストに含ませられる)

# format
class Step(BaseModel):
    a: str
    b: str

class Format(BaseModel):
    story: list[Step]

# request
completion = client.beta.chat.completions.parse(
            model="gpt-4o-2024-08-06",
            messages=[
                {"role": "system", "content": "You are a helpful assistant."},
                {"role": "user", "content": "Hello!"}
            ],
            response_format=Format,
        )

print(completion.choices[0].message.parsed)



この変更で、現在はエラーも解消され、問題なく動作しています!

また、リファレンスなども適宜アプデされているので、今後もモデルの変更時には特に気にかけてチェックしていきます。 そして技術的にできることを見つけて適応していきたいと思います!

社内への発信と今後の展望

今回のイベントは、私たち新規事業「GIFTech」の取り組みを社内外に知ってもらう素晴らしい機会となりました。社内メンバーだけでなく、そのご家族の方々にも私たちの挑戦を共有できたことは、プロジェクトの進行にも大きなモチベーションとなっています。エンジニアとして、技術の面白さや可能性を感じてもらえたことは非常に嬉しかったですし、今後のプロジェクトの成長につながる手応えを感じました。
エラーの悔しさを乗り越え、次回はさらに安定した体験を提供できるよう、引き続き改善と新しいチャレンジを重ねていきたいと思います。そして、今後も私たちのプロジェクトが社内外の多くの人々に役立つサービスとなることを目指して、頑張ります!
11月末にはターゲットユーザーへ展開する予定なので、多くの人に使ってもらえるよう心も開発も整備しておきます😌(緊張と楽しみでドキドキです)
今後も新たな発見や技術的な挑戦を楽しみつつ、成長していきたいです。

GIFTechについて知りたい方へ

公式サイト giftech.io

GIFTech2024春-ハッカソンイベントの開催概要 media.reazon.jp