LLMは何でも生成しなくていい?【後編】CDM Extract と GLiNER2.5 を日本語文120件で検証

GLiNER2.5をローカルで動かし、日本語の発注文120件で情報抽出を検証。Extract と比較しました。

赤いロボットがノートPCで日本語の単語を区切り、文章から情報を抽出するイラスト

前編で紹介した ScaleDown Extract と、最後に紹介したローカルで動く GLiNER2.5 を、同じ日本語の発注文120件で比較してみました。全5項目の F1 はほぼ互角でしたが、数量の出力仕様を考慮すると、Extract はかなり優秀なのではないか ということがわかりました(最初はローカルを狙ったので GLiNER2.5 だけ検証してたんですが、せっかくなので Extract も試したいなと思ったのでこういう記事になりました)

検証条件

通常の発注、表記ゆれ、未記載、訂正・否定、複数商品、発注の撤回など、12種類×10件の自作文章を ChatGPT に作らせました。「ノートPCを30台と書きましたが訂正します。正しい発注数量は20台です。納品期限は11月15日、予算は300万円以内です。」みたいなちょっと意地悪な文章も作成させてます。ここから情報を正しく抽出できるかを調べます。抽出対象は商品名・数量・納品期限・予算金額・予算条件の5項目です。正解も作らせており、モデルには渡していません。

GLiNER2.5 は約2.9億パラメータの多言語モデル fastino/gliner2.5-multi-v1 をノート PC の CPU で実行しました。指定した項目に当たる文字列を原文から探すモデルです。公式GitHub

いっぽうの Extract は OpenRouter の scaledown/extract を使用しました。実際の応答プロバイダーは ScaleDown ですが、なぜか一部のフォーマットが本家 API にくらべて制限されていて(後でも書きますが)完全に同じ条件では比較できてないです。

同じ文章・同じ5項目の説明で各文章1回ずつ実行し、返却値は補正せず採点しました。

単語分割によるGLiNER2.5の改善

GLiNER2.5 単独では、**全項目が正しく、余分な発注レコードもない場合だけ「完全一致」**としました。「20台」を「20」とした場合も不正解です(だいぶ厳しいか?)

最初の char 方式(一文字ずつ分割)では、商品名の「ノートPC」が「PC」になり、予算条件の「以内」に金額まで含まれるなど、抽出範囲がずれました。項目に説明文を付けても完全一致は5/120件、説明文なしでは4/120件(3.3%)でした。

ちょっとこれはさすがに精度が低すぎるなとおもったので、分かち書きで文字を分割することにしてみました。日本語の形態素解析ライブラリ SudachiPy を挟み、モデル・スキーマ・閾値を固定して単語分割だけを変更しました。A は短め、B は中間、C は複合語を長めにまとめるモードです。

単語分割完全一致平均推論時間(CPU)
文字単位(char)5/120件 (4.2%)0.220秒
Sudachi A54/120件 (45.0%)0.205秒
Sudachi B52/120件 (43.3%)0.201秒
Sudachi C55/120件 (45.8%)0.200秒

前処理だけで完全一致率が4.2%から45.8%に改善しました。 項目単位でも、商品名の再現率は32.8%→95.0%、予算条件は11.3%→68.7%に上がりました。ただし、これは正しい値がどこかのレコードに存在した割合で、商品と数量の対応までは保証しません。A/B/Cの差は小さく、Cがかならずしも最良ってわけではないみたいです(なお、推論時間は別の作業も同じ PC でしてるので固定順に測った参考値とおもってください)

Extract との直接比較

OpenRouter経由では入れ子の order 配列がバリデーションエラーになったため(なんだこの制限は)、Extract には5項目をフラットに抽出させることにしました。GLiNER2.5 の出力も項目ごとにして、正解579項目と照合しました。

ここからは値集合の比較であり、商品名と数量などが正しく組になったレコードを作れるかの評価ではありません。さっき書いた GLiNER2.5 単独の評価とは採点単位が異なります。

再現率は正解のうち拾えた割合、適合率は出力のうち正解だった割合、F1は両者の調和平均です。いずれも文字列の完全一致で採点してます。

方式再現率適合率F15項目の値集合が全一致
ScaleDown Extract79.1%75.6%77.3%14/120(11.7%)
GLiNER2.5 + Sudachi A87.7%71.0%78.5%54/120(45.0%)
GLiNER2.5 + Sudachi C88.1%69.9%77.9%55/120(45.8%)
GLiNER2.5 + char55.3%49.2%52.1%5/120(4.2%)

全5項目のF1はほぼ互角ですね。GLiNER2.5 は再現率で、Extract は適合率が上ですね。で、個別にみるとこんな感じ。

抽出項目ScaleDown Extractの再現率GLiNER2.5 + Sudachi Cの再現率
商品名98.3%95.0%
数量4.3%85.2%
納品期限97.4%95.7%
予算金額96.5%95.7%
予算条件98.3%68.7%

予算条件では Extract の圧勝ですね、GLiNER2.5 はここが明確に弱いですね。意味をあまり解釈できてないのかな。「300万円以内」と金額まで含めたり、余分な候補を出したりしてますね。Extract はちゃんと「以内」だけを取り出せてます。

数量の4.3%の解釈

Extract はここにだいぶ癖がありますね。「20台」を「20」、「20本」を「20」、「1,200本」を「1200」、「十本」を「10」と返しました。プログラムの補正ではなく、API自体が数量を数値へ正規化する ような挙動なのかな。正解を単位付きの原文文字列にしたため、数値として正しくても不正解になってしまってますね。ここは数量を理解できないわけじゃなくて、単位とは別に解釈しているというのを別で担保すればいいかもしれないです。まあ単位を無視して抽出できるほうが素直な気もします。

参考として数量を除く4項目で計算してみると、Extract はだいぶ強い。

数量以外の4項目ScaleDown ExtractGLiNER2.5 + Sudachi C
再現率97.6%88.8%
適合率92.4%70.5%
F1(上の値から算出)95.0%78.6%

残り4項目では Extract のほうが取り漏れも余分な候補も少ない結果でした。

未記載・撤回・複数商品の結果

ケース(各10件)ScaleDown ExtractGLiNER2.5 + Sudachi C
未記載項目あり:値集合が全一致6/10件0/10件
発注なし・撤回済み・例文:発注の値を誤って抽出7/10件8/10件
複数商品:値集合が全一致0/10件0/10件

「ノートPCを発注します。」のような未記載項目のある文でも Extract が優位。GLiNER2.5 は数量に「ノートPC」、納期などに「を発注」を入れるなど、無関係な部分を項目に割り当てがち。

一方、かなり意地悪な文章はどっちも騙されてますね。先に例を出したような、撤回された発注からも、両モデルとも値を抽出してしまいます。 原文の値を拾うことと、その発注が有効か判断することは別の用です。

複数商品も両方式とも値集合の全一致は0件でした。Extract は(前に書いた OpneRouter 版の謎の仕様のせいで)フラットな出力になってしまってるので、商品と数量の対応付けは評価できていません。

なお、GLiNER2.5 単独評価でも、未記載・複数商品のレコード完全一致は難しいようで、全方式で0/10件でした。Sudachi Cでは納期表記・語順や書式の変化は各9/10件、訂正・否定は2/10件でした。分かち書きで明記された値の抽出は改善するんですが、意味判断やレコード構築は難しいですね。

速度と費用

項目ScaleDown Extract(OpenRouter経由)GLiNER2.5 + Sudachi C
平均処理時間1.464秒(通信込み)0.200秒(ローカルCPU推論)
120件のAPI費用$0.00132544API費用なし(ローカル実行)
モデルの運用APIを呼び出すだけローカルに導入・管理
入力データの送信外部APIへ送信外部送信せず処理可能

時間は測定範囲がちがうので、純粋なモデルの速度差じゃないので参考程度に。API費用は今回 OpenRouter が返した合計で、同じ文章量・スキーマ・価格なら 10万件 で単純比例約 1.10 ドルくらいです。だいぶ安い。

おわりに

GLiNER2.5 は前処理次第ってかんじですかね。ローカル実行なので、うまく前処理ができればできそうではあります。一方、Extract はだいぶ雑にやってもそこそこの結果を返してくれそうです。実案件にそのまま使うのはまだ検証が必要でしょうけど面白い結果だと思います、もうすこしこのへんを掘り下げたい気もするので、今後も情報を追っていきたいと思います。

ロボットによる情報抽出、結果の検証、曖昧な項目の人による確認を描いたイラスト

それではまた。


検証メモ:2026年10月15日に検証しました。GLiNER2.5の実行環境はWindows / Python 3.12.14 / gliner2 2.1.0 / CPU 8スレッド、モデルはfastino/gliner2.5-multi-v1、閾値は0.5です。120件×4方式の単語分割比較で本測定480回を行いました。ScaleDown ExtractはOpenRouterのscaledown/extract(実プロバイダーScaleDown)を同じ120件に逐次1回ずつ実行しました。比較では5項目をフラットな値集合として採点しました。すべて今回作成した日本語の人工テスト文章に対する実測であり、外部の汎用ベンチマークではありません。