最近刷到几次关于 Jev 的讨论。最吸引我的是一句话:它不生成文本。平时接触的模型大多忙着写代码、解释思路,突然看到一个专门返回判断结果的模型,还挺想看看它到底怎么用。
TypeSafe 在 9 月 15 日发布了这个模型,把它叫作 System One。发布文章讲的是一种能让软件直接使用的快速决策能力。我看完最想试的是:把它放进一个 Agent 里,能在哪些地方派上用场?
于是就有了 dsh-jev-plugin,让 DeepSeek Harness 里的 Agent 也能调用 Jev。
它到底在判断什么
拿一条客服消息来说,正式回复之前,往往先要判断该交给哪个团队、用户是不是很着急、问题大概有多严重。这些问题的答案范围其实很小。
Jev 的用法是,把相关信息放进 state,再给它一组指定了类型的问题。这个插件接了三种基本类型:
noul:判断一句话成立的概率,返回 0 到 1 之间的数。choice:从指定标签中选一个,同时返回概率分布和置信度。score:按有序等级打分,同样带有概率分布和置信度。
TypeSafe 文档里有完整说明。我感兴趣的是,这样的结果很容易接进代码:选一条分支,给几个候选排个序,或者把拿不准的情况留给人看。
当然,类型正确和判断正确是两回事。结果即使完全符合接口格式,也可能判断错。一旦这个结果会影响 Agent 接下来做什么,就得把这件事放在心上。
想给 DSH 多接一件顺手的工具
DeepSeek Harness 的插件架构正好适合拿来做这个尝试。我把集成写成独立包,通过 dsh.bundle 给 profile 加入一个 tool-jev 条目。
Agent 原来使用的语言模型继续负责对话和执行任务,工具箱里增加两个入口:单个问题用 jev_decide,多个问题或需要详细判断标准时用 jev_evaluate。
整个调用过程不长:
DSH agent
-> jev_decide / jev_evaluate
-> shared Jev service
-> TypeSafe /v1/systemone
-> structured result returned to DSH代码里通过 ctx.tools.register(...) 注册工具,两个工具共用 Jev service。配置、取消、超时和重试也放在这一层处理,省得两个工具各自维护一套 HTTP 调用逻辑。
先把一个问题说清楚
比如让 Agent 判断一条消息该交给哪个团队,传给 jev_decide 的参数可以是这样:
{
"state": "The customer says their payment failed twice.",
"question": "Which team should handle this request?",
"kind": "choice",
"options": ["billing", "technical", "sales"]
}state 是要看的材料,question 说明要判断什么,options 则把答案范围列出来。插件会把这些参数整理成 Jev 原生的 questions map,把问题放在 decision 这个键下面,再请求 https://api.typesafe.ai/v1/systemone。
回到 DSH 的结果包含 model、answer 和 usage。我保留完整 JSON,同时加了一行方便阅读的摘要。Web 端还可以显示结果卡片,把标签、概率或评分直接展示出来,看一次判断不用再翻一大段工具输出。
同一段材料需要判断好几件事时,可以换成 jev_evaluate,直接传原生的问题集合。比如一次看客服消息的部门归属和紧急程度,但每个问题还是尽量问得单一、明确。
另外还配了一份 jev-decisions skill。工具注册进去,只是让 Agent 能用;skill 则补上什么时候值得用、拿到答案后怎么看的说明。否则很容易出现装了一个决策工具,最后所有分类还是主模型自己做的情况。
真接起来,容易漏的是 profile
从本地源码安装,先在插件目录运行 npm ci --legacy-peer-deps。已经装好 DSH 的话,可以单独建一个 Web profile,把 TYPESAFE_API_KEY 交给启动 DSH 的进程:
export TYPESAFE_API_KEY="your-typesafe-api-key"
dsh --profile jev-dev --from-default-profile web --dump-config
dsh plugin --profile jev-dev add /absolute/path/to/dsh-jev-plugin
dsh --profile jev-dev里面的路径要换成实际源码目录。如果用 PowerShell,设置环境变量那行改成 $env:TYPESAFE_API_KEY = "your-typesafe-api-key"。
初始化 Web profile 那一步只给全新的名称做一次。直接往一个新 profile 名称里装插件,只会创建基础配置,并不会顺带启用 Web 应用;已经有 Web profile 就可以跳过初始化。急着看第一张结果卡片时,这个细节还挺容易漏。
默认模型是 jev-latest。会话里的 /jev-status 可以看配置和调用情况,方便分清是没有读到 key,还是插件加载了、但根本没被调用。DSH 还在迭代,具体安装细节会继续放在项目 README 里维护。
工具执行前,也可以问它一下
显式调用的工具接好后,我还加了一个可选检查,挂在 DSH 的 tools/pre-execute 上。把指定工具的名字和参数交给 Jev 评估风险,再按配置决定放行、请求人工确认,还是拒绝。
这个 Hook 默认关闭。开启以后,执行工具会多一次远程判断;判断服务出错时,默认行为是放行。这两点要先想清楚。评分阈值也得拿日常开发命令试,正常操作总被打断,使用起来会很难受。
此外还有一层独立、可选的离线规则,用来匹配已知的命令形态。它先于语义检查运行,已经被规则拒绝的调用,就不必再花一次 Jev 请求得到相同结果。至于权限和隔离,仍然由各自的机制负责。
接下来想多试几个日常场景
我现在比较想搞清楚的是,哪些小判断值得从主 Agent 循环里单独拿出来。分类、候选打分看起来适合作为起点。算术交给代码,复杂调查则继续让 Agent 找材料、理清过程。
输入也想尽量给得克制一点。state 会发送到 TypeSafe,并进入 DSH 会话记录,所以不应该习惯性地把整段聊天都塞过去。一个小判断,最好能从一小段相关上下文里说清楚。
目前这个尝试就是:给 DSH 一个范围明确的问题,看看返回的概率分布,再观察它对下一步操作有没有帮助。接下来想攒一组日常样例,尤其看看那些结果会变化、模型拿不准的情况,实际用起来是什么感觉。
文中对应的是 9 月 22 日的代码版本。