見出し画像

【教育現場のAI活用の提案】Gemini×GAS×スプレッドシートで子どもたちのふり返りを自動的にフィードバックコメントする自己調整学習支援ツールを試作した話

こんにちは、ささです。

夏休みに入り、すっかり考え事モードが続いています。時間にゆとりがある夏休みを利用して普段できない新しいプロジェクトに使えるツールを開発している毎日です。完全に趣味の世界になってきました。


相変わらず長いタイトルですみません。そして結果的に文字数も長くなってしまいました。

結論はそのままタイトルのとおりです。
AIが児童生徒のふりかえりコメントのたたき台を自動でつくってくれる仕組みをスプレッドシート上で確認できるようにな仕組みを試作したってこと。」
成果物はコチラ↓



1. AIもくもく会とXでのポストから生まれたアイデア

以前、参加したAIもくもく会で、教育現場でのAI活用について議論する機会がありました。そこで「AIを使って子どもたちの学習履歴を分析できないか」というアイデアが出ました。

先日、Xで見かけたあるツイートがそのアイデアと結びつきました。

このツイートを見て、「AIを使って子どもたちの自己調整学習をサポートできるのでは?」とひらめきました。

現在、多くの学校で個別指導の時間不足が課題になっています。30人以上の生徒一人ひとりの学習状況を把握し、適切なフィードバックを行うのは容易ではありません。

そこで、Google の Gemini と スプレッドシートを組み合わせた、子どもたちの振り返りを支援するツールを考えました。AIが初期フィードバックを提供し、教師がチェックと追加コメントを行う。そんな流れで、よりきめ細かな学習支援ができるのではないかと考えました。

以降、自己調整学習の基本から試作ツールの仕組み、そして今後の可能性まで、お話しします。AIと教育の新しい可能性、一緒に探ってみませんか?

2. 自己調整学習って何だろう?

自己調整学習、聞いたことはあるけどイマイチピンとこない...そんな方も多いのではないでしょうか? 簡単に言うと、「自分で自分の学びをコントロールする力を育てる」ことです。

具体的には、こんなサイクルを回していきます。例えば小学生の漢字の習得についての学びサイクルでは・・・

  1. 計画(Plan): 「今日は漢字を10個覚えよう」と目標を立てる

  2. 実行(Do): 実際に漢字を勉強する

  3. 分析(Check): 「10個中7個覚えられた。なぜ全部覚えられなかったかな?」と自分の学び方振り返る

  4. 修正(Action): 「明日は覚えやすい方法を考えて、残り3個も覚えよう」と次の計画を立てる

このサイクルを繰り返すことで、子どもたちは少しずつ自分の学習をコントロールできるようになっていきます。

では、AIはこの自己調整学習のどんなところをサポートできそうでしょうか?

  • 振り返りの分析: 「7個覚えられたのはすごいね。特に難しい漢字も覚えられているよ」

  • 次のステップの提案: 「残りの3個は似た形の漢字があるから、一緒に覚えるといいかも」

  • 長期的な成長の可視化: 「先月より覚える速度が上がっているよ。頑張りが実を結んでいるね」

こんなふうに、AIが客観的な視点でフィードバックを提供することで、子どもたち自身の「気づき」を促し、自己調整学習のサイクルをスムーズに回すお手伝いができそうです。

もちろん、AIはあくまでもツール。最終的には子どもたち自身が自分で考え、決断する力を育てることが大切です。AIは、そのプロセスをサポートする「学びの伴走者」として活用できるのではないでしょうか。

3. 今回作ってみた試作品の仕組み

さて、実際に試作したツールの仕組みを紹介します。全体の流れはこんな感じです:

  1. 子どもが Google フォームで振り返りを入力

  2. 入力内容が自動でスプレッドシートに記録

  3. Google Apps Script (GAS) が Gemini API にアクセス

  4. Gemini AI が振り返りを分析し、フィードバックを生成

  5. フィードバックがスプレッドシートにフィードバックコメントを記録

この流れを図にすると、こんな感じになります。

使った役割を簡単に説明すると:

  • Google フォーム:子どもたちが簡単に振り返りを入力できる窓口

  • スプレッドシート:データの保存庫であり、個別フィードバック表示の場所

  • Gemini AI:振り返りの内容を理解し、適切なフィードバックを考える頭脳

  • Google Apps Script (GAS):全体の流れを制御する司令塔

特に Gemini AI を選んだ理由は、その高い言語理解能力と柔軟な対応力です。子どもたちの多様な表現を理解し、個別の状況に応じたフィードバックを生成できます。また、APIが無料だったことも大きいです(2024.7現在)

ポイントは、これらの要素をうまく組み合わせることで、教師の負担を増やすことなく、子どもたち一人ひとりに対して細やかなフィードバックを提供できる点。そして、そのフィードバックが自己調整学習のサイクルを促進するように設計されている点です。

4. 試作品、こんな感じです!

では、実際に作った試作品の画面をお見せしましょう。まずは、子どもたちが使う振り返りフォームから。
試作品のため、名前や単元名などの項目すらまだないのは御愛嬌ということで。

こ子どもたちがこのフォームに回答すると、その内容がスプレッドシートに記録されます。コレ自体は特に何もしなくても記録が溜まっていきます。

スプシにはこんな感じで自動的に「ふり返り」が記録されていく。(標準機能)


このふり返りデータをAI(gemini)に渡し、フィードバックコメントをしてもらうように依頼します。
ちなみに今回のプロンプトは次の通り。

以下は児童生徒の授業後の振り返りです。この振り返りに対する前向きで建設的なフィードバックを作成してください。

フィードバックは以下の点を含むようにしてください:

1. 良かった点の具体的な指摘
2. 改善できる点の優しい示唆
3. 今後の学習に向けた励まし

プロンプト

そのコメントをスプレッドシートに自動で記録させます。

右の文がgeminiによるフィードバックコメント
まだまだプロンプトに改善の余地はありそう

このシートでは:

  • 子どもの振り返り内容

  • AIによるフィードバック

が表示されます。

実際に動かしてみると、子どもたちの回答に応じて、AIが適切なフィードバックを生成してくれます(イマイチなときもまだありますが・・・)。

もちろん、AIの回答は教師がチェックし、必要に応じて修正や追加を行います。

この仕組みにより、子どもたち一人ひとりに対して、迅速かつ個別化されたフィードバックを提供することができます。同時に、教師の負担を軽減しつつ、きめ細かな指導を可能にするのです。

次のセクションでは、この仕組みの具体的な活用方法について考えてみましょう。

5. この仕組み、こんなふうに使えるかも?

さて、この試作品、実際の教育現場でどんなふうに活用できるでしょうか?いくつかの具体的なシーンを想像してみました。

こどもたちの振り返りをサポート

  1. 日々の授業後の振り返り
    例えば、算数の授業後。「今日の分数の足し算、最初は難しかったけど、図を使って考えたらできた!」という振り返りに対して、AIが「図を使う工夫が素晴らしいですね。他の問題でも使えそうですか?」とフィードバック。子どもの「気づき」を強化します。

  2. 週末の学習計画と実績の確認
    金曜日に「来週の漢字テストに向けて、毎日10個ずつ覚える」という計画を立て、月曜日に「土日で15個覚えた」と報告。AIが「目標の半分以上達成できていますね。残りの5個、どんなふうに覚える予定ですか?」と次の行動を促します。

  3. 長期休暇中の学習サポート
    夏休みの自由研究。「海の生き物について調べている」という報告に、AIが「面白そうですね。特にどんな生き物に興味がありますか?図書館で本を借りるのもいいかもしれません」とアドバイス。自主的な学習を後押しします。

先生の負担を減らしつつ、きめ細かなフォロー

  1. 個別のフィードバック作成の自動化
    30人分の振り返りにAIが下書きを作成。先生はそれをベースに、必要な修正や追加コメントを効率的に行えます。

  2. クラス全体の傾向把握のサポート
    AIが振り返りの内容を分析し、「今週は方程式の文章題に苦戦している生徒が多い」といった傾向を報告。先生は次の授業計画に活かせます。

  3. 要支援の生徒の早期発見
    継続的に否定的な振り返りをしている生徒や、学習意欲の低下が見られる生徒を早期に発見。先生が個別対応を行う際の参考になります。

自分の成長を実感できる「足跡」づくり

  1. 頑張ったポイントの可視化
    AIが振り返りから「協力して学んだ」「工夫して問題を解いた」といった良い点を抽出し、一覧表示。自己肯定感の向上につながります。

  2. 目標達成度の記録
    「漢字を50個覚える」といった目標の達成度を記録。達成時にはAIが祝福のメッセージを送り、モチベーション向上を図ります。

このツールを使うことで、子どもたち一人ひとりの学びのプロセスを丁寧に見守り、適切なタイミングで励ましやアドバイスを送ることができます。同時に、先生方の業務負担を軽減しながら、よりきめ細かな指導を実現できる可能性があるのです。


6まとめ 「現場でさくっと使えるツールが強い」


何より学校現場で手軽に使えるツールと言う視点が大事です。なんやかんやで学校の端末には制限がかかります。大掛かりなアプリを導入するって現場で働くイチ教師にとってそんな簡単ではないのです。

→だったら身近なスプレッドシートとフォームで運用できたらいいよねって話です。幸い、勤務校の制限にはGeminiはひっかかりませんでした。


おまけ 実際のGASコード

全体のイメージをclaude3.5に伝えて何度かやり取りをしたのちに出来上がったコード

// スプレッドシートのID(URLから取得できます)
const SPREADSHEET_ID = 'フォームの回答が集まるスプレッドシートのIDを入力してください';
// Gemini APIのAPIキー
const GEMINI_API_KEY = 'ここにgeminiのAPIキーを取得してコピペしてください';
// Gemini APIのエンドポイント
const GEMINI_API_ENDPOINT = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent';

function checkForNewResponses() {
  const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getActiveSheet();
  const lastRow = sheet.getLastRow();
  const lastColumn = sheet.getLastColumn();
  
  // 最後の行から順に処理していく
  for (let row = lastRow; row > 1; row--) {
    const feedbackCell = sheet.getRange(row, lastColumn);
    
    // フィードバックが既に存在する場合はスキップ
    if (feedbackCell.getValue() !== '') {
      continue;
    }
    
    // 回答を取得
    const responseRange = sheet.getRange(row, 2, 1, lastColumn - 2);
    const response = responseRange.getValues()[0].join(' ');
    
    // Gemini APIを使用してフィードバックを生成
    const feedback = generateFeedback(response);
    
    // フィードバックをスプレッドシートに記録
    feedbackCell.setValue(feedback);
    
    // テキストの折り返しを設定
    setWrapTextForRange(responseRange);
    setWrapTextForRange(feedbackCell);
  }
}

// セルのテキスト折り返しを設定する関数
function setWrapTextForRange(range) {
  range.setWrapStrategy(SpreadsheetApp.WrapStrategy.WRAP);
  
  // セルの高さを自動調整
  range.setVerticalAlignment("top");
  range.getSheet().autoResizeRows(range.getRow(), range.getNumRows());
}

function generateFeedback(response) {
  const prompt = `
以下は児童生徒の授業後の振り返りです。この振り返りに対する前向きで建設的なフィードバックを作成してください。
フィードバックは以下の点を含むようにしてください:
1. 良かった点の具体的な指摘
2. 改善できる点の優しい示唆
3. 今後の学習に向けた励まし

振り返り:
${response}

フィードバック:
`;

  const options = {
    'method': 'post',
    'headers': {
      'Content-Type': 'application/json',
      'x-goog-api-key': GEMINI_API_KEY,
    },
    'payload': JSON.stringify({
      'contents': [{
        'parts': [{
          'text': prompt
        }]
      }]
    })
  };

  try {
    const response = UrlFetchApp.fetch(GEMINI_API_ENDPOINT, options);
    const jsonResponse = JSON.parse(response.getContentText());
    return jsonResponse.candidates[0].content.parts[0].text;
  } catch (error) {
    console.error('Error calling Gemini API:', error);
    return 'フィードバックの生成中にエラーが発生しました。';
  }
}

// Gemini APIのテスト関数
function testGeminiAPI() {
  const testPrompt = "こんにちは、元気ですか?";
  
  const options = {
    'method': 'post',
    'headers': {
      'Content-Type': 'application/json',
      'x-goog-api-key': GEMINI_API_KEY,
    },
    'payload': JSON.stringify({
      'contents': [{
        'parts': [{
          'text': testPrompt
        }]
      }]
    })
  };

  try {
    const response = UrlFetchApp.fetch(GEMINI_API_ENDPOINT, options);
    const jsonResponse = JSON.parse(response.getContentText());
    const apiResponse = jsonResponse.candidates[0].content.parts[0].text;
    
    Logger.log('Gemini API Test Result:');
    Logger.log('Prompt: ' + testPrompt);
    Logger.log('Response: ' + apiResponse);
    
    // スプレッドシートにテスト結果を記録(オプション)
    const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getActiveSheet();
    sheet.appendRow(['API Test', new Date(), testPrompt, apiResponse]);
    
    return 'APIテスト成功. ログとスプレッドシートを確認してください。';
  } catch (error) {
    Logger.log('Error testing Gemini API: ' + error);
    return 'APIテスト失敗: ' + error;
  }
}

// 定期的に実行するためのトリガー関数
function setUpTrigger() {
  ScriptApp.newTrigger('checkForNewResponses')
    .timeBased()
    .everyMinutes(5)
    .create();
}

// ... 既存のコード ...

// Gemini APIのテスト関数
function testGeminiAPI() {
  const testPrompt = "以下の質問に簡潔に答えてください:1. 地球は何番目の惑星ですか? 2. 水の化学式は何ですか?";
  
  const options = {
    'method': 'post',
    'headers': {
      'Content-Type': 'application/json',
      'x-goog-api-key': GEMINI_API_KEY,
    },
    'payload': JSON.stringify({
      'contents': [{
        'parts': [{
          'text': testPrompt
        }]
      }]
    })
  };

  try {
    const response = UrlFetchApp.fetch(GEMINI_API_ENDPOINT, options);
    const jsonResponse = JSON.parse(response.getContentText());
    const apiResponse = jsonResponse.candidates[0].content.parts[0].text;
    
    Logger.log('Gemini API Test Result:');
    Logger.log('Prompt: ' + testPrompt);
    Logger.log('Response: ' + apiResponse);
    
    // スプレッドシートにテスト結果を記録
    const sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getActiveSheet();
    sheet.appendRow(['Gemini API Test', new Date(), testPrompt, apiResponse]);
    
    // 応答の内容を確認
    const lowerResponse = apiResponse.toLowerCase();
    const containsThird = lowerResponse.includes('3') || lowerResponse.includes('third') || lowerResponse.includes('三番目');
    const containsH2O = lowerResponse.includes('h2o') || lowerResponse.includes('h₂o');
    
    if (containsThird && containsH2O) {
      return 'APIテスト成功: 正確な回答が得られました。詳細はログとスプレッドシートを確認してください。';
    } else {
      return 'APIテスト警告: 応答は受信されましたが、期待された情報の一部またはすべてが含まれていない可能性があります。ログとスプレッドシートで詳細を確認してください。';
    }
  } catch (error) {
    Logger.log('Error testing Gemini API: ' + error);
    return 'APIテスト失敗: ' + error;
  }
}

// Gemini APIのテスト実行とレポート生成関数
function runAndReportGeminiAPITest() {
  const ui = SpreadsheetApp.getUi();
  const result = testGeminiAPI();
  ui.alert('Gemini APIテスト結果', result, ui.ButtonSet.OK);
}

スプシのIDとgeminiのAPIキーはご自身で取得してコピペしてください。

プログラムの認証後、一回だけfunction setUpTrigger()を動かしてトリガー設定をしてください。

その後はメイン関数であるcheckForNewResponses()が5分おきに発火します。時間間隔はあとからでも変更できます。
すぐに待てないというときには、ボタンクリックでcheckForNewResponses()が動きます。

念の為、ボタンもつけました。

ここまで長ーいこの記事を読んでくれた感謝の気持ちを込めて、この記事で紹介した試作品のフォームとスプシのリンクを共有してお渡ししたいと思います。コメントまたはXにて連絡ください。

追記:予想以上にリクエストが多く、対応しきれなくなってしまいました。とても嬉しいことです。
入力用のフォームURLを紹介させていただきます。試しに入力して挙動を確かめてもらえばと思います。
なお回答用のスプレッドシートはフォームを入力するとURLが出るような仕掛けになっています。

リンク先https://docs.google.com/forms/d/e/1FAIpQLSfnY0GW33R3Ignb12sA-jI0zRqlGgJ3QbrJoZHZ1SZptDKxbw/viewform


この記事が気に入ったらサポートをしてみませんか?