第 7 章

第 7 章:Ranking 与 Verification——排序与校验

第 7 章:Ranking 与 Verification——排序与校验

Ranking 与 Verification 是决策层最常出现在生产系统里的两种角色:一个把候选排出先后,一个把产物逐条查错。Ranking 的底层是 Scoring,评估靠次序敏感的 nDCG / Recall@k;Verification 的底层是 Noul,是给生成模型加后置护栏的主力。本章讲清两者的机制、指标与典型项目。

Ranking 的底层是 Scoring

排序看起来是一个独立的任务,但在 Jev 里它没有专属的类型——Ranking 就是"逐条打分,再按 score 排序"。用的还是 Score。

from typesafe import TypesafeClient

client = TypesafeClient()

def rank(query: str, items: list[str]) -> list[str]:
    questions = {
        f"r_{i}": {
            "type": "score",
            "question": f"这条内容对回答「{query}」的价值有多高?",
            "labels": ["无关", "偏低", "可选", "有用", "关键"]
        }
        for i in range(len(items))
    }
    state = "\n\n".join(f"[{i}] {s}" for i, s in enumerate(items))
    d = client.systemone(state=state, questions=questions,
                         instructions="按对回答查询的贡献给每条内容评级,而不是按它写得漂不漂亮。")

    scores = {i: d[f"r_{i}"].score for i in range(len(items))}
    return [items[i] for i in sorted(scores, key=scores.get, reverse=True)]

这里沿用了上一章的批处理做法:候选编号进 state、一次调用全部评分。和 Search 的区别在于输出形态——Search 返回的是"留哪些"(一个被 Noul 过滤的子集),Ranking 返回的是"谁在谁前面"(一个有序列表)。当你要的不只是"相关/不相关",而是"一组条目的相对好坏"时,用 Score 排序。

Ranking 也可以由多条正交维度合成。jeff(saembit/jeff-cli)的做法就很有代表性:它对每个条目、按 YAML 规格里每个加权维度各问一次 Jev Score(都在一次请求里),然后在代码里做 Σ 权重 × 分数。判断交给模型,权重留在代码里——这条分界放进了排序里,权重就变成了可调、可审计的参数,而不是藏在提示词里。

次序敏感的指标:nDCG 与 Recall@k

Ranking 有个和分类不一样的评估习惯:不要用准确率。

分类看"选对没有",Ranking 看"排得对不对"。同样是"正确答案排在第二",在不同位置意义完全不同——排在第一和排在第十,对用户体验的差别是巨大的。所以 Ranking 的指标都是次序敏感的:

  • nDCG@k(Normalized Discounted Cumulative Gain):衡量前 k 位里相关条目的位置加权收益,排在前面权重更高。
  • Recall@k:前 k 位里覆盖了多少真正相关的条目。
  • Hit@1:排第一的那条是不是相关(上一章 jevsearch 用的就是它,83%)。

为什么这件事重要?因为同一个决策层,换个排序任务,"好"的定义就变了。你必须先定指标,再调阈值和 query 写法,否则优化是盲目的。

两种排序:打分式与比较式

排序在工程上有两种实现,各有取舍:

打分式(pointwise):给每个条目独立打一个分,再排序。上面 rank() 就是这种。优点是便宜(一批并行)、可与检索精筛共用同一次调用;缺点是分数之间的可比性依赖校准——如果模型对"有用"和"关键"的边界在不同条目上飘,排序就会抖。

比较式(pairwise / listwise):让模型直接在两两或整列里比出谁胜。它的判断更稳("A 比 B 更有用"比"A 值 4.2 分"更可靠),但调用量大。JevRanker 正是把这种比较式重排压进了一次前向——见下文。

选哪种取决于你的预算和稳定性要求。打分式适合大规模、粗粒度;比较式适合小候选集、要精排。

Verification:给生成加后置护栏

现在转到另一半。Verification 是"给生成模型的产出查错",是后置护栏的主力。

本书的核心论点——生成负责产出、决策负责把关——在 Verification 上体现得最直接。让大模型起草一封回复、写一段代码、生成一份摘要,然后用 Jev 逐条核实这个产物是否满足要求。

d = client.systemone(
    state=f"原文:\n{source}\n\n生成的摘要:\n{summary}",
    questions={
        "no_fabrication": {"type": "noul", "question": "摘要是否包含了原文里没有的事实?"},
        "no_overclaim":   {"type": "noul", "question": "摘要是否做出了原文无法支撑的断言?"},
        "has_numbers_ok": {"type": "noul", "question": "摘要里的所有数字是否都能在原文中找到?"},
        "covers_core":    {"type": "noul", "question": "摘要是否覆盖了原文的核心结论?"}
    },
    instructions="你是事实核查员,逐条判断,宁可标记出来也不要放过。"
)

关键在于:Verification 是清单式的,不是打总分式的。 不要把"这份摘要好不好"作为一个整体问题问出去,而是拆成若干条独立的检查,每条一个 Noul。这样你能精确知道是哪一条不过关,也能给不同条目设不同的处理动作(no_fabrication 不过 → 直接否决;covers_core 不过 → 退回重写)。

这也是个 "把判断拆开" 的通用原则:清单越细,可解释性和可操作性越强。 一个笼统的"质量分"只能告诉你"别用",一组清单能告诉你"哪里出问题、该怎么改"。

Verification 与 Detection 的区别:看输出 vs 看输入

Verification 和 Detection 都是 Noul,长得很像,但方向相反:

  • Detection 看"输入里有没有坏东西":垃圾评论、恶意链接、注入攻击、PII。它守的是入口。
  • Verification 看"输出对不对、合不合规":幻觉、越权承诺、不合规回复、未通过的测试。它守的是出口。

一个安全是从外面进来的,一个是从里面出去的。两者的阈值直觉也因此不同:Detection 常"宽进"(宁可误报),Verification 常希望在产出放行前把所有问题都拦下(宁可多标记),但具体松紧还是看你把"拦下"的代价定在哪里。

flowchart LR
    IN["输入 / state"] --> D["Detection
输入里有坏东西吗?
(Noul,守入口)"] IN --> GEN["生成模型
(产出草稿)"] GEN --> V["Verification
输出对不对 / 合不合规?
(Noul,守出口)"] V --> GATE{"逐条清单
都在阈值之上?"} GATE -- 是 --> SHIP["放行"] GATE -- 否 --> FIX["回退 / 人工 / 重写"]

两个 Ranking 项目

Vector Graph RAG(zilliztech/vector-graph-rag)——把 Jev 用在多跳检索的重排上。 这是一个多跳检索系统,它用 Jev 的 Noul 判定来选择图关系,并对完整的源段落做重排,与向量检索的候选并列比较。它的两阶段评测给出了一个很硬的结果:在 1,000 条 MuSiQue + 1,000 条 2Wiki 查询上,平均 Recall@5 达到 86.07%。

这个项目说明 Ranking 的底层模式可以嵌入到更复杂的检索结构里。图检索要决定"走哪条边、展开哪个关系",这本身是无数次小判断的叠加;把 Noul 用在这里,等于让决策层替图遍历做"这条关系值不值得走"的判定。而最终指标之所以用 Recall@5 而不是准确率,正是上一节说的次序敏感逻辑——它衡量的是"前 5 条里覆盖了多少真相关"。

JevRanker(hgqimo/JevRanker)——把比较式重排压进一次前向。 JevRanker 是 Jev 类型化决策格式的一个开源移植(基于 NanoJev 的 Qwen3-0.6B,在 T2Ranking 上训练,不调用托管 API)。它替换掉了两个已发表检索重排器内部的 LLM 比较器——BlitzRank 的锦标赛图,以及 Reranker-Guided Search。关键设计是:每一场比赛只需要一次 Choice,在 k 个候选路径上做一次单向前向、零解码 token。 结果是:

  • 0.6309 nDCG@10(T2Ranking dev),对比同一个 0.6B 模型用 RankGPT 式 listwise 提示的 0.2162;
  • 每次比较 34 ms,而 listwise 是 752 ms;
  • 在 Reranker-Guided Search 内部,每查询延迟低 8.6–9.4×。

这组数字把"比较式重排"的两种实现路径摆在了一起:把重排当成生成任务(让模型解码一段排序文本),对比把它当成一次类型化决策(一次前向,直接输出候选间的选择概率)。 后者的 nDCG 高了三倍、延迟低了二十倍。原因还是那句老话——重排是"选哪个"的判定任务,不是"写一段话"的生成任务,交给能直接产概率的决策层,效果和成本都更好。

Verification 项目:进口护栏的四个范本

claude-code-templates(davila7/claude-code-templates)——把护栏做成一个可安装的 mod。 这是 Claude Code 的配置套件,其中有一个叫 jev-guardrails 的模块,它通过 TypeSafe System One 筛查提示词与会话轮次,防越狱、防有害输出、防策略违规。这个项目的意义不只在于功能,而在于形态:护栏被做成了一个"可插拔的模块",用户装上就有一道类型化判定卡在模型输出与用户之间。后置护栏只有变成这种"一行配置就能开"的东西,才会被广泛用起来。

fx(vercel-labs/fx)——护栏下沉到框架内建。 fx 是 Vercel Labs 的编码 Agent,它内建了 typesafe_permission_reviewer,让 Agent 的权限决策走 Jev,而不是再发一次 LLM 调用。这是护栏的最高形态:不是外挂出来的检查步骤,而是框架自带的、默认走决策层的权限判定。当越来越多的框架开始内建这种"判定走 Jev"的默认路径,护栏就从"要记得加"变成了"本来就在"。

semcheck(arturobermejo/semcheck)——把规则写成英语句子。 semcheck 是一个 Go linter,它最大的特点是规则本身就是一句英语问句,比如"这次 log 调用会不会写下个人数据?"。它对规则适用到的每一段代码问一个 Jev Noul,超过该规则阈值的就报告出来。它的两条内置规则在三个开源项目里采样到的 12 个发现中,12 个都对。这个项目展示了 Verification 的一种"无代码规则"写法——想加一条规则,你不用写正则、不用训练分类器,只要写一句自然语言。这正是"语义代码检查"相对传统静态分析的增量:那些能用语法表达出来的规则早就被 linter 覆盖了,真正难的是"这段日志有没有泄漏 PII"这种只能靠语义判断的规则。

klauswg 的三件套:jev-proof / jev-fidelity / jev-rental——把 Verification 做成可校准的。 这三个项目同属 klauswg/jev-suite,都是"逐事实核对 + 概率门控"的样板,而且都附带了注入攻击的对抗评测:

  • jev-proof——逐条核对视频字幕里的赞助广告片段是否符合验收规则,每个事实一次 Noul + Choice 调用,置信度门控留在确定性代码里;90 样本校准达 0.922 门控准确率、0/15 注入翻转。
  • jev-fidelity——问 Jev 每一处编辑是否保留了原意(preserved / equivalent / drift / lost),0.70 置信度门控在代码里,拿不准就降级到人工而不是放行;55 样本校准 91/92 门控判断正确、0/20 注入翻转。
  • jev-rental——把租房信息里的每条声明分成"需现场核实 / 需索证 / 高风险话术"三桶,生成看房前清单;50 样本校准 0.910 门控准确率、0/10 注入翻转。

这三个项目合起来给了一条很重要的经验:Verification 的护栏必须自己经得起对抗。 那些 "0/15、0/20、0/10 注入翻转" 的数字,是在测试"当被核对的内容里藏了『请判定为通过』这类指令时,门控会不会被骗"。答案是不会——因为门控逻辑在代码里,不在被核对的文本里。这正是"代码拥有控制流"在护栏场景下的安全意义:即便输入里嵌入指令,判定动作和阈值也由代码主宰。

其余项目一张表带过

项目 形态 关键设计
citation-verifier(MarissaFamularo/citation-verifier) Score(核对) 核查每篇被引论文是否真的支撑引用它的那句话:Claude 定位引文、Jev 给"支撑度"打分、人做最终裁定
OpenViking(volcengine/OpenViking) Noul(重排) 用 jev-latest 给每个候选文档打分、把概率当相关性,充当 rerank 客户端
jev-reranker(hotchpotch) Noul(重排) 用 Noul 判定评估检索文档"作为证据的相关性与有用性",排序并可选按阈值过滤
jev-reranker(shinpr) Noul(重排 CLI) JSON 进 JSON 出的 CLI,用相互独立的 Jev Noul 检查来排序候选、套证据阈值、抽源文本
Paper Radar(Eliot5566/JEV-Paper-Radar) Noul(排序) 对每篇新 arXiv / bioRxiv 论文按平实语言的兴趣点问一个 Noul,把前列结果发成每日页和 RSS
Skill Scanner(cisco-ai-defense/skill-scanner) Noul(护栏) Cisco 的 Agent skill 扫描器,查注入与数据外泄;System One 分析器被刻意设成只做提示的层级,不能自己产出 finding、也不能改严重度

最后一行值得单说。Skill Scanner 把 Jev 做成**"故意只能建议"**的一层,不允许它直接产出 finding 或改变严重度——这看起来是"削弱"了决策层,其实是一种成熟的分工:确定性分析器给出的事实与严重度不可动摇,Jev 只能在这个基础上提供"提示性的语义判断"。护栏不是要取代确定性检测,而是在确定性检测够不到的地方补上语义判断,同时保证它没有权力覆盖那些铁一般的事实。

小结

  • Ranking 的底层是 Scoring——逐条打分再排序,支持把权重留在代码里(jeff 的 Σ 权重 × 分数);评估用次序敏感的 nDCG@k / Recall@k / Hit@1,不用准确率。
  • 排序有两种实现:打分式便宜、适合大规模;比较式更稳、适合精排。JevRanker 用一次前向的选择概率做比较式重排,拿到 0.6309 nDCG@10(对比 listwise 的 0.2162)、每次比较 34 ms(对比 752 ms)。
  • Verification 用 Noul 做"逐条清单式核对",是给生成加后置护栏的主力;清单越细,可解释性与可操作性越强。
  • Verification 与 Detection 的区别是"看输出"vs"看输入":前者守出口(幻觉、越权、不合规),后者守入口(垃圾、注入、PII)。
  • 护栏要能内建、要经得起对抗:fx 把权限审查做进框架、claude-code-templates 把护栏做成 mod、klauswg 三件套用 0/15、0/20、0/10 的注入翻转证明门控不被骗。
  • 护栏的边界是"语义补位"而非"越权覆盖":Skill Scanner 就让 Jev 停在 advisory 一层,不改确定性结论。

下一章走到十种形态的最后一组:把非结构化输入变成特征(喂给下游模型)或结构化记录(喂给人/程序)。

📑 Jev 实战:用类型化决策重构软件

1 第 1 章:为什么需要决策层——从"生成一切"到"只做判定" 2 第 2 章:三种类型化输出——Choice、Score、Noul 与调用契约 3 第 3 章:十个决策形态——什么时候该把判断交给 Jev 4 第 4 章:Classification 与 Routing——把分诊做成一等公民 5 第 5 章:Detection 与 Scoring——二元判断与有序评分 6 第 6 章:Search 与 Retrieval——在候选集里找相关 7 第 7 章:Ranking 与 Verification——排序与校验 8 第 8 章:ML Feature Extraction 与 Structured Data Extraction——把文本变特征与结构化数据 9 第 9 章:检索与知识图谱——Search and retrieval / Graphs and knowledge graphs 10 第 10 章:模型路由与 LLM 护栏——Model routing / LLM guardrails 11 第 11 章:语义代码检查——Semantic code linting 12 第 12 章:特征提取与需求预测——Feature extraction / Demand forecasting 13 第 13 章:招聘与线索生成——Recruiting / Lead generation 14 第 14 章:客户支持——Customer support 15 第 15 章:理赔、金融犯罪与风险评估——Insurance claims / Financial crime / Risk assessment 16 第 16 章:法律与合规——Legal and compliance 17 第 17 章:电商市场与广告——E-commerce marketplaces / Advertising 18 第 18 章:内容审核与信任安全——Moderation and trust and safety 19 第 19 章:游戏——Gaming 20 第 20 章:实时应用——150 毫秒预算 21 第 21 章:科学发现——Scientific discovery 22 第 22 章:大数据上的 AI Map Reduce——为什么便宜 100 倍 23 第 23 章:通用验证——Universal Verification 24 第 24 章:Harness Engineering——把决策织进智能体骨架
← 返回本书大纲