1本目で、Jevは論者の選び方では、Claudeと約60%しか合わないと書きました。
では、Jevは何に使えるのか?
私はOrcaで、複数のAIに設計書を書かせ、別のAIにレビューさせています。
ディベートの前と後、そしてこの設計書の流れの中で、いくつか使い道を試しました。この記事では、試したもの、やめたもの、残したものを、数字つきで書きます。
前の記事は、こちらです。
呼び出し部品を標準ライブラリだけで書いた
調べた時点で、第三者が作ったJevのコマンドラインツールがありました。ただ、2,382行あり、中身を確かめるのが重いので使いませんでした。標準ライブラリだけで、呼び出し部品を書きました。使ったモデルは、jev-1.13.0です。
def ask(state, questions, model=MODEL, timeout=30, caller="", retries=2):
"""One request: `state` (str/dict/list) + a map of typed questions -> parsed response dict."""
body = json.dumps({"state": state, "model": model, "questions": questions}).encode()
for attempt in range(retries + 1):
req = urllib.request.Request(API_URL, data=body, method="POST")
req.add_header("Authorization", f"Bearer {api_key()}")
req.add_header("Content-Type", "application/json")
t0 = time.time()
try:
with urllib.request.urlopen(req, timeout=timeout) as resp:
data = json.loads(resp.read().decode())
break
except urllib.error.HTTPError as e:
if e.code in (429, 500, 502, 503, 504) and attempt < retries:
time.sleep(float(e.headers.get("Retry-After", 2 ** attempt)))
continue
raise RuntimeError(f"Jev HTTP {e.code}: {e.read()[:300]!r}")
_log_usage(data.get("usage", {}), time.time() - t0, caller or os.environ.get("JEV_CALLER", ""))
return data
決めたことは、3つです。
- 送るのは、3つのキー(状況・モデル・問い)だけ。30秒で打ち切る
- 再試行は、混雑や5xxのエラーのときだけ、2回まで。
Retry-Afterがあれば、その秒数だけ待つ - キーは、環境変数か、同期フォルダの外のファイルから読む。値は表示しない
呼ぶたびに、「いつ・誰が・何トークン・何ミリ秒」だけを1行記録します。送った中身は残しません。
日本語で試した
Jevの資料は、英語が主で、日本語は精度が下がるので、自分のデータで試すよう書かれていました。そこで、日本語20件(39の判断)をJevに判断させ、Claudeの判断と比べました。結果は、39判断のうち38が一致です。リクエストは21回でした。
分類・合否・振り分けは、問いが日本語でも英語でも全件一致しました。確信度は0.74〜1.00です。全件一致は、この3種類の話です。38/39は、日本語20件の全体の話で、別の試験です。
苦手なことは、資料に書かれていたとおりでした。文章を書く、計算する、日付を抜き出す、数を数える、画像を見る。否定や含意は、明示しないと読み取れません。
承認の自動化はやめた
最初に試したのは、危険なコマンドの承認の自動化です。Jevの紹介記事にあった「確率が2つとも0.9以上なら自動で許可する」という使い方を、そのまま試しました。
危険なコマンドの確率は0.02〜0.15で、向きは正しく出ました。ただ、安全な読み取り(grepやsed)でも「作業に必要か」が0.88〜0.89で、8件中0件しか通りません。git pull --rebaseの「元に戻せるか」は0.43でした。
そこで、紛らわしい24件で試し直しました。危険なもの(隠れた削除、作業の破棄、秘密の送信など)は、どのしきい値でも1件も通しません。しかし、通すべき読み取り・テストは、次のとおりです。
| しきい値 | 通った件数(通すべき10件のうち) |
|---|---|
| 0.9 | 0件 |
| 0.8 | 2件 |
| 0.7 | 3件 |
lsやgit statusでも、「作業に必要か」は0.55〜0.68でした。さらに、APIキーをcatで読む操作を、「元に戻せる」(0.82〜0.93)と判定しました。境界にならないので、承認の自動化はやめました。 代わりに、決まったコマンドの許可一覧で通すことにしました。
会話の圧縮もやめた
会話の記録が長くなったとき、捨ててよい部分をJevに振り分けさせる使い方も試しました。実際の会話の記録2本で、「捨てる」に振り分けられたのは、文字数の11%と30%だけでした。Jevは要約を書けないためです。私の指示は全件残ったので、安全ではありますが、効果が小さいのでやめました。
レビュー前の事前チェックに残した
最後に残したのが、レビュー前の事前チェックです。設計書に必須の項目が書かれているかを、レビューの前に確かめます。欠けていれば、レビューの2人を呼ばずに、設計へ戻します。
チェックリストは、2種類の項目でできています。1つは「〜が書かれているか?」という問いで、Jevに聞きます。問いの実物は、次のとおりです。
{"items": [
{"id": "current_problems", "question": "今のコードの問題点が、コードを読んで確かめた形で書かれているか?"},
{"id": "retry", "question": "同時更新の衝突(409)のときの再試行の方針が書かれているか?"},
{"id": "validation", "question": "入力チェックと、不正な入力のときに返すエラー(400 など)が書かれているか?"},
{"id": "tests", "question": "テスト計画(どのケースをどう確かめるか)が書かれているか?"},
{"id": "scope", "question": "今回の範囲に入れないことが明記されているか?"}
]}
もう1つは、図の数など、数える項目です。Jevは数えられないので、コードで数えます。
コードのnoulは、「書かれているか」を確率で返す問いの型です。
for it in items:
if "count" in it:
n = len(re.findall(it["count"], extract(doc, it["section"]) if it.get("section") else doc))
results.append({"id": it["id"], "p": 1.0 if n >= it.get("min", 1) else 0.0, "count": n})
else:
groups.setdefault(it.get("section"), []).append(it)
for section, its in groups.items():
state = extract(doc, section) if section else doc
if not state.strip(): # 見出しがない:項目は未記入なので、聞かずに0
results += [{"id": it["id"], "p": 0.0, "note": "section not found"} for it in its]
continue
qs = {it["id"]: {"type": "noul", "instructions": it["question"]} for it in its}
best = {}
for part in chunks(state): # 長いと断られるので分けて送る。書かれていれば、どこか1つの部分に出る
r = ask(part, qs, caller="precheck")
for k, v in r["answers"].items():
best[k] = max(best.get(k, 0.0), v["noul"])
- 数える項目は、基準の数以上なら1.0、満たさなければ0.0
- 同じ節の問いは、1リクエストにまとめる。見出しが見つからなければ、聞かずに0
- 3万字を超える文書は、
##の見出しで分けて送り、一番高い確率を採る。書かれていれば、どこか1つの部分には出るはずだからです。約3万トークンは通り、約5万トークンは断られました - しきい値は0.5。1つでも下回れば差し戻す。終了コード0(通過)、1(差し戻し)、2(エラー)で、親のエージェントが次の動きを分ける
結果は、判定(pass・return)、項目ごとの確率、リクエストの回数、入力トークン、かかった秒数を、JSONで返します。設計書1本の確認は、1〜6回のリクエストで、0.4〜2.3秒でした。
過去の設計書7本に当てた
7本とも、通過しました。
一番低い確率は、0.89〜0.95です。Jevに送った量は、設計書7本で16,405〜38,026トークンです。
うち3本は1回で送った量(16,405〜32,303)、別の3本は節ごとに6回に分けた合計(26,718〜29,819)です。
残る1本は38,026トークンで、1回では上限に当たったので、2回に分けて送りました。
レビューで不合格になった5本の理由は、コードと合わない説明、壊れるケースの見落とし、引用に実在の会社名など、すべて中身の誤りでした。事前チェックでは見つけられず、省けたレビューは0回です。
わざと崩した版でも試しました。
| 崩し方 | 結果 |
|---|---|
| 節を見出しごと消す | 差し戻し(コードが見つけた) |
| 見出しを残し、本文を「(未記入)」にする | 0.05で差し戻し(Jevが見つけた) |
| 図9個のうち8個を消す | 0.95で通過 |
| 図を全部消す | 0.96で通過(本文に図の説明が残るため) |
図の数はJevでは見抜けないので、数える項目にしました。数える項目にすると、全部消した版は差し戻されました。
実際の作業でも、12回(設計4・下書き8)すべて通過し、差し戻しは0回でした。計約20万トークン、8.5秒です。1回は0.3秒前後で、レビュー1回の5〜40分と比べれば、ほぼ時間はかかりません。ただ、保険にはなりますが、レビューの回数と時間は減りませんでした。
分かったこと
役目は、次のように分けるとうまくいきました。
- 数えるのは、コード
- 書かれているかを見るのは、Jev
- 正しいかを見るのは、レビューの2人
Jevは、「選ぶだけ」「あるかないか」の判定の部品です。仕事の正しさは見ません。ディベートでは票を数える役、設計書では事前チェックの役に残し、承認の自動化と会話の圧縮はやめました。図は、今の役割分担です。
1本目の票の数え上げも、同じ考え方です。Jevに任せたのは選ぶ部分だけで、論を書くのも、まとめを書くのも、Claudeです。
決めるのは人です。Jevを何に使うかも、私が決めています。
続き
海外Yパパさんの動画で具体的に使っている仕組みを参考に、私が必要とする使いかでどう使うかを書いてみます。

