AI Native

让 Jev 替你刷信息流:三源新闻日报的实现

最近 Jev 超火。我拉数据那天,GitHub Trending 前 20 里有 6 个 Jev 生态仓库,HN 首页挂着《OpenAI is well positioned to fast-follow Jev》和 JevBench 的 Show HN。

学一个新东西,我的习惯是拿它干一件具体的事。这次选了每天都要做的刷信息流:早上过一遍 Hacker News 热榜、GitHub Trending、Agent Skills 生态的新仓库,三个源 90 条上下,最后要一份 Top 5 的中文简报。

这件事顺下来正好落在 Jev 的位置上:**刷信息流这件事,九成模型调用是判断题,只有最后写摘要那一口是作文题。**相关吗(判断题)、什么类别(判断题)、可操作性几折(判断题)、值不值得进简报(判断题)——这些不需要生成一段话,只需要一个可以进 if 分支的答案。Jev 恰好只做这件事。这篇文章记录把日报搭起来的全过程,判断层全程真 key 直连,代码开源。

一、Jev 是什么

TypeSafe AI 9 月 15 日发布,创始人 Diogo Almeida 是 InstructGPT 和 RLHF 的共同发明人,种子轮 $40M,DCVC 领投。名字取自 Jevons 悖论——资源越便宜,消耗越多——定价也照这个意思定的:输入 $0.042/百万 token,输出免费,端到端 70~500ms。

它只做判断,不做生成。LLM 是自回归的,一个 token 一个 token 往外蹦;Jev 换了架构,把 state 读一遍,所有答案一次并行输出。

同一个问题,两种输出

拿日报里真实的一个问题来看:「这条内容值得进今天的简报吗」。

问生成模型,得到的输出大致长这样(示意):

这条内容讨论的是某开源项目的发布动态,与 AI 工程相关,
有一定的参考价值。总体来看建议纳入简报……

人能读,但代码想用这个答案,还得再写一个解析器从自然语言里抠出「建议纳入」四个字——或者干脆再调一次模型来解析。问 Jev:

{"answers": {"digest_worthy": {"noul": 0.87}}}

然后就是一行普通的分支:

if answers["digest_worthy"]["noul"] >= 0.6:
    candidates.append(item)

daryl 那篇管这个叫「模型答案直接进代码分支」。我更直白的感受是:判断题不再需要用作文题的格式交卷,也就不再按作文题的价格收费。

三原语

调用只有一个端点,POST https://api.typesafe.ai/v1/systemone。请求带 state(任意文本或 JSON)和一组 questions,每个问题只能是三种原语之一;一次调用里所有问题并行作答,加问题不加延迟:

原语问什么入参出参
choice选哪个选项criteria 为 {选项: 判定描述},最多 255 项choice + 每选项 probabilities + confidence
score落在量表哪一级criteria 为有序等级描述,2~10 级,从低到高score(从 0 级起算,可为小数)+ probabilities + confidence
noul陈述为真的概率只有 instructionsnoul,0~1,没有 confidence 字段

官方文档的客服工单例子,一笔工单三个问题一次问齐:

{
  "state": "Hi, I've been trying to connect my Stripe account for 3 days...",
  "model": "jev-latest",
  "questions": {
    "department": {"type": "choice", "instructions": "Which team should handle this",
      "criteria": {"billing": "...", "technical": "...", "sales": "..."}},
    "frustration": {"type": "score", "instructions": "How frustrated the customer appears",
      "criteria": ["Calm, just stating facts", "Frustrated but civil", "Very angry, strong language"]},
    "is_urgent": {"type": "noul", "instructions": "The message conveys urgency"}
  }
}
{
  "answers": {
    "department": {"choice": "technical",
      "probabilities": {"billing": 0.159, "technical": 0.84, "sales": 0.001},
      "confidence": 0.596},
    "frustration": {"score": 1.035, "confidence": 0.842},
    "is_urgent": {"noul": 0.999}
  },
  "usage": {"input_tokens": 312, "output_tokens": 48}
}

写代码之前有四个点要知道。

probabilities 和 confidence 是两个轴。probabilities 回答「答案是什么」,confidence 回答「这个答案能不能直接拿来行动」。Jev 用 RLCD(面向校准决策的强化学习)训练,模型说 0.9,实测对九成左右。让普通 LLM 在 prompt 里「输出一个概率」也能得到数字,但那个数字没有校准。

Noul 的答案没有 confidence 字段。二值判断里概率本身就是信念强度,官方干脆不给第二个字段。代码里统一读 answer.confidence 的话,noul 问题会拿到 None——Langfuse 拿 Jev 做 evals 时踩过这个坑,我的程序层也绕开了它。

「不会幻觉」是 schema 保证的,不是测出来的。choice 只能从枚举里选,格式不会错,但选错合法值完全可能。type safety 不等于 accuracy,官方自己也认。

边界照官方的 jaggedness 清单转述:字面理解指令、不能算数计数、日期当文本不做比较、state 塞满无关内容会掉精度(context rot)、不抗提示注入、不能弃权(二值问题会硬选一个「最不错的」)、不输出任何理由。所以社区通行的分工是:算数、排序、过滤留给代码,Jev 只读一遍 state 下判断。

二、这个位置上已经长出了什么

官方发布时带了五个 demo,数字都是官方自报、未经第三方复现:

demo干什么数字
1kpapers.com1018 篇论文分类共 $0.08,中位 256ms/篇
browser-use/jev-ultrafast浏览器 agent 订机票7.1s / $0.0039
typesafe-computer-useMac 桌面自动化$0.0002/step,OCR 不走截图
jev-trader做市机器人每个 Monad 区块决策一次,模型延迟约 81ms
jev-drone无人机判断层 2.5Hz,控制与安全在代码层 50~500Hz

jev-drone 那行值得多看一眼:判断 2.5Hz,控制和安全 50~500Hz,两层分开,安全从不交给模型。我做日报抄的就是这个结构。

一周内社区的实测更贴近日常工程:

用法怎么用实测数字
检索重排score 打分替代向量排序top-1 命中 5%→18%,1200 次调用 $0.0645
引用核查choice(supports/contradicts/says_nothing)4/4 抓出植入错误,置信度门槛 0.8
工具调用护栏(pi-warden)每次工具调用前 4 问,约 250ms17000 次调用拦下 42 次,约 88% 拦得对
提示注入筛查每段 4 个 noul抓住余弦相似度排第一的注入
evals 裁判noul/score 替代 LLM-as-judge与 Claude Fable 5.1 一致率 91.5%,$160/百万答案,Claude 本尊 $33,000
级联路由Jev 分类意图,简单分支纯代码约 $6,480 vs $30,400 每百万工单

项目侧,fast-jev-compaction(对话历史剪枝,6329★,daryl 的《把 Agent 的判断题从大模型里拆出来》有逐行拆解)之外,还有 vercel/eve(前端工程判断)、jev-review(代码评审)、pg-jev(Postgres 集成)、SemIf/kev、laya 这些在各自领域复刻同一模式的仓库。模式归拢起来大概五种:问题一次问齐按需取(fan-out)、按「错了多贵」定置信度门槛(confidence gating)、多维打分权重在代码里合成(composite scoring)、判断分流后简单分支零模型调用(cascade)、先检索再逐条廉价判断(retrieve-then-judge)。

新闻日报用的是 cascade 加 composite:90 条先过判断层,程序过滤排序剩 5 条,生成模型只碰这 5 条。

三、为什么筛选需要一层判断

朴素做法是什么样:把 90 条丢给一个对话模型,一段 prompt 让它挑 10 条、写摘要、排好序。能用,效果未必差。问题出在成本结构和可编程性上——每次筛选都是一次全量生成,筛选逻辑活在 prompt 里,想调「更看重可操作性还是新鲜度」,只能改 prompt 重跑,效果听运气。

把判断拆出来之后,结构变成四层:

层谁在干jev_news 里对应什么
慢思考层(生成)摘要模型(任意 OpenAI 兼容端点)Top 5 的一句话中文摘要 + 今日总结导语
快判断层Jev90 条 × 4 个问题,实测每次约 730 输入 token(state 加四问题)
确定性层纯代码过滤、去重、排序、复合权重,零成本
兜底层纯代码Jev 不可用时按原始热度排序,降级交付

拿到概率之后还有一个好处:答案可以分带处理,而不是硬二值。参考 daryl 那篇的分带思路,noul 落点可以映射到三档动作——高置信直接自动化、中间带进复核队列、低置信丢弃。我的实现只用了两档(一个 0.6 的闸门加复合排序),先跑起来,分带是稳定之后的迭代方向。

还有一件事值得在动手前想清楚:这个判断错了会怎样。资讯筛选是只读的,错一条顶多简报里多一条不值得看的内容,没有任何副作用——这类场景可以放心全自动。daryl 那篇把风险分了三级,L1 只读可逆(分类、筛选、路由)直接自动化,L2 修改状态但可回滚要兜底,L3 不可逆或对外的必须人审。日报在 L1,这也是我选它当第一个 Jev 项目的原因。

四、写个新闻筛选的示例

HN 热榜 / GitHub Trending / Agent Skills

HN topstories(50) + GitHub Trending(20) + Agent Skills(20)
    ↓ fetchers.py      三个 fetcher 归一化为统一 Item;跨天去重只留新增
判断层 Jev(jev_client.py,直连 api.typesafe.ai)
    ↓ 类型化答案矩阵(noul/choice/score,带 probabilities/confidence)
程序层 digest.py      过滤 / 排序 / 去重,纯代码
    ↓ 只剩 Top 5
生成层(任意 OpenAI 兼容端点) 一句话中文摘要
    ↓
digest.html(日报)+ stats.md(运行统计)+ judgments.json(原始判断)

仓库五个文件,下面按数据流向拆。

三源归一化

📍 来源:fetchers.py 第 28~77 行

HN 走官方 Firebase API(免 key),50 条 item 详情并发拉取。GitHub 没有 official trending API,用 search API 近似:近 7 天新建加 stars:>10 滤掉刷星仓库。Agent Skills 用 topic:agent-skills 加近 30 天有推送过滤——换 topic 就换关注领域。三个 fetcher 的产出统一成 Item(id, source, title, url, meta),下游只认这个结构,不关心来源。这是「state 进、类型化答案出」对异构源的适配方式:判断层不关心 state 从哪来。

判断层:不到八十行的 REST 封装

📍 来源:jev_client.py 第 28~68 行

官方有 Python SDK(pip install typesafe-sdk),我没用。日报只需要拼请求、记用量、并发三件事,requests 裸调够了,而且裸调的请求响应可以直接放在文章里讲:

def system_one(self, state, questions: dict) -> dict:
    payload = {"state": state, "model": self.model, "questions": questions}
    headers = {"Authorization": f"Bearer {self.api_key}",
               "Content-Type": "application/json"}
    for attempt in range(self.max_retries + 1):
        resp = requests.post(ENDPOINT, json=payload, headers=headers,
                             timeout=self.timeout)
        if resp.status_code == 429 or resp.status_code >= 500:
            if attempt < self.max_retries:
                time.sleep(0.5 * (2 ** attempt))   # 退避重试
                continue
        resp.raise_for_status()
        data = resp.json()
        # 记录 usage.input_tokens 和延迟,供成本表用
        return data["answers"]

90 条内容走 system_one_many(第 65 行),线程池 8 并发。官方限流 1200 请求/分钟,这个量级碰不到。每条 item 一次调用、四个问题并行作答——这就是官方说的「加问题不加延迟」,问题数量翻倍,延迟和输入 token 都几乎不变。

问题集:一个问题只装一个判断

📍 来源:digest.py 第 17~49 行

QUESTIONS = {
    "is_relevant": {
        "type": "noul",
        "instructions": "这条内容与 AI / LLM / Agent 工程明显相关(纯财经、政治、娱乐不相关;"
                        "AI 行业动态、模型发布、开源项目、开发工具都算相关)"},
    "category": {
        "type": "choice",
        "instructions": "这条内容的主要话题归类",
        "criteria": {
            "model": "新模型发布、评测、训练相关",
            "open_source": "开源项目 / 仓库动态",
            "tool": "开发者工具、框架、基础设施",
            "industry": "行业动向、融资、政策",
            "product": "AI 产品发布或更新",
            "other": "以上都不是"}},
    "actionability": {
        "type": "score",
        "instructions": "对正在做 AI 产品的开发者,这条内容的可操作性(能否直接上手用/集成/参与贡献)",
        "criteria": [
            "纯新闻,无可操作点",
            "值得知道,但暂无动作",
            "可以动手试试,优先级不高",
            "值得本周就上手或集成",
            "直接影响我的项目,立刻行动"]},
    "digest_worthy": {
        "type": "noul",
        "instructions": "这条内容值得进入「给追踪 AI 工程前沿的读者」的今日简报"},
}

actionability 和 digest_worthy 拆成两个问题,学的是 fast-jev-compaction 把 keepCall 和 keepResult 拆成两个 noul 的做法。「值得知道」和「值得动手」经常冲突——HN 首页那条《OpenAI is well positioned to fast-follow Jev》,前者高后者低。两个判断塞进一个问题,答案会糊掉。官方 jaggedness 清单里专门有这条提醒。

is_relevant 是闸门,低于阈值直接丢,后续零成本。criteria 里每个选项都写了判定描述而不是光秃秃一个词——choice 的选项描述是模型选对的依据,写得越具体,误分越少。

程序层:判断能解决的全走代码

📍 来源:digest.py 第 71~96 行

for item, ans in judged:
    if ans["is_relevant"]["noul"] < relevant_threshold:
        continue
    key = re.sub(r"[^\w]", "", item.title.lower())[:60]   # 同题异源去重
    if key in seen:
        continue
    seen.add(key)
    actionability = min(1.0, max(0.0, ans["actionability"]["score"] / (n_levels - 1)))
    digest_worthy = ans["digest_worthy"]["noul"]
    ranked.append({...,
        "rank_key": W_ACTIONABILITY * actionability + W_DIGEST * digest_worthy})
ranked.sort(key=lambda r: r["rank_key"], reverse=True)

过滤、去重、排序全在代码里,复合权重 0.6 和 0.4 是两个常量。想改口味改常量,不用动任何 prompt。score 归一化时除以 n_levels - 1,因为 Jev 的 score 从 0 级起算。这一层的每个判断都不花钱——按官方 jaggedness 清单,排序和去重本来就是模型不可靠、代码一行的事。

这个项目我是每天跑一次的,所以去重不止发生在单次运行内,还发生在天与天之间:HN 的热榜一挂就是两三天,不挡的话同一条新闻天天见。判断过的条目 id 记进 output/state.json(保留 14 天),第二天只对新增条目调 Jev——既不重复读新闻,也不重复付费。判断层失败时这些 id 不记账,第二天自动重判。

生成层和兜底层

📍 来源:digest.py 第 98 行起、第 5669 行;main.py 第 7089 行

生成层只对 Top 5 调摘要模型,一次一句中文摘要,走标准 OpenAI 兼容端点(.env 里改 OPENAI_BASE_URL 就换厂商)。

兜底层是这次实现里我最晚补的一块。判断层挂了怎么办?日报是 L1 只读场景,正确答案是降级而不是报错退出:main.py 里判断层整体 try/except,异常时 fallback_ranking 按原始热度(HN 分数、GitHub star)排序,简报照出,标注「今日判断层不可用」。流水线的可用性不该取决于一个上线八天的 API。

五、跑出来了什么

先跑 python main.py --dry-run,只拉源不调模型,这步不需要任何 key。我写作当天的真实输出:

[fetch] 90 items in 6.6s
  hn:49805509    GPT-6 Sol and Luna
  hn:49803892    Claude Opus 5.5
  hn:49805278    'We hacked the FBI:' Hackers say they have data on all FBI employees
  ...

python main.py 跑全流程。判断层对每条内容发出的请求,就拿 HN 那条 Claude Opus 5.5 来说:

{
  "state": {"source": "hackernews", "title": "Claude Opus 5.5",
            "url": "https://news.ycombinator.com/item?id=49803892",
            "points": 1229, "comments": 218},
  "model": "jev-latest",
  "questions": { "...": "同上 QUESTIONS,四个问题原样发送" }
}

实测当天(2026-09-23,90 条全量判断)judgments.json 里的原始答案,挑三条对照看。高相关的:

{"id": "gh:1374005005", "title": "tamaratran/fast-jev-compaction",
 "answers": {
   "is_relevant": {"type": "noul", "noul": 0.98},
   "category": {"type": "choice", "choice": "open_source", "confidence": 0.95,
     "probabilities": {"open_source": 0.96, "tool": 0.04, "model": 0.0,
                       "industry": 0.0, "product": 0.0, "other": 0.0}},
   "actionability": {"type": "score", "score": 2.74, "confidence": 0.74, "...": "..."},
   "digest_worthy": {"type": "noul", "noul": 0.6}}}

被闸门拦掉的(FBI 数据泄露那条,is_relevant 只有 0.1,后面三个问题照常作答但程序层第一道闸就丢弃):

{"id": "hn:49805278", "title": "'We hacked the FBI:' ...",
 "answers": {
   "is_relevant": {"type": "noul", "noul": 0.1},
   "category": {"type": "choice", "choice": "other", "confidence": 0.81,
     "probabilities": {"other": 0.84, "industry": 0.16, "...": 0.0}},
   "actionability": {"type": "score", "score": 0.11, "confidence": 0.91}}}

边缘样本最有意思:《Can gzip be a language model?》is_relevant 0.82、归类 model 但 confidence 只有 0.59——判断层自己知道这条不好判。这种低置信度条目正是该进人工复核队列的,一把梭路线里它只是模型一句话里的一个去留。

当天运行的完整统计(stats.md):

阶段数字
拉取三源 90 条(新增 90,跳过已判断 0)
判断90 次 Jev(jev-latest),中位 477ms/次,输入 65,652 tokens,约 $0.0028
闸门is_relevant ≥ 0.6 保留 50 条
摘要5 次(glm-5.3-flash),509 + 1128 tokens,约 ¥0.0008
耗时端到端 48.5s(拉取 6.2s + 判断 5.8s + 摘要 36.4s)

答案全部落在 judgments.json,每条的 probabilities 和 confidence 都在。

每天打开的是 digest.html:单文件、内联样式、零依赖,浏览器直接开。「今日总结」是摘要层多生成的一段导语,把 Top 5 压成两三句话;往下是「今日最值得看」置顶卡片(标题链接、一句话摘要、来源徽章、热度、判断分数),再往下是按模型 / 开源 / 工具 / 行业 / 产品双栏排的分类速览,成本收进页脚。同内容的 markdown 版本和判断细节、延迟、各源吞吐在 stats.md——日报是产品,判断矩阵是仪表盘,两份文件分开。

当天日报(digest.html 的「今日最值得看」)长这样:

  1. addyosmani/agent-skills —— Addy Osmani 出品的 AI 编程代理工程技能库,助你构建可靠生产级代码。· 98,502★
  2. K-Dense-AI/scientific-agent-skills —— 把 AI 代理变成 AI 科学家的技能库,含 165 项验证技能与百余科学数据库。· 46,172★
  3. VoltAgent/awesome-agent-skills —— 千余个官方与社区 agent 技能精选合集,兼容 Claude Code 等主流工具。· 34,754★
  4. alibaba/open-code-review —— 阿里开源的代码审查工具,规则管线结合 LLM Agent,经大厂规模实战验证。· 39,820★
  5. sickn33/agentic-awesome-skills —— 本地代理优先控制平面,集成 2445+ 智能体技能,支持发现验证与规划。· 46,802★

页面顶部是一段生成的今日总结导语(「今日入选条目高度聚焦于智能体技能这一方向……」),往下是按模型 / 开源 / 工具 / 行业 / 产品双栏排的 50 条分类速览,每条带链接和热度。

对照一条:不判断直接生成的路线在 baseline.py,90 条一次性塞给摘要模型,一段 prompt 挑 10 条写摘要。两条路线跑同一批数据的实测(comparison.md):

维度不用 Jev(一把梭)用 Jev(四层架构)
模型调用1 次大调用(glm-5.3-flash)90 次 Jev + 5 次摘要
tokens11,058(in+out)判断 65,652 in(输出免费)+ 摘要 1,637
耗时114.7s判断 5.8s + 摘要 18.7~36.4s
成本¥0.0055$0.0028(判断)+ ¥0.0008(摘要)
输出形态一段散文表格,程序没法消费类型化矩阵,阈值、权重、路由都是代码
调筛选口味改 prompt 重跑,效果听运气改 RELEVANT_THRESHOLD 或两个权重常量,立刻生效
可解释性为什么选这条,问模型去judgments.json 全存档,confidence 低的可自动进复核队列
失败模式漏选、编造标题、格式漂移,都不可观测schema 锁死格式;判断层挂了有兜底

这张表里有一格要诚实地说清楚:raw 成本上一把梭反而便宜。判断层每次调用都重复发送 state 和四个问题的定义,90 次就是 6.5 万输入 token;一把梭把 90 条塞进一次调用只花 1.1 万 token。这个规模下 Jev 路线总成本大约是一把梭的 4 倍——几厘钱对几分钱的差别。

那为什么还选四层架构?三个在账单之外、但真实存在的差别。一是第二天的账单:跨天去重之后,判断层只对新增条目付费(HN 热榜第二天往往只有一二十条新的),一把梭每次都是全量 90 条重新生成。二是对标价尺度的敏感度:一把梭的成本 = 全量内容 × 所用生成模型的单价,拿旗舰模型当筛选器就是 Langfuse 那组数字($33,000 vs $160 每百万答案);判断层把单价锁死在 $0.042/M,换什么摘要模型都不影响筛选成本。三是** 4.5 倍的端到端时延差**(114.7s vs 25.5s)和那张「输出形态」行——阈值可调、置信度可路由、失败可观测,这些不是一把梭加钱能买到的。

两条路线的输出质量倒是接近:baseline 挑的 10 条和 Jev 路线保留的 50 条高度重叠,都抓住了 Claude Opus 5.5、GPT-6、agent-skills 生态这些主线。差别在 Jev 路线把「为什么是这 50 条」写成了可以审计的数字。

六、什么时候用 Jev,什么时候不用

这个问题躲不开:Structured Output(让普通 LLM 按 JSON Schema 输出)也能拿到类型化答案,传统分类器更便宜,什么时候值得引入一个新模型?

方案擅长短板
Jev判断快(70~500ms)、输出带校准概率、价格低闭源 early access、无理由输出、英文优先
Structured Output任何有 API 的模型都能做、生态熟概率未校准、延迟和价格按生成算、格式偶尔漂
传统分类器/规则确定、免费、可解释覆盖不了语义判断,改类别要重标注

我的决策标准就两条。判断量要大——一天几百次以上,延迟和单价的差距才会变成真金白银;要的是结构化判断而不是一段话——如果下游本来就是人读,直接用生成模型反而省事。日报 90 条 × 每天,两条都占。反过来,一天十几次判断、或者答案要给客户看理由的场景,Structured Output 甚至直接调对话模型更合适。

七、边界和校准

有几点是跑之前就担心、实测部分兑现的。中文科技媒体的标题歧义会让 category 在 model 和 tool 之间漂——这次没出现大规模漂移,但《Can gzip be a language model?》确实贴着阈值边缘:is_relevant 0.82 过了闸门,归类 model 的 confidence 只有 0.59,判断层自己知道这条不好判。score 的等级描述写得含糊时 probabilities 会摊平、置信度跟着降——Top 5 里几条 skills 仓库的 actionability confidence 都在 0.7 以下,下一步打算把五个等级的描述改得更互相排斥。

比这些更根本的一件事:概率不是安全证明。「noul = 0.9」说的是九成把握,不是这九成里没有对抗性输入——Jev 自己就不抗提示注入,我的 state 里现在只有标题、链接和分数,注入面很小,但如果以后把网页正文拉进 state,得先过一遍 daryl 那篇提到的提示注入筛查(每段几个 noul 的用法)。正确的上线姿势是 shadow mode:先并行跑不接管,拿人工决策对答案,记录分歧样本,分布稳定后再逐步放权。日报已经天然走了一半——输出我每天都会人工过目。

结语

判断题交给判断模型,作文题交给生成模型,算术留给代码。

仓库地址:jev_news,clone 后 cp .env.example .env 填 TYPESAFE_API_KEY 和摘要层的 key 即可复现全文流程。下一步把这个流程封成 Skill,每天一句「今日简报」就能用,那是这个系列的第二篇。

JevAI NativeAgent

← 返回AI Native