前回「Generative AI (ChatGPT) × SpreadSheetで業務効率化/自動化」という記事を書きました。記事の中では、GenerativeAI全般とどのように付き合っていくか、その全体的な指針となるようなものを個人的な整理も兼ねてまとめました。
最近遅ればせながら、ChatGPT PlusでGPT-4を使い始め、コーディング能力の高さに感動したので、今回のブログではGPT-4を使って、プログラミングを効率化する方法を探って(まとめて)いきたいと思います。
趣旨としては以下になります。
- ChatGPT(GPT-4)になるべくコーディングを任せて、プロトタイプやサンプルプログラムを素早く作ることができるのではないか。
- 本実装までのリードタイムを短くすることができるのではないか。
- テストやリファクタリング、仕様書作成なども一部任せることができるのではないか
- 納品までのリードタイムも短くできるのではないか。
- もしくは、限られた時間の中で、お客様へのヒアリングや改善提案など(今の所)人間にしかできないインサイトが必要な事柄に時間を割くことができるようになるのではないか。それによって、より創造的な仕事ができるようになるのではないか。
- 上記を達成するために、適切なプロンプトエンジニアリングを行う方法を習得・開発することが必要ではないか。
今回のブログでは1を念頭において、3について調査やまとめた内容を公開します。また、それを踏まえて、実際にGoogle Apps Scriptを対象として、実用的なアプリケーションをChatGPT(GPT-4)になるべく任せる形で作っていく試みをします。
正直なところ、1についてはGitHub Copilot Xもリリースされていますし、いわずもがな、な部分はあるかもしれません。とはいえ、いったん今の所の状況整理の意味も兼ねて改めてまとめてみたいと思います。
目次
ChatGPTとプロンプトエンジニアリング
プロンプトエンジニアリングとは何か
今回、ChatGPT(GPT-4)にきちんと指示・命令を出すためにも、改めてプロンプトエンジニアリングについてまとめてみます。前回の「Generative AI (ChatGPT) × SpreadSheetで業務効率化/自動化」に「ChatGPTの使い方(プロンプトデザイン)」という部分でも一部まとめてがありますので、こちらも別途ご覧ください。
さて、プロンプトエンジニアリングとは、人工知能や機械学習の一分野で、コンピューターやAIに指示や質問を与える際に、どのように文章や情報を提示するかを工夫する技術のことを言います。これにより、コンピューターやAIがより効果的に理解し、正確で役立つ回答や結果を提供できるようになります。
例えば、学校で先生が「この数式を解いて」と言ったとき、生徒はどの数式を解けば良いかを理解する必要がありますね。プロンプトエンジニアリングも同様で、AIに与える情報や質問の仕方を工夫することで、AIが望ましい答えを導き出せるようになります。
Prompt Engineering Guide
プロンプトエンジニアリングに関して、良い教材を見つけました。Prompt Engineering Guideというサイトです。このサイトはDAIR.AIのプロジェクトで、Prompt Engineeringについて、研究者や実践者に教育することを目的としているそうです。有志で日本語訳が随時行われており、大変参考になりますので、ぜひアクセスしてみてみてください。以下では、個人的に気になった・有用に感じた部分を抜粋していきます。
まずは基本となるプロンプトの要素についてです。単に命令するだけでなく、文脈や入力データ、出力指示子をいれるとより正確な回答が得られやすいということですね。
プロンプトの要素
プロンプトには、以下のいずれかのコンポーネントが含まれることがあります。命令 - モデルに実行してほしい特定のタスクまたは命令
文脈 - 外部情報や追加の文脈が含まれる場合があり、モデルをより良い応答に導くことができます。
入力データ - 応答を見つけたい入力または質問
出力指示子 - 出力のタイプや形式を示します。
以下、区切りを入れたりするのは発想としてなかったので参考になります。
プロンプトをデザインする一般的なTips
指示はプロンプトの最初に配置し、指示と文脈を区切るために「###」のような明確な区切り記号を使用することが推奨されています。
例えば:
プロンプト:
### 指示 ### 以下のテキストをスペイン語に翻訳してください。 Text: "hello!"
出力:
¡Hola!
不正確さを避ける
詳細に記述したりフォーマットを改善したりする上記のようなヒントを考慮すると、プロンプトを巧みに操ろうとしたり、不正確な説明を作り出してしまったりするといった罠へ陥りやすくなります。具体的で直接的である方が良い結果が得られます。ここでの類似性は、効果的なコミュニケーションと非常に類似しています--直接的であるほど、効果的にメッセージが伝わります。
例えば、プロンプトエンジニアリングの概念を学びたいと思うかもしれません。
プロンプトエンジニアリングの概念を説明してください。説明は短く、数文で、あまり詳しくしないでください。
上記のプロンプトから、どのように文を数え、スタイルを指定するかは明確ではありません。上記のプロンプトでも、まだ良い回答を得ることができますが、非常に具体的かつ簡潔で、的を射たプロンプトの方が良いでしょう。以下のようなものです。
高校生に対して、プロンプトエンジニアリングの概念を2〜3文で説明してください。
以下はコード生成が事例として出されていたので引用をしてみました。SQLもいけるのは嬉しいですね。コード生成については、後述で様々なプロンプトのパターンを紹介します。
プロンプトの例
コード生成LLMは非常に効果的なコード生成のアプリケーションの一つです。Copilotはその素晴らしい例です。巧妙なプロンプトを使えば、多くのコード生成タスクを実行できます。以下にいくつか例を見てみましょう。
まず、ユーザーに挨拶する簡単なプログラムを試してみましょう。
プロンプト:
/*ユーザーに名前を聞いて、「こんにちは」と言ってください。*/
出力:
let name = prompt("あなたの名前は何ですか?");console.log(`こんにちは、${name}さん!`);
言語の指定さえ必要ありませんでした。
次に、もう少しプロンプトの設計に努力を加えることで、LLMがどれほど強力であるかを示したいと思います。
プロンプト:
"""テーブル名 departments、カラム=[DepartmentId、DepartmentName]テーブル名 students、カラム=[DepartmentId、StudentId、StudentName]コンピュータサイエンス学科のすべての学生のためのMySQLクエリを作成してください。"""
出力:
SELECT StudentId、StudentNameFROM studentsWHERE DepartmentId IN (SELECT DepartmentId FROM departments WHERE DepartmentName = 'Computer Science');
これは非常に印象的です。この場合、データベースのスキーマに関するデータを提供し、有効なMySQLクエリを生成するように求めました。
以下は、日経Web版でも紹介されていた「ステップバイステップで考えてみましょう」といれると性能が上がるというやつですね。(参考:ChatGPTを賢くする呪文)日本語の場合、下記のような方法でもまとめていくことができます。ChatGPTと会話を続けていると、回答に満足できない(意図した出力結果とは異なる)場合や、そもそもの思考過程が異なっているのではないかと思うような結果に出くわします。以下のように情報の訂正や削除を依頼すると、望んだ回答に近づけます。
- (コード作成を依頼して出力された結果の一部の訂正を依頼したい場合など)XXXとXXXの部分に私の期待する結果とは異なる部分があります。XXX(求める結果を指定する)のようにコードを修正してください。このとき、XXXという条件も考慮してください。
- (出力された結果/依頼内容に対して)一歩(ステップバイステップで)ずつ考えてください。
- (出力された結果/依頼内容に対して)論理的に考えてください
- (出力された結果/依頼内容に対して)この問題を段階を分けて解いてください
Chain-of-Thoughtプロンプティング
より最近提唱されたアイデアの1つは、zero-shot CoT(opens in a new tab) (Kojima et al. 2022)のアイデアです。これは、元のプロンプトに「ステップバイステップで考えてみましょう」という文言を追加することを含みます。単純な問題を試して、モデルがどのように機能するかを見てみましょう。
プロンプト:
私は市場に行って10個のリンゴを買いました。隣人に2つ、修理工に2つ渡しました。それから5つのリンゴを買って1つ食べました。残りは何個ですか?
出力:
11個のリンゴ
答えは不正解です!それでは、特別なプロンプトで試してみましょう。
プロンプト:
私は市場に行って10個のリンゴを買いました。隣人に2つ、修理工に2つ渡しました。それから5つのリンゴを買って1つ食べました。残りは何個ですか?ステップバイステップで考えてみましょう。
出力:
最初に、10個のリンゴから始めました。隣人と修理工に合わせて、リンゴを2つずつ渡し、残りは6個になりました。次に、5つのリンゴを買い、11個になりました。最後に、1つのリンゴを食べたため、残りは10個になります。
この単純なプロンプトがこのタスクで効果的であることは驚くべきことです。これは、プロンプトに使用できる例があまりない場合に特に有用です。
以下は日本語訳がなく英語のままですが、コード生成に関する内容でしたので引用しておきます。仕様書とはまた違いますが、順序立てて要求仕様/仕様/コーディング時のコメントのようなノリで書いてあげることでコード生成できるということでしょう。ただ、引用の中にもあるように、importがなかったり出力された結果を単にコピペするだけでは動作しない場合がある点には注意が必要ですね。なので、やはりこのあたりは人間が補完することになると思います。
Generating Code
Turn Comments Into Code
You can also use the code generation capabilities of these LLMs to generate code from comments alone. Let's look at another example that passes the instructions as a comment block:
Prompt:
"""1. Create a list of movies2. Create a list of ratings for these movies3. Combine them to make a json object of 10 movies with their ratings."""
Output:
movies = ["The Shawshank Redemption", "The Godfather", "The Dark Knight", "Schindler's List", "Pulp Fiction", "The Lord of the Rings: The Return of the King", "Forrest Gump", "Star Wars: Episode V - The Empire Strikes Back", "Inception", "The Silence of the Lambs"] ratings = [9.3, 9.2, 9.0, 8.9, 8.9, 8.9, 8.8, 8.7, 8.7, 8.6] movie_ratings = {} for i in range(len(movies)): movie_ratings[movies[i]] = ratings[i] json_object = json.dumps(movie_ratings, indent=4) print(json_object)
The generated code looks like working code. However, the output doesn't contain an important
import
statement, i.e.,import json
. While these models generate working code, you must pay close attention to small details like this and always make sure to test your code.
コード生成の具体的なプロンプトについては、次の段落で紹介します。実際に筆者がやってみた感想として、最初は指示を与えてコードをバリバリ書いてくれるので面白いのですが、そのうち細かい調整を人間側がやるばかりになり、ChatGPTに働いてもらうというよりはChatGPTに働かされているような感覚になるシーンもありました(笑)。このあたりのAIと人間の関係性などについては今回のブログの趣旨ではありませんので、詳しくは突っ込みませんが、体験としては中々面白く感じている次第です。
コード生成に関するプロンプトの解説記事
Chat GPT For Programming: 100+ Coding Prompts For Chat GPT
英語の記事ですが、コード生成のためのプロンプトが100個以上まとまっているのが上記のブログです。正直なことを言うと、これらのプロンプトを筆者は全て試したわけではありません(というか、ほとんどまだ試していません)。
また、原文は英語ですので、日本語にした場合、きちんと動作するのか?という点については調査が必要です。ですが、単にコードを生成するだけではなく、コード補完やバグ検知、コードレビューなどコーディングに関わる様々な部分で利用できる、という点については学ぶべき点が多いと思いましたので紹介します。ラバーダック法のスゴイ版と思って、ちょっと手が止まったらとりあえず投げてみて、問題解決を促すみたいな意味合いで使うのも全然アリだと思います。
コード生成:コードの完成:
- [ファイルフォーマット]を解析し、[情報]を抽出する[言語]スクリプトを作成し、以下の要件を満たしてください : [要件リスト]。
- [デザインパターン]に従い、[操作リスト]のエンドポイントを含む[ドメイン]の[言語]マイクロサービスを開発してください。。
- [入力変数]に基づいて[条件]で[data structure]をフィルタリングする[言語]の関数を記述し、[出力説明]を行ってください。
- [戦略または技術]を使用して[問題]を解決する[言語]アルゴリズムを設計してください。
- [入力変数]と予想される出力:[出力説明]を使用して、[タスク]を非同期に処理する[言語]関数を実装してください。
バグ検出:
- [言語]コードを完了して、[ファイルフォーマット]を解析し、[情報]を抽出してください:[コードスニペット]。
- [デザインパターン]の[使用例]の[言語]実装を完成させてください:[コードスニペット]。
- 次の機能にキャッシュメカニズムを実装するために不足している[言語]コードを埋めてください:[コードスニペット]。
- [データ構造]を[出力形式]に変換する[言語]コードを完了してください。:[コードスニペット]。
- [問題]のマルチスレッドソリューションの[言語]実装を完成させてください:[コードスニペット]。
コードレビュー:
- 次の[言語]コードの論理エラーを特定してください:[コードスニペット]。
- 与えられた[言語]コードの潜在的なパフォーマンスの問題を特定してください:[コードスニペット]。
- 次の[言語]コードにリソースリークがある場合は、修正を提案してください:[コードスニペット]。
- 次の[言語]コードに潜在的なデッドロックの問題がないかどうかを確認してください:[コードスニペット]。
- 次の[言語]コードが[プラットフォームまたは技術]と互換性があるかどうかを評価してください:[コードスニペット]。
- [コードスニペット]を分析して、コードのスメルをチェックし、改善提案を行ってください。
- [コードスニペット]を確認して、適切なログ記録とモニタリングのプラクティスを行っているかどうかを確認してください。
- [コードスニペット]を確認して、スケーラビリティの問題がないかどうかを確認してください。
- [コードスニペット]のテストカバレッジを評価してください。
- [コードスニペット]を[プラットフォームまたは技術]との互換性について評価してください。
以下の引用は上記の原文です。
Generate code:
Code completion:
- Create a [language] script to parse [file format] and extract [information] with the following requirements: [requirements list].
- Develop a [language] microservice for [domain] that includes endpoints for [operations list] and adheres to [design pattern].
- Write a [language] function to filter [data structure] based on [condition] with the following inputs: [input variables] and expected output: [output description].
- Design a [language] algorithm to solve [problem] using [strategy or technique].
- Implement a [language] function that handles [task] asynchronously with the following inputs: [input variables] and expected output: [output description].
Bug detection:
- Complete the [language] code to parse [file format] and extract [information]: [code snippet].
- Finish the [language] implementation of [design pattern] for [use case]: [code snippet].
- Fill in the missing [language] code to implement a caching mechanism for the following function: [code snippet].
- Complete the [language] code to convert [data structure] into [output format]: [code snippet].
- Finish the [language] implementation of a multithreading solution for [problem]: [code snippet].
Code review:
- Locate any logic errors in the following [language] code snippet: [code snippet].
- Identify potential performance issues in the given [language] code: [code snippet].
- Find any resource leaks in the following [language] code and suggest fixes: [code snippet].
- Check for potential deadlock issues in the given [language] code: [code snippet].
- Review the following [language] code for potential SQL injection vulnerabilities: [code snippet].
- Analyze the given [language] code for code smells and suggest improvements: [code snippet].
- Check the following [language] code for proper logging and monitoring practices: [code snippet].
- Review the given [language] code for potential scalability issues: [code snippet].
- Assess the test coverage of the following [language] code: [code snippet].
- Evaluate the given [language] code for compatibility with [platform or technology]: [code snippet].
「ChatGPT」を使用してコードを記述–プロンプト作成のヒントと注意点
こちらの記事は共感度が高かったので引用しました。さすがにプロンプトを一回投げて全て終わり、のようにはうまくいかないですし、本当にこの処理は問題ないのか?というのは現時点でのGPTの性能では人間がチェックしないと厳しい部分があるのが実際です。以下の引用のようなスタンスで使っていくのが今の所は良いのではないでしょうか。余談ですが、筆者は学生時代に一度プログラミングを挫折しています。当時は素のテキストエディタやコンソールにコードを書いて、、、みたいな時代でエラーがでても何が何やらサッパリわからない、みたいな状況だったのを思い出します。その後だいぶ時間が経過し、VSCodeのコード補完に感動し、これなら少し自分でもできるかも?と思い始めて、プログラミング/コーディングを再開したみたいな経緯があります。そうした観点からも、CenerativeAIの進化のおかげでプログラミングをする敷居はだいぶ下がったなぁと感じますね。
ChatGPTが処理に成功して、うまくやってのけるのは、コーディングをすでに理解している人が特定のルーチンを構築して特定のタスクを完了できるように支援することだ。メニューバーで動作するアプリを求めてはならない。だが、メニューバーにメニューを配置するルーチンを頼んで、その出力をプロジェクトに貼り付けると、非常にうまくいくだろう。
ChatGPTを使用して、手法の実演、小規模なアルゴリズムの作成、サブルーチンの記述をしてみよう。さらには、大規模なプロジェクトを複数のチャンクに分割するのを手助けしてもらい、それらのチャンクのコーディングを手伝ってほしいと頼むことも可能だ。
英語について
OpenAIの公式サイトにGPT-4(やその他のエンジン)と各言語の性能比較が掲載されています。
GPT-4 3-shot accuracy on MMLU across languages という項目を参照ください。結論的には(当然ながら)日本語より英語のほうが5.6%ほど正確なようです。といっても、この5.6%の差がどの程度なのかは実感としてわからないところではあるのですが、もし英語を使えるのであれば英語でChatGPTを使用した方がよいということになるでしょう。
残念ながら、筆者の場合は、例えば英語を使ってコード生成などの文脈でChatGPTを使えるほどの英語力があるかと言われれば、かなりダウトです。おそらく結果的にトータルでは日本語の方が、品質が高いものができるのではないかと思います。とはいえ、今後折をみて英語を使って可能な限り英語化についてもチャレンジしてみたいと思います。
ChatGPTでGASのコーディングを行う
ここでは、実際にChatGPT(GPT-4)でGoogle Apps Scriptのコーディングを行ってみた事例を紹介してみたいと思います。
ChatGPTでコード生成:Googleフォーム回答者に回答スプレッドシートの閲覧権限を付与する
今回は、Googleフォームでアンケート回収を行い、その回答者に対して回答用のスプレッドシートを共有する、というシーンを想定して作ってみます。Googleフォームに回答をしても、全体の回答は回答者は見ることができないので、閲覧権限付与を自動化しよう、というシーンですね。これをフルスクラッチで開発してもらおうと思います。
なお、前提でGoogleフォームではメールアドレスの収集を必須としておきます。
ChatGPTにコーディングの依頼をする
さっそくですが、以下のような内容でコード生成の依頼をしてみます。とりあえず手元にonSubmitがあったのでコードスニペットを適当に貼り付けました。また、Googleフォームの回答スプレッドシートも参考までにシートをそのままコピペしました。
ChatGPTがコードを生成する
関数名は違いますが、とりあえず結果が返ってきました。なので、素直にこの内容をGoogle Apps Scriptのスクリプトエディターにコピペします。
ChatGPTとエラーを解消していく①
上記画像では切れてますが、setupTriggerを予め実行せよとのChatGPTからの指示がありましたので、実行してみるとエラーが発生しました。
というわけで、エラーの解消についてChatGPTに聞いてみます。
ChatGPTとエラーを解消していく②
で実際にこのsetupTriggerを試したりしてもうまくいかないので、筆者がもっている知識として手動でスクリプトエディタのGUIからトリガーを設定しました。(このあたりがChatGPT任せには中々できない、もしくは筆者のプロンプトエンジニアリングの力量不足でうまく行かない部分とも言えるでしょう)
トリガーが設定できたので、Googleフォームで回答してみると、onFromSubmit()でエラーがでるのでこれもChatGPTに聞いてみました。
ChatGPTとエラーを解消していく③
先ほどのエラーは解消されましたが、次のエラーが発生します。ここも特に何も考えずにとりあえず聞いてみます。
ChatGPTにコード生成をほぼほぼ任せられた
上記のコードをコピペするとうまく動きました!というわけで、いったんこれで内容としては完成です。
ちなみにコメントの日本語化もこのあとお願いしました。
ChatGPTでコード修正:ファイル・フォルダの一覧取得(サブフォルダ含む)
次に、他人が作ったコードの修正をChatGPTに依頼してみます。お題としては、Googleドライブ内の特定のフォルダIDを指定して、ファイルおよびフォルダの一覧を取得するというものです。
ステップとしては、①自分の理解のためにコードにコメントを書いてもらう、②既存のコードではGoogleスプレッドシートに記録するファイル名にリンクがないので、リンク挿入してもらうようにコードの修正依頼をかける、という2ステップを踏むことにしました。
既存のファイル・フォルダ一覧の仕組み
スプレッドシートのB1にフォルダID、B2にファイル・フォルダ一覧の記録を行う(新しく作成する)シート名を記入します。
スクリプトエディタで実行すると、ご覧のようにファイルIDやURL、ファイル階層およびファイル名を記録してくれます。このままでも十分使えるのですが、個人的な好みでファイル名にリンク挿入までしてほしいなと。リンク挿入は以前に試そうとして、すんなりいかなかった記憶があるので。この部分をChatGPTに実装してもらいます。
ChatGPTにコードにコメントを書いてもらう
元々のスクリプトは他の方が作ったものなのですが、コメントが部分的にしかなかったため、コメントを書いてもらうことにしました。
以下は出力結果の一部ですが、丁寧に一行一行コメントを記載してくれています。ある程度処理のまとまりでコメントしてもうのでも良かったのですが、これはこれで理解促進のためにはよいのかもしれません。
ChatGPTにコードを修正してもらう
さて、次に実際にコードを修正してもらいます。
setValuesメソッドでもHYPERLINK関数を指定してあげればリンク設定はできるのですが、ひとまずChatGPTの提案に従って、setRichTextValuesを使う方針で今回は実装を進めてみることにします。最終的に出力されたコードをコピペでスクリプトエディタに反映して実行をしてみたところ、エラーが発生しました。
ChatGPTとエラーを解消していく①
エラー修正の提案を依頼していきます。
ChatGPTとエラーを解消していく②
再びエラーになるので、修正依頼をかけます。
修正内容を確認し、スクリプトエディタにコードを反映します。
ChatGPTに微調整を依頼する
エラーは解消されたのですが、元々のコードと出力結果が見た目変わっていませんでした(笑)
うまくファイル名にurlのリンク挿入をしたいという意図が伝わってなかったようです。そのため、再度依頼をしました。
出力された結果を確認します。
コードを確認し、スクリプトエディタに貼り付けて実行します。
見事にファイル名にURLリンク挿入が反映されました!ここまでおおよそ30分くらいでしょうか。もらったコードをほぼ読むことなく(ChatGPTに依頼をかけながら自分も理解していく感じ)、狙い通りのものが作れたという感じです。
お得なメルマガ特典のお知らせ
今なら、以下のメルマガ登録を頂ければメルマガ特典として、上記で紹介した「ChatGPTでGoogleフォーム回答者に回答スプレッドシートの閲覧権限を付与する」で作成したファイルをファイルをシェアいたします!