用 Jev 加速 RAG 检索并降低成本,这事到底能不能成?实测了一下
作者:kikuziro(Qiita)
我在 RAG 的各个环节插进 Jev,测了测哪里会发生什么变化。
这篇写给谁
- 心里在想「Jev 到底能不能用在 RAG 检索上?」的人
- 热爱 RAG 检索的人
Jev 是什么
Jev 是 TypeSafe AI 在 2026 年 9 月 15 日发布的模型。解说文章已经很多了,这里粗略讲一下:一句话说,它是不生成文本的 AI 模型。 给它「状态」和「带类型的提问」,它会一次性带着概率返回答案,不写文章。
响应:约 70〜500ms
价格:输入 $0.042/百万 token,输出免费
提问类型:选项、yes/no、分档评分
特征:多个问题在一个请求里并行处理
提供状况:early access
测了什么
RAG 检索的流程是「提问 → 向量检索 → 重排 → LLM 回答」。这里面能插 Jev 的地方有三处:检索之前、重排、调用 LLM 之前。我在每一处都放了 Jev,验证速度和成本会不会改善。
1. 重排 —— 想确认:在排序精度上,能追上专用重排器吗(插入位置:重排)
2. 「无法回答」的判断 —— 想确认:答案不在文档里时,能在调用 LLM 之前拦住吗(插入位置:LLM 之前)
3. 把 1 和 2 合成一次请求 —— 想确认:合并之后精度会掉吗、能快多少省多少(插入位置:重排)
4. 拦掉范围外的提问 —— 想确认:「今天晚饭吃什么」这种能不做检索就弹掉吗(插入位置:检索之前)
验证的准备
数据集
首先需要「这个问题的答案写在这个 chunk 里」这样的正确答案数据。我用了虚构公司的内部规程和业务手册,人事、财务、总务、IT、安全卫生 5 个领域 × 8 份文档 × 10 个 chunk,共 40 份文档 400 个 chunk。
写的时候我记录了哪个事实写在哪个 chunk 里、哪个事实故意没写。所以正解标签可以从这个记录机械地推出来。每个问题先用向量检索取前 20 条,然后打两个标签。
相关度:0:无关 / 1:同一领域 / 2:同一规程的另一个事项 / 3:正是这条
是否包含答案:光凭这个 chunk 能不能回答问题(yes / no)
话虽如此,如果记录时漏写了,那它就直接变成错误的正解数据。 所以我用了两种方式双重检查:
- 人的眼睛:对 14 个「擦边」问题,我把排在前面的 chunk 全部自己读了一遍
- 另一个 AI:不让它看记录,让 Claude Opus 5 来判定
内容基本一致,和人与人对答案时的偏差是同一水平,所以判断这份正解数据可用。
· 提问种类 可回答 | 提问 「交通费报销的截止日是?」 | 检索排第一的 chunk 交通费报销须在每月 25 日前申请。 | 能答吗 ○ 25 日 | 件数 60 件
· 提问种类 擦边 | 提问 「产假期间社保费免除,要什么时候之前申请?」 | 检索排第一的 chunk 育儿休假期间的社保费,经本人申请可予免除。手续在人事部办理。 | 能答吗 × 没写期限 | 件数 40 件
· 提问种类 完全无关 | 提问 「今晚吃什么好?」 | 检索排第一的 chunk 员工食堂营业时间为 11 点至 14 点。 | 能答吗 × 根本不是一回事 | 件数 20 件
所谓擦边,指的是话题和提问完美对上、但关键答案偏偏没写的 chunk。
验证环境
区域:东京(ap-northeast-1)
调用方:日本本地 PC
检索:DynamoDB(向量检索,取前 20 条)
Embedding:Amazon Titan Text Embeddings V2(1024 维)
重排器:Cohere Rerank 3.5 / Amazon Rerank 1.0(Bedrock)
对比用 LLM:Claude Haiku 4.5
回答生成 LLM:Claude Haiku 4.5
Jev:jev-1.13.0(直连 API,Python SDK typesafe-sdk 0.7.0)
验证一:重排
做法: Cohere 和 Amazon 是把提问和 20 个 chunk 交给 Bedrock 的重排功能来排序;Claude Haiku 4.5 是给 20 个 chunk 编号,让它「按相关度从高到低排列编号」。
Jev 的做法是:对 20 个 chunk 各生成一个「这条和提问的相关度是多少?」的分档评分问题,20 个问题打包成一次请求发出去。
段阶评分的 criteria 是从 0 分开始顺序排列的说明数组。
3 分的说明里我写了「不管有没有写出答案」,
是为了不让「有无答案」混进相关度里。
三个指标:
· 指标 Recall@1 | 看什么 含答案的 chunk 排到第 1 的比例 | 满分 1.000
· 指标 Recall@5 | 看什么 含答案的 chunk 进前 5 的比例 | 满分 1.000
· 指标 nDCG@5 | 看什么 前 5 条的排序和「相关度从高到低」有多接近 | 满分 1.000
结果:
· 手法 不做重排 | Recall@1 0.800 | Recall@5 1.000 | nDCG@5 0.814 | 速度 — | 1000 次查询 —
· 手法 Cohere Rerank 3.5 | Recall@1 0.950 | Recall@5 1.000 | nDCG@5 0.884 | 速度 198ms | 1000 次查询 $2.00
· 手法 Amazon Rerank 1.0 | Recall@1 0.850 | Recall@5 0.967 | nDCG@5 0.819 | 速度 337ms | 1000 次查询 $1.00
· 手法 Claude Haiku 4.5 | Recall@1 1.000 | Recall@5 1.000 | nDCG@5 0.960 | 速度 981ms | 1000 次查询 $2.73
· 手法 Jev | Recall@1 0.983 | Recall@5 1.000 | nDCG@5 0.965 | 速度 290ms | 1000 次查询 $0.25
首先 Haiku 可以直接排除——光为了排序要花将近 1 秒,而且是最贵的。为了排序专门调一个 LLM,看不出有什么好处。
然后两个重排器和 Jev 在精度和速度上没什么大差别。有差别的是价格,Jev 是八分之一。
看到这里会想「Jev 不错嘛!!」——但这个精度不太能信。
不做重排的 Recall@5 是 1.000,这意味着向量检索那一步,答案就已经进了前 5。 也就是说,重排器本来就没有出场机会。
400 个 chunk 这个规模太小了。 要正经比精度,得用更大的语料重测。
验证二:能不能判断「回答不了」
chunk 取到了,但答案没写在里面就没意义。 如果能对擦边问题判断出「答不了」,就可以不调 LLM 直接返回「没找到相关信息」,从而省钱。
做法:
- 重排分数的阈值:重排器返回的最高分低于阈值就判定为不可回答。这是 RAG 里很古老的做法。阈值是在打开测试集之前,用 40 个问题定的。 Cohere 是 0.672,Amazon 是 0.0006——手法不同,分数的量级就不同,必须分别定。
- Claude Haiku 4.5:把提问和前 5 个 chunk 给它,让它用 yes/no 回答「光凭这些信息能答吗」
- Jev:把前 5 个 chunk 和一个 yes/no 问题一起发过去
三种手法用的前 5 条,都是经过 Cohere Rerank 3.5 重排后的前 5 条。
结果:
· 手法 Cohere Rerank 3.5 阈值 | 正确率 65.0% | 擦边的漏放率 25.0% | 可回答的误拦率 53.3% | 额外时间 +0ms | 额外成本 +$0
· 手法 Amazon Rerank 1.0 阈值 | 正确率 65.8% | 擦边的漏放率 95.0% | 可回答的误拦率 3.3% | 额外时间 +0ms | 额外成本 +$0
· 手法 Claude Haiku 4.5 | 正确率 98.3% | 擦边的漏放率 2.5% | 可回答的误拦率 1.7% | 额外时间 +584ms | 额外成本 +$1.04
· 手法 Jev | 正确率 99.2% | 擦边的漏放率 0.0% | 可回答的误拦率 1.7% | 额外时间 +263ms | 额外成本 +$0.05
Cohere 放过了四分之一的擦边问题,同时弹掉了一半可回答的问题。反过来 Amazon 虽然误拦少,但放过了 95% 的擦边问题。
作者举了两个真实发生的例子:
· 提问 防灾储备的应急食品,要在保质期前多久换成新的? | 有答案吗 没写 | 检索第一条的 chunk 「储备的食品和饮用水应在保质期前更换为新品。储备品的更换时期由……总务部规定」 | Cohere 0.8306 → 放行 | Jev 0.09 → 拦住
· 提问 我接下来要休长假。多久不登系统,我的 ID 会被停掉? | 有答案吗 写了 | 检索第一条的 chunk 「信息系统部……将停用连续 45 天没有登录记录的账号」 | Cohere 0.3305 → 弹掉 | Jev 0.95 → 放行
作者的推测:
Cohere 的学习数据规格里写着「所有问题必须至少有一个正例」,所以对「答案在某处」有预设的模型,可能本来就难以判断没有答案的提问。
而 Haiku 和 Jev 两边基本都没漏。
表里没体现出来的更大效果
其实「回答不了」一旦判对,后面那一次 LLM 调用就整个消失了。这个成本削减没有出现在上面的表里。
用 Haiku 4.5 生成回答,一次大约 1.5 秒,1000 次 $1.37。只针对「答不了的问题」比较一下:
· 没有 Jev | 判断 — | 生成回答 1,459ms | 合计 1,459ms
· 有 Jev | 判断 263ms | 生成回答 不调用 | 合计 263ms
不到五分之一。 为了返回一句「没找到」,不再需要让人等 1.5 秒。
成本更极端:Jev 的判断 1000 次查询 $0.05,生成回答一次 $0.00137。1000 个问题里只要拦住 37 个,Jev 的钱就赚回来了。
当然,能回答的问题会因此慢 263 毫秒。 但拦住一个问题带来的回报很大,所以只要答不了的问题哪怕只有几个百分点,就值得装。
验证三:重排和回答判断,能不能一次做完
Jev 能并行处理问题,所以能不能把重排和回答判断合成一次请求? 于是我对每个 chunk 同时发两个问题。
这样就能一边按相关度排序,一边用「noul 最高的 chunk 也够不到 0.755 就判不可回答」来切。增加的只有 yes/no 的问题,请求还是一次。
三种构成对比:
· 构成 ① 重排器 → 用重排分数阈值 | nDCG@5 0.884 | 回答判断正确率 65.0% | 速度 198ms | 每 1000 次查询成本 $2.00
· 构成 ② 重排器 → 用 Jev 判断回答 | nDCG@5 0.884 | 回答判断正确率 99.2% | 速度 468ms | 每 1000 次查询成本 $2.05
· 构成 ③ Jev 一次同时做重排+回答判断 | nDCG@5 0.960 | 回答判断正确率 99.2% | 速度 292ms | 每 1000 次查询成本 $0.34
③ 的回答判断和 ② 一个问题都不差,排序还比 ①② 更好。速度是 ② 的六成,价格是六分之一。
省下来的是重排器那一次调用。
验证四:把范围外的提问拦在门口
RAG 检索里,「今天晚饭吃什么」或者乱敲的键盘这种无关、无意义的提问,本来就不需要检索。
所以我在检索之前先用 Jev 问「这个提问在范围内吗」,范围外的话,Embedding、检索、重排、LLM 全部跳过。
返回的是选中的标签和每个标签的概率。放行的条件是「概率最高的标签是 in_scope」,没有用阈值。
结果:
· 构成 不拦(检索→重排→LLM 拒绝) | 范围外提问的响应时间 1,794ms | 每 1000 件成本 $3.28
· 构成 用 Jev 拦 | 范围外提问的响应时间 241ms | 每 1000 件成本 $0.044
只问一个问题,所以瞬间返回。检索和 LLM 都不用走,价格变成七十五分之一。
精度方面:100 个范围内提问里错拦了 2 个,20 个无关提问拦住了 19 个。 放过去的那 1 个是:
「写个用 Python 每晚备份照片文件夹的脚本」
看来是被我在范围内写的「数据备份」带偏了。
无意义输入 10 条全部判成 unclear。不过「详细说说」这类接续发言 5 条也全被判成 unclear。 初次还是接续,应用侧是知道的,所以接续时把对话历史一起传过去,或者干脆跳过门卫,是更推荐的做法。
范围内的写法不同,成绩会明显变化。 最初我只写了「人事、财务、总务、IT、安全卫生」这 5 个词,结果 34 个问题里错拦了 5 个。 像「得了流感几天不能去公司?」这种不出现「公司」「规程」字样的提问被弹掉了。
改成把处理的规程全部写出来之后,错拦变成 0 件。实际用的 in_scope 是这一大段:
关于在这家公司工作,员工会问公司内部 help desk 的那种提问。help desk 处理的是:休假与考勤、育儿休假与护理休假、红白喜事休假与慰问金、人事考核、招聘与试用期、停职、离职。通勤费与出差费、经费报销、预付款与备用金、发票与付款、备品采购、公司卡、预算。福利、员工证等出借物品、会议室与公务车、邮件与快递、来客、出入楼、防灾储备。信息安全、账号与密码、出借电脑、软件、远程连接、邮件与聊天、系统故障与安全事件、数据备份。健康体检、压力检查、产业医、长时间劳动、工伤与通勤灾害、传染病、避难演练、办公环境。即使措辞很随便、即使不出现「公司」「规程」这些词、即使规程里没写答案,也算在内。
不是让模型从语料里猜,而是用文字写明这个系统要回答什么。5 个词是不够的。
总结:速度和成本
· 放 Jev 的位置 重排 | 做什么 替换 Cohere | 速度 198ms → 290ms | 每 1000 件成本 $2.00 → $0.25(八分之一)
· 放 Jev 的位置 回答不了的判断 | 做什么 调 LLM 之前拦住 | 速度 1,459ms → 263ms(快 5.6 倍) | 每 1000 件成本 $1.37 → $0.05(二十七分之一)
· 放 Jev 的位置 门卫 | 做什么 检索之前拦住 | 速度 1,794ms → 241ms(快 7.4 倍) | 每 1000 件成本 $3.28 → $0.044(七十五分之一)
重排是替换,所以比较对象是 Cohere。速度反而稍输,起作用的是价格,即便如此也是八分之一。
剩下两个是加法,比较对象是「不装 Jev 的情况」:回答判断是检索重排都做完之后只拦 LLM → 二十七分之一;门卫是连检索都不做 → 七十五分之一。
拦得越早,效果越大,就是这个关系。
结语
用 Jev 改善 RAG 速度、降低成本是可行的。 能体感到「爆速」的,我认为限于范围外、超纲的提问。(毕竟一旦有 LLM 参与,等待这件事是不会变的。)
把以前让 LLM 判断的地方交给 Jev,延迟和成本都会下降。 另外,在检索之前做门卫,比起让判断本身变快,「后面的处理整个不用调」这个效果更大。在靠前的位置拦住答不了的问题,检索、重排、LLM 就都不会跑。
但是,拦住了不该拦的提问就会变成信任问题。 这里必须慎重地决定阈值。另外,对能回答的提问来说,延迟和成本多少是变差的,所以最好先基于实际数据分析「答不了的问题占多大比例」,再决定要不要上。
至于重排的精度,这次的数据说明不了什么。 手搓的小语料没能拉开差距,所以如果要用它来判断要不要上,必须用真实数据认真测一遍。
之后想试着验证的方向
① LLM 的模型选型
采用 Jev 做重排,可以把不需要的 chunk 切掉,只留下能导向答案的高纯度 chunk。有了这样的 chunk,也许原本要用 Sonnet 的场合用 Haiku 也足够。 作为应用篇,也许还能根据回答判断的置信度,在 Sonnet 和 Haiku 之间分流,实现最优的模型选择。
② 护栏判断
这次的门卫是白名单式的用法,黑名单式的护栏用途也可以考虑。 这一类看起来 Amazon Bedrock Guardrails 也能替代,所以做对比验证是有价值的。
链接
原文:https://qiita.com/kikuziro/items/2be9091b328d8b844640
TypeSafe 的 Jev 发布公告:https://typesafe.ai/blog/introducing-system-one-models-and-jev
#Jev #RAG #实测