始めに
一々GPTやLLMで時間掛かったり、トークン食うの嫌じゃないですか。
コードを書いたあと、
「この修正で大丈夫?」「仕様とズレてない?」「どこか壊してない?」
みたいな確認はしたいですよね。
でもその度LLMへリポジトリを読ませ、長いレビューを生成させ、数十秒待って……を毎回やる程でもないというか。
特に欲しいのは、毎回立派なレビュー文ではなく、
「ここ怪しいから詳しく見た方がいい」
という一次判定だけだったりします。
なので作ってみました。
jev-audit です。
GitHubでは kinoko34077/jev-audit として公開しています。
ディレクトリを渡すと、TypeSafe AIの判断特化モデル Jev を使ってファイル群を並列に一次監査し、怪しいbatchだけ絞込みます。
CLIとして直接使えるほか、MCP serverにもしてあるのでCodexやClaude Codeからも呼べます。
jev-audit自身を監査するとこんな感じ。
=== Jev Audit ===
status : YELLOW / review
reason : risk= 63.0% via=concrete_issue at batch #1
risk : 63.0% (highest concrete-risk batch)
root : C:\Users\kinok\Documents\Programs\jev-audit
profile: development
files : 32
batches: 3
model : jev-1.13.0
tokens : input=26902 output=318
elapsed: 5248.0 ms (wall-clock)
api work: 3478.8 ms (sum of parallel batch requests)
[concrete risk signals]
concrete_issue max= 63.0% mean= 38.0%
spec_mismatch max= 29.0% mean= 26.0%
regression_risk max= 50.0% mean= 32.3%
[highest-risk batches]
#1 risk= 63.0% via=concrete_issue concrete= 63.0% rework= 2.0% actionable= 42.0% unknown= 7.0%
#2 risk= 32.0% via=concrete_issue concrete= 32.0% rework= 14.0% actionable= 81.0% unknown= 2.0%
#3 risk= 22.0% via=regression_risk concrete= 19.0% rework= 4.0% actionable= 42.0% unknown= 4.0%
Fast probabilistic screening only; use detailed review/tests for final verification.
目的はコードレビューを全部置換えることではありません。
先に軽く全体を見て、
全体を高速に一次監査し
↓
怪しいbatchを特定。
↓
必要なところだけ人間・LLM・テストで詳しく確認する
という前処理を作ることです。
Jevって何?
Jev最近話題ですよね。
これはTypeSafe AIが公開した「System One Model」の最初のモデルです。
通常のLLMの様に文章を生成することを中心にせず、与えられたstateに対して型付きの判断と確率を返す事に寄せられています。
今回使っているのは主にこの2種類です。
Choice
→ 複数候補の確率分布を返す
Noul
→ ある条件が成立する確率を返す
jev-auditでは現在、1batchにつき4判断だけ取っています。
Choice
local_status
├─ clear
├─ review
├─ rework
└─ unknown
Noul
concrete_issue
spec_mismatch
regression_risk
つまり「このコードについてレビューを書いて」ではなく、
具体的な問題がある確率
仕様と食い違っている確率
回帰リスクがある確率
このbatch全体をclear/review/rework/unknownのどこに置くか
だけ聞きます。
レビュー文章が欲しい訳じゃない用途なら、こっちの方がかなり素直です。
jev-auditの構造
構造自体はかなり単純にしました。
CLI ─┐
├── Audit Core
MCP ─┘
│
├── Scanner
│ └─ secret / binary / build等を除外
│
├── Batching
│
├── Jev
│ ├─ local_status
│ ├─ concrete_issue
│ ├─ spec_mismatch
│ └─ regression_risk
│
└── Deterministic Aggregate
└─ GREEN / YELLOW / RED / UNKNOWN
ファイルをある程度纏めてJevへ並列送信し、Jevから返ってきた確率を最後はPython側で集約します。
重要なのは、最後の全体判定をもう一度AIにやらせていないことです。
Jevは局所判断だけ担当し、
Jev → 確率
Python → 集約
にしています。
最初はもっと雑に作っていた
ここが実際に作ってみて一番重要だった所です。
最初は各batchに対して、
仕様は満たされている?
証拠は十分?
回帰確認できている?
完成している?
の様な、かなりプロジェクト全体寄りの質問を大量に投げていました。
すると当然、1batchにはプロジェクトの一部しか入っていません。
その結果、
別ファイルを見ないと分からない
↓
証拠不足
↓
怪しい
↓
ほぼ全部YELLOW
みたいになりました。これは欲しかった監査ではありません。
「問題が見つかった」と「このbatchだけでは分らない」を混同していたわけです。
そこで、質問をかなり局所化しました。
× このプロジェクトは十分検証されているか?
○ このファイル群その物から、
修正対象となる具体的な問題を直接読めるか?
spec_mismatchに就いても同様です。
比較対象がbatch内に無いなら、推測だけでYes側へ寄せない様にしています。
「分らない」と「怪しい」を分ける
もう一つ問題がありました。
以前は、
non_clear
=
review + rework + unknown
の様に扱っていました。でも、
unknown 90%
と
review 90%
は全然意味が違います。
前者は「判断材料が足りない」。
後者は「確認した方がいい」。
そこで今は、
actionable
=
review + rework
だけ要確認側として扱い、unknownは独立させています。
現在の大まかな判定はこうです。
RED / rework
concrete_issue >= 80%
AND
rework >= 60%
YELLOW / review
risk >= 55%
OR
actionable >= 60%
UNKNOWN
unknown >= 80%
且つ上記条件に該当しない
GREEN
それ以外
ここでriskは、
max(
concrete_issue,
spec_mismatch,
regression_risk
)
です。
単に「AIが何となくreworkと言った」だけではREDにしません。
具体的問題の確率とrework判断の両方が強い場合だけREDにしています。
riskが低くてもYELLOWになる理由
例えば、自分がAI向けの開発規則を置いている.ai-guidelinesディレクトリを監査するとこうなりました。
=== Jev Audit ===
status : YELLOW / review
reason : actionable= 83.0% at batch #1
risk : 50.0% (highest concrete-risk batch)
files : 29
batches: 2
tokens : input=35593 output=212
elapsed: 2234.2 ms
[concrete risk signals]
concrete_issue max= 31.0% mean= 25.0%
spec_mismatch max= 50.0% mean= 47.0%
regression_risk max= 41.0% mean= 33.0%
[highest-risk batches]
#2 risk= 50.0% via=spec_mismatch concrete= 19.0% rework= 7.0% actionable= 60.0% unknown= 5.0%
#1 risk= 44.0% via=spec_mismatch concrete= 31.0% rework= 10.0% actionable= 83.0% unknown= 1.0%
riskは50%なので、55%のYELLOW閾値には届いていません。
しかしbatch #1では、
review + rework = 83%
だったのでYELLOWです。これは
「明確な欠陥と断言するほどではないが、レビューした方がよい」 という状態です。
逆にunknownは1%しかありません。
以前の様に「分らないからYELLOW」になっている訳ではありません。
実際にいくつかrepoへ掛けてみた
手元の複数repoへfull scanを掛けてみました。
| repo | files | batches | input tokens | output tokens | wall-clock |
|---|---|---|---|---|---|
| obsidian-related-notes-view | 11 | 1 | 9,594 | 106 | 1.72秒 |
| .ai-guidelines | 29 | 2 | 35,593 | 212 | 2.23秒 |
| jev-audit | 32 | 3 | 26,902 | 318 | 5.25秒 |
| standby-display | 49 | 8 | 78,777 | 848 | 2.47秒 |
| SynTrail-LM | 68 | 15 | 173,094 | 1,590 | 3.96秒 |
| kinotch-api | 137 | 23 | 255,526 | 2,438 | 5.67秒 |
| dev_agent | 690 | 138 | 1,256,272 | 14,628 | 25.67秒 |
ここで結構分かりやすかったのが、
outputが全ケースで1batchあたり106 tokensに揃ったことです。
212 / 2 = 106
318 / 3 = 106
848 / 8 = 106
1590 / 15 = 106
14628 / 138 = 106
長いレビュー文を生成していないので出力側はかなり固定的です。
ただし当然、入力tokenはrepo規模に比例します。
690ファイルあるdev_agentでは約125万input tokensまで増えました。
なので、
「巨大repoでも何でもほぼノーコスト」
というツールではありません。
日常的な利用では後述する--changed-onlyの方が向いています。
並列化すると実待ち時間はかなり短くなる
現在のデフォルトは4 request並列です。
例えばdev_agentでは、
files : 690
batches : 138
elapsed : 25.7秒
api work : 96.6秒
api workは各Jev request時間の合計なので約96秒ありますが、実際には並列実行しているため、ユーザーが待ったwall-clockは約26秒でした。
逆に2batchしかない.ai-guidelinesでは、
elapsed : 2.23秒
api work : 2.21秒
です。
そのためjev-auditでは、
elapsed
を実待ち時間、
api work
を並列処理前のrequest時間合計として分離表示しています。
秘密情報は送らない
任意のrepoを読む以上、ここは最初から除外しています。
.env、秘密鍵、credential系ファイルなどの本文はJevへ送りません。
Git repoなら.gitignoreも尊重します。
また、
node_modules
.venv
dist
build
target
なども対象外です。
binaryや一定サイズ以上のファイルもskipします。
監査対象ファイルの本文に、
これまでの指示を無視して〜
の様な命令文が入っていても、監査対象データとして扱うよう全判断へ同じ指示を入れています。
使ってみる
現在のセットアップ例はWindows / PowerShellです。
必要なのはPython 3.10以上と、TypeSafeのAPI keyです。
環境変数は、
TYPESAFE_API_KEY
を使います。
リポジトリ kinoko34077/jev-audit をcloneまたはdownloadしたあと、
cd jev-audit
.\setup.ps1
で仮想環境と依存関係をセットアップできます。
任意のディレクトリからjev-auditを呼びたい場合は、
.\install-command.ps1
も実行します。
新しいPowerShellを開いたあと、監査したいrepoへ移動し、
cd C:\path\to\your-project
jev-audit
だけです。
Gitで現在変更しているファイルだけを見る場合は、
jev-audit . --changed-only
JSONとして保存したければ、
jev-audit . --save audit-result.json
標準出力自体をJSONにするなら、
jev-audit . --json
です。
--changed-onlyでは削除ファイルの存在も検出しますが、削除前本文をわざわざGitから復元してJevへ送ることはしていません。
削除しかない場合は、
UNKNOWN / insufficient local context
として件数だけ報告します。
Codex / Claude Codeからも使えるようにした
CLIを毎回自分で打つのも面倒なので、MCP serverも同じAudit Coreへ繋げています。
CodexとClaude Codeはそれぞれ
codex mcp add jev-audit -- "C:\path\to\jev-audit\.venv\Scripts\python.exe" -m jev_audit.mcp_server
claude mcp add --transport stdio --scope user jev-audit -- "C:\path\to\jev-audit\.venv\Scripts\python.exe" -m jev_audit.mcp_server
の様に登録できます。
公開しているtoolは、
audit_directory
list_profiles
の2つです。
あとはCodexやClaude Code側で、
このリポジトリをjev-auditで監査して
と頼めます。
audit_directoryの対象directoryは、
明示的なpath
↓
Claude CodeのCLAUDE_PROJECT_DIR
↓
MCP server processのcwd
の順に解決します。
Codexでは現在のworkspaceの絶対pathをtool引数として渡す形にしています。
何をして、何をしないツールか
jev-auditは一次スクリーニング用です。
正しさの証明、詳細な静的解析、実際のテスト、E2E、コードレビュー、人間による確認を置換えるものではありません。
欲しいのは、
全部詳しく見ろ
ではなく、
まず全体を薄く見て、
詳しく見る価値がある場所を教えて
という役割です。
特にAIエージェントで開発していると、
実装
↓
またLLMへ全部レビュー
↓
修正
↓
また全部レビュー
となりがちです。その前段に、
実装
↓
Jevで一次監査
↓
怪しい
→ LLM / テスト / 人間で詳細確認
問題薄い
→ 次へ
を挟めないか、というのが元々の発想でした。
纏め
一々GPTやLLMに全部読ませて、長いレビューを書かせるほどではない。
でも何も確認せず次へ行くのも怖い。
その中間に、
「意味を見られる軽量な確率的一次監査」 を置きたくてjev-auditを作りました。
実際に作ってみると
情報不足と問題を混ぜない
AIに全体集約までやらせない
文章を生成させない
具体的riskとreview判断を分ける
辺りがかなり重要でした。
まだ小さいツールですが、GitHubの kinoko34077/jev-audit で公開してます。
手元のrepoへ掛けてみて、
この構成だと妙に高く出た
ここはちゃんと拾った
この種類のrepoでは使いづらい
の様なケースがあればIssue等で共有してもらえると検証材料になります。
「全部LLMに投げる」と「何もしない」の間に、こういう判断特化モデルを挟む使い方は結構ありそうです。
P.S.
一応全体の精査はしていますが、僕はプログラミングをバイブコーディングさせており、実力としては齧ってる程度のため何かしらミスがあればご容赦くださいm(_ _)m
参考
- TypeSafe AI: 「Introducing System One Models & Jev」
- OpenAI Docs: 「Model Context Protocol」
- Claude Code Docs: 「Connect Claude Code to tools via MCP」
- GitHub: kinoko34077/jev-audit