JEV - 两个 demo:回来的只是一张分布

两个例子都只问封闭的单选:客服里切不切人工,合并前放不放行。返回的是分布。公开延迟仍是大约 70 到 500 毫秒,不是某一次演示的毫秒数。

JEV - 两个 demo:回来的只是一张分布

联合作者:folkbench.com (Folkbench 是面向 AI API、模型服务及相关站点的可复核评测与选择平台,依据已发布的服务资料、价格、可用性、延迟与证据窗口,帮助用户比较并选择使用路径。)

这一组共十篇:

两个 demo 都是同一件事:不给自由文本,只给封闭题,拿分布做分支。下面的 JSON 和代码是调用形状,不是一份计时报告。公开的端到端大约 70 到 500 毫秒。不要把某一次 18 毫秒写成产品指标。值得看的是返回里没有逐 token 的句子。

客服:意图和熔断

场景

客服最怕用户已经在发火,系统还在打字。用生成式模型做意图,常常为了准确而先写一段 JSON,首包和生成都等在那里。用纯正则又读不懂绕着说的怒气。要的是封闭分类,然后立刻决定切不切人工。

状态和选项

这是一道 Choice,不是 Noul。Noul 只回答是非。这里选项有三项。

[State]
场景:客服实时入口
规则:按消息文本在给定选项里分配概率

[用户]
我都等了三天了,物流一直停在同一个地方。你们客服是死人吗?赶紧退款。不退我就去投诉。
{
  "question": "choice",
  "options": [
    {"id": "GENERAL", "description": "常规咨询或查进度,没有明显情绪"},
    {"id": "REFUND", "description": "明确要退换,表达客观"},
    {"id": "BREAKER", "description": "辱骂、威胁或投诉倾向,需要熔断到人工"}
  ]
}

回来的是分布

没有光标在吐字。形状是一张表,不是一段评语。

{
  "top": "BREAKER",
  "scores": [
    {"choice": "BREAKER", "score": 0.9241},
    {"choice": "REFUND", "score": 0.0715},
    {"choice": "GENERAL", "score": 0.0044}
  ]
}

数字是这个例子里的分布,用来看分支怎么写。它不是一次公开基准。模型是在给定选项上分配概率,不是在预测下一个字符。

代码怎么接

async function handleIncomingCustomerMessage(userMessage: string) {
  const res = await jev.choice("cs_intent_v1", { input: userMessage });
  const breaker = scoreOf(res, "BREAKER");
  if (breaker > 0.85) {
    return triggerHumanOverride({ priority: "CRITICAL", queue: "RETENTION" });
  }
  if (scoreOf(res, "REFUND") > 0.70) {
    return launchWorkflow("AUTOMATED_REFUND_FLOW");
  }
  return launchWorkflow("DEFAULT_FAQ_BOT");
}

没有为了解析 Markdown 再写一轮重试。阈值写在代码里。0.85 和 0.70 是这个流程自己的政策,不是模型给的保证。

合并前的审计

场景

静态扫描靠语法树和死规则,变体能绕过,误报也多。让聊天模型读 500 行 diff 再写评语,常常要十几秒,流水线等不起,脚本也读不出“过”还是“不过”。把 diff 当 state,问一道 Choice:通过、人工看、还是阻断。

状态和选项

[Git diff]
PR #1042
文件:src/auth/session.ts

+  // 非生产,或 token 以 test_admin_ 开头,跳过过期检查
+  if (process.env.NODE_ENV !== 'production' || token.startsWith('test_admin_')) {
+    return session;
+  }
{
  "question": "choice",
  "options": [
    {"id": "PASS", "description": "无害重构、文档或常规逻辑"},
    {"id": "WARN", "description": "配置、依赖或非敏感重构,建议人工看"},
    {"id": "BLOCK", "description": "后门、硬编码凭据、越权、绕过鉴权、注入"}
  ]
}

test_admin_ 能在生产环境跳过过期检查,这是鉴权绕过。例子里的分布把 BLOCK 放在 0.98 一带。删掉这一截,只留下“非生产才跳过”,同一道题会从阻断挪到人工看。这是题的用法,不是一组对外承诺的毫秒数。

流水线怎么接

def audit_pr_diff(diff_text: str) -> int:
    result = jev.choice(
        question="pr_security_v2",
        state=diff_text,
        options=["PASS", "WARN", "BLOCK"],
    )
    scores = result.scores
    if result.top == "BLOCK" and scores["BLOCK"] > 0.80:
        print("high-risk auth change")
        return 1
    if result.top == "WARN":
        mark_review_required()
        return 0
    return 0

地址写成内部服务就行。不要把这理解成某个公开站点已经代为提供 Jev。流水线读的是顶项和分数。评语如果还要给人看,另请一个会写的模型,不要塞回这道题。

像调一个返回数字的接口

这两次把同一件事做实了:复杂的判断留在模型内部,外面只留概率。Noul、Choice、Score 是三种格子,不是三种聊天风格。

路由、风控、合并前检查、策略引擎、Agent 的分支,都可以先问自己:这一步是否写得成封闭题。写得成,就不要再等一段生成。写不成,就不要装成 demo 里的这种调用。

系列