「AI にコード書かせるなら、結局どの言語がいいの?」
X でよく見るやつ:
「Python が一番安定する」
「TypeScript は型があるから有利」
「Rust はコンパイル通らなくて地獄」
「Ruby? 2026年にもなってまだ使ってるの?」
でも、実測データ付きの記事 が見当たらない。
みんな感想で語ってる。
ないなら作ろう。ということで──
Claude Opus 4.6 に同じ Todo API を 4言語×5回 = 計20回 書かせて、全部テストした。
結果は予想と全然違った。
なぜ「4言語×5回」なのか
AI のコード生成って、毎回ちょっと違うコードが出る。
1回だけ試して「TypeScript 最強!」って言っても、たまたまかもしれない。だから5回ずつ回した。
選んだ4言語にも意図がある。
| 言語 | なぜ選んだか |
|---|---|
| TypeScript | 静的型付け × Web最大勢力。AI コード生成の「本命」 |
| Python | 動的型付け × AI/ML の母語。学習データ量なら最強 |
| Rust | 厳格コンパイラ。「AI には無理」って言われがち |
| Ruby | 表現力特化。「オワコン」って言われがちだけど本当? |
この4つで差が出ないなら、マジで「言語は関係ない」 と言い切れる。
検証方法:ズルできない仕組みにした
全体フロー
大事なのは 3つの「同一」。
| 条件 | やったこと |
|---|---|
| 同一プロンプト | 全言語に同じ PROMPT.md を渡す |
| 同一テスト | 全言語に同じ curl テスト(7項目) |
| 同一AI | Claude Code(Opus 4.6)で全20回 |
言語ごとにプロンプト変えたら、それは プロンプトの差 を測ってることになる。変数は 言語だけ。
仕様:いわゆる「よくある Todo アプリ」
┌─────────────────────────────────────────┐
│ Todo REST API(1ファイル完結) │
│ │
│ GET /todos → 一覧取得 │
│ POST /todos → 新規作成 │
│ PUT /todos/:id → 更新 │
│ DELETE /todos/:id → 削除 │
│ │
│ DB: SQLite / Port: 8080 │
└─────────────────────────────────────────┘
AI コーディングの "Hello World" みたいなやつ。
これで差が出るなら、もっと複雑なタスクでは壊滅的な差になるはず。
テスト項目(7つ)
# 1. GET /todos → 200 が返る
# 2. GET /todos → 配列が返る
# 3. POST /todos → 201 が返る
# 4. POST /todos → title を含むオブジェクトが返る
# 5. POST → GET → 作成済みアイテムが入っている
# 6. PUT /todos/1 → 更新内容が反映される
# 7. DELETE /todos/1 → 削除メッセージが返る
ステータスコードだけじゃなく レスポンスの中身まで検証 してる。「200返ったけど空っぽ」みたいな"なんちゃって成功"は通さない。
結果:全部動いた。煽りタイトルが死んだ。
正直に言う。
タイトルは 「動的型付けが最強だった」 か 「Rust信者死亡確認」 で煽るつもりだった。
総合スコア
| 言語 | テスト合格率 | ビルド成功率 | 平均コード行数 |
|---|---|---|---|
| TypeScript | 100%(35/35) | 100%(5/5) | 115行 |
| Python | 100%(35/35) | 100%(5/5) | 122行 |
| Rust | 100%(35/35) | 100%(5/5) | 173行 |
| Ruby | 100%(35/35) | 80%(4/5) | 105行 |
全部100%。全部動いた。
20回連続でこれを見ることになった↓
=== Todo API Test Suite ===
PASS: GET /todos returns 200
PASS: GET /todos returns array
PASS: POST /todos returns 201
PASS: POST /todos returns todo with title
PASS: GET /todos after POST has item
PASS: PUT /todos/1 returns updated todo
PASS: DELETE /todos/1 returns deleted message
===========================
Result: 7/7 passed, 0/7 failed
途中から感動より 退屈 のほうが勝った。
ちょっと待って、これすごくない?
2023年の GPT-4 や Claude 2 で同じことやったら、こうはならなかったと思う。
なんでこうなったのか。「AI が賢くなった」だけじゃない。
各言語のエコシステムが成熟して、パターンが固まった から。
「Express + SQLite ならこう書く」「FastAPI + SQLite ならこう書く」──こういうお手本コードがネット上に大量にある。AI はそのパターンを再現してるだけとも言える。
つまり:エコシステムが安定してる言語ほど、AI の生成精度が上がる。
これ、後で出てくる Ruby の失敗で裏付けられる。
でも「差がない」は嘘。体験は全然違う
テスト合格率は同じ。でも 使ってみた感覚 が全然違う。
ここからが本番。
Rust だけビルドに60秒かかる
| 言語 | 何が起きる | 起動まで |
|---|---|---|
| TypeScript |
npm install → tsx で実行 |
3秒 |
| Python |
pip install → そのまま実行 |
3秒 |
| Ruby |
bundle install → そのまま実行 |
5秒 |
| Rust | cargo build --release |
65秒 |
20倍。Rust だけ20倍。
なにが問題かっていうと、AI Coding Agent の仕事って基本こういうループなんよ:
この 「ビルド」のところで毎回1分待つ ことになる。
人間がコーヒー入れに行く時間じゃない。Agent がただ待つ時間。しかも API 課金も発生しない。純粋に 何もしてない時間。
今回は Todo アプリだから65秒で済んだけど、依存クレートが増えたら初回ビルドは 5〜10分 になったりする。その間に TS なら何回イテレーション回せるか……。
Rust が「遅い」のはランタイムじゃない。ビルドが。
誤解しないでほしいんだけど、「Rust 使うな」って話じゃない。フェーズを分けよう って話。
Rust だけコードが1.5倍長い
| 言語 | Run-1 | Run-2 | Run-3 | Run-4 | Run-5 | 平均 | 振れ幅 |
|---|---|---|---|---|---|---|---|
| Ruby | 98 | 117 | 94 | 103 | 114 | 105 | 23行 |
| TypeScript | 131 | 114 | 128 | 114 | 92 | 115 | 39行 |
| Python | 134 | 131 | 119 | 114 | 114 | 122 | 20行 |
| Rust | 167 | 171 | 178 | 176 | 175 | 173 | 11行 |
なんで Rust だけ多いの? 型定義の義務 のせい。
同じ「Todo」を表現するのにこれだけ違う:
// Rust: 構造体が3つ必要(15行)
#[derive(Debug, Serialize, Deserialize)]
struct Todo {
id: i64,
title: String,
completed: bool,
created_at: String,
}
#[derive(Debug, Deserialize)]
struct CreateTodoRequest {
title: String,
}
#[derive(Debug, Deserialize)]
struct UpdateTodoRequest {
title: Option<String>,
completed: Option<bool>,
}
# Ruby: 1行(型定義ゼロ)
params = JSON.parse(request.body.read)
Rust 15行 vs Ruby 1行。 AI が書いても人間が書いても、この差は消えない。
コード行数 = トークン消費量 だから、API 課金ベースだと Rust は 1.5倍のコスト。
でもちょっと面白い発見がある。上の表の 「振れ幅」 を見てほしい。
Rust が一番安定してる。 振れ幅わずか11行。
型システムが厳格だから、書き方の自由度が低い。結果として AI の出力がほぼ同じパターンに収束する。
冗長だけど安定。自由だけどブレる。面白いトレードオフ。
Ruby の「依存関係トラップ」
今回 唯一のビルド失敗 がこれ。Ruby の Run-1。
Sinatra could not start, the required gems weren't found!
Add them to your bundle with:
bundle add rackup puma
Sinatra 4.x で rackup が別 gem に分離された。 AI がこの breaking change を知らなかった。
# Run-1(失敗)── rackup がない
gem 'sinatra'
gem 'sqlite3'
gem 'puma'
# Run-2以降(成功)── プロンプトで rackup を指定
gem 'sinatra'
gem 'sqlite3'
gem 'puma'
gem 'rackup' # ← これ1行で全部解決
Ruby が悪いわけじゃない。AI の学習データの鮮度 の問題。
ただ、こういう差は出る:
AI にとって一番都合がいいのは「古いコードがそのまま動く」フレームワーク。
Express は10年以上 API が変わってないから、学習データがどの時期のものでも通用する。Sinatra は Ruby コミュニティの「前に進む」文化を反映して、大胆に依存を整理する。
後方互換性の高さが、AI 時代のフレームワーク選びの 新しい評価軸 になりそう。
教訓:AI にコード書かせるなら、フレームワークの最新バージョン情報をプロンプトに含めろ。
AI が選ぶフレームワーク、面白いくらい偏ってる
同じ仕様を投げても、言語ごとにまったく違うコード が出てくる。でもフレームワーク選択は完全に固定。
Hono? 選ばない。Flask? 選ばない。Axum? 選ばない。 全部「そのエコシステムで最もメジャーなやつ」一択。
TypeScript:Express + better-sqlite3
import express, { Request, Response } from "express";
import Database from "better-sqlite3";
const db = new Database("todos.db");
db.exec(`
CREATE TABLE IF NOT EXISTS todos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
completed INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)
`);
const app = express();
app.use(express.json());
npm ダウンロード数で Express は月間3000万超。Fastify は300万、Hono は100万未満。AI は 「最もコード例が多いやつ」 を選ぶ。正確さを最大化する合理的な戦略。
Python:FastAPI(Flask は選ばれない時代に)
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import sqlite3, uvicorn
class CreateTodo(BaseModel):
title: str
app = FastAPI()
5回とも FastAPI。一度も Flask は出てこなかった。 2026年の AI にとって Python Web API は「FastAPI がデフォルト」。
しかも面白いのが、動的型付け言語のはずの Python が Pydantic で事実上の型定義をやってる こと。Rust の構造体と似たアプローチだけど、バリデーション機能も兼ねてるから実用的。
Rust:actix-web + Mutex
use actix_web::{web, App, HttpServer, HttpResponse};
use rusqlite::Connection;
use std::sync::Mutex;
struct AppState {
db: Mutex<Connection>,
}
5回とも actix-web。Axum は一度も選ばれなかった。 Axum は Tokio 公式なのに。
理由は単純で、actix-web のほうが歴史が長くて Stack Overflow のコード例が多いから。本番コードなら r2d2 でコネクションプールを使うべきだけど、Todo アプリなら Mutex で十分ではある。
Ruby:Sinatra のミニマリズム
require 'sinatra'
require 'sqlite3'
require 'json'
set :port, 8080
DB = SQLite3::Database.new('todos.db')
DB.results_as_hash = true
平均105行で最短。 型定義なし、設定最小限。Ruby の「書くべきコードが少ない」哲学が AI 生成でもそのまま出てる。
バリデーションなし、エラーハンドリングも最小限。良くも悪くも 「仕様通りに動くものを最短で」 が徹底されてる。
同じプロンプトなのに毎回コードが違う問題
地味だけど、これ結構大事な発見。
TypeScript の Run-1 と Run-2 を比較してみた:
| ポイント | Run-1 | Run-2 |
|---|---|---|
| DBパス | path.join(__dirname, "todos.db") |
"todos.db" |
| WALモード | あり | なし |
| 型定義 |
interface で別途定義 |
インライン |
| 日時フォーマット | datetime('now') |
strftime で ISO 8601 |
| 行数 | 131行 | 114行 |
どっちも正しい。でも設計判断が違う。
Run-1 は丁寧派。Run-2 は最小限派。AI は毎回サイコロを振って、ちょっとずつ違うアプローチを選んでる。
ただし アーキテクチャレベルでは安定(5回とも Express + better-sqlite3)。
安定 ←──────────────→ 不安定
フレームワーク ████████████████████ ほぼ固定
DB ライブラリ ████████████████████ ほぼ固定
全体構造 ████████████████░░░░ だいたい同じ
細部の設計判断 ████████░░░░░░░░░░░░ 毎回違う
コーディング規約 ██████░░░░░░░░░░░░░░ バラバラ
大きな方向性は同じだけど、細部がブレる。 これが AI コード生成の現在地。
チームで使うときどうする?
同じ仕様なのに、生成タイミングで WAL モードが入ったり入らなかったり。コードレビューのコストが上がる。
対策はシンプル:
皮肉なことに、AI コード生成の品質を上げるには 人間がより細かく設計判断を事前に決める必要がある。AI は「何を作るか」は分かるけど、「どう作るか」は毎回揺れる。
最終スコアカード
| 観点 | TypeScript | Python | Rust | Ruby |
|---|---|---|---|---|
| テスト合格率 | ⭐⭐⭐ 100% | ⭐⭐⭐ 100% | ⭐⭐⭐ 100% | ⭐⭐⭐ 100% |
| ビルド成功率 | ⭐⭐⭐ 100% | ⭐⭐⭐ 100% | ⭐⭐⭐ 100% | ⭐⭐ 80% |
| 起動速度 | ⭐⭐⭐ 3秒 | ⭐⭐⭐ 3秒 | ⭐ 65秒 | ⭐⭐⭐ 5秒 |
| コードの短さ | ⭐⭐ 115行 | ⭐⭐ 122行 | ⭐ 173行 | ⭐⭐⭐ 105行 |
| 依存の安定性 | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
| 生成の安定性 | ⭐⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
| 総合 | S | S | B+ | A- |
各言語を一言でまとめるとこう:
TypeScript ── 万能。迷ったらこれ。
Python ── TS と互角。AI/ML やるなら最適。
Rust ── 動くけど待つ。プロトタイプ向きではない。
Ruby ── 最短最速。ただし依存関係に注意。
言語選択より大事だった3つのこと
20回回して気づいたんだけど、言語の違いより効いたのは別のところ だった。
1. プロンプトの精度 > 言語選択
Ruby が失敗したのは「Ruby だから」じゃなくて「プロンプトに rackup の指示がなかったから」。
プロンプト直したら Ruby も100%成功した。
言語を変えるよりプロンプトを直すほうが効果でかい。
2. テスト駆動が AI 時代にこそ効く
「全言語100%」って確認できたのは、先にテストを定義してたから。
テストなかったら「動いてるっぽいけど PUT のレスポンスが仕様と違う」みたいなバグ、絶対見逃してた。
AI 時代の TDD。テストが「AI の品質保証」になる。
3. 「何を作りたいか」を言語化する力
AI は「Todo API 作って」で動くコードを返す。でも──
- 「WAL モード使いたい」→ 言わないと入らない
- 「ISO 8601 にしたい」→ 言わないと
datetime('now')になる - 「バリデーション入れたい」→ 言わないと入らないことがある
設計意図は言わなきゃ反映されない。
AI 時代に磨くべきは「プログラミング言語の知識」じゃなくて 「何を作りたいか言語化する力」。
再現方法
検証コードは GitHub で全部公開してます。
環境
| 項目 | バージョン |
|---|---|
| macOS | Darwin 24.3.0(Apple Silicon) |
| AI モデル | Claude Opus 4.6 |
| Node.js | v22.16.0 |
| Python | 3.14.3 |
| Rust | 1.93.1 |
| Ruby | 4.0.1(Homebrew) |
リポジトリ構成
benchmark/
├── spec/PROMPT.md # 共通仕様書
├── test/test_api.sh # 共通テスト(7項目)
├── run_benchmark.sh # ベンチマークランナー
└── results/
├── typescript/run-{1-5}/ # 生成コード + result.json
├── python/run-{1-5}/
├── rust/run-{1-5}/
└── ruby/run-{1-5}/
動かしてみる
# 1. クローン
git clone https://github.com/matsubara457/ai-coding-agent-benchmark.git
cd ai-coding-agent-benchmark
# 2. TypeScript run-1 を起動
cd benchmark/results/typescript/run-1
npm install
npx tsx app.ts
# → http://localhost:8080/todos
# 3. テスト(別ターミナル)
bash benchmark/test/test_api.sh
# → 7/7 passed が出るはず
まとめ
| 知見 | 一言 |
|---|---|
| 全言語100% | 「この言語は AI と相性悪い」はもう通用しない |
| Rust はビルドが60秒 | コードは正しい。待つのが辛い |
| Ruby は依存関係が罠 | Sinatra 4.x の breaking change |
| コード量は Rust 1.5倍 | 型定義の宿命。トークンコストに直結 |
| 最短は Ruby | 平均105行。ただし動かないリスク付き |
| 鉄板は TS / Python | 速い・安定・ちょうどいい |
| プロンプトが言語より効く | 言語変えるより仕様を明確に |
「AI にコード書かせるなら何の言語がいい?」
「何でもいい。もうそのレベルの議論は終わった。」
これが20回ベンチマーク回した人間の結論。
差がつくのは言語選択じゃなく、プロンプトの質 と 仕様の明確さ。
AI 時代に磨くべきスキルは「プログラミング言語の知識」じゃなくて「何を作りたいか言語化する力」だと、20回の実験で確信した。
検証コードは全部 GitHub に上げてあるので、ぜひ自分の環境で回してみてください。
違うモデルや仕様で試したら、きっと面白い結果が出るはず。
いいねとストックしてくれると次の検証のモチベになります。
面白い結果が出たら、コメントで教えてください。