AI 採点を作り込むにあたり、私たちはひとつの問題を長い間議論しました。AI が出した点数は、本採点として数えてよいのか。数えるなら、間違っていたときの責任は誰が取るのか。数えないなら、AI の価値はどこにあるのか。
最終的な結論はこうです。ドラフトを書くのは AI、最終決定を下すのは教師。しかもこの境界は製品説明に書くのではなく、データモデルに書き込みます。
ドラフトは拡張カラムへ、業務状態には触れない
学習記録テーブルには明示的な業務状態カラム(submitted / reviewed など)と点数カラムがあります。AI の出力はこれらのカラムには書き込まず、attributes という JSONB 拡張カラムに書き込みます。
01// 草稿挂在扩展属性上,业务状态列不动02record.attributes["ai_feedback"] = {03 "score": 82,04 "comment": "第二问的推导跳了一步,建议补上边界条件…",05 "model": "glm-4",06 "generated_at": "2026-06-25T10:12:03Z",07 "draft": true08}0910// 终审仍走教师既有的 feedback 接口11POST /tv1/teacher/homeworks/{hid}/feedbackクラス一括採点は部分失敗に耐えられること
ひとつのクラスには数十件の提出があります。7 件目がタイムアウトしただけでバッチ全体をロールバックするわけにはいきません。そこでバッチ API はチャンク単位で処理します。1 件の失敗でバッチを中断せず、エラーは件ごとに返し、次回は自動でリトライします。すでにドラフトがある記録はスキップされるため、トークンを二重に消費しません。
- submitted 状態の記録のみを処理し、最終確認済みのものにはドラフトを生成しない
- ドラフト済みの記録は自動でスキップし、モデルの重複呼び出しを防ぐ
- 1 件の失敗はその件にのみ error を返し、同バッチの他の課題には影響しない
- チャンク処理で 1 バッチの上限は 100。1 リクエストでモデルサービスを落とさないためです
未設定時のグレースフルデグラデーション
LLM エンドポイントが未設定のとき、AI 採点 API は 501 を返し、その他の機能はまったく影響を受けません。この設計により、AI を試したい顧客も、AI を一切受け入れたくない顧客も、同じバージョンを実行できます。
AI が速くできる部分はできる限りやり切ります。しかし「結果に誰が責任を持つのか」という問題だけは、モデルに任せません。