Spring AI 接入 Jev 决策模型,分类打分更简单

最近 AI 圈里 TypeSafe 的 JEV 决策模型非常火。核心原因很简单:大家苦于用 Chat Model 做结构化判断太久了——为了一个简单的是非题或三选一,写一大坨 Prompt 约束 JSON Schema,大模型还得慢吞吞吐几十个 Token,耗上一两秒不说,反序列化还经常偶发报错。

而 JEV 走了一条完全不同的路子:它根本不生成文本,只做概率判断。 输入一段文本和几个问题,底层几百毫秒内就能并发返回纯数值的强类型结果:

  • Noul:是非题,返回 0 到 1 的概率;
  • Choice:单选题,返回标签、概率分布及置信度;
  • Score:打分题,按量表给出连续浮点分值。

没有 Prompt 模板,更不需要解析 JSON。紧接着,Spring AI 社区官方迅速跟进,推出了 spring-ai-typesafe 项目。那么,我们在实际的 Spring AI 工程里,该如何高效使用这个决策模型?

Maven 依赖与配置

如果要在 Spring Boot 里用,直接引入官方 Starter:

1
2
3
4
5
<dependency>
<groupId>org.springaicommunity</groupId>
<artifactId>spring-ai-starter-typesafe</artifactId>
<version>0.3.0-SNAPSHOT</version>
</dependency>

环境要求 JDK 17 和 Spring AI 2.0.1 以上。

接着把 API Key 填进 application.yml:

1
2
3
4
spring:
ai:
typesafe:
api-key: ${TYPESAFE_API_KEY}

配置好后,Spring Boot 就会自动把 TypeSafeClient 注入进容器。

工单分流测试案例

来看一个最典型的场景。客服系统收到了一条工单:
"Help! My payouts have been failing for 3 days."(救命!我的提现已经连续失败 3 天了。)

我们想一次性搞清楚:这事急不急?该派给财务、技术还是销售?用户的沮丧程度大概是多少?

写起来就这么简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.example.demo;

import java.util.Map;
import org.springaicommunity.typesafe.TypeSafeClient;
import org.springaicommunity.typesafe.question.Choice;
import org.springaicommunity.typesafe.question.Noul;
import org.springaicommunity.typesafe.question.Score;
import org.springaicommunity.typesafe.response.SystemOneResponse;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class TicketTriageRunner implements CommandLineRunner {

private final TypeSafeClient typeSafeClient;

public TicketTriageRunner(TypeSafeClient typeSafeClient) {
this.typeSafeClient = typeSafeClient;
}

@Override
public void run(String... args) {
String ticket = "Help! My payouts have been failing for 3 days.";

SystemOneResponse response = typeSafeClient.systemOne(
ticket,
Map.of(
// 是非题:是否紧急
"is_urgent", Noul.of("Does this convey urgency?"),

// 选择题:分派到哪个团队
"department", Choice.builder()
.instructions("Which team should handle this?")
.option("billing", "Payments, invoicing, refunds")
.option("technical", "Bugs, outages, integrations")
.option("sales", "Pricing, upgrades, new accounts")
.build(),

// 打分题:用户情绪
"frustration", Score.of("How frustrated is the customer?",
"Calm", "Frustrated", "Very angry")
)
);

// 取出来直接是 Java 原生类型
double urgency = response.noulValue("is_urgent"); // 0.95
String department = response.choiceValue("department"); // "billing"
double confidence = response.choice("department").confidence(); // 0.82
double frustration = response.scoreValue("frustration"); // 1.10

System.out.println("紧急度: " + urgency);
System.out.println("分流部门: " + department + ",置信度: " + confidence);
System.out.println("沮丧值: " + frustration);
}
}

Jev 决策模型的优势

最直接的感受就是快。因为不用等大模型一个个往外蹦字,三个问题并发算下来,通常也就两三百毫秒,消耗的 Token 只有几十个。

但真正解决工程痛点的是它的返回值设计:

你拿到 department 是 billing 的同时,还能拿到一个 0.82 的置信度。

很多时候大模型分类翻车,不是因为它完全选错,而是它在两个选项之间犹豫,最后硬猜了一个。有了置信度,你的业务代码就很好写了:置信度高于 0.8 的直接系统自动派单;介于 0.6 到 0.8 的,派单时打个标记建议人工确认;低于 0.6 的干脆转给通用客服。这种确定性在以前纯靠 Prompt 很难稳妥做到。

还有哪些用法?

除了这种单点判断,官方还提供了 typesafe-spring-ai 扩展模块,把 JEV 挂到了 Spring AI 的常用链路上:

  • ChatClient 自省重试:用 JevSelfRefineAdvisor 充当裁判。比如工具调用返回了离谱数据,在把结果交给用户前先拦截,打回让模型重试。
  • 安全守门员:配置 JevGuardrailAdvisor。遇到越狱或者违规输入,在进大模型之前直接拦下来,一次几十毫秒,省下无谓的模型调用费。
  • RAG 过滤与重排:在检索之后、喂给大模型之前,用 JevDocumentFilter 剔除无关内容和注入风险,再用 JevDocumentReranker 重排。

大模型适合用来写文章、做复杂推理或者跟用户聊天。但要是系统里充斥着大量的意图识别、分类路由和数值评分,真没必要让 Chat Model 去受罪,换成 JEV 这种快思考模型,代码简单,接口也稳得多。