目次
- 1 結論:AIはコードを書ける。でも「動くか」は人間が回さないと分からない
- 2 なぜ「重複ファイル検出ツール」を題材にしたか
- 3 Step 1:AIへの最初の指示と、出てきたコード
- 4 Step 2:実際に動かしたら、一発で落ちた
- 5 なぜAIは「正しそうで動かないコード」を書くのか
- 6 Step 3:直し方の指示で結果が変わる
- 7 Step 4:v2を実行。今度は正しく動いた
- 8 Step 5:v2が動いた後に、もう一段だけ意地悪をした
- 9 AIにツール開発を任せるときの実用ルール
- 10 指示の出し方テンプレート(再現用)
- 11 このツールの使い方(コピペで使えます)
- 12 FAQ:AIにコードを書かせるときの素朴な疑問
- 13 まとめ:AI開発の品質は「実行ループ」を誰が握るかで決まる
結論:AIはコードを書ける。でも「動くか」は人間が回さないと分からない
「AIにコードを書かせれば、もうプログラミングは要らない」とよく言われます。半分は本当で、半分は嘘です。
この記事では、AIエージェント(Claude Code)に小さなツールを実際に作らせた全工程を、出てきたコードと実行ログそのままで公開します。先に結論を言うと、AIが最初に出したコードは一発では動きませんでした。しかも、そのバグは「AIがサボったから」ではなく、AIにコードを書かせるときに構造的に起きるものでした。
題材は「指定したフォルダの中から、中身が同じ重複ファイルを探すCLIツール」。よくある実用ニーズです。これをAIに作らせ、実際のファイルで動かし、バグを踏み、直すまでをやります。AIにコードを書かせている人、これから任せたい人が、どこを自分で確認すべきかが分かる内容にしました。
実行日は2026年5月17日。Pythonが入っていれば誰でも同じことを再現できます。
なぜ「重複ファイル検出ツール」を題材にしたか
AIの実力を見るには、簡単すぎる課題ではダメです。「Hello Worldを書いて」では差が出ません。
重複ファイル検出は、見た目は単純ですが落とし穴があります。テキストファイルだけでなく、画像や動画のようなバイナリファイルも対象になる。ファイル名が違っても中身が同じなら重複。サイズが大きいファイルもある。この「言われなくても考慮すべき条件」を、AIが自分で気づいて織り込めるかが見どころです。
そして実務でよく欲しくなるツールでもあります。写真フォルダの整理、ダウンロード地獄の掃除など。読者がそのまま使える実用性もあるので、これを選びました。
Step 1:AIへの最初の指示と、出てきたコード
最初の指示はあえてシンプルにしました。実際に多くの人がやる指示の出し方です。
「指定フォルダ内の重複ファイルを内容のハッシュで検出するPython CLIを書いて」
これに対してAIが出してきたのが、次のコードです(実物そのまま)。
#!/usr/bin/env python3
"""フォルダ内の重複ファイルを内容ハッシュで検出するCLI(v1)。"""
import sys, os, hashlib
def file_hash(path):
h = hashlib.md5()
# テキストとして開いて読む(素朴な実装)
with open(path, "r") as f:
h.update(f.read().encode())
return h.hexdigest()
def main(root):
seen = {}
for dirpath, _, files in os.walk(root):
for name in files:
p = os.path.join(dirpath, name)
digest = file_hash(p)
seen.setdefault(digest, []).append(p)
for digest, paths in seen.items():
if len(paths) > 1:
print("重複:", paths)
if __name__ == "__main__":
main(sys.argv[1])
パッと見、悪くないコードです。os.walk でサブフォルダも辿るし、MD5ハッシュで中身を比較している。ロジックとしては正しい。ここでコードレビューだけして「OK」と言ってしまう人が多いと思います。私もコードだけ見たら通していたかもしれません。
問題はここからです。
Step 2:実際に動かしたら、一発で落ちた
テスト用に、わざと現実に近いフォルダを用意しました。中身が同じテキストファイル2つ、ユニークなテキスト1つ、そして中身が同じ画像(バイナリ)2つです。実務のフォルダはこういう混在が普通です。
このフォルダに対してv1を実行しました。結果がこれです(実行ログそのまま)。
Traceback (most recent call last):
File "dedup_v1.py", line 24, in <module>
main(sys.argv[1])
File "dedup_v1.py", line 17, in main
digest = file_hash(p)
File "dedup_v1.py", line 9, in file_hash
h.update(f.read().encode())
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc6 in position 0: invalid continuation byte
UnicodeDecodeError。バイナリファイル(画像)を open(path, "r") でテキストとして読もうとして、文字コード変換に失敗してクラッシュしました。
これはプログラミングをやる人にはおなじみの初歩的ミスです。ファイルのハッシュを取るならバイナリモード("rb")で開くのが鉄則。AIはそれを知らないわけがありません。なのに、なぜこのコードを書いたのか。ここがこの記事の核心です。
なぜAIは「正しそうで動かないコード」を書くのか
AIは指示の言葉に最適化してコードを書きます。今回の指示は「重複ファイルを検出するCLIを書いて」。この文面だけ見れば、テキストファイルを読むコードは「正しい」のです。指示の中に「画像も対象」とは書いていないからです。
人間の熟練エンジニアなら、「重複ファイル検出」と聞いた瞬間に「画像や動画も来るな、ならバイナリで開かないと」と暗黙の前提を補います。この暗黙の前提の補完が、AIは指示されないと弱い。これがAIにコードを書かせるときに構造的に起きるズレです。
つまり、AIが出すコードは「指示した条件では正しい」。でも実務のデータは指示に書いていない条件を必ず含んでいる。だから、コードレビューだけでは不十分で、実データで一度回すまで「動く」とは言えないのです。これはAIの能力不足というより、指示と現実のギャップの問題です。
Step 3:直し方の指示で結果が変わる
ここでAIに修正を依頼します。指示の出し方で結果が大きく変わるので、2パターン比較します。
悪い指示は「エラーが出たから直して」。これだとAIはエラー箇所だけを最小限いじり、根本原因を踏まえない場当たり修正になりがちです。
良い指示は、現象と原因仮説をセットで渡すこと。私はこう指示しました。
「画像などバイナリファイルでUnicodeDecodeErrorになった。ファイルはテキストと限らないので、ハッシュ計算をバイナリ前提に直して。あと大きいファイルでもメモリを食わないようにして」
原因(バイナリをテキストで開いている)と、ついでに改善してほしい点(大きいファイル対策)まで渡しました。返ってきたのがv2です(実物)。
#!/usr/bin/env python3
"""フォルダ内の重複ファイルを内容ハッシュで検出するCLI(v2)。"""
import sys, os, hashlib
def file_hash(path, chunk=65536):
h = hashlib.md5()
with open(path, "rb") as f: # "r" から "rb" へ
for block in iter(lambda: f.read(chunk), b""):
h.update(block)
return h.hexdigest()
def main(root):
seen = {}
for dirpath, _, files in os.walk(root):
for name in files:
p = os.path.join(dirpath, name)
seen.setdefault(file_hash(p), []).append(p)
found = False
for digest, paths in seen.items():
if len(paths) > 1:
found = True
print(f"[重複] {digest[:8]}")
for p in paths:
print(f" - {p}")
if not found:
print("重複ファイルはありませんでした")
if __name__ == "__main__":
main(sys.argv[1])
修正は2点。open(path, "rb") でバイナリモードに変更。さらに、ファイルを一気に read() せず6万バイトずつチャンクで読むようにして、巨大ファイルでもメモリを食わないようにしてあります。出力も「どのファイルが重複か」が読みやすい形になりました。原因と要望を具体的に渡すと、AIは指示以上の改善まで返してきます。指示の解像度が、出力の質に直結します。
Step 4:v2を実行。今度は正しく動いた
同じテストフォルダでv2を実行した結果です(実行ログそのまま)。
[重複] 6f5902ac
- testdir/a.txt
- testdir/b_copy.txt
[重複] 8189bf88
- testdir/img1_dup.bin
- testdir/img1.bin
テキストの重複ペア(a.txt と b_copy.txt)と、バイナリの重複ペア(画像2つ)の両方を正しく検出。ユニークなファイルは重複として出ていません。クラッシュもしません。これでようやく「動くツール」になりました。
ここまでの工程を整理します。
| 工程 | 内容 | 結果 |
|---|---|---|
| v1:素朴な指示 | 「重複検出CLIを書いて」だけ | コードは正しそう |
| v1を実データで実行 | バイナリ混在フォルダ | クラッシュ(UnicodeDecodeError) |
| v2:原因+要望つき指示 | 原因と改善点を明示 | バイナリ対応+メモリ対策まで改善 |
| v2を実データで実行 | 同じフォルダ | 正しく重複検出 |
コードを見ていた段階では、v1もv2も「正しそう」でした。差が出たのは実データで回した瞬間だけです。
Step 5:v2が動いた後に、もう一段だけ意地悪をした
ここで止めてもよかったのですが、この記事で「人間が想定外の入力を試せ」と書いておいて自分がやらないのは筋が通りません。なので実際にもう一段試しました。フォルダの奥深く(サブフォルダのさらに下)に、既存ファイルと同じ中身のファイルを置く。さらに、中身が空のファイルを2つ置く。この状態で再実行した結果がこれです(実行ログそのまま)。
[重複] d41d8cd9
- testdir/empty2.dat
- testdir/empty1.dat
[重複] 6f5902ac
- testdir/a.txt
- testdir/b_copy.txt
- testdir/sub/deep/a_again.txt
[重複] 8189bf88
- testdir/img1_dup.bin
- testdir/img1.bin
良かった点は、深い階層に置いたファイルもちゃんと同じグループに束ねられたこと(3つに増えています)。os.walk の再帰は効いている。
問題は1行目です。中身が空のファイル2つが「重複」として検出されました。ハッシュ d41d8cd9 は、空データのMD5として有名な値です。技術的には「中身が同じ(どちらも空)」なので正しい。でも、フォルダ整理の道具としては、空ファイル同士を重複扱いされても普通は嬉しくありません。0バイトのログファイルや書きかけのメモが、全部「重複グループ」にまとめられてしまうからです。
これはAIが悪いのではありません。私が「重複とは何か」をAIに厳密に定義しなかったから、AIは一番素直な定義(バイト列が一致)で実装した。それだけです。実務でこのツールを使うなら、「サイズ0は対象外にする」か「空ファイルは別表記にする」という仕様を人間が決めて、追加で指示する必要があります。仕様の曖昧さは、実データで回して初めて表面化する。これもコードレビューだけでは絶対に出てこなかった発見です。
つまり検証は1回では足りません。「動いた」の後に、想定外の入力でもう一段叩く。ここまでやって、ようやくツールの素性が見えます。
AIにツール開発を任せるときの実用ルール
今回の1件から、AIエージェントにコードを任せるときの線引きが見えます。
| 任せていい | 人間が必ずやる |
|---|---|
| 構文・定型ロジックの記述 | 実データで一度実行する |
| ライブラリの使い方 | 想定外の入力(バイナリ・空・巨大)を試す |
| エラーの修正案 | エラーの原因を言語化して渡す |
| リファクタ・整形 | 「動いた」の最終判断 |
ポイントは、AIに「書かせる」のは安全だが、「動くと判断する」のは人間の仕事だということです。AIはコードを書くのは速いし上手い。でも、自分の書いたコードを実環境で回して結果を見ることは(指示しない限り)しません。この検証ループだけは人間が握る。逆にここさえ握れば、開発速度は確実に上がります。
指示の出し方テンプレート(再現用)
今回うまくいった指示の出し方を、そのまま使える形にしておきます。
最初の依頼は「何を・どんな入力で・どう出力するか」を1文ずつ書く。「重複ファイルを検出。入力はフォルダパス。テキストもバイナリも対象。出力は重複グループ一覧」。この「バイナリも対象」を最初から入れていれば、v1のクラッシュは起きませんでした。
修正依頼は「現象+原因仮説+追加要望」の3点セット。「◯◯でエラー。原因は△△だと思う。ついでに□□も改善して」。これがAIから一番良い修正を引き出す形でした。
このツールの使い方(コピペで使えます)
完成したv2は、そのまま実用ツールとして使えます。Pythonが入っていれば追加インストール不要です。
# 上のv2コードを dedup.py として保存して実行するだけ
python3 dedup.py /整理したいフォルダのパス
写真フォルダやダウンロードフォルダを指定すると、中身が同じで名前だけ違うファイルを一覧で出します。削除は自動でしません(重複の一覧表示までで、消すかは人間が判断)。誤削除が怖いツールなので、検出と削除を分けてあります。
FAQ:AIにコードを書かせるときの素朴な疑問
Q. 結局、AIにコードを書かせる意味はあった?
あります。v1からv2までの全工程で、私が書いたコードは1行もありません。書いたのは指示文だけ。バイナリ対応もチャンク読みも、人間が手で書けば調べる時間がかかります。検証だけ人間がやれば、開発は確実に速くなります。
Q. 最初から完璧なコードを出させる方法は?
指示の段階で入力の種類を具体的に書くことです。今回なら「テキストもバイナリも対象」と最初に入れていれば、v1のクラッシュは起きませんでした。AIの精度は指示の解像度で決まります。
Q. AIが「動きました」と言ったら信じていい?
実行ログを見せてもらわない限り信じない方がいいです。AIはコードを書きますが、それを実環境で回したかは別問題。今回も、AIにコードを書かせた直後の段階では、まだ一度も動かしていません。実行は人間か、明示的に指示した場合のAIがやる工程です。
Q. もっと複雑なツールでも同じ進め方でいい?
同じです。規模が大きくなるほど「実データで回す」「想定外の入力を試す」の重要度が上がります。複雑なツールほど、コードレビューだけで品質を判断するのは危険になります。
まとめ:AI開発の品質は「実行ループ」を誰が握るかで決まる
AIエージェントに重複ファイル検出ツールを作らせた実録でした。
要点です。
- AIが最初に出したコードは、コードとしては正しそうだったが、バイナリファイルで実際にクラッシュした
- 原因はAIの能力不足ではなく、指示に書いていない暗黙の前提(バイナリ対応)をAIが補完しなかったこと
- 修正依頼は「現象+原因仮説+追加要望」の3点セットが効く。原因まで渡すと改善まで返ってくる
- AIにコードを書かせるのは安全。だが「動く」と判断するのは人間の仕事
- 実データで一度回すこのループだけ人間が握れば、開発速度は確実に上がる
AIにコードを書かせる人が増えていますが、差が出るのは「書かせ方」ではなく「検証の握り方」です。コードレビューで止めず、必ず実データで一度回す。これだけで、AI開発の事故はかなり防げます。
【ノーコード】n8nとGeminiで問い合わせメールを自動でスプシ転記→Slack通知する仕組みを作る
Difyの「質問分類器」ノードを触ってわかった、n8nとの設計思想の決定的な違い