はじめに
ルーブリック1枚作るのに30〜60分かかっていました。
観点別評価が必須の時代、「16マスの記述基準をひとつずつ考える」作業が地味につらい。そこで Google Apps Script(GAS)× ChatGPT API でこれを5分に圧縮しました。
この記事ではコア実装を紹介します。
Before:何が辛かったか
手作業を分解するとこうなります。
- 新しいシートを作り、タイトル・作成日・合計点欄を置く
- 観点数と段階数を決め、枠を色分けする
- 各マスにA/B/C/Dラベルと配点を入れる
- 16マス分の記述基準を文章でひねり出す(最大の難所)
- 列幅・行高・枠線を整える
1〜3・5は「整える作業」で毎回20分弱を消費。肝心の4が残エネルギーでやっつけになりがちでした。
実装:何を自動化するか
| 担当 | 作業 |
|---|---|
| GAS | 表組み(枠・色分け・配点・ラベル)を自動生成 |
| AI(ChatGPT) | 記述基準の文章をたたき台として生成 |
| 人 | AI下書きの確認・修正・最終判断 |
Step 1: スプレッドシートにメニューを追加
// スプレッドシートを開いた時に「ルーブリック生成」メニューを追加する
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('ルーブリック生成')
.addItem('新規ルーブリック作成', 'createRubric')
.addItem('新規ルーブリック作成(AI記述基準付き)', 'createRubricWithAI')
.addSeparator()
.addItem('APIキーを設定(AI機能用)', 'setApiKey')
.addToUi();
}
onOpen はスプレッドシートを開くと自動実行される特殊関数です。次回からはメニュークリックだけで使えます。
Step 2: 表組みのコア
function generateRubricSheet(criteriaText, numLevels, taskTitle, aiDescriptions) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// 課題名と日付でシート名を作る(上書き防止)
var sheetName = 'ルーブリック_' + taskTitle.substring(0, 15) + '_' +
Utilities.formatDate(new Date(), 'Asia/Tokyo', 'MMdd');
var sheet = ss.getSheetByName(sheetName);
if (sheet) sheetName = sheetName + '_2';
sheet = ss.insertSheet(sheetName);
// 改行区切りで観点を配列化(空行は除外)
var criteria = criteriaText.split('\n').filter(function(c) { return c.trim() !== ''; });
var levelLabels = getLevelLabels(numLevels); // A/B/C/D 等
// 観点(行) × 段階(列) のマスを埋める
for (var j = 0; j < criteria.length; j++) {
var row = j + 4;
sheet.getRange(row, 1).setValue(criteria[j]);
for (var k = 0; k < numLevels; k++) {
var cell = sheet.getRange(row, k + 3);
var cellText = (aiDescriptions && aiDescriptions[j] && aiDescriptions[j].levels[k])
? levelLabels[k] + '(' + (numLevels - k) + '点)\n\n' + aiDescriptions[j].levels[k]
: levelLabels[k] + '(' + (numLevels - k) + '点)\n\n【記述基準をここに入力】';
cell.setValue(cellText);
}
}
}
split('\n').filter(...) で観点を1行ずつ配列に変換。あとは二重ループでマスを埋めるだけです。
Step 3: ChatGPT APIで記述基準を生成
function generateDescriptionsWithAI_(criteriaText, numLevels, taskTitle, apiKey) {
var systemPrompt =
'あなたは中高の理科・物理教員です。ルーブリックの記述基準を作成してください。' +
'各評価観点について、段階ごとに具体的な記述基準(30〜60字)をJSON形式のみで返してください。';
var payload = {
model: 'gpt-4o-mini',
messages: [{ role: 'system', content: systemPrompt }],
temperature: 0.7
};
var response = UrlFetchApp.fetch('https://api.openai.com/v1/chat/completions', {
method: 'post', contentType: 'application/json',
headers: { 'Authorization': 'Bearer ' + apiKey },
payload: JSON.stringify(payload),
muteHttpExceptions: true
});
if (response.getResponseCode() !== 200) return null;
}
2つのポイント:
-
gpt-4o-miniで1枚あたりの費用を数円以下に抑える -
muteHttpExceptions: trueでAPI障害時もGASが落ちない
セキュリティ:APIキーの扱い方
❌ やってはいけないこと
// コードに直書きするとコード共有時にキーが漏れる
var apiKey = 'sk-xxxxxxxxxxxxxxxxxxxx';
✅ 正しい方法:Script Properties に保存
// スクリプトエディタ → プロジェクトの設定 → スクリプト プロパティ に保存
var apiKey = PropertiesService.getScriptProperties().getProperty('OPENAI_API_KEY');
コードを共有してもキーは出ていきません。
個人情報をAIに渡さない
APIに送るのは「観点名・段階数・課題名」だけです。特定の生徒の答案・氏名・成績は送りません。
After:どう変わったか
| 作業 | Before | After |
|---|---|---|
| 表組み(枠・色・配点) | 〜20分 | 数秒(GAS自動) |
| 記述基準の文章 | 30〜40分 | 確認・修正のみ |
| 合計 | 30〜60分 | 5分前後 |
副次効果として「作り直しが気軽になった」ことが大きかったです。手作業だと「また30分」で諦めていた観点調整が、サクッとできるようになりました。
AIの文言は必ず人が確認する
生成された記述基準はあくまで下書きです。
- 学校・学年の評価方針との整合
- 指導要領との合い具合
- 生徒の実態レベル感
これらは人が見て初めて担保されます。ツールでは生成マスに「★要確認」のしるしを入れています。
まとめ
GAS × ChatGPT API で、ルーブリック作成の「考えるべき部分に時間を使える」状態を作れました。
- GASが担う: 表組みの定型作業(枠・色・配点・ラベル)
- AIが担う: 記述基準の文章のたたき台
- 人が担う: 最終確認と修正・評価判断
校務自動化のGASを他にも作っています。通知表コメント・採点集計・テスト問題チェックなど、順次共有予定です。