2025年3月13日木曜日

人に易しい事、AIに易しい事

こんにちは横井です。 

基本的にAIコーディングはLLMがフレームワークまたはライブラリ、そしてアーキテクチャやデザインパターンなど学習済みの言語が対象であれば、コーディングはすごく容易いことです。一方、学習していないことに対しては、LLMは知らない部分は自分で補完しようとするので、これがいわゆるハルシネーションという架空のアウトプットを出してしまいます。

人によっては嘘をアウトプットしてると言われることにもなっています。

生成AIが世間で騒がれるようになってから私もGeneXusエバンジェリストとして生成AIがGeneXus言語でコーディングできるのか?ということにはずっと取り組んできました。GPT-4がリリースされてから2年近く経過している今現在ではGeneXusに関する学習がされていると感じられるアウトプットは結構増えてきています。ただそれは十分なカバー量ではなく、他の学習済みの言語のようなレベルにはほど遠いというのが現状です。

文法を学習してないと言う事に関しては、カスタムインストラクションの中に言語の文法や他言語とのマッピングというような形で情報を追加してあげれば、ある程度アウトプットを再現する事はできます。

ただどうしても難しい事があります。GeneXusではSQLは一切書きません。SQLを書かないと言う事はテーブルの指定もしない。そしてテーブル間のJOINの指定をしません。

指定するのはデータを抽出したい項目名とそれらに対する条件(抽出条件やソートオーダー)です。この文法 - for eachコマンドになりますが、命令に関しては他の言語に例を見ないGeneXus特有のものです。

その発想の話は過去の記事に記載があります。

要約すると、DBアクセスに関しては裏側の技術知らなくてもシステムの表面上、見た目上で必要な項目さえ与えてあげれば後はGeneXusが推論し、SQLを生成する。というものです。

従って、GeneXusが解析するGeneXus言語上での指定は先に言ったとおり、「データとして必要となる項目」だけです。

しかし、AIコーディングでは「データを抽出する」と言うキーワードが入った瞬間に、LLMはSQLを想定し、あるいはSQLを使ったライブラリーのAPIを想定したコードを書いてしまいまい、GeneXus言語でのfor eachコマンドにはならないのです。

DBアクセスという難しい操作を人に易しくする為に考え出されたGeneXus言語 : for eachコマンドですが、LLMの学習状況を踏まえるとAIにとっては再現するのは難しい事で、なんとも皮肉な状況になっています。

では。

2025年3月4日火曜日

卵が先か?鶏が先か?AIコーディングはプロマネ育成ツール

こんにちは、横井です。 

先日、AIコーディングについてあるお客さんと雑談していた時の事です。私が「AIコーディングが普及すると、要件定義力と開発方法論に基づいたプロジェクトマネジメント力があれば、ソフトウェア開発はできてしまう」といった話をすると、「てことは、プロマネがいれば開発ができるけど、プロマネはどうやって育成したらいい?普通はコーディングから始まって一通り開発プロセスを経験の上に成り立つものだよね?AIコーディングを推進して実践する場が無くなったらプロマネ自体が育たないよね?」と、言われました。

確かに。私がAIコーディングを経験して「こりゃ凄い!人に依頼してるのと変わらない!」と感じることができるのは、年齢も50代半ばに差し掛かり、30年以上ソフト開発の現場に関わってきたからこそ。というのは事実です。

その時は「仰るとおりです。ただ、AIコーディングが普及することで例えばサービス会社は状況が180度変わります。人員不足の世の中で猛烈なスピードでサービスを開発する事が可能になります。では、SIerやIT子会社といった開発を生業とする会社はどうなりますか?AIコーディングとの向き合い方はどうしますか?そこは問われてくると思います」と答えました。


そうは言ったものの、確かにその通り。どうしたものか。。と考え込みました。

あれこれ考えた末たどり着いたのは「コーディングを出発点として一通り開発プロセスを学ばなくてもマネジメントを学ぶことは可能」でした。

日本では徒弟制度とか、経験第一主義な所はありますが、これはよくある議論で実戦を積まないと出来ない派と理論を学べば出来る派の話になります。が、私の結論はそのハイブリット的なものです。

私の発想は「要件定義力やマネジメント力があればAIコーディングが成立する」というものです。これは逆に言うと「要件が明示的に伝えられず、プロセスに基づいたマネジメントもできないと、まともなコーディングをしてくれない」という事になります。そしてこれは私自身もAIコーディングとして経験しましたが、「どうやったらまともなコーディング、まともなアプリが実装できるのか?」という事を考えながらトライ&エラーでAIコーディングを続ける事で(今時点での)ベストプラクティクスに辿り付きました。つまり、AIコーディングを実践すること自体が開発経験を積むのと同じ事だと思います。

要はAIコーディング自体をトレーニングとして実践することで、マネジメント経験やプロセスの必要性を身をもって体験できます。しかも通常の開発では半年、1年と期間をかけないと一通りのプロセスの体験は出来ませんが、AIコーディングならもっと短いスパンでサイクルを経験することができます。

「AIコーディングでは実際の開発をしている訳ではないから、経験にならないのでは?」という意見もあるかもしれません。それであれば、新人教育の中で技術習得の前にAIコーディングによるマネジメント体験をさせれば、その後の技術教育やOJTでもマネジメントの必要性、重要性をわかった上で取り組むことが出来るのではないでしょうか?また、今時点では全ての開発がAIコーディングに取って代わられるわけではありません。実戦経験のチャンスは十分ありますので、教育の一貫として取り組んでみるのもいいと思います。

生成AIを色々体感した上で、周りの人と会話すると若干かみ合わない事が出てくるのですが、ある意味「突拍子もない事、突拍子もない発想」というのが生成AIが存在する今現在、そしてこれからの未来では必要なのではないでしょうか。

では。

2025年2月27日木曜日

AIテストは信用できる? AIテストの外堀の埋め方

こんにちは、横井です。

前回はAIコーディングに対する品質担保についてお話ししました。結論としては人がコーディングしようが、AIがコーディングしようが、設計通りに実装できているか? を確認するにはテストが必要。というごくごく当たり前の話でした。(笑)

もう一つは生成AIでもテストコードは生成可能という話です。しかし、そのテストコードがどれだけ信頼できるかは、作成方法や段取りに大きく依存する問題でもあります。

一般的な開発プロセスでは、まず設計を行い、次にアプリケーションコードを作成し、最後にテストコードを作成するという流れになります。しかし、その場合、テスト実行時にエラーが発生した際、問題がアプリケーションコードにあるのか、テストコードにあるのか判断が難しくなるという課題があります。これはAIコーディングに限らず、スクラッチでの開発においても同様の悩みとなります。つまり、アプリケーションコードの品質を担保するためにテストコードが必要となり、そのテストコードの品質を担保するためにさらにテストコードが求められる、いわゆる「テストコードの無限ループ」問題に突き当たります。

このような問題に対する解決策として、TDD(テスト駆動開発)の手法が提唱されています。TDDとは、アプリケーションコードを作成する前に、まずテストコード、すなわちテストケースを作成し、その状態で初めてアプリケーションコードを実装するという流れです。常にテストコードを実行し、テスト結果がグリーン(合格)の状態を維持することを重視する考え方です。

ただし、TDDのポイントは単にテストコードを先に作成することではなく、まずはテストケースを漏れなく洗い出すことにあります。そしてそのためには、十分な設計が不可欠です。設計が整っていなければ、網羅的なテストケースの洗い出しは難しくなります。つまり、TDDとは、テストコードを作成するためにテストケースを検討し、その検討のために設計をしっかり行うという、一連の決められたプロセスに基づいてワークフローを回すことが肝心なのです。

以上の話はスクラッチ開発での一般的な話ですが、実際にはこの方法論はAIコーディングにおいても十分に適用可能です。常にテスト結果を確認しながら開発を進めることで、生成AIの高速なコーディング能力と、求める品質の両立が実現できると考えます。

では。



すみません、追記です。

TDDを実践することでコードの品質を上げることができると書きましたが、この場合当然の事ながらテスト実行の回数が増えます。CLIベースのテストツールだと、テスト実行中のモニタリング情報を秒単位で出力します(画面でリフレッシュさせているような感じ)。結果として、例えばエラーが1つしか出なくても、テストが完了するまでのモニタ表示用の出力が延々と続き、結果としてLLMへの送信量が莫大になります。しかも、膨大なログを解析するの時間もかかり、結果一つしかエラーが無いとか、エラーがゼロとかだと、API呼び出しの待ち時間とコスト消費が馬鹿になりません。(あっという間にチャージしたクレジットが溶けていきます)

これはAIコーディングを品質良く実施する事の可否と、技術的コスト的問題は別物であるという事です。なので、私のブログを見たからといってすぐさまTDDに取り組むのであればそれなりのお金の消費を覚悟する必要があります。

では。


2025年2月21日金曜日

AIコーディングの品質はどう担保する?

こんにちは、横井です。

今回は、AIコーディングにおける品質担保についてです。以前の記事でも触れたように、LLM(大規模言語モデル)が学習済みのアーキテクチャやデザインパターン、アルゴリズムを活用すれば、人間が苦労して作業するよりも遥かに高速にコーディングが可能になります。しかしそれと、実際に要件や仕様を満たしたコードが得られているかどうかは、また別の問題です。

まず、LLMの種類によってもコーディングの品質は大きく異なります。私自身は(コーディングのさせ方にも影響されるのでしょうが)、Claude 3.5 Sonnet 一択です。最近リリースされ、評判の高いGemini 2.0 Proについては、私にはあまり合わない印象を受けました。いかにマネジメント方法でコーディングをコントロールできるように見えても、実際には要件を無視したコードや、途中で省略されたコードが生成され、期待外れとなるケースが多々ありました。無償なのでなんとか使いこなそうと試みるものの、金銭面では節約できても、結果として時間がかかり、満足度が低くなってしまうという現実もあります。

次に、仕様通りのコーディングが実現されているかどうかという点ですが、結局のところ、テストを行って確認するしかありません。幸い、現在では多様なテストツールが存在します。私も色々とテストコードをAIコーディングしてみましたが、実際に試してみると、ソースコードとテストコードの両方が作成された後、テスト実行でエラーが発生した際に、どちらに原因があるのか判断がつかなくなり、場合によってはテストコード自体を修正してしまうこともあるのです。こうなると、テストコードの実装が問題なのか、テストケースそのものが変わってしまっているのかが不明瞭となり、混乱を招きます。

また、以前にも書きましたが、テストエラー発生→エラー修正→テスト再実行→テストエラー発生と修正とエラーの無限ループも起きがちです。どうしても視野が局所的になり、局所的な修正になるので、あちらを直せばこちらがおかしくなる。みたいな事になってしまいます。

そこで、テスト実行後にいきなり修正を加えるのではなく、テスト結果をまずファイルに出力し、エラー(Test Fail)が発生した場合は原因と対応策もファイルに追記するテストレポートの作成を義務付けるなどのルールを設ける事で、いきなり修正→エラー頻発といった負の連鎖を防ぐ事ができます。

この様にコードを自動的に生成してくれるといっても、その品質を担保するためには色々な工夫が必要になってきます。

では。


2025年2月20日木曜日

全体を把握すること、全てを見通すこと

 

こんにちは、横井です。

AIコーディングを進めていると、あたかもAIがリポジトリ全体を見通して作業しているかのように錯覚することがあります。

実際にはAIはその都度のリクエストに対して応答しているだけです。LLM(大規模言語モデル)やエージェントのメモリ機能のおかげで、連続してリクエストを送ると、あたかも学習し成長しているかのような印象を抱いてしまいます。

しかし、例えばコードにエラーがあり修正を行うのですが、エラーが解消されない場合は再び修正を試みる。。といったコード修正の無限ループに陥った場合、一度作業を中断して状況を見直し再び作業を再開すると、これまでの経緯が反映されず、ルールに反した動作が現れることがあります。その結果、コードが破損し「最初から作り直した方が早いかな?」といった残念な感じになることもありました。

また、AIコーディングでは、依存関係の確認、すなわちクロスリファレンス機能が機能していない点も問題です。たとえば、GeneXusでは、オブジェクトや項目属性がどこで利用されているかがクロスリファレンスとして即座に把握できるため、使用されているものは削除できない安全策が整っています。しかし、スクラッチ開発におけるソースコードの管理では、GitHubのようなリポジトリでも依存関係が完全には把握されず、「問題ない」と判断して削除したファイルが、実は他の部分から参照され、システムが正常に動作しなくなるといった事態が起こりやすいです。まあ、これはAIコーディングに限った話ではありませんが、GeneXus開発に慣れているとクロスリファレンス機能が存在するのが当たり前だったので結構困りました。

別な話としては、アジャイルにAIコーディングを進めると、機能を追加してくなかでリファクタリングを提案してくるのですが、あたかも全てを見直してコード修正してくれているようで実はメモリに残っている範囲でリファクタリングを行い、随分と初期に行ったコーディング個所が漏れ落ちてしまう事もあります。

例えばデータベースアクセスのコードが、効率向上を考慮してコネクションプールを利用するようにリファクタしてくれるのですが、初期のコーディング部分は直接接続のまま残されてしまっていたり。といった具合です。

このように人は広い視野で物事(リポジトリ内)を記憶しておくことができるので「ここ大丈夫だったかな?」と目くばせする事ができます。(もちろん、業務システムの様に量が多く、漏れ抜けが許されない場合は横展開チェックなど記憶に頼らない確認手段は必要ですが)

一方でLLMはリポジトリ全体を記憶しておくこと、記憶し続ける事が現状では難しいので、その都度のリクエストに含まれる情報や短期的なメモリ機能の範囲でしか「把握」という状況ができません。

なんらか代替手段が無いと業務システムのような規模は難しいなと感じています。

私がAIコーディングにおいてリポジトリ管理として望む点は、以下になります。

  • クロスリファレンス機能
    • 例えば、グラフデータベースのように各ソースコード間の関係性を表現できる仕組みがあれば、どの部分に依存しているかが一目で分かり、誤って必要なファイルを削除してしまうといったリスクを減らすことができます。
  • リポジトリ(ソースコード)全体の把握
    • こちらは、リポジトリ全体を文脈で検索可能なデータベース化ができれば。と思います。現状のRAG(Retrieval Augmented Generation)で実現できるかは不明な部分もあります。ソースコードのファイルは大きいため、通常RAG化する場合はファイルを複数のチャンクに分割してベクトル化します。ひとつのチャンク内に収まる文脈であれば、文脈検索により正確な抽出が可能です。しかし、ロジックが分割されたチャンクに跨った状態だと、文脈が分断され検索精度が出ない(ヒットしない)可能性もあります。逆に、ソースコード全体を丸ごとベクトル計算してしまうと、文脈が広がりすぎてベクトルの意味が希薄になってしまいます。そのため、適切な文脈情報を保持するには、チャンク分割は避けられませんがその要求は矛盾したものとなってしまいます。ただ単に機械的に分割するのではなく、ロジックの処理単位に分割できれば、チャンク単位での検索でも高い正確性が持てるかもしれません。ただ、この場合はどうやって分割するか? コードのロジックを解釈しながら分割ができるのか? といった技術課題が多々あり実現可能かどうかは未知数ですが、今後の技術の進展に期待したいところです。

といった感じで、全体を把握する・全てを見通す。という人にはごく当たり前にできる事が実は結構難解で高度な機能なのだとAIを使い込んでみて気づかされました。

では。

2025年2月19日水曜日

AIコーディングはアジャイル向き?ウォーターフォール向き?


こんにちは、横井です。

先日の投稿では、AIコーディングの品質向上のためには、適切なプロセス定義が重要であると述べました。そこで、プロセスを定義する=ウォーターフォールという表現を用いましたが、これは必ずしも「AIコーディングはウォーターフォール向き」という意味ではありません。では逆に、AIコーディングはアジャイル向きなのでしょうか?

どのようなプロセスがAIコーディングに適しているのか考えてみましょう。

まず、プロセスを明確に定義するという観点では、それぞれのプロセスに対するインプットとアウトプットを明確にする。作業計画を策定し、その計画をさらに具体的なタスクに落とし込む。といった事が重要です。たとえば、コーディング前にドキュメントをレビューする。修正作業に入る前には各修正箇所をピックアップし修正理由や内容をドキュメント化する。といった手順が考えられます。一見すると、これはウォーターフォールモデルのような厳格なプロセスに見えます。

しかし、実際のところ、段取り的にはウォーターフォールに近いものの、AIコーディングは複数人での開発や、各工程を別々の担当者が分担する従来の開発体制とは異なります。(もちろん、今後はマルチエージェントへと機能が進化すると思うので、役割ごとのエージェントとか、コーディング自体も複数のエージェントで分担する。とか組織的なエージェントになる可能性はあります)  また、業務システムのようにたくさんの機能を持つシステムを開発する場合、一度に全ての設計書やドキュメント、機能をまとめて実装するのは、今時点でのAIコーディングには適していません。

大規模な機能を実装する場合は、まずスコープ(一回のコーディング対象)を小さく区切り、その単位ごとに設計、計画、コーディング、テストというサイクルを回す必要があります。これは、アジャイルやスクラムにおけるイテレーションやスプリントに近い作業単位の感覚と言えるでしょう。つまり、プロセスの段取り自体はウォーターフォール的に定義しながらも、実際のドキュメント作成やコーディングは、ひとつの大規模なチームではなく、小単位に分かれてサイクリックに進める流れとなります。

人が実施する従来のアジャイル開発との大きな違いは、ドキュメンテーションやコーディングのスピードにあります。通常、2週間から3週間で一サイクルを回すところを、AIコーディングではそのサイクルを1日で完了できる場合もあります。現在はAPIのトークン数やリクエスト回数の制限があるため、すべてが高速に進むわけではありませんが(大抵は最初は凄いスピードでコーディングしていきますが、途中からAPIのリクエスト待ちが発生しコーディング時間より待ち時間の方が長くなります)、基本的には非常に迅速なサイクルでの開発が可能となっています。

このように、AIコーディングに最適なプロセスとは、単純にウォーターフォールかアジャイルかという二元論ではなく、ウォーターフォール的なプロセス定義と、アジャイル的なサイクル回しハイブリッドであると考えられます。

では。

 

2025年2月18日火曜日

AIの賢い使い方、エージェントとして使う方法

こんにちは。横井です。

今回は、LLM(大規模言語モデル)やエージェントをどのように活用すればよいのか、その基本的な考え方を書いてみたいと思います。

まず最初に大切なのは、何をアウトプットとして求めているのか? という作業のゴールを明確にすることです。当然これは人が指示する事になります。このゴールの定義が曖昧だとアウトプットも想定したものと違ったものになってしまいがちです。

次にどのようゴールを達成するか──いわゆる「How」の部分は、LLMに考えさせるのがポイントだと思います。色々試してみた経験として人が一から十までHowの部分を指定すると、その指定から漏れた物の挙動が不安定になり思ったアウトプットになりませんでした。

ただし、この「How」の部分には方法論やプロセスといった進め方の方針が必要です。ここに関してはそれらをあらかじめルールとして定義し、前提として伝えておく必要があります。つまり方針は人が指示をし、その方針に則ってLLMがHowを考える。という分担になります。

たとえば(コーディング作業で例えると)、

  • コーディングする前に必ずドキュメントを書いておく
  • コーディング前にやるべきことをリストアップしておく
  • アプリケーションコードとテストコードをセットで書く
  • テストコードを先に書く

といった手順や方針です。これらはある意味、「ウォーターフォール型」のように、プロセスの進め方を先に定めてしまうこととも言えます。こうした方法論や方向性を設定したうえで、アーキテクチャや要件、そして実装したい機能をもとに「具体的にどう作るか」というステップをLLMに考えさせるのです。

次に、作業計画についてです。これはHowの部分をさらに具体的な作業レベルのタスクにブレイクダウンし、詳細化させる事です。これもLLMに任せた方がよいです。タスクを細かく分解してもらうことで、「何をいつ、どの順序で行うか」を明確化できますし、その進捗を管理するToDoとしても活用できます。LLM自身が考える事で、ゴールへ向かう道を見失わずに、一直線で進むことが可能になります。

以上のように考えると、人が考えて指示すべきことと、LLMが考えたり作業したりすべきことを明確に定義・分担することが重要だといえます。具体的に言えば、人間が考えるべきことは主に以下の二点です。

  1. ゴールの定義
  2. LLMに仕事を考えさせたり、実行させるための方法論やプロセスの方向付け

一方、ゴールを達成するための具体的なステップやタスクのブレイクダウン、作業順序、ドキュメント出力などについては、LLMに考えさせた方が良いです。そして、人はLLMが出してきた実現手段や実行計画、To Doリストなどをレビューするという役割を担います。

エージェント機能を使う場合は、たとえばシステムプロンプトやカスタムインストラクション、ルール設定などにおいて、どのレイヤーで何を定義するかを整理し、指示の重複や矛盾を起こさないようにすることが肝心です。

こうした工夫をこらせば、自動的・自律的にLLMやエージェントに作業を進めてもらうことも十分に可能になるのではないでしょうか。繰り返しになりますが大切なのは、「人が定めるべき前提や方針」と「LLMに委ねるべき具体的な実行手段や計画」の切り分けを明確にし、お互いの役割をはっきりさせることだと感じています。

では。