第2回:自然言語→SQL エージェントで KOI を測る ― 品質を守りながら費用対効果の高いモデルを選ぶ
![]()
前回の記事では、AI の費用対効果を測る単位 KOI(KPI ÷ コスト、つまり 1 ドルあたりの成果) と、それを実データで測る道具 Nishiki を紹介しました(詳しくは前回の記事とNishiki のプロジェクト記事をご覧ください)。今回は、より業務に近い題材で実際に測ってみます。題材は Text-to-SQL です。人間が自然言語で質問すると、AI が SQL を生成して社内データベースに問い合わせ、答えを返すタイプのエージェントです。
想定する業務 ― 社内セルフ BI
どこの会社にもある場面を思い浮かべてください。営業や経営が「先月の東エリアの売上トップ 5 商品は?」と知りたいとします。従来はデータアナリストが毎回 SQL を書いて答えていました。ここに AI エージェントを噛ませると、次のようになります。
人間: 「東エリアの売上トップ5商品は?」 ← 自然言語
↓ ① AI が意図を汲んで SQL を生成
↓ ② その SQL を社内DBで実行 → 行データが返る
↓ ③ (必要なら)AI が結果を自然言語で言い換えて返す
人間: 「A, B, C … です」
アナリストの手作業が要らなくなります。これは 1 回きりのチャットではなく、社内ツールとして月に何千〜何万回も自動で回るものです。だからこそ、使うモデルの「賢さ」と「コスト」の両方が効いてきます。
このタスクでの「AI の賢さ」とは何か
この記事で最もお伝えしたいのはこの点です。Text-to-SQL における賢さは、一般的な頭の良さではなく、次の 3 つが噛み合う力を指します。
- 人間の言葉の意図を正しく汲む ― 「トップ 5」「東エリア」「先月」が何を意味するか
- DB のスキーマを理解する ― どのテーブルの、どのカラムを、どう結合すればよいか
- 意図に合った SQL を書ける ― 集計・絞り込み・並べ替え・結合が正しい
この 3 つが揃って初めて「正しい答え」が出ます。つまり測るべき賢さは、人間の言葉を解釈して、それに見合った正しいクエリを組み立て、社内資源を正しく引いてこられるかです。
見た目ではなく「実際に正しい答えが出たか」で採点する
Nishiki はこのサンプルで、生成された SQL の文字列を採点しません。その SQL を実行して返ってきた結果の行が、正解と一致するかで採点します(実行精度)。
- 書き方が違っても、同じ正しい行が返れば ○(
price >= 500でもprice > 499でも同じ結果になります)。 - それらしい SQL でも、実行結果がズレれば ✗。
これは業務に即した採点だと考えています。欲しいのは「見栄えの良い SQL」ではなく「正しい数字」だからです。なお、安全のため、採点時の実行は必ず読み取り専用接続で行い、DB を書き換えることはありません。
KOI で測ると何が見えるか
今回はあえて難しい 14 問(ウィンドウ関数・相関サブクエリ・アンチ結合・HAVING など、実務の分析クエリ級)を用意し、価格帯の違う 5 モデルに解かせました。候補には、全モデル中いちばん安い小型モデル llama3b も入れてあります。素の「最安ルーティング」なら真っ先に選ぶモデルです。合格率 ÷ 1 件コスト=KOI で並べ、まず「最低これだけは当ててほしい」という品質フロア(今回は 80%)で足切りします。
下表は実測値です(14 問・OpenRouter・総額 約 $1.2)。route と単価は .nishiki/MODELS.yaml の通りです。
| モデル(route) | 合格率 | 1 件コスト | KOI | 判定 |
|---|---|---|---|---|
llama3b(meta-llama/llama-3.2-3b-instruct) | 0.07(1/14) | $0.00003 | ✗ フロアで失格 ― 最安ですが正解 7% | |
deepseek(deepseek/deepseek-v4-pro) | 0.93(13/14) | $0.00044 | 2135 | ★ 最良コスパ ― バーを超えて低コスト |
glm46(z-ai/glm-4.6) | 0.57(8/14) | $0.00196 | ✗ フロアで失格 ― SLA 未満 | |
gpt4(openai/gpt-4) | 0.86(12/14) | $0.00969 | 88 | 通過・中価格 |
gpt54pro(openai/gpt-5.4-pro) | 1.00(14/14) | $0.07047 | 14 | frontier・満点だがコスパは最下位 |
この表から、「ただの最安選び」と KOI の違いが読み取れます。
① 一番安いモデルは「素の KOI」が最高で、しかも実務では使えません。 llama3b はほぼ無料なので、正解率がたった 7% でも小さなコストで割れば KOI は 2551 と最大になります。素朴に KOI 順で並べると、これが首位になってしまいます。それを止めるのが品質フロアです。7% は当然、57% の glm46 も失格します。フロアが無ければ「1 ドルあたりの成果」は、93% 間違えるモデルを誤って推奨してしまいます。
② フロアを超えた中で勝つのは deepseek で、しかも最安ではありません(最安は失格した llama3b です)。deepseek が勝つ理由はコストではなく、KPI とコストの比です。80% のバーを 93% で超えつつ $0.00044 と低コストで、KOI は 2135 になります。
③ frontier は合格率が最高(100%)でも KOI は最下位(14)です。 約 160 倍のコストで、deepseek 比で +7 点(93→100)しか買えていません。これを大量運用で払い続けることが、KOI が可視化する「コストに見合わない選択」です。
下の散布図が一枚で示します。縦軸が正解率、横軸がコスト(対数)です。フロア 80% のラインより下(llama3b・glm46)はグレーで失格です。deepseek は「バーの上・コストは左端」の位置にあり、frontier は「天井だが右端」です。
つまり KOI が指すのは「最安」でも「最高品質」でもありません。最安(llama3b)はフロアで失格し、最高品質(frontier)はコスパが最下位です。KOI が当てるのは、あなたの品質バーを超える中で、1 ドルあたりの成果が最大の一点です。
なお、レイテンシは KOI とは別軸で、式には入れない参考値です。今回は gpt4 が最速で約 2.4 秒、frontier が最遅で約 41 秒でした。
実際のダッシュボード(nishiki koi-report --web の Measured タブ)はこのように表示されます。上段にカード(累計コスト・平均 KOI・レイテンシ・件数)、中段に per-item の推移チャート、下段に KPI フロアのスライダー付き leaderboard が並びます。スライダーを動かすと足切りラインが変わり、最適モデルがその場で入れ替わります。

「測る」だけでなく「上げる」― 最適化ループ
モデルを選ぶのは最適化の半分です。もう半分は、同じモデル・同じコストのまま、プロンプトを磨いて合格率を上げることです。スキーマの与え方を整える、代表的な質問例を 2〜3 個添える、指示を締める。こうすると合格率が上がり、コストは据え置きなので、KOI が上がります。
「モデル差し替えでコストを下げ、プロンプト改善で合格率を上げる」。この before → after の両輪が、「安さだけ」でも「品質だけ」でもなく比(KOI)を最適化するということの中身です。Nishiki は実測のたびに基準が更新されるので、回すほど精度が上がります。
これは Text-to-SQL に限りません ― RAG/社内資源活用でも同じ
業務で必ずしもこの形で使うとは限りません。ですが本質はこう整理できます。
「AI が人間の意図を解釈して、社内の資源を正しく引いてくる」タイプの活用は、どれも同じ枠組みで KOI を測れます。
Text-to-SQL は、その一例(資源=データベース、引き方=SQL)にすぎません。同じ形は他にもあります。
- RAG(社内文書 QA): 資源=ドキュメント/ナレッジベース、引き方=検索+要約。「質問に対して、正しい根拠を引いて正しく答えたか」を採点すれば、モデル選びの KOI がそのまま測れます。
- ツール/API 呼び出しエージェント: 資源=社内 API・業務システム、引き方=関数コール。「正しいツールを正しい引数で呼べたか」を採点します。
- 書類照合・抽出(前回紹介した実例): 資源=帳票・契約書、引き方=抽出。
いずれも「賢さ(=タスクの正解率)÷ コスト」という同じ物差しで、あなたのユースケースに見合った賢さを一番安く出せるモデルはどれかを実測できます。採点の当て方だけがタスクごとに変わります(完全一致・実行一致・あるいは別モデルによる判定=LLM-as-judge)。Nishiki はこの採点を組み込みの安全な部品から選ぶので、AI が勝手に危険なコードを書くことはありません。
要するに、RAG でも Text-to-SQL でもツール呼び出しでも、「社内資源を AI に正しく引かせる」活用はすべて、KOI で費用対効果を測り、最適なモデルへ寄せられます。「賢い=高い方が安心」という前提を、数値で見直すことができます。
手順(マニュアル)― nishiki コマンドで最適モデルと KOI を出す
ここからは実際の操作手順です。サンプルはリポジトリに自己完結で同梱してあります(合成の小さな DB + 正解セット+エージェント)ので、そのまま順に実行できます。エージェントのソースは一切書き換えません。Nishiki が計測時に候補モデルをメモリ上で差し替えるだけです(injection.choke: agent:generate_sql)。
以下の出力例は、実際にこのサンプルを測ったときの値です(難問 14 問・5 モデル・OpenRouter・総額 約 $1.2)。コマンドと表示の形はそのままで、数値はあなたが測るモデル・データ・その日の価格で変わります。
自分のプロジェクトで一から測る場合 ― 初回起動〜プロファイル生成
このサンプルはプロファイルが同梱済みなので後述の手順 1 から始められますが、自分の AI プロジェクトを測るときは、その前に「初回セットアップ」と「プロファイル生成」があります。全体像は次の通りです。
nishiki # 初回だけセットアップウィザードが立ち上がる
nishiki init --target <あなたのプロジェクトのパス> # ソースを読んでプロファイルを自動生成
nishiki measure --experiment <上で作られた .nishiki> # KPI を実測
nishiki koi-report --experiment <同> --web # KOI 表・最適モデル
① 初回の nishiki(セットアップウィザード) ― 初めて起動すると 3 つだけ聞かれます。
=== Nishiki setup (first run only; no flags needed afterward) ===
[1/3] Choose the orchestrator brain (the LLM that writes the config):
1) claude_p [✓ available] ← 設定を書く「頭脳」。claude / codex / OpenRouter / 任意コマンド から選ぶ
2) codex [— not found]
...
[2/3] KOI candidate model source: OpenRouter の代替候補も出す? [y/N]
[3/3] Data residency policy: 1) 自社クラウド内に限定(機微データ向け) / 2) 無制限(外部 route も比較に入れる)
答えは保存され、以後は聞かれません。ここで選ぶ「頭脳(brain)」は、次の init であなたのコードを読み、KPI と候補を自動で書き起こす LLM のことです。
② nishiki init --target <dir>(プロファイル生成) ― 指定したプロジェクトのソースを読み、「このエージェントは何を出力しているか」から KPI を自動判定します(ラベルを選ぶ=分類、テキストを抜く=抽出、クエリを作る=SQL など)。そして対象プロジェクト直下に .nishiki/ プロファイルを作ります。
<あなたのプロジェクト>/.nishiki/
KOI.yaml 自動判定した採点レシピ(task_type / scorer / フロア)+ choke(モデル差し替え点)
MODELS.yaml 候補モデルのメニュー(現行モデル+任意で OpenRouter 代替、価格つき)
AGENT.md 対象の要約メモ
対象のコードや DB・データには一切触れません(.nishiki/ というツール用の隠しフォルダを足すだけで、gitignore 対象です)。これで手順 1 以降(measure → koi-report)は同梱サンプルと全く同じになります。
頭脳(brain)が無いマシンでも測れます。 init の自動執筆には claude/codex/OpenRouter のいずれかが必要です。ですが手が無くても、
.nishiki/KOI.yamlとMODELS.yamlを手書きすれば済みます(このサンプルがまさにその手書きプロファイルの実例です)。measureとkoi-reportは頭脳を一切使わない素の計測なので、GPU 箱や CI でも動きます。「AI に自動で書かせる」か「自分で書く」かの違いだけで、測る部分は同じです。
以下は、その手書きプロファイル同梱済みのこのサンプルを実際に回す手順です。
0. 準備
pip install git+https://github.com/matu79go/nishiki.git # or: pip install -e . (clone 済みなら)
cd samples/text_to_sql
まず結果だけ見たいなら、この時点で nishiki koi-report --web を実行すれば鍵なし・課金なしで同梱の実測結果をダッシュボード表示できます(.nishiki/runs/ をリプレイするだけです)。以下は自分で測り直す手順です。
1. 鍵を置く(数セントで実測できます)
echo 'OPENROUTER_API_KEY=sk-or-...' > .env # .env は gitignore・絶対に commit されない
.env は自動で読み込まれます。既存の環境変数があればそちらが優先されます。
2.(任意)候補モデルのメニューを見る
nishiki models --search deepseek # OpenRouter のライブ価格を鍵なしで引く
どのモデルを候補にするかは .nishiki/MODELS.yaml に書いてあります(route スラッグ+100 万トークンあたりの価格)。今回は frontier〜低価格を価格の梯子に沿って 5 つ並べ、いちばん下に全モデル中いちばん安い小型モデル llama3b を置きました。「素の最安ルーティングが選ぶ役」として、あえて含めています。価格帯を意図的に散らしているのが要点です。
補足:このサンプルの候補は
nishiki modelsで自動ピックせず、手で選びました。 理由は 2 つあります。①再現性 ―nishiki modelsはライブの OpenRouter catalog を引くので、日によって並びも価格も変わります。サンプルは誰がいつ clone しても同じになってほしいので、候補を固定して同梱しました。②狙いの明確さ ―「最安=正解ではない」を示すには、frontier・中位・低価格・そして「最安だが弱い」小型モデルまで、価格と品質の両方を意図的に散らす必要があります。だからllama3b(最安・弱)を敢えて足しました。本番であなたのプロジェクトを測るときは逆で、nishiki init --source openrouterがnishiki modelsのライブ価格から候補を価格層ごとに自動で組みます(+コードから抽出した現行モデル)。手で選ぶのはあくまで「デモを固定したい」からで、通常運用は自動で構いません。
3. まずコスト概算(probe=少数だけ試走)
いきなり全部を実行する前に、各モデルを数問だけ試して全体費用を見積もります。
nishiki measure --experiment .nishiki --mode probe --probe-n 3
[probe] in-scope=14 / trial run of 2 items per candidate
q1 gpt54pro: score=1.00 $0.0705 41000ms
q1 deepseek: score=1.00 $0.0004 8400ms
q1 llama3b: score=0.00 $0.0000 760ms
...
probe actual spend $0.18 / full-run projection $1.20
full-run projection が本計測でかかる概算額です。想定外に高ければここで気づけます。
4. 本計測(run=全問×全モデルを採点)
nishiki measure --experiment .nishiki --mode run
14 問すべてを各モデルに解かせ、生成 SQL を read-only で実行 → 結果一致で 1/0 を採点し、モデルごとに合格率とコストを集計します。
q1 deepseek: score=1.00 $0.0004 8448ms
q2 deepseek: score=1.00 $0.0005 5100ms
...
[deepseek] KPI 0.93 NGrec - $0.0061($0.00044/item) err=0
[llama3b] KPI 0.07 NGrec - $0.0004($0.00003/item) err=0
...
→ .nishiki/runs/<stamp>_run.json
next: nishiki koi-report --experiment .nishiki
結果は .nishiki/runs/*.json に保存されます(次回同じモデルで測り直す情報も last_run.json に残ります)。
5. 最適モデルと KOI 表を出す(ここが目的です)
nishiki koi-report --experiment .nishiki --web
KOI dashboard ready (recommended: deepseek)
→ http://127.0.0.1:8765/#measured
ターミナルに推奨モデルが出て、ブラウザに KOI ダッシュボードが立ち上がります。表は「まずフロア(合格率の下限)で足切り → 通過組を KOI(合格率 ÷ コスト)降順」で並びます。フロアはスライダーで動かせるので、「合格率 90% は死守したい」など SLA を変えると、最適モデルがその場で入れ替わる様子を確認できます。(ブラウザ無しでターミナルに表だけ出すなら --web を外します。)
6.(任意)1 件ごとの内訳を見る
nishiki history --experiment .nishiki
各質問について、どのモデルがどんな SQL を出し、当たったか・何トークン・いくらか、を 1 件ずつ確認できます。
7.(任意)ライブ KOI ― 動かしながら測る
nishiki run --experiment .nishiki --fresh --watch -- \
python agent.py "How many products cost 500 dollars or more?"
エージェントを起動コマンドごとラップし、呼び出しの実トークンを読んで逐次 KOI を表示します(追加の API 呼び出しはしません)。本番エージェントに繋ぐときも、この一本でライブ計測できます。ダッシュボードの Live タブでは、1 コールごとに KOI と累積コストが動き、全候補が実測 $/item でローリング再ランクされます。

8. KOI を「上げる」― 最適化ループ
最適モデルが決まったら、次は同じモデル・同じコストのまま合格率を上げます。.nishiki/KOI.yaml の run.prompt を磨いて(例:代表的な質問と模範 SQL を 2〜3 個添える)再計測するだけです。
# .nishiki/KOI.yaml の run.prompt を編集して…
nishiki measure --experiment .nishiki --mode run
nishiki koi-report --experiment .nishiki --web # 合格率↑ → KOI↑ を before/after で確認
フロア(floors.kpi_floor)を業務の SLA に合わせて上げ下げすれば、「その品質ラインを満たす中で一番コスパの良いモデル」を選び直せます。
9. すべてを任せる場合
手順を覚えなくても、このディレクトリで nishiki と打つだけで構いません。オーケストレータが init → 計測 → KOI 表まで対話的に導きます(あなたの言語で応答します)。
(価格は OpenRouter のリスト価格=100 万トークンあたり USD で、nishiki models でライブ取得します。合格率・コストは同梱の実測値です。数値は測るモデルとデータで変わります。DB は完全に架空・ドメイン中立の合成データです。)