はじめに
こんにちは、セーフィーのイマドです。
この記事はSafie Engineers' Blog! Advent Calendar 13日目の記事です。
セーフィーでは「映像から未来をつくる」というビジョンのもと、AIなどの技術をクラウドや映像と紐付けることでさまざまな業界の不を覆すソリューションを日々模索しています。
そんな折、画像生成AIのStable Diffusionや人間のように自然な対話ができるChatGPTなど、様々な技術がソーシャルメディア上で話題になってきました。実際に使ってみるとその完成度に衝撃を受けたという人も多いのではないでしょうか、私もその一人です。
これらの最新技術は別に雲の上の話ではなく、実は全ての人が少し手を伸ばせば届く距離にあるわけです。
そこである考えが浮かんできました。
世の中にある最新技術や既存の技術要素を部品に見立てて、レゴのように組み合わせることで業界や顧客の課題を解決できる価値を簡単に作れてしまうのではないか… そしてあわよくば、プログラミングとか面倒なことはAIにまかせてしまいたい…
今回はそんな夢みたいな話を現実にしてくれるかもしれない組み合わせを見つけたのでご紹介します。
それが「対話AIのChatGPTと、ローコードツールPipedreamの組み合わせ」です。 次章からそれぞれを解説していきます。
各種技術の紹介
OpenAI ChatGPT
だそうです
以下からChatGPTのお試しをすることが可能です。(要OpenAIアカウント) https://chat.openai.com/chat
こちらのChatGPT使い方総まとめを見てもらうとわかるように、質問への応答からコードの生成まで幅広くこなしてくれます。
この記事が公開される頃にはChat GPT系の記事が充実していると思われるので、詳しく知りたい方は他の記事も参照してみてください。
QiitaのChatGPT記事一覧 ちなみに、執筆当時(2022/12/06)まだChatGPTのAPIは公開されていません。現在インターネット上で見かけるChatGPTのAPIで〜してみた系の記事は、後述するGPT-3の言語モデル”text-davinci-003”の可能性があります。
今回このChatGPTには、私がこれから行うアプリケーション開発のアシスタントになってもらいます。
OpenAI API(GPT-3 text-davinci-003)
こちらはChatGPTと混同しがちですが、ChatGPTより前に開発された言語モデルです。
有料ですがAPIが公開されており使い勝手が良いので、今回は部品の一つとして使わせてもらいます。
Pipedream
Pipedreamとは、ひとことで言えば「Zapier上でAWS Lambdaが使えるワークフローツール」です。 簡潔なインターフェースでZapierのように様々なサービスと簡単に接続するだけでなく、AWS LambdaのようにJavascript/Python/Goといった言語(とbash)で直接処理を記述/実行が可能です。
WEB上でコーディングが完結する。
これが、Pipedreamの最大の特徴であり、ZapierやAWS Lambdaとの違いになります。
たとえば、Zapierでもモジュールを作成することでnpmパッケージを扱うことができますが、ローカルでCLIを叩きながらデプロイしなければなりません。それがなんとPipedreamではWEB上でnpmパッケージが扱えます。
Pythonでも科学計算用のライブラリをimport可能で、ちょっとした処理ならPipedreamだけで済みそうですね。
公式サイト https://pipedream.com/
執筆している現在、日本語で検索すると産業用システムに対するマルウェアの方が出てきてしまう状況なので、これを機に日本語の記事が増えてくれることを望みます。
価格
https://pipedream.com/docs/pricing/
Pipedreamでは、Developer Tierとして、個人利用であれば無料で月10,000回の呼び出しが実行できるようになっています。
この呼び出しとは、ワークフロー内のステップ数ではなくワークフローが呼び出された回数のことです。そのため、5つのステップで構築したワークフローを実行した場合、それを1回の呼び出しとしてカウントします。 無料枠では333回呼び出し/日までという制限もありますが、Zapierの無料枠は月100回までと比べるとなんて太っ腹…!(組織だと66呼び出し/日でした) お試しなら良いですが、止まってはいけない運用をするのであれば有料版を検討してくださいね。
また、PipedreamはOSSとして公開されているため、これを自分のサーバーにデプロイして使ってみるのも良いかと思います。 https://github.com/PipedreamHQ/pipedream
15分でAIチャットボットを作ってみる
背景
弊社のSlackチャンネルの一部では、プライベートな一面を引き出し社員同士の理解を深めるという名目のもと、Colloという奇天烈カラクリロボットがユーザーに質問を投稿しています。
ですがこのCollo、毎日仕事の時間に質問してくるのです。 質問される側にとってはたまったものではありません。そのため、最近はみんなColloの質問を無視しがちになっています。
本来であれば、聞く時間をお昼時にするとか、みんなが興味をもってくれそうな質問をするとか、もっと回答してもらいやすい方法を考えるべきです。
そこで、社員をもうひとり用意し、一人が仕事をしている間に代わりに回答してもらうことで回答率100%を目指すことにしました。
ざっくり構成を考えてみる
Pipedreamを使えば、以下のような構成で作成できそうです。Pipedreamでは、処理の単位をステップ。一連のステップの組み合わせをワークフローと呼んでいます。
では、次節から具体的に組み上げていきます。
STEP1:特定のチャンネルで特定の文字列を検知(Slack)
このステップでは、上のようなメンションを検知してワークフローが開始されるように、トリガーを設定していきます。
アプリからSlack→New Mention(Instant)を選択し、反応するチャンネルを指定。
アカウントの連携を済ませ、チャンネルを指定することで特定のチャネルへの投稿を検知することができるようになります。
ここでは、冒頭の「ねえねえ」をキーワードに指定しました。これで、「ねえねえ」を含むメッセージが指定されたチャンネル上で投稿されるとトリガーが発火されます。
ここで問題が発生しました。ignore botsをfalseにしても、なぜかColoの投稿だけ検知してくれません。他の機能ではちゃんとignore botsをfalseにしてもColoの投稿を検知してくれたので、バグかもしれません…。
→バグでした。フォーラムに投稿したところすぐに再現性のあるバグとしてIssueが建てられました。めっちゃ対応早い この記事が公開される頃には修正されているかもしれませんね。
しかたないので、今回は別のやり方で実装してみました。
- 「New Message in Channels(Instant)」で、特定のチャネルにきた投稿すべてを検知
- 「Filter」→「Continue based on Condition」を用い、検知されたメッセージのうち「ねえねえ」を含むものだけ次のステップに通す。
このやり方の欠点としては、すべての投稿に対してTriggerが実行されてしまうことで余計な呼び出しが発生してしまう点が挙げられます。
STEP2:文字列から必要な部分だけを取り出す(Function)
先程のステップで「ねえねえ」を含む投稿をトリガーにワークフローが実行されるようになりました。ここでもう一度、質問文を見てみましょう。
このうち1行目は要らないので削る必要がありますが、文字の処理はノーコードの範疇では難しそうですね。Pipedreamではプログラミング言語で直接処理を書くことができますが、面倒です。
ここは、AIに考えてもらいましょう。 いい感じのものが出てきました。 (今回は簡単な処理ですが、正規表現が必要なもっと複雑な処理でもChatGPTはよしなに生成してくれます。)
出力されたコードをPipedreamの様式に合うように少し改変します。ステップ名は”format_question”としました。
前のSlackのメンショントリガーステップからデータを取り出すために
steps.{{step_name}}.event.text
を指定しています。今回のstep_nameは”trigger"です。
export default defineComponent({ async run({ steps, $ }) { // 変数strに文字列を格納する var str = steps.trigger.event.text; // 改行コード(\n)で文字列を分割する var lines = str.split("\n"); // 2行目以降を抽出する var extracted = lines.slice(1); // 抽出した文字列を出力する return extracted.join("\n"); }, })
抽出した文字列をreturnで返すことで、次のステップから format_question.$return_value
で値を取り出すことができます。
このようにツールではカバーしきれない処理をAIに書かせるというのは、部分的にプログラムを記述できるローコードツールならではの使い方かもしれませんね。
STEP3:回答文を生成する
ここでは、OpenAIのAPI(text-gpt-003)に質問内容を渡して回答文を生成してもらいます。 ※回答文を生成するAIはChatGPTではなくtext-davinci-003という自然言語モデルになります。ChatGPTはAPIが公開されていないので仕方ありません。
Open AIアカウント設定
OpenAIのAPIを使うためには、アカウント登録と有料アカウントへの変更が必要になります。 https://beta.openai.com/account/billing/overview
「Setup Paid account」からカード情報を入力してください。 https://openai.com/api/pricing/
価格表にあるトークン(tokens)という単位ですが、入力プロンプトの文字数と出力された文字数を足し合わせた数がリクエストごとにカウントされ1,000トークンごとに所定の金額が課金されます。 今回質問に回答するのはDavinciという言語モデルなので、1,000トークン(文字)ごとに$0.02が必要になります。
APIキーの発行
以下のURLから、APIキーの発行が可能です https://beta.openai.com/account/api-keys
Pipedreamの環境変数にAPIキーを設定
Pipedreamでは、Enviroment Variablesから環境変数を設定することができます。 https://pipedream.com/settings/env-vars
「NEW ENVIROMENT VARIABLE」でキーを設置します。
今回は”OPENAI_APIKEY”という名前で環境変数を設定しました。
これで、ワークフローの中から{{process.env.OPENAI_APIKEY}}でキーを取り出す事ができるようになりました。
OpenAI APIへのリクエスト
それでは、OpenAIのGPT-3 text-davinci-003”に回答文を生成してもらいましょう。 OpenAIのエンドポイントは https://api.openai.com/v1/completions です。
シンプルに回答してもらうだけなら、以下のようなリクエストをOpenAIにPOSTするだけで良いです。
POST https://api.openai.com/v1/completions Header: Authorization:Bearer {{process.env.APIKEY}} Content-Type:application/json Body: { "model": "text-davinci-003", "prompt": {{ここにプロンプトが入ります。}}, "max_tokens": 1000 }
Bodyに指定しているパラメータの解説
model:今回使用するモデルを指定します。今回は現在公開されているAPIの中で一番高性能な”text-davinci-003”を指定して使います。 prompt:AIに入力するプロンプトになります。 max_tokens:回答に対する最大トークン数(≒文字数)を指定しています。text-davinci-003のmax_token数は4000なので、input/output合わせて4000を超えないように指定しましょう。
パラメータについては、OpenAI API(GPT-3) 入門 (1) - 事始め が詳しかったです。
これをPipedreamに反映させると以下のようになります。
実行結果はこちら これで、AIに回答文を生成してもらうことができましたね。
AIにキャラクターを付与する
GPT-3 text-davinci-003をそのまま使うと、当たり障りのない口調のキャラクターになってしまいます。 今回は質問された本人のように回答して欲しいので、弊社の従業員投票1位に輝いたことのある「とある社員」の偶像になってもらうことにしました。
今回利用したのはChatGPTとは違いますが、使い方は基本的には同じなはずなのでChatGPT使い方総まとめを参考にプロンプトを生成してみました。本人のSlack投稿などをかき集め、キャラクターを作り上げています。(この記事は本人に許可を頂いて作成しています。)
Pipedream上ではこのようになります
STEP4:回答をスレッドに投下する。
最後に、生成された回答文をSlackに返しましょう。
「Slack」→「Reply to a Message thread」を選択してステップを作成していきます。
入力している内容は以下です。
Bot Username:Slack上で表示されるボット名 Icon(emoji):ボットのアイコンを好きな絵文字にすることができます。今回は社員のアイコンを絵文字にしてから指定しました。 Thread Timestamp:親メッセージのタイムスタンプを指定します。今回のトリガーとなったメッセージのタイムスタンプを持ってきました。 Channel:親メッセージのあるチャネルを指定します。今回はトリガーとなったメッセージからチャネルを紐付けています。 Text:ここに投稿内容を記載します。今回は、OpenAI APIから返却されたテキストを挿入しています。 `steps.post_request_openai.$return_value.choices[0].text`
テスト/デプロイする
「Test」を押して、ちゃんと一連のワークフローが実行できるか試してみましょう。
ちゃんと意図したとおりに動きましたでしょうか。
さて、このままでは新しい投稿があってもワークフローが実行されませんので、右上のDeployボタンを押して、変更を反映させます。デプロイが完了することでワークフローが有効になり、次回から自動で返信されるようになります。
結果
見事、回答率100%を達成することができました。
用意しているプロンプトが「以下の質問に対して回答してください {質問文}」で終わるように作ってあるため、質問文が空になってしまったときはAIが勝手に質問文を生成して勝手に回答してくれています。意図していなかったのですが、これはこれで面白いですね。
おわりに
今回は、AIの力を借りながらPipedreamというワークフローツールで社員のように回答してくれるAIチャットボットを共同開発してみました。
ChatGPTのコード生成は素晴らしく、ちょっとした処理ならコーディングする必要もないくらいプロセスを簡潔化してくれました。まだプログラム全体を代わりに作成してもらうことは難しいかも知れないですが、ワークフローツールのようなステップ単位の処理やFaaS(Function as a Service)などではすぐに実用可能な技術なのではないでしょうか。回答生成で使用したtext-davinci-003もAPIとして気軽に利用でき、一時期話題になっていたドラマの登場人物っぽいチャットボットが簡単に作れるようになったのだと実感しています。
また、PipedreamはZapierよりも高度なことができるローコードツールという印象です。今回は簡単な処理しかしていませんが、Pythonを使った複雑な科学計算なども扱えることから様々なシーンに応用できそうです。
個人的には、ノーコードツールでは役不足なところをプログラミングにより補完できる幅をもたせたものがローコードツールだと思っていますが、プログラミングが必要ということは専門的知識が必要であり私のようなプログラマではない半端者には難しいところがありました。
しかし、ChatGPTのような文字生成AIが誕生したことでローコードツールの敷居は非常に低くなり、既製品として用意されていないモジュールを自分でも作れるようになりました。ローコードツールの特性としてもChatGPTとの組み合わせは非常に相性が良いように思います。
世の中には素晴らしい技術やサービスが点在しています。それらをレゴのように組み立てることで、プログラマではない私達にも様々なことが実現できるという可能性を感じていただけたのではないでしょうか。
セーフィーでは、業界の不に対し既存の技術を組み合わせ仮説検証を高速化し、誰よりも早く本質的な価値を創りあげていく仲間を幅広く募っています。一緒に映像から未来をつくる夢物語を現実にしていきませんか(カジュアル面談やってます。ぜひお話ししましょう)
ここまでお読みくださりありがとうございました。 最後にこの記事とプログラムを手伝って頂いたAIさんからひとこといただきましたので、こちらに掲載させていただきます。