Summary
- 「ローカル動作するJevっぽいものを調べてたら、なんとマルチモーダル対応もできてた!」に触発され、M1 Mac mini上のIBM Granite 4.1 3Bで、
logprobsを利用したJev風の選択判定を試した - 日本語Amazonレビュー3,000件の感情分析では正答率70%、応答時間は中央値401ms、平均486msとなり、ローカルLLMとして十分な速度で動作した
- positiveとnegativeは比較的判定できた一方、neutralでは高い確信度で誤答するケースが多く、汎用性・確率の信頼性ではJevが優れる結果となった
やらないこと
- Jevの実行(すでに色々な方が実践されているので・・・)
- Jevの完全互換実装
- JevとGraniteの厳密な同一条件での比較
今回の感情分析は、データセットのラベルをそのまま正解として評価したものである。レビューの感情には人間でも判断が分かれるものが含まれるため、正解率だけでモデルの能力を完全に評価できるわけではない。
本記事のポイント
きっかけ
今回の出発点は、ローカル動作するJevっぽいものを調べてたら、なんとマルチモーダル対応もできてた!を読んだことである。この記事では、llama.cppとQwen3-VLを組み合わせ、Jevのように選択肢ごとの確率を取得する仕組みが紹介されている。
IBM製のオープンLLMであるGraniteを活用してみるとどうなるだろうか?と考えた。問い合わせの分類や感情分析のようなテキスト判定であれば、軽量なローカルLLMでも十分試せるのではないか。
そこで、手持ちのM1 Mac mini上にGranite 4.1 3Bを構築し、Jevに似た選択判定と、日本語のAmazonレビュー文章の感情分析を試すことにした。
Jevとは何か
Jevは、一般的なチャットボットのように長い文章を生成するためのサービスではない。
入力された文章や状態に対して、あらかじめ定義された質問への判断結果を構造化して返す。代表的な判定形式には、次のようなものがある。
-
Choice:複数の選択肢から一つを選ぶ -
Score:定義された尺度でスコアを返す -
Noul:ある主張が真かどうかを判定する
たとえば、問い合わせの担当部署を判定する場合、通常のLLMは次のような文章を返す。
この問い合わせはネットワーク障害に関する内容なので、
情報システム部門が担当するのが適切です。
Jevのような仕組みでは、アプリケーションが扱いやすい形で結果を返す。
{
"choice": "technical",
"probabilities": {
"technical": 0.82,
"billing": 0.12,
"sales": 0.06
},
"confidence": 0.82
}
この形式であれば、回答文から担当部署を抽出する処理は不要である。結果をそのままルーティングに利用し、確信度が低い場合だけ人間の確認に回す、といった実装が可能になる。
Jevを複数の汎用LLMと比較した検証では、Jevは常に最高精度になるモデルではないものの、速度、費用、確率の扱いやすさに強みがあると報告されている。
ローカルLLMでJevっぽい回答を得る方法
今回のローカルLLMでは、選択肢のラベルを1文字に割り当てる。
A: negative
B: neutral
C: positive
そして、モデルには次のように指示する。
Answer with a single letter.
APIリクエストでは、出力トークン数を1に制限する。
{
"max_tokens": 1,
"logprobs": true,
"top_logprobs": 5
}
LLMは、次に出力するトークンの候補それぞれに確率を持っている。たとえば、感情分析で次のような分布になったとする。
A: 0.10
B: 0.15
C: 0.75
この場合はC、つまり解答がpositiveである可能性が最も高いことを示す。logprobsで返る値は対数確率であるため、通常の確率へ戻すにはexpを使う。
probability = exp(logprob)
参考記事で、max_tokens: 1で生成を止め、logprobsとtop_logprobsから候補と確率を取得する方法が説明されている。
確率は正答確率そのものではない
ここで注意したいのは、取得した確率をそのまま正答確率と考えてはいけないことである。取得しているのは、あくまで次に出力するトークンの確率である。
Cのトークンを出力する確率が95%
という結果は、
この判定が95%の確率で正しい
という意味ではない。
今回の実験でも、誤答にもかかわらず90%以上の確信度を示すケースが確認できた。特にneutralの判定では、この問題が顕著であった。
モデルが高い確信度を示しているにもかかわらず、正解ラベルと一致しない場合がある。そのため、確信度は人手確認へ回す基準の候補にはなるが、検証なしに正答率と読み替えてはいけない。
やったこと
実行環境
今回の実験は、すべてM1 Mac mini上で実施した。
- CPU: Apple M1
- Memory: 16GB
- Runtime:
llama.cpp - Model: IBM Granite 4.1 3B
-
granite-4.1-3b-Q4_K_S.ggufを利用した - 3Bクラスの量子化モデルであるため、リソースの潤沢でないPCでも動かしやすい
-
Jevのような判断専用モデルと同じ能力を期待することはできないが、問い合わせ分類やレビュー分類のような定型的な判定であれば、ローカルでも十分に動作する可能性がある。
llama-serverを起動する
GGUFファイルを指定し、llama-serverを起動する。
./llama-server \
-m /path/to/llm/granite-4.1-3b-Q4_K_S.gguf \
--port 8081 \
-c 4096
起動後は、OpenAI互換のChat Completions APIを利用できる。
http://127.0.0.1:8081/v1/chat/completions
今回は短い問い合わせやレビューを扱うため、コンテキスト長は4096に絞った。コンテキスト長を大きくすると長文を扱いやすくなる一方、メモリ使用量や処理時間への影響があるためである。
例題(社内ITの問い合わせ)の選択判定
まず、Claudeに適当な問題を作ってもらった。社内ページが開けない問い合わせを例にした。
次の問い合わせについて、最初に確認すべき事項として
最も適切なものを選んで。アルファベット1文字で回答して。
問い合わせ:
午前中から社内のページが開けません。勤怠のページもファイル置き場も表示されず、
何度更新しても同じです。会社のスマートフォンからはインターネットを使えるので、
インターネット全体が止まっているわけではなさそうです。パソコンの右下にある
マークがいつもと違うのですが、どこを見ればよいのか分かりません。
A: 利用者のメール署名を作り直す
B: プリンターの印刷キューをすべて削除する
C: パソコンが社内ネットワークまたはWi-Fiに接続されているか確認する
実行コマンドは次のとおりである。
curl -s http://127.0.0.1:8081/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages":[{
"role":"user",
"content":"次の問い合わせについて、最初に確認すべき事項として最も適切なものを選んで。アルファベット1文字で回答して。
問い合わせ:午前中から社内のページが開けません。勤怠のページもファイル置き場も表示されず、何度更新しても同じです。会社のスマートフォンからはインターネットを使えるので、インターネット全体が止まっているわけではなさそうです。パソコンの右下にあるマークがいつもと違うのですが、どこを見ればよいのか分かりません。
A: 利用者のメール署名を作り直す
B: プリンターの印刷キューをすべて削除する
C: パソコンが社内ネットワークまたはWi-Fiに接続されているか確認する"
}],
"max_tokens": 1,
"logprobs": true,
"top_logprobs": 5
}' \
| jq '[.choices[0].logprobs.content[0].top_logprobs[]
| {token, prob: ((.logprob | exp) * 100)}]'
結果は次のようになった。
[
{
"token": "C",
"prob": 99.99998807907176
},
{
"token": "c",
"prob": 0.00001051330716206155
},
{
"token": "B",
"prob": 0.00000004098888708075776
},
{
"token": "D",
"prob": 0.00000000392670198508416
},
{
"token": "A",
"prob": 0.0000000032096384308787535
}
]
正答であるCが、ほぼすべての確率を占めた。
このように、問い合わせの状況と選択肢の対応が明確な問題では、Granite 4.1 3Bでも期待通りに判定できた。
計算問題では誤答した
次に、計算問題を試した。
次の計算結果として最も適切なのはどれ?アルファベット1文字で回答して。
37 + 48 = ?
A: 75
B: 85
C: 95
正答はBである。しかし、1トークンだけ生成させると、次のような結果になった。
[
{
"token": "A",
"prob": 0.7764694159509001
},
{
"token": "B",
"prob": 0.1632617626813211
},
{
"token": "C",
"prob": 0.023538035366513613
},
{
"token": "最",
"prob": 0.014071944493287627
},
{
"token": "",
"prob": 0.009015754615200005
}
]
正答のBではなく、Aの確率が最も高くなった。一方、回答を1文字に制限せず、普通に計算(文章を生成)させると正答した。
curl -s http://127.0.0.1:8081/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"messages":[{
"role":"user",
"content":"37+48=?"
}]
}' \
| jq .
返答は次のような内容であった。
The sum of 37 and 48 is 85.
37 + 48 = 85
You can arrive at this result by adding the tens and ones places separately:
- Tens place: 30 + 40 = 70
- Ones place: 7 + 8 = 15
Then, combine the results:
70 + 15 = 85
つまり、モデルは自由に推論すれば正答できるが、最初からA、B、Cの1文字だけを求めると、計算に必要な推論を十分に行えない場合がある。
自由推論と記号抽出を分ける
この問題への対策として、2段階方式を試した。
Step 1:制約なしで問題を解き、根拠を説明させる
Step 2:根拠と問題文を確認し、選択肢の記号だけを出力させる
Step 1では、計算や判断のために十分な出力を許可する。
そして、Step 2では、選択肢の記号だけを出力させる。さらに、llama.cppの文法制約を使い、出力をA、B、Cに限定する。
root ::= [ABC]
実装例は次のとおりである。
ask_choice() {
local question="$1"
local grammar_chars
grammar_chars=$(echo "$question" \
| grep -oE '^[A-Z]:' \
| tr -d ':' \
| tr -d '\n')
if [[ -z "$grammar_chars" ]]; then
echo "Error: 問題文からA-Zのラベル行が検出できませんでした" >&2
return 1
fi
local step1_payload step1
step1_payload=$(jq -n --arg q "$question" \
'{
messages: [{
role: "user",
content: (
"次の問題に対して、選択肢の中から最も適切なものを選び、"
+ "根拠を簡潔に説明して。\n\n"
+ $q
)
}],
max_tokens: 200,
temperature: 0.2,
top_p: 0.9
}')
step1=$(curl -s \
http://127.0.0.1:8081/v1/chat/completions \
-H "Content-Type: application/json" \
-d "$step1_payload" \
| jq -r '.choices[0].message.content')
if [[ -n "$ASK_CHOICE_DEBUG" ]]; then
echo "=== STEP1 ===" >&2
echo "$step1" >&2
echo "==============" >&2
fi
local step2_payload answer
step2_payload=$(jq -n \
--arg q "$question" \
--arg ans "$step1" \
--arg g "root ::= [${grammar_chars}]" \
'{
messages: [{
role: "user",
content: (
"以下は問題文(選択肢を含む)と、それに対する回答の根拠です。"
+ "回答の根拠が導いた結論に最も合致する選択肢の記号1文字だけを出力して。\n\n"
+ "問題文:\n"
+ $q
+ "\n\n回答の根拠:\n"
+ $ans
)
}],
max_tokens: 2,
temperature: 0,
grammar: $g
}')
answer=$(curl -s \
http://127.0.0.1:8081/v1/chat/completions \
-H "Content-Type: application/json" \
-d "$step2_payload" \
| jq -r '.choices[0].message.content')
echo "$answer"
}
この関数を利用し、先ほどの問題を解く。
ask_choice "37 + 48 = ?
A: 75
B: 85
C: 95"
結果は次のようになり、正答できることを確認した。
B
ただし、これでは二度推論が走り、効率が良いとは言えない。また、問題によっては、二度目の推論がなくとも正答できるケースもあった。したがって、以前から言及されていることではあるが、計算問題とは相性が悪く、ユースケースとして向かないものと思われる。
日本語Amazonレビューの感情分析
利用したデータセット
次に、日本語Amazonレビューの感情分析を試した。こちらのデータセットを拝借した。
このテストデータには、Amazonレビューと、positive、neutral、negativeの感情ラベルが含まれている。今回の判定では、感情と選択肢を次のように対応付けた。
A: negative
B: neutral
C: positive
モデルへ与えたプロンプトは次のようなものである。
Classify the following user review as either negative, neutral, or positive.
Answer with a single letter.
Review: <レビュー本文>
A: negative
B: neutral
C: positive
ベンチマーク用スクリプトを実装した
レビューを3,000件手作業でcurlするのは現実的ではない。そこで、CSVファイルを読み込み、レビューを1件ずつllama-serverへ送信するBashスクリプトを実装した。
このスクリプトでは、次の処理を行う。
- CSVファイルを1行ずつ読み込む
- レビュー本文と正解ラベルを取り出す
-
curlでllama-serverへ問い合わせる - 応答時間をミリ秒単位で計測する
-
logprobsを確率へ変換する -
A、B、Cを感情ラベルへ変換する - 正解・不正解を判定する
- 累計正答率を表示する
- 応答時間の最小値、中央値、平均値、最大値を表示する
- 全件処理後に最終正答率を表示する
#!/bin/bash
# 環境変数のデフォルト値設定
ENDPOINT="${ENDPOINT:-http://127.0.0.1:8081/v1/chat/completions}"
CSV_FILE="${1:-.}"
# 使用方法
if [[ ! -f "$CSV_FILE" ]]; then
echo "Usage: $0 <csv_file>"
echo "Environment: ENDPOINT (default: http://127.0.0.1:8081/v1/chat/completions)"
exit 1
fi
echo "=========================================="
echo "Sentiment Classification Benchmark"
echo "=========================================="
echo "Endpoint: $ENDPOINT"
echo "CSV File: $CSV_FILE"
echo "=========================================="
echo ""
declare -a RESPONSE_TIMES
correct_count=0
total_tests=0
# CSVファイルを1行ずつ処理
while IFS=',' read -r text sentiment source; do
((total_tests++))
# ヘッダー行をスキップ
if [[ $total_tests -eq 1 ]]; then
continue
fi
text=$(echo "$text" | sed 's/^[[:space:]]*"//; s/"[[:space:]]*$//')
sentiment=$(echo "$sentiment" | sed 's/^[[:space:]]*"//; s/"[[:space:]]*$//')
item_num=$((total_tests - 1))
echo "=== Item $item_num ==="
echo "Text: $text"
echo ""
start_time=$(date +%s%N)
response=$(curl -s "$ENDPOINT" \
-H "Content-Type: application/json" \
-d '{
"messages": [{
"role": "user",
"content": "Classify the following user review as either negative, neutral, or positive. Answer with a single letter.\n\nReview: '"$text"'\n\nA: negative\nB: neutral\nC: positive"
}],
"max_tokens": 1,
"logprobs": true,
"top_logprobs": 5,
"temperature": 0
}')
end_time=$(date +%s%N)
response_time=$(( (end_time - start_time) / 1000000 ))
RESPONSE_TIMES+=("$response_time")
answer=$(echo "$response" \
| jq -r '.choices[0].logprobs.content[0].top_logprobs[0].token')
logprob=$(echo "$response" \
| jq '.choices[0].logprobs.content[0].top_logprobs[0].logprob')
confidence=$(echo "$logprob" \
| awk '{printf "%.2f", exp($1) * 100}')
answer=$(echo "$answer" | tr '[:lower:]' '[:upper:]')
case "$answer" in
A) predicted_sentiment="negative" ;;
B) predicted_sentiment="neutral" ;;
C) predicted_sentiment="positive" ;;
*) predicted_sentiment="unknown" ;;
esac
is_correct=0
if [[ "$predicted_sentiment" == "$sentiment" ]]; then
((correct_count++))
is_correct=1
fi
cumulative_accuracy=$(( correct_count * 100 / (total_tests - 1) ))
min_time=${RESPONSE_TIMES[0]}
max_time=${RESPONSE_TIMES[0]}
sum_time=0
for time in "${RESPONSE_TIMES[@]}"; do
if (( time < min_time )); then min_time=$time; fi
if (( time > max_time )); then max_time=$time; fi
((sum_time += time))
done
avg_time=$(( sum_time / (total_tests - 1) ))
sorted_times=($(printf '%s\n' "${RESPONSE_TIMES[@]}" | sort -n))
n=${#RESPONSE_TIMES[@]}
if (( n % 2 == 1 )); then
median_time=${sorted_times[$((n / 2))]}
else
median_time=$(( \
(sorted_times[$((n / 2 - 1))] + sorted_times[$((n / 2))]) / 2 \
))
fi
echo "--- Answer ---"
if [[ $is_correct -eq 1 ]]; then
echo "Predicted: $predicted_sentiment [CORRECT]"
else
echo "Predicted: $predicted_sentiment [INCORRECT]"
fi
echo "Correct : $sentiment"
echo ""
echo "--- Results ---"
printf "Current Response Speed : %dms\n" "$response_time"
printf "Cumulative Response Speed: min=%dms, median=%dms, avg=%dms, max=%dms\n" \
"$min_time" "$median_time" "$avg_time" "$max_time"
printf "Confidence : %.2f%%\n" "$confidence"
printf "Accuracy : %d/%d (%d%%)\n" \
"$correct_count" "$((total_tests - 1))" "$cumulative_accuracy"
echo ""
done < "$CSV_FILE"
echo "=========================================="
echo "=== Final Statistics ==="
echo "Total tests: $((total_tests - 1))"
overall_accuracy=$(( correct_count * 100 / (total_tests - 1) ))
echo "Overall accuracy: $overall_accuracy% ($correct_count/$((total_tests - 1))"
echo "=========================================="
スクリプトの出力
実行結果を以下に示す。3,000件のテストデータをGraniteに分類させた。
(中略)
=== Item 2999 ===
Text: (省略)
--- Answer ---
Predicted: positive [CORRECT]
Correct : positive
--- Results ---
Current Response Speed : 400ms
Cumulative Response Speed: min=13ms, median=401ms, avg=486ms, max=4320ms
Confidence : 100.00%
Accuracy : 2104/2999 (70%)
=== Item 3000 ===
Text: (省略)
--- Answer ---
Predicted: positive [CORRECT]
Correct : positive
--- Results ---
Current Response Speed : 276ms
Cumulative Response Speed: min=13ms, median=401ms, avg=486ms, max=4320ms
Confidence : 100.00%
Accuracy : 2105/3000 (70%)
==========================================
=== Final Statistics ===
Total tests: 3000
Overall accuracy: 70% (2105/3000)
==========================================
感情分析の結果
3,000件を処理した結果は次のとおりである。 正答率は70% であった。
| 指標 | 結果 |
|---|---|
| テスト件数 | 3,000件 |
| 正解件数 | 2,105件 |
| 誤答件数 | 895件 |
| 正答率 | 70% |
| 最小応答時間 | 13ms |
| 中央値 | 401ms |
| 平均値 | 486ms |
| 最大応答時間 | 4,320ms |
Jevの比較検証では、日本語商品レビュー3クラス分類の正答率が82.5%であった。評価条件、モデル、プロンプト、サンプル数が異なるため単純比較はできないが、今回のGranite 4.1 3BはJevより明確に低い結果となった。
一方、ローカルLLMの検証として見ると、3,000件を外部APIなしで処理し、70%の正答率を得られた点は悪くないと考えている。
結果の考察
positiveとnegativeは比較的判定しやすかった
今回の実行結果を確認すると、positiveとnegativeが正解ラベルであるレビューでは、多くのケースで正答していた。positiveとnegativeは、レビュー本文に感情を直接表す表現が含まれることが多い。そのため、小規模なローカルLLMでも分類しやすかったと考えられる。
neutralの判定で苦戦した
一方、neutralでは誤答が多かった。neutralのレビューには、次のような特徴がある。
- 強い満足も不満も表明していない
- 商品の事実だけを説明している
- 一部は満足しているが、一部には不満がある
- 「普通」「値段相応」「可もなく不可もなく」といった曖昧な表現がある
- positiveまたはnegativeの表現を含むが、全体としては中立である
例えば、次のレビューは判断が難しい。
目的は果たせましたが、特に感動はありません。
これはneutralとも読めるが、文脈によってはpositiveにも読める。
値段相応の商品です。
このレビューも、neutralと判断できる一方で、表現上はややnegativeに感じられる可能性がある。
感情分析の正解ラベルがneutralであっても、レビューの文章だけから一意に判断できるとは限らない。この曖昧さが、今回の誤答の大きな要因になったと考えている。
高い確信度でneutralを誤答する
今回の検証で特に気になったのは、neutralの誤答だけではない。誤答しているにもかかわらず、90%以上の確信度を示すケースが存在した。モデルが次のような判断をしていたことになる。
予測:positive
確信度:90%以上
正解:neutral
これは、実運用では注意が必要な挙動である。単純に「確信度が低いものだけ人間に回す」という設計にすると、このような誤答を見逃す可能性がある。モデルがneutralをpositiveやnegativeへ寄せる傾向を持っている場合、確信度だけでは判断の安全性を担保できない。
今回取得した確信度は、モデルが次に出力したラベルのトークン確率である。データセットの正解率に対して校正された確率ではないため、当然ながらこのようなことは起こり得る。この点は、Jevとの大きな違いである。
Jevの比較検証では、出力された確率やconfidenceが実際の正解率とどの程度一致するかも評価されていた。一方、今回のGraniteや一般的なローカルでは、確信度の校正を実施しない。
したがって、今後実用化するなら、次のような対策が必要になる。
- neutral判定専用のプロンプトを用意する
- positive、neutral、negativeの判断基準を明示する
- 代表的なneutralレビューをFew-shot例として与える
- 選択肢の説明文を改善する
- 出力確率を検証データで校正する
- neutralの判定だけ別モデルやルールで再確認する
- positiveとnegativeの差が小さい場合はneutralへ寄せる処理を検討する
まとめ・所感
GraniteでもJevっぽい仕組みは作れる
今回は、ローカルLLMでJevのような判定を実現し、さらにマルチモーダル対応まで行っていた記事を読み、「Graniteだったらどうなるんだろう」と考え、IBM Granite 4.1 3BをM1 Mac mini上で動かした。
結果として、次の仕組みは実現できた。
- 選択肢をA、B、Cなどの記号へ変換する
-
logprobsから候補と確率を取得する - 判定結果を感情ラベルへ変換する
一方で、計算問題のように途中の推論が必要なタスクでは、最初から1トークンに制限すると誤答するケースがあった。複雑な問題において、従来のLLMでは自由推論と記号抽出を分離する必要があると思われるが、Jevではそうした分離が必要ない点は新たな特徴と言えるだろう。
GraniteによるAmazonレビュー感情分析は正答率70%
日本語Amazonレビュー3,000件に対して感情分析を行った結果、正答率は70%であった。また、応答速度の
中央値401ms、平均486msで3,000件を処理できた。
Jevの比較検証では、Jevの日本語レビュー感情分析の応答時間中央値は約241msであり、正答率は82.5%であった。また、フロンティアモデルを使った実験では、日本語レビュー分類におけるOpenAIモデルの中央値が約647〜798msであったとのこと。
今回のGraniteは、正答率と速度の両面でJevに及ばなかった。ただし、外部APIではなく、M1 Mac mini上のローカル環境だけでこの結果を得られたことは、予想していたよりも健闘だったのではないか。丁寧に条件を揃えた比較ではないが、M1 Mac mini上の3Bローカルモデルが、フロンティアモデルに近いオーダーの応答速度で動作した点は興味深い。
neutralの見極めにはチューニングが必要
今回の結果から、Graniteで特に難しかったのはneutralの判定である。
positiveとnegativeが正解のレビューでは、多くのケースで正答できた。感情が明確に表現されているレビューであれば、3BクラスのローカルLLMでも十分に処理できる。しかし、neutralのレビューでは誤答が多かった。
さらに、誤答にもかかわらず90%以上の確信度を示すケースも見られた。これは単なる精度の問題ではなく、確信度の扱いにも問題があることを示している。
Graniteや従来のローカルLLMを実用的な感情分類器として利用するには、少なくとも次のチューニングが必要になるだろう。
- neutralの定義を明示する
- neutralの具体例をプロンプトへ追加する
- mixedとneutralを区別する
- positive、neutral、negativeの判断基準を文章化する
- 検証データを使って確信度を校正する
- neutralだけ別の判定処理へ分岐する
特に、neutralは単に「positiveでもnegativeでもないもの」と定義するだけでは不十分である。レビューのどの表現をneutralとみなすのかを具体的に与える必要がある。
ローカルLLMを選ぶ価値
GraniteのようなローカルLLMは、Jevの代わりにそのまま使えるわけではない。しかし、次のような条件では候補になるのではないか。
- レビューや問い合わせを外部へ送信できない
- 小規模なデータを処理したい
- 多少の誤答を人間が確認できる
- 問題の種類を限定できる
今回の感情分析のように、positiveとnegativeが比較的明確なデータであれば、70%という正答率でも用途によっては役立つ可能性がある。一方、neutralのような曖昧なクラスを高い信頼性で判定したい場合は、プロンプトやモデルのチューニングが必要である。さらに、確信度を使って自動処理と人手確認を振り分ける場合は、確信度の校正も欠かせない。
Jevは汎用的かつ高速な判断部品として優れている
今回の結果を踏まえて、Jevの優位性を理解できた。Jevは、判断専用のインターフェースを持ち、プロンプトやLLM呼び出し方法の工夫無しに、選択肢や確率、confidenceを構造化された形式で返す。さらに、複数の種類の判断を扱える。生成AIによる業務変革における新たな選択肢として、今後も注目したい。
