0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Gemini APIのスコアリングを安定させる5つのテクニック

0
Posted at

はじめに

僕はGemini APIを使って、動画や画像を分析し0〜100点のスコアを返すシステムを開発しています。

ところが、同じ入力を2回分析しても、スコアが ±15〜20点ブレるという問題に直面しました。

1回目: B (68点)
2回目: A (80点)

これではユーザーの信頼を得られません。

この記事では、試行錯誤の末にAPIコスト増なしでブレを ±5点以内に抑えた5つのテクニックを紹介します。

前提: パラメータだけでは解決できない

最初に試したのは Gemini API の生成パラメータの調整でした。

generationConfig: {
  temperature: 0,
  topK: 1,
  seed: 42,
}

結果: 最高評価が連発しました。

ランダム性を完全に排除すると、モデルが「最も確率の高いトークン」だけを選ぶため、高スコア方向に偏ります。Gemini の seed パラメータもベストエフォートであり、決定論的な出力は保証されません。

パラメータチューニングだけでスコア安定化は不可能というのが最初の学びでした。

テクニック1: スコアを5点刻みに制限する

最もインパクトが大きかった変更です。

LLMにとって「67点と73点の違い」を一貫して判断するのは難しい。しかし「65点と75点のどちらか」なら、判断の分解能が下がる分、一貫性が上がります。

プロンプト側

**重要**: スコアは必ず5の倍数で返すこと(例: 65, 70, 75)。中間値(67, 73等)は禁止。

サーバー側(バリデーション)

LLMがプロンプトを無視して中間値を返すことがあるので、サーバー側でも丸めます。

const roundTo5 = (score: number): number => Math.round(score / 5) * 5;

for (const item of result.items) {
  if (typeof item.score === "number") {
    const rounded = roundTo5(item.score);
    if (item.score !== rounded) {
      item.score = rounded;
    }
  }
}

プロンプトで指示 + サーバーで強制の二重保証がポイントです。

テクニック2: CoT(Chain-of-Thought)スコアリング

通常のプロンプト:

各項目にスコアとコメントを付けてください。

これだと、LLMは「なんとなく」スコアを決めがちです。

改善後: 思考の手順を明示的に指定します。

## スコアリング手順(この順序に従うこと)
1. まず対象を観察し、各評価軸ごとに「何が見えたか」を事実として列挙する
2. 各事実をルーブリックの段階(S/A/B/C/D)に照合し、該当する段階を決定する
3. 該当段階のスコアレンジ内で、5点刻みのスコアを1つ選ぶ
4. 全軸のスコア平均を計算し、overallScore とする
5. overallScore に対応するグレードを判定する

「観察 → ルーブリック照合 → スコア決定」の順序を強制することで、根拠に基づいたスコアリングになり、ブレが減ります。

テクニック3: 複数グレードの出力例でアンカリング

改善前のプロンプトには中間グレードの出力例が1つだけありました。

// Bグレードの例のみ
{ "overallGrade": "B", "overallScore": 68, ... }

これだとLLMは「Bグレードの雰囲気」しか掴めず、S〜Dのスケール感が不安定になります。

改善後: S(高評価)・B(中間)・D(低評価)の3パターンの出力例を追加しました。

// Sグレード(90100点)の例
{ "overallGrade": "S", "overallScore": 95,
  "items": [{ "category": "項目A", "score": 95, "comment": "..." }] }

// Bグレード(6074点)の例
{ "overallGrade": "B", "overallScore": 65,
  "items": [{ "category": "項目A", "score": 75, "comment": "..." }] }

// Dグレード(039点)の例
{ "overallGrade": "D", "overallScore": 30,
  "items": [{ "category": "項目A", "score": 25, "comment": "..." }] }

スケールの「両端と中央」を例示することで、LLMがスコアレンジ全体を正しく認識できるようになります。これをアンカリングと呼びます。

テクニック4: カテゴリ別ルーブリック(採点基準表)

「良いかどうか」の基準が曖昧だと、LLMは毎回違う観点で採点します。

解決策として、評価カテゴリごとの詳細なルーブリックを作成しました。

### 評価項目X
- S(90-100): [具体的な観察可能な基準]
- A(75-89): [具体的な観察可能な基準]
- B(60-74): [具体的な観察可能な基準]
- C(40-59): [具体的な観察可能な基準]
- D(0-39): [具体的な観察可能な基準]

各スコアレンジに具体的な観察可能な基準を紐づけることで、「この状態はB(60-74)の範囲だ」という判断が安定します。

ルーブリックの設計は手間がかかりますが、スコア安定化への効果は絶大です。

テクニック5: overallScoreをサーバー側で再計算する

LLMに overallScore と各項目の score を両方返させると、しばしば矛盾が生まれます。

{
  "overallScore": 82,
  "items": [
    { "score": 70 }, { "score": 65 }, { "score": 75 },
    { "score": 60 }, { "score": 70 }, { "score": 65 }
    // 平均: 67.5 なのに overallScore  82...
  ]
}

これを防ぐため、overallScore はLLMの出力を信用せず、サーバー側で各項目の平均から再計算します。

const avgScore = items.reduce(
  (sum, item) => sum + item.score, 0
) / items.length;
result.overallScore = roundTo5(avgScore);

// グレードもスコアから再計算
const scoreToGrade = (score: number): string => {
  if (score >= 90) return "S";
  if (score >= 75) return "A";
  if (score >= 60) return "B";
  if (score >= 40) return "C";
  return "D";
};
result.overallGrade = scoreToGrade(result.overallScore);

LLMの出力は「各項目のスコア」だけを信頼し、集計はコードで行う。これにより、少なくとも「個別スコアと総合スコアの矛盾」は完全に排除できます。

temperature の設定

最終的に temperature: 0.1 に落ち着きました。

結果
0 (+ topK:1, seed:42) 高評価に偏る。使い物にならない
0.1 安定性と多様性のバランスが良い
0.3 やや安定。ブレは残る
1.0(デフォルト) ブレが大きい

temperature: 0 がダメだったのは意外でした。完全に貪欲なデコーディングにすると、モデルが「最も無難な(=高い)スコア」に偏る傾向があるようです。

まとめ

テクニック 効果 コスト
5点刻みスコア ◎ ブレ幅を物理的に制限 なし
CoTスコアリング ◎ 根拠ベースの採点 出力トークン微増
複数グレードの出力例 ○ スケール全体を固定 プロンプト長増加
カテゴリ別ルーブリック ◎ 採点基準の統一 設計工数
overallScore再計算 ○ 矛盾を排除 なし

最も重要な学び: LLMのスコアリング安定化は、パラメータチューニングではなくプロンプト設計で解決する問題でした。

「何を見て、何を基準に、どう判断するか」を明確に指示すれば、LLMは驚くほど一貫した採点者になります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?