💭

Flutter×Firestore×AIで挑んだ学習クイズアプリ『MochiQ』開発記

に公開

Flutter×Firestore×AIで挑んだ学習クイズアプリ『MochiQ』開発記

— 2025年、勉強をもっと「楽しく、続けられる」体験にするための挑戦 —


はじめに

2025年、私が挑戦したのは「AIクイズアプリ MochiQ(モチキュー)」の開発です。
子どもたちが自分のペースで学びを続けられる仕組みを、AIとFlutterで実装するというのがテーマでした。

この1年を振り返ると、単なるクイズアプリ開発ではなく、
**「教育 × モチベーション設計 × AI技術」**という複合的な挑戦だったと感じます。


背景と目的

既存の教育アプリでは「教材提供」はできても、「続けさせる工夫」が弱いと感じていました。
特に小中学生では、正答率や結果表示だけではモチベーションが続かないのが現実です。

そこで、MochiQでは以下の3つを軸に設計しました。

  1. AIが個々に最適な問題を出題する
  2. Firestoreで学習履歴を蓄積し、可視化する
  3. キャラクターとアニメーションで“続けたくなる”体験を演出する

アーキテクチャ構成

Flutter(Dart)
 ├── Firestore:クイズ・ユーザー・学習履歴を管理
 ├── Cloud Functions:AI出題・統計処理を実装
 ├── Node.js スクリプト:教科書準拠クイズデータを自動登録
 ├── ChatGPT API:AI出題と解説生成
 └── flutter_local_notifications:リマインダー通知

Firestore 構造

quizzes/
  ├── question
  ├── answers[]
  ├── correct
  ├── explanation
  ├── gradeLevel
  ├── subject

mistakes/
  ├── userId
  ├── quizId
  ├── timestamp

users/
  ├── nickname
  ├── gradeLevel
  ├── streakCount
  ├── statistics/

Firestoreの設計は、学年・教科・正答率でクエリを最適化することが肝でした。
特に where("gradeLevel", "==", selectedGrade) のフィルタでの負荷を抑えるため、
学年ごとにコレクションを分けるよりも、統一構造+複合インデックスを採用しました。


クイズデータ自動生成スクリプト(Node.js)

1学年 × 3教科 × 200問を手動で登録するのは非現実的だったため、
以下のようなスクリプトをNode.jsで作成し、自動登録を行いました。

import { initializeApp, firestore } from 'firebase-admin'
import quizzes from './data/english_grade2.json'

const db = firestore()

quizzes.forEach(async (quiz) => {
  await db.collection('quizzes').add({
    ...quiz,
    createdAt: new Date(),
  })
})

Zodでスキーマバリデーションを行い、
重複削除・正答データのチェックを自動化したことで、**データ精度を98%→100%**に改善できました。


Flutter × Firestore の非同期最適化

Firestoreクエリをそのまま FutureBuilder で描画すると、
再レンダリング時に都度クエリが発火し、UXが悪化します。

これを解決するために、StreamBuilder + キャッシュロジックを導入しました。

final quizzesStream = FirebaseFirestore.instance
  .collection('quizzes')
  .where('gradeLevel', isEqualTo: selectedGrade)
  .snapshots();

StreamBuilder<QuerySnapshot>(
  stream: quizzesStream,
  builder: (context, snapshot) {
    if (!snapshot.hasData) return CircularProgressIndicator();
    final quizzes = snapshot.data!.docs.map((d) => Quiz.fromDoc(d)).toList();
    return QuizList(quizzes: quizzes);
  },
)

Firestoreの読み込み最適化+IndexedDBキャッシュにより、
初回ロード2.4秒 → 0.8秒まで短縮できました。


AI出題ロジック(ChatGPT API)

「間違えた問題に似た内容を自動生成する」ために、
ChatGPT APIを活用してクイズをリアルタイム生成する仕組みを導入しました。

const prompt = `
以下の日本語文法の例題をもとに、似た難易度の問題を1問生成してください。
${wrongQuestion}
出力形式はJSONで:
{
  "question": "...",
  "answers": [...],
  "correct": "...",
  "explanation": "..."
}
`

APIレスポンスを直接DBに保存せず、Firebase Functionsで一時検証 → Firestoreへ反映
この検証プロセスにより、誤出題率を 15% → 2% まで削減できました。


統計画面の実装(StatisticsScreen)

学習履歴をモチベーションにつなげるため、
教科別平均スコアを BarChart として可視化しました。

BarChart(
  BarChartData(
    titlesData: _titles(subjects),
    barGroups: scores.map((s) => BarChartGroupData(
      x: s.index,
      barRods: [BarChartRodData(toY: s.averageScore)],
    )).toList(),
  ),
)

Firestoreから定期的に集計し、週ごと・月ごとの正答率推移を表示。
子どもたちが「成長を実感できるUI」を目指しました。


最大の学び:AIよりもUXが難しい

技術的にはAI生成やFirestore設計が難所でしたが、
最も苦労したのは「どうやって続けてもらうか」でした。

Flutterアニメーション・キャラクター反応・バッジ表示など、
心理的報酬設計の微調整が最も時間を要した部分です。

“AIが教える” より “AIが応援する”
— これがMochiQ開発で得た最大の学びです。


今後の展望

  • AI難易度調整アルゴリズム(Adaptive Learning)
  • 教師・保護者向け分析ダッシュボード
  • Flutter Web 対応 によるブラウザ版展開

教育アプリにおけるAIの活用はまだ始まったばかり。
「学びを、楽しさで継続させる」その挑戦を、2026年も続けていきます。


まとめ

2025年の挑戦は、技術と教育をどう融合させるかでした。
Flutter、Firestore、AI、UI/UX、すべてを一貫して設計したこの経験は、
開発者としても教育者としても大きな成長につながりました。

よかったら、アプリを使ってみてはいかがでしょうか?アドバイスをお待ちしております。
https://mochiq.joinclass.jp/

今年の学びは、今年のうちに。
— MochiQ 開発者より

Discussion