在《黑衣人 2》中,J 探员去一家看似普通的邮局找 K。他打开一台信件分拣机,发现里面藏着个外星人,正飞快地给信件分类。
这是个有点荒诞的小场景,但它也给了我们一个思考 AI 的实用视角。
在接收到某个东西和对它进行处理之间,通常还有一个更小的决定要做:这东西该归到哪一类?
尽早把这个决定做对,系统的其余部分就能顺着正确的路径走下去。
在开发 AI 软件的过程中,我一直在想那个小外星人。
一个应用可能会收到账单问题、Bug 报告、产品照片和预约演示的请求。每一种都需要不同的处理方式。但我们最后往往让同一个大语言模型去检查所有内容,再判断下一步该做什么。这既没效率,也不划算。
所以我认为,专用模型会在 AI 的未来扮演更重要的角色。举个例子:Jev 就是为软件可执行的结构化决策而生的。Coinbase 专门针对其 Onramp 服务中的欺诈检测,对 Qwen3.5-9B 做了适配。每个模型都专注于一项明确的任务,产出也可以被衡量。
https://x.com/brian_armstrong/status/2109412046244913643
我正在构建这个“分拣层”
熟悉的请求可以直接进入既定工作流。需要更多推理的请求则交给另一个模型。模棱两可的请求会被标记出来,等待澄清或人工复核。
潜在的节省来自于:只给每个请求分配它真正需要的处理量。接下来我们还得衡量,这个分拣器做出的正确决定是否足够多,多到值得让它存在。
我们的起点是 CludeMem。当时我们在琢磨:AI 应该记住什么、检索什么,以及哪些东西在不必要地消耗 token。长期偏好、临时指令和未解决的问题,理应区别对待。但在做这些决定之前,我们需要先对信息分类。
这就演变成了更广义的分类层的构想。同样的步骤可以用来分拣客服请求、路由文档,或者决定由哪位专家来处理任务。
GIF
随着越来越多的专用模型出现,应用必须决定哪些输入值得它们关注。这正是我们在做的部分:对进来的内容分类,在本地处理熟悉的情况,把更难的交给合适的模型或审核流程。
隆重介绍 Clude Cat(Cat 代表 categorisation,即分类 😉)

在存储记忆、检索文档、调用工具或生成回复之前,通常都要先判断:我们面对的是什么类型的信息。
这类判断无处不在。
假设有人给一家软件公司写信:
“我在哪里可以下载发票?”
一个 AI Agent 可以读取消息、查看可用工具、揣摩客户意图,然后决定去找发票。
一条更直接的工作流可能是这样的:
消息 → 账单文档请求 → 账户验证 → 发票检索。
语言模型依然可以负责撰写回复。而最初的路由决策可以在本地完成。
现在换条消息:
“我被扣了两次钱,账户被锁了,我要取消。”
如果自信满满地把这条塞进单一的发票工作流,只会制造更多麻烦。这里有好几个问题要解决,正确的应对方式可能需要进一步澄清,或者直接转给人工。
分拣器需要有权限说一句:“我没法可靠地归类这个。”
这是产品的关键一环。一个总是自信地把请求发往错误目的地的系统,会因为后续纠错的成本,把自己的速度优势全赔进去。
对客户来说,好处是少等一会儿、少重复一遍。
对开发者来说,这是一个显式的决策,可以检查、测试和修改。他们能看到选中的类别、模型版本、处理耗时,以及系统是否拒绝做出判断。
在底层,文本实现从一个叫编码器(encoder)的小型预训练模型开始。
它把一条消息转换成一组数字,用来表示其含义的各个维度。开发者管这种表示叫 embedding(嵌入)。
“我的发票在哪?”和“我需要一份账单副本”用词不同。但它们的数值表示可能足够相似,让系统认出这是同一类请求。

分类层利用这些表示,为开发者定义的各个类别打分。
我们实现了两种方法。一种把收到的消息与每个类别的示例做比较;另一种从带标签的示例中学习类别之间的边界。
在拟合(fitted)方案中,我们固定编码器,只训练它上面一层更小的决策层。这样就不必为每个应用重新训练基础模型。
开发者仍然需要定义类别的含义,并把它们与有用的动作连接起来。分类器不可能凭空发明出公司的部门结构、退款政策或账户权限。
它还需要一套接受策略。
得分最高的类别也可能并不匹配。两个类别的分数可能几乎打平。一个陌生的请求可能长得像某个熟悉的请求。
我们目前的本地得分并不是校准过的概率。0.92 分并不自动等于“有 92% 的概率正确”。
我们必须测试当这些分数主导决策时会发生什么。
因此输出会区分三种情况:已接受的类别、需要复核的请求和技术故障。超时、取消和模型错误也需要可预期的处理方式。
这就是围绕分拣器的工程工作。它决定了其他应用能否安全、一致地使用这个结果。
我们用 770 条银行类请求做了一次实验,看看这种方法能不能减少生成式模型的工作量。
第一种配置把所有请求都发给本地运行的 Qwen2.5 7B 模型做分类。
第二种先用我们的本地分类器,再把无法解决的请求发给 Qwen。
结果如下:
- Qwen 调用次数从 770 次降到 227 次。
- 正确分类数从 535 次提升到 642 次。
- 所有输入的准确率从 69.5% 升至 83.4%。
- 累计查询耗时从 299.7 秒降至 87.7 秒。
本地阶段省掉了 543 次 Qwen 调用,减少了 70.5%。
缓存保持开启状态,且直接方案在组合方案之前运行。耗时数据不包含初始化和预热。我们只测量了分类环节,没有生成最终的客户回复,也没有向模型供应商付费。
这些数字只描述这套配置。它们不能证明比所有 LLM 都强,也不能证明客户一定能省钱。
后来另一项独立实验,在 24 种旅行和办公场景意图上测试了拟合后的本地分类器。
720 条请求中,它在本地接受了 688 条。其中 681 条正确,7 条错误。剩下 32 条留待复核。
这给了我们两个不同的指标:
- 覆盖率:它在本地处理了 95.6% 的请求。
- 接受精确率:在它接受的决策中,99.0% 是正确的。
两者都得放进结果里看。一个分类器完全可以只挑少数简单的请求接受,从而刷出惊人的精确率。
我们还用 100,000 条不属于其支持类别的陌生输入做了测试。它的准确率超过 94%。
识别出系统不知道的东西,依然是这项工作的一部分。
速度同样需要严谨对待。在另一项 CPU 热启动测试中,完整的银行分类器在 M4 Max 上的中位耗时约为每条请求 1.8 毫秒。这包含了分词、嵌入和打分。
这不包括下载模型和启动的时间。这只是分类的测量值,不是解决用户完整请求所需的时间。它也不能说明在手机或普通笔记本上会有同样表现。
Jev 之所以出现在这场讨论里,是因为它已经在处理类似的一类决策。
TypeSafe 把 Jev 定义为一个用于有限判断的模型,包括在给定的选项间做选择,以及把请求路由给普通代码、专用模型或人工。\Jev 的意图路由文档\
在我看来,Jev 的角色是一条可选的上报路径,专门处理本地分类器无法可靠解决的请求。
我们正在实现的架构很直白:
传入请求 → 本地分类 → 熟悉的请求走既定路径;不确定的请求交给 Jev、其他模型或人工复核。
如果没有 Jev,同一个本地分类阶段也可以把无法解决的请求交回应用现有的 LLM、澄清步骤或审核流程。
类别、接受阈值和兜底方案都由开发者掌控。他们可以把本地分类器接入现有工作流,并衡量它能接管哪些决策。
目前,Jev 的集成以影子模式运行,在五个大类主题上对比决策结果,但不改变应用的实际行为。下一步是测试选择性上报能否改善整个工作流。上面的 Qwen 结果并不是 Jev 的基准测试。
这才是我们需要衡量的东西:减少不必要的模型调用、更快地处理熟悉的请求,并为需要更多关注的情况提供一条明确的路径。
我们已经开始把同样的思路扩展到图像。
假设一家企业收到一张收据、一张报错截图和一张产品照片。每一种都需要不同的处理路径。
收据可以送去收据提取。截图可以进入客服工作流。产品照片可以进入商品目录工作流。拿不准的图像可以送去复核。
分类器负责选择目的地。而读取消费总额、诊断错误、识别产品细节,仍然是各自独立的任务。
我们的实验性图像实现使用预训练的 CLIP 编码器来生成图像的数值表示。
在一个小型诊断测试中,一个拟合后的研究候选模型正确分类了 20 张食品照片中的 19 张。它还把全部 30 张豆叶图像送去了复核。
唯一的错误是把一个瓶子的营养成分表和条形码当成了收据。
你能看出问题所在。两者都可能包含密集的文字、数字和矩形排版。我们需要用示例来教会模型区分应用真正在意的那条边界。
这个样本太窄,不足以支撑生产环境的结论。标签是从数据集派生出来的,而非独立裁定,测试中也没有新的收据或截图样本。公开 demo 用的是另一套基线,所以不应把拟合候选模型的结果算在它头上。
图像处理也比文本分类更吃资源。在 M4 Max 上,热启动的中位处理耗时在 Node 中约为 36 毫秒,在 Chromium 中约为 197 毫秒。浏览器端首先需要约 85 MiB 的模型文件,外加运行时环境。
本地执行同样有成本。下载体积、内存占用、启动时间和设备性能,都得纳入评估。
我设想的产品会嵌入现有应用中,由它来决定下一步做什么。
开发者定义类别、提供代表性示例、连接目标路径,并决定分类不确定时该怎么处理。
首次部署应该只观察当前工作流,而不改变其结果。之后我们可以把建议的决策与已验证的结果做对比,再允许分类器接管路由。
我们需要像审视被拒绝的请求一样,仔细检查那些被接受的错误。否则,一个自信的错误决策就会藏在一个让人安心的高分背后。
训练、校准和测试也需要各自独立的数据。训练用来学习类别。校准用来确定接受规则。受保护的测试用来检验冻结后的结果。
一旦某次测试错误影响了下一版模型,那条样本就变成了开发数据。下一次评估就需要全新的测试集。
邮件分拣机里的那个小外星人,让人们能形象地理解这份工作。但要造出一个真正有用的版本,就得搞清楚它到底能处理哪些输入、什么时候该求助,以及犯错的成本有多高。
下一步是用带有独立标签、并记录每个结果的真实工作流来做测试。我们需要衡量有多少请求走了本地路径、有多少交给了别的模型、有多少出了错,以及在计入这些错误之后,整个应用是否变得更快或更便宜。
是时候扩大规模,给这个本地模型加点猛料了。





