jev-typed-decisions
GitHubJEV类型化判定Skill,通过结构化调用实现分类、打分及判断,返回概率分布而非文本。适用于工单分派、内容审核、意图路由等需结果稳定可比的场景。
Trigger Scenarios
Install
npx skills add kunpengtalk/OmniStudio --skill jev-typed-decisions -g -y
SKILL.md
Frontmatter
{
"name": "jev-typed-decisions",
"description": "用 JEV \/ SystemOne(TypeSafe 协议)做**类型化判定** —— 把「是\/否」「选哪个」「打几分」变成一次结构化调用,拿回概率分布而不是一段需要解析的文本。适用:分类与打标、工单分派、紧急度打分、简历\/文档评分、内容审核护栏、检索结果重排、意图路由、字段抽取、按置信度分流。当需要**结果稳定可比较**、答案必须落在给定的选项或档位里、或同一批内容要跑很多个判断时使用(\"帮我按这个标准打分\"、\"这批数据分类一下\"、\"判断是不是垃圾邮件\"、\"给这几段回答打个分\")。Answer typed questions (choice \/ score \/ noul) about a piece of state and get probabilities back — classification, rubric scoring, guardrails, reranking, intent routing, extraction — instead of sampling prose from a chat model."
}
JEV / SystemOne:类型化判定
它解决什么问题
用聊天模型做分类、打分、判断,得到的是生成的一段话:要写解析、格式会飘、同一个输入 跑两次可能不一致、多问几件事还会互相"带节奏"。JEV 把这类判断变成一次结构化推理:
- 三原语:
noul(是/否,返回 P(true))、choice(在给定选项里选一个)、score(在有序档位上打分); - 一次请求可以问很多个问题,并行且互不影响(同一个 state,各问各的);
- 答案被约束在你给的选项/档位/概率分布里 ——
probabilities加起来约等于 1,confidence是分布的集中度; - 输出 0 个 token:不是逐字生成的,所以也没有"输出跑偏"这件事。
三个可直接调用的入口(同一套协议、同一个后端,选哪个看你在哪):
- Agent 工具
jev_evaluate—— 在这个应用的 Agent 里直接用(本地/云端由设置决定,免费); - 本机网关
POST /v1/systemone—— 外部 agent(Claude Code / Codex / 你自己的脚本)用; - 官方 SDK ——
typesafe-sdk/@typesafe-ai/sdk,只改TYPESAFE_BASE_URL与TYPESAFE_API_KEY两行,就能从官方切到本机网关(协议逐字段一致)。
界面上试:左侧一级菜单的 JEV 页(默认排在 Agent 与通话之间),结构同语音合成页 —— 左栏顶部切「本地运行 / 云端接入」(本地可装引擎、下权重、启动模型;云端填 Base URL 与 Key), 下面是 state 与问题清单;右栏是概率分布与置信度。侧栏有五个中英双语示例 (工单分派 / 简历评分 / 内容护栏 / 检索重排 / 意图路由),点一下就能装进左栏直接跑; 「复制调用示例」一键拿到 cURL / Python / JS 三种写法。
先决定用哪个原语
| 你要问的 | 用 | 拿回来的 |
|---|---|---|
| 是不是 / 有没有 / 成立吗 | noul |
noul(P(true),0..1) |
| 若干个无序选项里是哪个 | choice |
choice + probabilities + confidence |
| 在一条有序档位线上处于哪一档 | score |
score(期望档位,可带小数)+ legend + probabilities + confidence |
选择规则很简单:能排序就用 score,不能排序就用 choice,只有两种情况就用 noul。 把可以排序的东西写成 choice("低/中/高")会丢掉"到底有多靠近下一档"这个信息, 而 score 的期望值(2.99/5)恰恰是它最有用的地方。
直接调用(网关)
curl -s http://127.0.0.1:<网关端口>/v1/systemone \
-H "Authorization: Bearer $OMNI_GATEWAY_KEY" \
-H "Content-Type: application/json" \
-d '{
"state": "I was charged twice for the same order. Please refund the duplicate.",
"model": "jev-latest",
"questions": {
"department": { "type": "choice", "instructions": "Which team should handle this?",
"criteria": { "billing": "invoices, payments, refunds", "technical": "bugs and outages", "sales": null } },
"urgency": { "type": "score", "instructions": "How urgent is this request?",
"criteria": ["not urgent", "soon", "critical"] },
"refund_requested": { "type": "noul", "instructions": "Does the customer ask for money back?" }
}
}'
网关端口与 Key:应用 → 设置 → 网关(Key 在那里创建)。响应:
{
"model": "jev-1.13.0",
"answers": {
"department": { "type": "choice", "choice": "billing", "confidence": 0.93, "probabilities": {"billing":0.93,"technical":0.05,"sales":0.02} },
"urgency": { "type": "score", "score": 2.4, "confidence": 0.71, "legend": {"0":"not urgent","1":"soon","2":"critical"}, "probabilities": {"0":0.02,"1":0.56,"2":0.42} },
"refund_requested": { "type": "noul", "noul": 0.97 }
},
"usage": { "input_tokens": 168, "output_tokens": 0 }
}
用官方 SDK(只换两行)
import os
os.environ["TYPESAFE_BASE_URL"] = "http://127.0.0.1:<网关端口>" # 官方是 https://api.typesafe.ai
os.environ["TYPESAFE_API_KEY"] = "<设置 → 网关里的 API Key>"
from typesafe_sdk import Noul, Score, Choice, TypeSafeClient
with TypeSafeClient() as client:
r = client.system_one(
state="I was charged twice. Please refund the duplicate.",
questions={
"department": Choice(instructions="Which team?", criteria={"billing": None, "technical": "bugs"}),
"urgency": Score(instructions="How urgent?", criteria=["not urgent", "soon", "critical"]),
"refund": Noul(instructions="Does the customer ask for money back?"),
},
)
print(r.answers["department"].choice, r.answers["urgency"].score, r.answers["refund"].noul)
import { TypeSafeClient, choice, noul, score } from "@typesafe-ai/sdk";
process.env.TYPESAFE_BASE_URL = "http://127.0.0.1:<网关端口>";
process.env.TYPESAFE_API_KEY = "<设置 → 网关里的 API Key>";
const client = new TypeSafeClient();
const r = await client.systemOne({
state: "I was charged twice. Please refund the duplicate.",
questions: {
department: choice("Which team?", { billing: null, technical: "bugs" }),
urgency: score("How urgent?", ["not urgent", "soon", "critical"]),
refund: noul("Does the customer ask for money back?"),
},
});
console.log(r.answers.department.choice, r.answers.urgency.score, r.answers.refund.noul);
更多可复制的例子(分派 / 打分 / 护栏 / 重排 / 抽取 / 按置信度分流)见
reference/examples.md;完整字段与错误码见 reference/api.md。
写问题的四条硬规矩
- 一个维度一个问题。 "这条投诉是紧急的还是关于账单的"是两个判断,拆成两个问题。 合成一个,两个维度会互相污染,而且你没法分别设阈值。
- 描述情形,不要描述程度。 档位写"导出按钮在 Safari 上崩溃,有临时绕法",不要写"中等严重"。 模型只需要认得出情形,映射到几分是你的代码该做的事 —— 而且这样换档位不用重训。
- 给判定标准而不是给答案。
criteria是"什么算这个选项",写清边界与反例, 尤其是容易混淆的那两个选项之间差在哪。 - 别把问题名当提示。 问题名只是你自己取的回执键,模型看不到它
(官方明确这么说)。想告诉模型什么,就写进
instructions或criteria。
还有两条经验性的:
- instructions 可以是对象或数组。 要引用一大段结构化数据时,把问题和数据分开:
{"task": "...", "field": "…"};比把所有东西糊成一个长字符串稳。 - 同一批数据问很多问题时,一次请求全问掉。 它们并行、互不影响,而且
state只处理一次。
怎么读答案(这一节最容易被忽略)
probabilities是完整分布,别只看第一名。{"billing":0.51,"technical":0.49}和{"billing":0.99}的choice都是billing,但前者的意义完全不同。confidence是分布的集中度(0=完全平摊,1=全压在一个选项上)。它衡量的是"分布有多集中", 不是"答案有多对" —— 官方文档也强调这点。正确的用法是设阈值分流: 高置信度走自动处理,低的转人工/换更强的模型/加一问。score是期望值,可以落在两档之间,这正是它的价值(2.99 比"3 分"信息量大)。 分档做阈值时用probabilities里相邻档位的概率,而不要只看期望值。noul没有 confidence(只有两个结果,一个概率就说完了)。自己按业务代价定阈值: 误判成本高就要求 >0.95,漏判成本高就放到 >0.6。别默认 0.5。
什么时候不要用它
- 要生成文本(摘要、回复、改写)—— 那是聊天模型的事,JEV 只回答被约束的问题。
- 需要长链推理 / 多步工具调用 —— 它是一次前向判定,不做 agent 循环。
- 需要精确计算(算术、日期差值)—— 概率模型给的是"判断",不是"计算"。 日期这类"抽取"可以问,但结果要自己校验一遍。
- state 超过上下文:官方 JEV 是 64k(state 32k + 最长问题);本地 Laya 更小
(英文 512 / 多语言 1024 token)。超了要先摘要或切片,别指望它自己截。本地模型
对中文的支持明显弱于英文 —— 中文内容优先走云端,或换
laya-multilingual。
排查
503 configuration_error:本地运行时没装、本地地址为空、云端 Key 也没配。 去 JEV 页左栏顶部切到「本地运行」装引擎与权重,或切到「云端接入」填 Key。401 / 403:401 = Key 无效,403 = 请求里根本没有 Key(官方的两种失败是分开的)。422:请求体不合规,detail[].loc直接指出哪个字段(例如body.questions.x.criteria)。502:后端连不上或响应不符合契约。本地运行时的话看应用日志(omi logs, sourcesystemone)里的systemone.laya.*事件。- 本地第一次调用很慢:首次要把权重下到 Hugging Face 缓存(几百 MB)。
- 结果看起来"太自信":检查档位/选项的描述是不是互相重叠了 —— 描述含糊时模型会挤在一个 选项上。置信度低反而是它在说"这两个我分不清"。
证据都在 <dataDir>/logs/app.log(omi logs --source systemone)与用量的「调用来源 →
JEV 类型化判定」(价格 0,只记次数与 tokens)。
Version History
- 24199d4 Current 2026-09-21 23:52


