はじめに
Gemini 3.5 Flash がリリースされ、「理論値ではコーディング性能が 3.1 Pro を超える」という情報が出回っています。
一方で X(旧Twitter)では「ハルシネーションが多い」「Claude Sonnet にも届いていない」という声も。
実際のところどうなのか。Tauri + Rust でMacアプリを開発している個人開発者の視点から、実際のコードを使って検証しました。
検証者プロフィール
- macOS向けユーティリティアプリを複数開発・販売しているソロ開発者
- 普段のAIワークフローにGeminiを組み込んで使用
- Tauri + Rust + Swift スタック
検証方法
使用モデル
- Gemini 3.1 Pro
- Gemini 3.5 Flash(新モデル)
テスト内容
意図的にバグを仕込んだ約200行のRust(ADB操作系)コードを渡し、バグをすべて発見・修正させる。
50行以下のコードは運が良ければどのモデルでも書ける。100行を超えると一気に崩壊するのが従来のFlashの実態だったため、今回は200行・14個のバグを用意しました。
バグの内訳
| カテゴリ | 個数 | 例 |
|---|---|---|
| ロジックバグ(メイン) | 7個 | タイムアウト後出しチェック、APKインストール失敗の見逃し |
| 非同期バグ | 2個 | CPUを100%使うビジーループ、設計上の競合リスク |
| 軽微・ADB特有の罠 | 3個 |
\r改行コード残留、一時ファイル放置 |
| テスト欠落 | 2個 | エッジケース未テスト |
ADB特有の知識が必要なバグ(installコマンドのexit code問題など)を意図的に含めています。
指示書(プロンプト)
以下のRustコードにはいくつかのバグがあります。
バグをすべて特定し、修正したコードを提示してください。
バグの説明も日本語で添えてください。
シンプルな指示のみ。モデルの素の実力を測るため、ヒントは一切なし。
検証コード(バグあり版)
// adb_device_manager.rs
use std::process::{Command, Stdio};
use std::time::{Duration, Instant};
use std::sync::{Arc, Mutex};
use tokio::time::sleep;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct AdbDevice {
pub serial: String,
pub state: DeviceState,
pub properties: HashMap<String, String>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum DeviceState {
Online, Offline, Unauthorized, Unknown,
}
pub struct AdbManager {
devices: Arc<Mutex<Vec<AdbDevice>>>,
adb_path: String,
command_timeout: Duration,
}
impl AdbManager {
pub fn new(adb_path: String) -> Self {
AdbManager {
devices: Arc::new(Mutex::new(Vec::new())),
adb_path,
// BUG 1: 5msになっている(本来は5s)
command_timeout: Duration::from_millis(5),
}
}
pub fn execute_command(&self, serial: &str, args: &[&str]) -> Result<String, String> {
let start = Instant::now();
// "-s <serial>" の後にコマンド引数を連結
let mut cmd_args = vec!["-s", serial];
cmd_args.extend_from_slice(args);
let output = Command::new(&self.adb_path)
.args(&cmd_args)
.output()
.map_err(|e| format!("Command failed: {}", e))?;
// BUG 4: タイムアウトをコマンド実行「後」にチェックしている
if start.elapsed() > self.command_timeout {
return Err("timed out".to_string());
}
Ok(String::from_utf8_lossy(&output.stdout).to_string())
}
pub async fn wait_for_device(&self, serial: &str, timeout_secs: u64) -> Result<(), String> {
let deadline = Instant::now() + Duration::from_secs(timeout_secs);
loop {
// BUG 8: sleepがない → CPU 100%
let devices = self.get_connected_devices()?;
if devices.iter().any(|d| d.serial == serial) {
return Ok(());
}
if Instant::now() >= deadline {
return Err("timeout".to_string());
}
}
}
pub fn install_apk(&self, serial: &str, apk_path: &str) -> Result<(), String> {
let result = self.execute_command(serial, &["install", "-r", apk_path])?;
// BUG 11: ADBはinstall失敗時もexit code 0を返す
if result.contains("Failure") {
return Err(format!("Install failed: {}", result));
}
Ok(())
}
pub fn take_screenshot(&self, serial: &str, save_path: &str) -> Result<(), String> {
let temp_path = "/sdcard/screenshot_temp.png";
self.execute_command(serial, &["shell", "screencap", "-p", temp_path])?;
// BUG 12: pullしても一時ファイルを削除していない
self.execute_command(serial, &["pull", temp_path, save_path])?;
Ok(())
}
}
結果
バグ発見数
| モデル | 発見数 | 正解数(/14) |
|---|---|---|
| Gemini 3.1 Pro | 14個 | 14/14 |
| Gemini 3.5 Flash | 14個 | 14/14 |
両モデルとも全バグ発見。精度は同等でした。
出力速度
| モデル | 応答時間(体感) |
|---|---|
| Gemini 3.1 Pro | 約40秒 |
| Gemini 3.5 Flash | 数秒(体感10倍以上) |
これが一番驚いた差です。
修正アプローチの違い
精度は同等でしたが、修正の方向性に興味深い差がありました。
Bug 4(タイムアウト後出しチェック)
3.1 Pro:tokio::time::timeoutを使った非同期タイムアウトに書き直し
3.5 Flash:spawn() + try_wait()のポーリングループで実装
どちらも正しいアプローチですが、3.5 Flashの方がより「sync寄り」の実装を選んでいました。
Bug 10(Mutex poison処理)
3.1 Pro:into_inner()で安全にデータを救出
3.5 Flash:expect()でフェイルファスト
設計思想が逆で、どちらが「正解」かはユースケース次第。こういうところに個性が出ます。
Bug 6(remote_pathのスペース処理)
3.1 Pro:「Command::new経由だから問題ない」とスルー(ADB的に正確な判断)
3.5 Flash:format!("\"{}\"", remote_path)でクォートを追加(やや過剰対応)
ここは3.1 Proの方が正確な理解を示していました。
コスト・速度まとめ
アプリ(無料プラン)
| モデル | 料金 | 速度 |
|---|---|---|
| 3.1 Pro | 無料 | 遅い |
| 3.5 Flash | 無料 | 爆速 |
API(有料プラン / Pay-as-you-go)
Google AI Studioの公式表示はシンプルです。
| モデル | 入力(/100万トークン) | 出力(/100万トークン) |
|---|---|---|
| Gemini 3.5 Flash | $1.50 | $9.00 |
| Gemini 3.1 Flash-Lite | $0.25 | $1.50 |
| Context Caching | $0.15 | — |
出力\$9.00は旧世代「Gemini 3 Flash Preview」(\$3.00)の3倍。Googleの言う「他社フラッグシップより安い」は競合他社との比較であり、自社旧世代との比較では大幅値上げです。
個人開発者向けの整理:
- 検証・プロトタイプ段階 → 無料枠(Free Tier)で十分。トークン課金なし
- 本番・商用運用 → \$1.50/\$9.00。大量出力用途はコスト試算必須
おまけ:Gemini本人に価格を聞いてみたら普通にハルシネーションだった
検証中に「3.5 FlashのAPI料金は?」と本人(?)に聞いてみたところ:
「入力 約\$0.50 / 出力 約\$3.00(/100万トークン)です!」
これ、旧世代「Gemini 3 Flash Preview」の価格です。
正しい価格(\$1.50/\$9.00)を伝えると:
「大変失礼いたしました!ご提示いただいた情報が100%正確です!」
と即謝罪。自分自身の最新料金を把握していないというLLMあるあるなハルシネーションでした。コーディング検証では優秀だったのに、自己紹介でつまずくという...
ハルシネーション検証記事がハルシネーションで締まるのは出来すぎですね。
結論
| 項目 | 判定 |
|---|---|
| コーディング精度(200行・バグ修正) | 3.1 Pro ≒ 3.5 Flash |
| 出力速度 | 3.5 Flash が圧勝(10倍以上) |
| APIコスト(出力) | 3.5 Flash が$9.00/100万トークン(旧世代比3倍) |
| アプリ無料枠での実用性 | 3.5 Flash が最強 |
「アプリの無料枠で使うなら3.5 Flashに乗り換え一択」
「API有料運用でコスト重視なら3.1 Flash-Liteを検討」
Xで言われていた「Sonnet以下」という評価について——少なくともRustコードのバグ修正タスクにおいては、今回の検証範囲では十分実用的でした。ハルシネーションが多いという報告は会話系・情報検索系の話で、コード修正タスクは別物かもしれません。
使用した検証コード(修正済み版)
気になる方はコメントで教えていただければ共有します。
個人開発でMacアプリを作っています。ADB・MTPまわりのTauriアプリ開発に興味がある方はぜひ。