概要
生成AIの回答の確信具合を数値で評価したい。
OpenAI系のAPIのレスポンスは"logprobs"の設定で確信具合を取得できる。
今回はレスポンスからわかる分析データも一緒に表示するチャットシステムを以下の内容をベースに構築する。
logprobsについて
logprobs(log probabilities、対数確率)は、モデルが各トークン(単語や記号など)をどれくらいの確信で予測したかを数値的に示すもの。
Logprobs が高い(0 に近い)ほど、モデルはそのトークンを「自信を持って選んだ」といえる。
各トークンのlogprobsを集計して出力全体の確率を出す。
今回のコードでできること
チャットをすると右側に確信度の分析結果が一緒に出力される。
exp(合計 logprob)が今回の出力が生成される確率。ただし、これは小さくなりすぎるので、比較するなら平均確率で十分だと思われる。

動機
- プロンプトの効果をlogprobsの値を元に分析・比較したい
ソースコード(Pythonファイル)
import gradio as gr
import requests
import json
import math
def chatgpt_chat(message, history, system_prompt):
chatgpt_history = []
if system_prompt and system_prompt.strip():
chatgpt_history.append({"role": "system", "content": system_prompt})
for row in history:
chatgpt_history.append({"role": row["role"], "content": row["content"]})
chatgpt_history.append({"role": "user", "content": message})
try:
url = "http://127.0.0.1:8000/v1/chat/completions"
data = {
"model": "openai/gpt-oss-20b",
"messages": chatgpt_history,
"logprobs": True,
"top_logprobs": 5,
"temperature": 0.7,
"max_tokens": 512,
}
response = requests.post(
url, headers={"Content-Type": "application/json"}, data=json.dumps(data)
)
if response.status_code == 200:
res_json = response.json()
print(json.dumps(res_json, ensure_ascii=False, indent=2)) # デバッグ出力
answer = (
res_json.get("choices", [{}])[0]
.get("message", {})
.get("content", "レスポンスにテキストがありません。")
)
# --- Log probability 情報 ---
logprob_data = res_json.get("choices", [{}])[0].get("logprobs", {})
if logprob_data and "content" in logprob_data:
# 各トークンのlogprobを合計
logprobs_list = [
t["logprob"]
for t in logprob_data["content"]
if "logprob" in t
]
if logprobs_list:
total_logprob = sum(logprobs_list)
avg_logprob = total_logprob / len(logprobs_list)
final_prob = math.exp(total_logprob) # 全体確率(かなり小さくなる)
avg_prob = math.exp(avg_logprob) # 平均確率(1トークンあたり)
logprob_text = (
f"🧮 トークン数: {len(logprobs_list)}\n"
f"🔢 合計 logprob: {total_logprob:.4f}\n"
f"📉 平均 logprob: {avg_logprob:.4f}\n"
f"🎯 平均確率: {avg_prob:.6f}\n"
f"(exp(合計 logprob) = {final_prob:.6e})\n\n"
f"---\n詳細:\n{json.dumps(logprob_data, ensure_ascii=False, indent=2)}"
)
else:
logprob_text = "logprob が含まれていません。"
else:
logprob_text = "(Log probabilities 情報はありません)"
else:
answer = f"Error: {response.status_code}"
logprob_text = response.text
except Exception as e:
answer = "エラーが発生しました。"
logprob_text = str(e)
return answer, logprob_text
# --- UI構築 ---
with gr.Blocks() as demo:
gr.Markdown("## 🤖 ChatGPT ローカルサーバー (/v1/chat/completions 対応)")
system_prompt = gr.Textbox(
label="System Prompt",
value="あなたは親切なAIです。",
interactive=True,
)
with gr.Row():
with gr.Column(scale=3):
chatbot = gr.Chatbot(label="💬 Chat", type="messages", height=500)
user_input = gr.Textbox(label="メッセージを入力", placeholder="入力してEnter...")
send_btn = gr.Button("送信", variant="primary")
with gr.Column(scale=2):
logprob_box = gr.Textbox(
label="🧠 Log Probabilities",
interactive=False,
lines=25,
placeholder="モデルの確率出力がここに表示されます。",
)
# メッセージ処理
def process_message(message, history, system_prompt):
answer, logprobs = chatgpt_chat(message, history, system_prompt)
history = history + [{"role": "user", "content": message}, {"role": "assistant", "content": answer}]
return history, "", logprobs
# ボタンおよびEnterで実行
send_btn.click(
process_message,
inputs=[user_input, chatbot, system_prompt],
outputs=[chatbot, user_input, logprob_box],
)
user_input.submit(
process_message,
inputs=[user_input, chatbot, system_prompt],
outputs=[chatbot, user_input, logprob_box],
)
demo.launch(debug=True, share=False, inbrowser=False)