1. トップ
  2. 新着ニュース
  3. IT
  4. IT総合

生成AIはプログラミングに何をもたらすのか?

ASCII.jp / 2023年6月21日 9時0分

アルゴリズムよさようなら

 まずは、以下のビデオを見ていただきたい。

 私が、まだプログラマになりたての頃、IBMの大型機の端末にこんな具合で大きく時間を表示している人がいた。HP95LXという1991年に発売された超小型パソコンの表計算ソフトで、やっぱりこんな感じで時計を表示するサンプルマクロもあった。

 仕事の道具を、ちょっとだけ遊び心をもって違うことに使ってみるのは楽しい。そんな気分で、エクセルでもこんな時計表示をやってみたいと思っていたのだが、そのままになっていた。それが、ChatGPTに頼んでみるとスルスルとVBAのコードが出てきて、30分ほどでちゃんと動くものになっていた。

 VBAの達人の方々ならともかく、私のようにふだんVBAに親しんでいない人間としては画期的なことである。しかも、ふだんのプログラミングとは比べようもなくラクである。

 生成AIによって、プログラミングの世界が大きく変化することになると思う。前回の「ChatGPTでプログラミングのフラット化がはじまっている」に続いて、ChatGPTでコードを生成して動かす。今回は、その基本テクニックを紹介したいと思う。

どう動かすかではなく何を作りたいかを伝える

 私が、このVBAを書いてもらうためにChatGPTに与えたプロンプトは次のようなものである。

EXCELのVBAで時計を表示するコードを書いてください。

「時」と「分」と「秒」を表現する数字は、16行×3列のセルを黒で塗ることで表現します。

数字の「2」は、以下のパターンで「1」に相当するセルは塗る、空白は塗らないで表現します。 11   1   1   1   1   1   1   1 11 1 1 1 1 1 1 111 時、分、秒の間に「:」を16行×1列で次のパターンで表現します。1が塗り、空白は塗らない。 1 1 1 1 各数字や「:」の間は1列空いているものとします。 1分に1回時間を更新してください。

 ChatGPTによるコードの生成は、まだ始まって数カ月の発展段階にある。プログラミングは、この業界にとっては飯のタネの根幹をなすものなので、みんなやっていたとしても黙ってノウハウを蓄積しているのかもしれない。あるいは、コード生成できるのは知ってはいても、いままでゴリゴリ書いてきたスタイルを維持するほうが安全と考えているのかもしれない。

 コード生成のための《プロンプトエンジニアリング》というものがあるわけだが、いわば、《プロンプトプログラミング》というような確立されたジャンルになると思う。それは、いま見えている範囲で書き出すと、次のような特徴がある。

1)手順やアルゴリズムで書くのではなく問題を表現する 2)人に伝えるように例示を使って説明する 3)参考になるコードがあればそれを与えて理解を促す 4)対話的(段階的)にすすめる

 もちろん、手順やプロセス、あるいはアルゴリズムをChatGPTに伝えることもできる。そのほうが有効な場合はそうするとよいだろう。しかし、ChatGPTプログラミングでは、「こんなものが作りたい」と問題を定義するように伝えるのがよい。

 理由ははっきりしていて、そのほうが人間もラクだし誤解がないからだ。3つの数字を並べ変えるとき「大きい順に並べる」と書くほうが、並べ変える手順を伝えるより間違いがないのは明らかだ。いわば《静的》なプログラミングができる。これが、プロンプトプログラミングの最大のメリットだと思う。

 IFやWHILEや変数の組み合わせによるアルゴリズムがこんがらがってバグになる。私ば、7年ほど「全国小中学生プログラミング大会」に関わってきたが、子どもたちの「プログラムが動かなくて苦労した」とか「何度も投げ出したいと思った」といった声を聴くたびに、心が痛むのだった。

 そのいまいましい世界から人々が救い出されるというだけでも、《静的》なプログラミングには意味がある。ちょうど、作りたいプログラムの概念をリングノートに鉛筆でスケッチするような、絵のような《静的》さかげんだ。

 すべてを《ことば》だけで説明するとしたらそのための《言語力》のほうがよほど大変では? という意見もありそうだが、次の《例示》と《コードを与える》で解決することも多い。

《例》を示してやる――まさにプロンプト的な

 次に、いかにもChatGPTプログラミング的といえるのが、《例示》を積極的に使うことだ。これは、OpenAIも言っていることでプロンプトエンジニアリングの基本の1つである。今回の例では、数字の「2」を表示する例をあげて、ほかもこんな調子でやってねと伝えている部分である。

 ちなみに、私は「2」の例をプロンプトで与えたのだが、ChatGPTが書きだしたコードでは「0」が生成されていた。ほかの数字については自分で書いてねときたのだが、頼めばすべての数字を生成してくれそうである(今回は、1、3~9のフォントは自分でコードに書き加えたのだが)。

ChatGPTはプログラムのコードもむしゃむしゃと食べているらしい

 ChatGPTには、人間の言葉だけでなくコードを与えてしまうことは、すでに裏技的に行われていたことだ。彼らは、プログラムのコードも学習していて与えたコードを理解することができる。その例として、さきほどのVBAにタイマー機能を追加することをこの手法でやってみることにする。

 パソコンの画面に時分秒が大きく出るならば、ハッカソンなどのイベントで、ハックタイムなどの終了までの時間を表示するやつを作ってみたくなる。同じセッションで続けて、タイマーを追加してほしいとプロンプトを与えてもよいのだが、新たなセッション(画面左上から「+ New Chat」を選ぶ)でもよい。私がChatGPTに与えたプロンプトは、次のようなものだった。

以下のコードでエクセルのVBAとして時計が動いています。 これを改造して時刻とタイマーが表示されるVBAにしてください。 A1のセルにタイマーのタイムアップ時刻を15:30(午後3時30分のとき)のように与えます。 タイマーは、タイムアップまでの残り時間を赤い色で塗って表示。 秒ごとに更新。 タイマーの時、分、秒は、時刻と同じデザインで時刻の下に1行の間隔をあけて表示。 -------------------------- Option Explicit Dim StopFlag As Boolean Sub DisplayClock()       Dim CurrentTime As Date       Dim CurrentHour As Integer : : ※前述の時計表示のVBAのコードを貼りつけてある。

 正直なところ、これは出てきたコードを実行してもすぐには動かなかった。タイマーの値が正しく表示されなかったり、24時をまたぐ場合の処理が適切でなかったり。何回かのやりとりのあと、最終的にコードを見直して指示を与えることもして、ようやく動かすことができた。「タイマーとは」と丁寧に説明すべきところだった(前回記事の「空き時間とは」参照)。

 このやり方の変形として、複雑なプログラムを作りたいときに、「このプログラムから呼び出されることを想定して関数のコードを書いてください」ということもできる。

 ChatGPTが、コードを理解しているように見えるというのは凄いことだ。プロンプトではすべてを言葉で表現しなければならないという限界をあっさりと超えてしまうからだ。これは、かつて第四世代言語などといわれた時代のコードジェネレーターとは隔世の感がある。

 こうしてできたエクセルのVBAで動く時計&タイマーを、以下に示す。A1のセルにタイムアップの時間を入力して実行。A1が空のときはただの時計となる。

プログラミングは《対話》によって行われることになった

 プログラムの複雑さが増すにしたがってプロンプトも長くややこしいものとなり、ChatGPTとの間にも誤解が生じがちだ。そこで、OpenAIのテクニカルレポートにも書かれていることだが《few-shot prompt》という技を使う。つまり、いちどに完成形のコードを求めるのではなく、段階的に理解をうながしながら作り上げる。

 同じくテクニカルレポートに出てくる「幻覚」(ハルシネーション=でっちあげ)は、コード生成でも出てくる。これは、単なるコーディングミス(関数と変数、型の定義の間違いなど)やゴールに対する誤解によって生ずるように見える。

 前回記事でも書いたとおり実行時に出たエラーをそのままChatGPTに返してやって修正してもらうことができる。もちろん、間違っている点が明確であれば「〇〇ではなく××です」と指摘すればよい。そうやって、段階ごとに動きコードを導いて、次の段階に進めていくわけだ。

 こうなると本当に、ChatGPTと一緒にプログラムを書いている気分になってくる。

エラーを伝えるとお詫びとともに修正内容とコードをすぐに返してくる。こんないい同僚のいるプログラマは幸せだと思う。

 なお、ここで「OpenAIのテクニカルレポート」と呼んでいるのは、3月27日に発表された"GPT-4 Technical Report"のことである。内容は多岐にわたっており、ChatGPTで何かをしようという人は一度は目を通しておくべき内容である。これについては、2017年頃から深層学習のセミナーをご一緒させていただいた丸山不二夫さんによる「GPT-4 Technical Report を読む」が参考になる。

プロンプトプログラミングの良い点、気になる点

 プロンプトプログラミングについて、以下のようにまとめてみた。

プロンプトプログラミングの良い点

1)時間がかからない(書いてもらえる) 2)解説付き、コメント付きでコードが出てくるので、学びになる 3)テストデータを生成もできる 4)コードの品質の属人的なバラつきをなくすことができるかもしれない

 一方、まだ課題も多いのでその点もまとめておく。

プロンプトプログラミングのダメなところ

1)プロンプトのノウハウが発展段階 2)大規模開発の手法が確立されていない 3)対話を続けると混乱に陥ることがある 4)検証しないとバグの温床になる(ただの生成ツールと考えよ)

 前回記事でも指摘したように、やりとりを繰り返しているとChatGPTが混乱状態に陥ることがある。その場合には、同じセッションでは使えるようなコードには到達できないので、新たにセッションを始めたほうがよい。

 最後の「検証しないとバグの温床になる」は、前向きにとらえれば、まだ人間のやることが残っているという意味でもある。ChatGPTは、あくまでプログラマがラクするための道具であって、その生成されたコードを人間が管理しながら使うというのが、まともなシステム開発では適切な付き合い方なのだろう。

 ということで、なにぶん発展段階にあるChatGPTによるコード生成のお話なので、決定的な誤解もあるかもしれない。最後に、今回生成したエクセルで時計を表示するVBAのコード、タイマー付きバージョンを以下に紹介しておく。

 VBAの実行方法については、すぐにできるので各自調べていただきたい。A1のセルに「15:20」などと入れて実行するとその時間までのタイマーも表示される。終了は、Ctrl-Breakやウィンドウを閉じる、タスクの終了などで行う。

Option Explicit Dim StopFlag As Boolean Dim TimerFlag As Boolean Dim Pattern_num(0 To 9) As String Dim Pattern As String Dim TargetTime As Date Dim i As Integer Dim j As Integer Sub DisplayClockAndTimer()       Dim CurrentTime As Date       Dim CurrentHour As Integer       Dim CurrentMinute As Integer       Dim CurrentSecond As Integer       Dim RemainingTime As Date       Dim RemainingHour As Integer       Dim RemainingMinute As Integer       Dim RemainingSecond As Integer       ' Initialize StopFlag       StopFlag = False       ' Initialize TimerFlag       TimerFlag = True       If Range("A1").Value = "" Then               TimerFlag = False       Else               ' Get target time from A1               TargetTime = Range("A1").Value + Date               If TargetTime <= Now Then                       TargetTime = DateAdd("d", 1, TargetTime)               End If       End If       ' Clear cells       Range("A1:AA35").Interior.Color = RGB(255, 255, 255)       ' Set Column Widths and Height       Range("A:AA").EntireColumn.ColumnWidth = 6       Range("1:35").EntireRow.RowHeight = 16       Do While Not StopFlag               ' Get current time               CurrentTime = Now               CurrentHour = Hour(CurrentTime)               CurrentMinute = Minute(CurrentTime)               CurrentSecond = Second(CurrentTime)               ' Display current time (Black)               DisplayNumber Range("A1"), CurrentHour \ 10, False               DisplayNumber Range("E1"), CurrentHour Mod 10, False               DisplayColon Range("I1"), False               DisplayNumber Range("K1"), CurrentMinute \ 10, False               DisplayNumber Range("O1"), CurrentMinute Mod 10, False               DisplayColon Range("S1"), False               DisplayNumber Range("U1"), CurrentSecond \ 10, False               DisplayNumber Range("Y1"), CurrentSecond Mod 10, False               If TimerFlag = True Then                       ' Calculate remaining time                       If TargetTime >= CurrentTime Then                             RemainingTime = TargetTime - CurrentTime                             RemainingHour = Hour(RemainingTime)                             RemainingMinute = Minute(RemainingTime)                             RemainingSecond = Second(RemainingTime)                     Else                             RemainingTime = 0                             RemainingHour = 0                             RemainingMinute = 0                             RemainingSecond = 0                     End If                       ' Display remaining time (Red)                       DisplayNumber Range("A19"), RemainingHour \ 10, True                       DisplayNumber Range("E19"), RemainingHour Mod 10, True                       DisplayColon Range("I19"), True                       DisplayNumber Range("K19"), RemainingMinute \ 10, True                       DisplayNumber Range("O19"), RemainingMinute Mod 10, True                       DisplayColon Range("S19"), True                       DisplayNumber Range("U19"), RemainingSecond \ 10, True                       DisplayNumber Range("Y19"), RemainingSecond Mod 10, True               End If               ' Wait 1 second               WaitSecond               ' Allow other events               DoEvents       Loop End Sub Sub StopTimer()       ' Set StopFlag to true to stop the timer       StopFlag = True End Sub Sub DisplayNumber(TopLeftCell As Range, Number As Integer, IsTimer As Boolean)       ' Define patterns for numbers       Pattern_num(0) = "111" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "111"       Pattern_num(1) = "11 "& _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         "111"       Pattern_num(2) = "11 " & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "111"       Pattern_num(3) = "111" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         "11 " & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         "111"       Pattern_num(4) = "1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "1 1" & _                         "1 1" & _                         "111" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1"       Pattern_num(5) = "111" & _                         "1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "111" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         "11 "       Pattern_num(6) = " 11" & _                         "1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "1 " & _                         "111" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "111"       Pattern_num(7) = "111" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 " & _                         " 1 "       Pattern_num(8) = "111" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         " 1 " & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "111"       Pattern_num(9) = "111" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "1 1" & _                         "111" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         " 1" & _                         "11 "       ' Display number       For i = 1 To 16               For j = 1 To 3                       If Mid(Pattern_num(Number), (i - 1) * 3 + j, 1) = "1" Then                               If IsTimer Then                                       TopLeftCell.Offset(i - 1, j - 1).Interior.Color = RGB(255, 0, 0)                               Else                                       TopLeftCell.Offset(i - 1, j - 1).Interior.Color = RGB(0, 0, 0)                               End If                       Else                               TopLeftCell.Offset(i - 1, j - 1).Interior.Color = RGB(255, 255, 255)                       End If               Next j       Next i End Sub Sub DisplayColon(TopLeftCell As Range, IsTimer As Boolean)       ' Define patterns for colon       Pattern = " " & _                           " " & _                           " " & _                           " " & _                           "1" & _                           "1" & _                           " " & _                           " " & _                           " " & _                           "1" & _                           "1" & _                           " " & _                           " " & _                           " " & _                           " " & _                           " "       ' Display colon       For i = 1 To 16               For j = 1 To 1                       If Mid(Pattern, (i - 1) * 1 + j, 1) = "1" Then                               If IsTimer Then                                       TopLeftCell.Offset(i - 1, j - 1).Interior.Color = RGB(255, 0, 0)                               Else                                       TopLeftCell.Offset(i - 1, j - 1).Interior.Color = RGB(0, 0, 0)                               End If                       Else                               TopLeftCell.Offset(i - 1, j - 1).Interior.Color = RGB(255, 255, 255)                       End If               Next j       Next i End Sub Sub WaitSecond()       ' Wait for 1 second       Application.Wait (Now + TimeValue("0:00:01")) End Sub  

遠藤諭(えんどうさとし)

 株式会社角川アスキー総合研究所 主席研究員。MITテクノロジーレビュー日本版 アドバイザー。プログラマを経て1985年に株式会社アスキー入社。月刊アスキー編集長、株式会社アスキー取締役などを経て、2013年より現職。人工知能は、アスキー入社前の1980年代中盤、COBOLのバグを見つけるエキスパートシステム開発に関わりそうになったが、Prologの研修を終えたところで別プロジェクトに異動。「AMSCLS」(LHAで全面的に使われている)や「親指ぴゅん」(親指シフトキーボードエミュレーター)などフリーソフトウェアの作者でもある。趣味は、カレーと錯視と文具作り。2018、2019年に日本基礎心理学会の「錯視・錯聴コンテスト」で2年連続入賞。その錯視を利用したアニメーションフローティングペンを作っている。著書に、『計算機屋かく戦えり』(アスキー)、『頭のいい人が変えた10の世界 NHK ITホワイトボックス』(共著、講談社)など。

Twitter:@hortense667

この記事に関連するニュース

トピックスRSS

ランキング

記事ミッション中・・・

10秒滞在

記事にリアクションする

記事ミッション中・・・

10秒滞在

記事にリアクションする

デイリー: 参加する
ウィークリー: 参加する
マンスリー: 参加する
10秒滞在

記事にリアクションする

次の記事を探す

エラーが発生しました

ページを再読み込みして
ください