用 Jev 一次调用同时拿部门和情绪分:工单自动分派落地

先说结论

  • Jev 的 choicescorenoul 三种原语可以在一次 API 请求中混合使用,对同一段 state 独立回答不同问题,适合工单分派这种多维判断。
  • 把工单文本放进 state,用 department 做 choice、用 frustration 做 score,能同时得到“该路由到哪个部门”和“客户情绪等级”。
  • noul 响应只有 noul 值,没有 confidencechoicescore 才有 confidenceprobabilities
  • 我的两条转人工规则是:任一 confidence 低于 0.80 转人工;部门概率前两名差值小于 0.15 转人工。这两条不是官方建议,需要拿自己业务数据回测。
  • 成本参考中,官方定价 $42/十亿输入 token 未能从本次给出的官方文档链接直接核实;社区二手文章按 $0.042/MTok 计算,等价于 $42/十亿 token,下文会明确标注来源和推算过程。

为什么官方 quickstart 的工单示例值得展开

官方 Quick start 里有一个客服工单示例:一段 Stripe 集成失败的客户消息,官方同时问三个问题——department 是 choice,frustration 是 score,is_urgent 是 noul。它演示的核心是“一次调用混用多种原语”,但并没有进一步展开工程落地时要关心的两件事:confidence 怎么用于分流?probabilities 怎么参与路由决策?

这篇文章就把这个示例展开:请求体怎么写、响应字段怎么读、阈值规则怎么设计、成本怎么按量级估算。

场景与输入:把工单文本放进 state

根据官方 State 文档state 是模型要评估的内容,可以是字符串、JSON 对象或数组。字符串适合简单场景;如果要让模型同时看到工单类型、客户等级、订单上下文等结构化信息,建议用对象。

我这里保持和官方 quickstart 一致的字符串 state。它的内容是:

Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP.

这个文本同时表达了“技术集成问题”和“客户很着急”,非常适合同时问部门与情绪。

完整请求体:一次请求里混用 choicescore

下面请求体字段形状来自官方 quickstart 示例;model"jev-latest"

{
  "model": "jev-latest",
  "state": "Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP.",
  "questions": {
    "department": {
      "type": "choice",
      "instructions": "Which team should handle this",
      "criteria": {
        "billing": "Payment or subscription issues",
        "technical": "Bugs or integration problems",
        "sales": "Pricing or account questions"
      }
    },
    "frustration": {
      "type": "score",
      "instructions": "How frustrated the customer appears",
      "criteria": [
        "Calm, just stating facts",
        "Frustrated but civil",
        "Very angry, strong language"
      ]
    },
    "is_urgent": {
      "type": "noul",
      "instructions": "The message conveys urgency or time-sensitivity"
    }
  }
}

这里 departmentcriteria 是枚举对象,三个值之间没有天然顺序;frustrationcriteria 是有序列表,从冷静到愤怒,模型返回的是等级而不是自由文本。官方 Primitives 文档里说得很清楚:choice 适合“无顺序的已知选项”,score 适合“有谱系、可描述等级的判断”。所以我不会把情绪写成 choice,也不会把部门写成 score。

响应怎么读:三种原语的形状不同

官方 Primitives 文档给出的返回形状是:

  • choice:返回 choiceprobabilitiesconfidence
  • score:返回 scorelegendprobabilitiesconfidence
  • noul:只有 noul 值,0 到 1,没有 confidence

这里有一个容易踩错的点:probabilitieschoicescore 里都是对象,键是选项或等级,不是数组。比如 department.probabilities{"billing": ..., "technical": ..., "sales": ...},不能用列表下标去取。

下面是一个形状示意,具体概率数值不是官方逐字响应:

answers.department.choice -> "technical"
answers.department.probabilities -> {"billing": 0.10, "technical": 0.80, "sales": 0.10}
answers.department.confidence -> 0.93

answers.frustration.score -> 1
answers.frustration.legend -> ["Calm...", "Frustrated...", "Very angry..."]
answers.frustration.probabilities -> {"0": 0.10, "1": 0.60, "2": 0.30}
answers.frustration.confidence -> 0.90

answers.is_urgent.noul -> 1.0

重点不要记错:noul 没有 confidence,也不带 probabilities。你如果按 answers.is_urgent.confidence 去取,会直接报错。

阈值分流:两条规则是我自己的设计

官方文档没有给出“confidence 低于多少转人工”这类操作建议。下面是我自己设计的规则,标注清楚,适合先跑通再按业务校准。

def route(answers):
    dept = answers["department"]
    frust = answers["frustration"]

    # 我的规则 1:任一 confidence 低于 0.80 转人工
    if dept.confidence < 0.80 or frust.confidence < 0.80:
        return "human"

    # 我的规则 2:部门概率前两名太接近转人工
    probs = dept.probabilities
    top_two = sorted(probs.values(), reverse=True)[:2]
    if top_two[0] - top_two[1] < 0.15:
        return "human"

    return dept.choice

为什么这样设计?如果部门第一名是 technical,第二名是 billing,差值只有 0.05,说明模型自己也拿不准,自动分派容易错。如果 confidence 本身过低,说明模型对这类输入不熟。两条规则都属于工程防御,不应替代人工抽检。

这两个阈值不是拍脑袋就可以上线:0.80 和 0.15 只是起点。你需要拿自己的历史工单数据跑一个小样本,看 confidence 分布和前两名概率差的分布,再决定截断点。

成本与延迟:可复算的推算

工单给的参考口径是:官方定价 $42/十亿输入 token,官方示例 392 tokens。但这两个数字我在本次给定的官方 quickstart、primitives、state 文档中都没有直接核实到。我看到的第三方校准文章 Web of Mike 的 Jev benchmark 中使用了 $0.042/MTok 来计算单次成本,换算后正好是 $42/十亿 token。因此下面把单价标为社区二手,官方定价请以官方定价页为准,这里如实标“未能核实”。

同样,392 tokens 在给定链接中没有出现。社区二手基准里 60 例工具调用分类任务的平均输入 tokens 是 413。所以我用 413 做算式,你如果拿到准确 token 数,替换即可。

自己推算,按 413 tokens 输入:

单次输入成本 = 413 tokens / 1,000,000 * 0.042 USD
           = 0.000017346 USD

一天一万单输入成本 = 10,000 * 0.000017346
                 ≈ 0.173 USD

如果你改用 392 tokens:

392 / 1,000,000 * 0.042 * 10,000
≈ 0.165 USD

这个估算只算了输入 token,没有算输出 token,也没有算 API 并发、重试和网络延迟。延迟参考同样来自那篇社区二手文章:jev-latest 的 p50 延迟约 421.6 ms,p95 约 542.0 ms。这是非官方数据,测试环境为美国波特兰住宅网络,不代表生产 SLA。

踩坑:三个“不要”

  • 不要把整段会话历史塞进 state。官方 State 文档建议 state 是“给专家看的材料”,而不是把所有上下文倒进去。每个原语只做秒级判断,输入过长会抬高 token 成本、增加噪声,还容易让模型抓不住关键事实。
  • 不要把 confidence 当准确率。社区第三方基准显示,低置信度答案更容易错,所有错误答案的置信度都低于 1.000;但这不意味着 confidence 0.9 就等于 90% 准确率。它只是模型对当前判断的置信度,不能替代业务指标。
  • 不要一个问题上写“分析并给出处理建议”。官方 Primitives 文档明确说,System One 模型用来做快速、聚焦的判断,“Analyze this message and determine the best course of action”不是好问题。你可以拆成 frustrationdepartmentis_urgent 三个小问题,用代码组合结果。

上线前清单

  • 先拿 50~100 条真实历史工单,人工标注部门和情绪,跑一遍 API,记录 confidence 分布和错误位置。
  • 看部门概率前两名差值的分位数,选你业务能接受的转人工比例;我给的 0.15 是起点,不代表最优。
  • confidence 低于 0.80 的样本占比,如果太高,说明你的 criteriastate 写得不够清晰,先修问题定义。
  • 用 object 型 state,把会话摘要、订单、策略等分层放入,避免无限追加原始聊天记录。
  • 小流量灰度时同时记录模型路由与人工路由的差异,不要一上来全自动。

这次没核实的

  • 官方定价 $42/十亿输入 token:我在提供的官方文档链接里没找到定价页,仅从社区二手文章中看到 $0.042/MTok。官方性质未能核实。
  • 官方示例 392 tokens:给定链接中未能核实该数字;成本推算采用了社区二手基准的 413 tokens。
  • 延迟数字:只有社区二手来源,官方 SLA 或生产延迟未能核实。
  • 响应示例中的具体概率数值:本文用示意值,非官方逐字响应。

参考来源

评论区

0 条评论

登录后可评论。

三分钟热度 246 阅读