Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

同じ質問に対して毎回異なる回答が返される:Temperature・システムプロンプト・検索安定性のチューニング

はじめに

「同じ質問をしているのに、毎回違う回答が返ってくる」――これはエンタープライズ環境で Dify を運用するチームから最も多く寄せられる不満の一つである。ユーザーから見れば「システムが不安定」に映るこの問題だが、実際にはシステムが壊れているわけではなく、LLM の出力制御が適切に設計されていない状態を示している。

本記事では、回答の不一致を引き起こす3つのレイヤー(LLM パラメータ、プロンプト構造、検索の安定性)を分析し、エンタープライズ品質の安定した出力を実現するための具体的な手法を解説する。


症状

症状具体例
事実関係は同じだが表現が毎回異なる「有給休暇は年20日です」と「年間の有休付与日数は20日となります」
回答の構成や順序が変わる箇条書きの項目順が入れ替わる
同じ質問なのに異なる情報が引用される検索結果が毎回変わるため参照するチャンクが異なる
回答の長さが大きく変動する同じ質問に対して3行の回答と15行の回答が返る
稀に矛盾する回答が返る「可能です」と「できません」が混在する

原因分析

回答の不一致は、単一の原因ではなく3つのレイヤーが複合的に作用して発生する。

flowchart TD
    A[回答の不一致] --> B[レイヤー1: LLMパラメータ]
    A --> C[レイヤー2: プロンプト構造]
    A --> D[レイヤー3: 検索の安定性]
    
    B --> B1[Temperature が高い]
    B --> B2[Top-P が高い]
    B --> B3[Presence/Frequency Penalty]
    
    C --> C1[役割定義が曖昧]
    C --> C2[出力形式が未指定]
    C --> C3[判断基準が不明確]
    
    D --> D1[検索結果が毎回異なる]
    D --> D2[Top-K が大きすぎる]
    D --> D3[Rerank スコアの揺れ]

レイヤー1:LLM パラメータの影響

Temperature(最も重要)

Temperature は LLM の出力における確率分布の「平坦度」を制御するパラメータである。

Temperature 値挙動適用シーン
0.0ほぼ決定的出力(最も確率の高いトークンを常に選択)分類、データ抽出、コード生成
0.1〜0.3高い安定性を維持しつつわずかなバリエーションFAQ回答、マニュアル参照、契約書チェック
0.4〜0.7適度なバリエーション一般的な文章作成、メール下書き
0.8〜1.0高い創造性ブレインストーミング、コピーライティング
1.0超非常に発散的(予測不能)通常は使用しない

重要:Temperature = 0.0 に設定しても、完全に同一の出力が保証されるわけではない。LLM プロバイダのインフラ側での浮動小数点演算の差異や、バッチ処理の違いにより、わずかな揺れが生じる可能性がある。

Top-P(Nucleus Sampling)

Top-P は、累積確率が指定値に達するまでのトークン候補のみを考慮する。Temperature と併用する場合、両方のパラメータが出力の多様性に影響する。

# 安定性を最大化する設定例
llm_settings:
  temperature: 0.1
  top_p: 0.9          # 1.0に近いほど制約が少ない
  max_tokens: 2048
  presence_penalty: 0.0
  frequency_penalty: 0.0

Dify LLM ノードでの設定

Dify の LLM ノードでは、これらのパラメータをノードごとに個別設定できる。

# Workflow LLM ノードの設定
llm_node:
  model: gpt-4o
  temperature: 0.1        # 安定性重視
  top_p: 0.95
  max_tokens: 1024
  system_prompt: |
    あなたは社内規定に基づいて回答するアシスタントです。
    ...

レイヤー2:プロンプト構造の影響

Temperature を下げるだけでは安定性は確保できない。プロンプトの構造が曖昧だと、モデルは「どう答えるか」の自由度が高いため、毎回異なるアプローチで回答する。

不安定なプロンプトの例:

あなたは社内のヘルプデスクです。
ユーザーの質問に丁寧に答えてください。

このプロンプトでは以下が未定義:

  • 回答のフォーマット(箇条書きか、段落か)
  • 情報源の優先順位(ナレッジベースの情報を使うのか、一般知識か)
  • 回答の長さの目安
  • 情報が見つからない場合の挙動
  • 推測や補完をしてよいかどうか

安定したプロンプトの例:

あなたは株式会社ABCの社内ITヘルプデスクアシスタントです。

## 回答ルール
1. 回答は必ず「結論」「詳細」「参考情報」の3セクションで構成すること
2. 回答の根拠は、提供されたコンテキスト情報のみに基づくこと
3. コンテキストに該当する情報がない場合は「この質問についての情報は
   現在のナレッジベースに含まれていません。IT部門(内線: 1234)に
   お問い合わせください」と回答すること
4. 推測や一般的な知識に基づく補完は行わないこと
5. 回答は200文字以内に収めること

## 出力フォーマット
### 結論
[1〜2文で端的に回答]

### 詳細
[必要に応じて箇条書きで補足]

### 参考情報
[参照したドキュメント名を記載]

レイヤー3:検索の安定性

ナレッジベースを使用している場合、同じ質問に対して毎回異なるチャンクが検索されると、LLM に渡されるコンテキストが変わり、結果として回答も変動する。

検索結果が不安定になる原因:

原因メカニズム
ベクトル検索の近似性ANN(近似最近傍)アルゴリズムは完全な再現性を保証しない
Top-K が大きすぎる境界付近のチャンクが入れ替わりやすい
類似スコアが近いチャンクが多いわずかなスコア差で順位が変動する
複数ナレッジベースの検索異なるナレッジベースの結果のマージ順が不安定

解決策

ステップ1:Temperature を適切に設定する

シナリオ別推奨設定:

用途TemperatureTop-P理由
社内FAQ0.0〜0.10.9事実の正確な伝達が最優先
契約書レビュー0.00.9法的リスクの一貫性が必要
技術ドキュメント回答0.1〜0.20.95正確性と自然さのバランス
メール文案作成0.3〜0.50.95適度な表現のバリエーション
アイデア出し0.7〜0.90.95多様な発想が必要

ステップ2:プロンプトに構造的制約を組み込む

構造化出力の強制:

## System Prompt

以下のフォーマットに従って回答してください。
フォーマットから逸脱しないでください。

回答フォーマット:
---
【判定】: [該当 / 非該当 / 判定不能]
【根拠】: [コンテキストから引用した該当箇所]
【補足】: [必要な場合のみ、1〜2文で補足]
---

JSON 出力の強制(Workflow ノード間のデータ受け渡し):

以下のJSON形式で出力してください。JSON以外のテキストは出力しないでください。

{
  "category": "技術質問 | 手続き質問 | クレーム | その他",
  "confidence": 0.0〜1.0,
  "answer": "回答テキスト",
  "source": "参照したドキュメント名"
}

ステップ3:検索の安定性を確保する

# 安定性重視のナレッジベース検索設定
knowledge_retrieval:
  retrieval_mode: hybrid
  top_k: 3                    # 小さめに設定して境界の揺れを抑制
  score_threshold: 0.6        # 高めに設定して低スコアの不安定チャンクを除外
  reranking:
    enabled: true
    model: rerank-multilingual-v3.0

検索安定性向上のためのポイント:

  1. Top-K を小さくする:Top-K=3 なら、上位3件は比較的安定する。Top-K=10 にすると下位の入れ替わりが激しくなる
  2. Score Threshold を高めに設定する:低スコアのチャンクほどスコアの揺れで順位が変動しやすい
  3. Rerank を有効にする:Rerank モデルが一貫した基準で再スコアリングすることで、結果の安定性が向上する
  4. 単一ナレッジベースで検索する:複数ナレッジベースのマージは結果の不安定性を増大させる

ステップ4:出力の後処理で安定性を補強する

LLM の出力に後処理を加えることで、表面的な揺れを吸収する。

flowchart LR
    A[ユーザー質問] --> B[ナレッジ検索]
    B --> C[LLM生成]
    C --> D[フォーマット検証ノード]
    D -->|OK| E[回答返却]
    D -->|NG| F[フォーマット修正ノード]
    F --> E

Code ノードによるフォーマット検証の例:

import json

def main(text: str) -> dict:
    """LLM出力が指定フォーマットに準拠しているか検証する"""
    try:
        result = json.loads(text)
        required_keys = ["category", "confidence", "answer", "source"]
        
        for key in required_keys:
            if key not in result:
                return {
                    "valid": False,
                    "error": f"必須キー '{key}' が欠落しています",
                    "original": text
                }
        
        if result["confidence"] < 0 or result["confidence"] > 1:
            return {
                "valid": False,
                "error": "confidence の値が範囲外です",
                "original": text
            }
        
        return {"valid": True, "data": result}
    
    except json.JSONDecodeError:
        return {
            "valid": False,
            "error": "JSON パース失敗",
            "original": text
        }

ステップ5:シード値の活用(対応モデルの場合)

一部の LLM プロバイダは seed パラメータをサポートしており、同一シードを指定することで出力の再現性を高められる。

# OpenAI API の seed パラメータ(対応モデルの場合)
llm_settings:
  model: gpt-4o
  temperature: 0.0
  seed: 42                # 固定シード値

注意:seed パラメータは出力の再現性を「高める」が、完全な同一性を「保証」するものではない。また、Dify のノード設定画面から直接 seed を設定できない場合は、API 経由でのカスタム設定が必要になる。


予防策

1. アプリケーション設計時のパラメータ設計書

新しい Dify アプリケーションを構築する際、以下の項目を事前に決定しておく。

項目決定事項
Temperature用途に応じた値FAQ: 0.1, 文案: 0.5
出力フォーマット固定テンプレートJSON / 3セクション構造
回答長上限・下限100〜300文字
情報不足時の挙動固定文言「情報がありません」
推測の可否許可/不許可不許可

2. 回帰テストの実施

定期的に同一の質問セットを投入し、回答の一貫性をチェックする。

import hashlib

def test_consistency(api_client, query: str, runs: int = 5):
    """同じ質問を複数回実行し、回答の一貫性を確認する"""
    answers = [api_client.chat(query=query)["answer"] for _ in range(runs)]
    hashes = [hashlib.md5(a.encode()).hexdigest() for a in answers]
    unique = len(set(hashes))
    rate = 1 - (unique - 1) / runs
    return {"query": query, "unique_answers": unique, "consistency_rate": rate}

for q in ["有給休暇の申請方法は", "経費精算の締め日はいつ", "VPN接続できない場合の対処法"]:
    r = test_consistency(client, q)
    print(f"[{'OK' if r['consistency_rate']>=0.8 else 'WARN'}] {q}: {r['consistency_rate']:.0%}")

3. 安定性に関するチェックリスト

  • Temperature は用途に応じて適切に設定されているか
  • システムプロンプトに出力フォーマットが明示されているか
  • 「情報がない場合」の挙動が定義されているか
  • 推測や補完の可否がプロンプトに明記されているか
  • ナレッジベース検索の Top-K は必要最小限か
  • Score Threshold は十分に高く設定されているか
  • Rerank が有効になっているか
  • 定期的な回帰テストの仕組みがあるか

まとめ

回答の不一致が発生した場合、Temperature だけに注目するのは不十分である。真にエンタープライズ品質の安定した出力を実現するためには、以下の3層を統合的に設計する必要がある:

  1. LLM パラメータ層:Temperature を用途に応じて設定し、不必要な発散を抑制する
  2. プロンプト構造層:出力フォーマット、判断基準、拒否条件を明示的に定義し、モデルの自由度を制限する
  3. 検索安定性層:Top-K を絞り、Score Threshold を高めに設定し、Rerank で一貫した再スコアリングを行う

これら3層のうち、最も効果が大きいのはプロンプト構造の改善であることが多い。Temperature を下げるだけで解決しない場合は、まずプロンプトの構造化を見直すことを推奨する。


参考資料