2026-09-30代码级
本文覆盖:架构分层 → 统一路由代码 → 两引擎 API 细节 → 置信度门控 → 判断元数据回流 → 实测数据 → 实验设计 → 已知坑清单。所有数据来自 2026-09-29/30 实测。
┌────────────────────────────┐
state + questions │ unified_judge.py │
──────────────────→│ route_question() 逐题路由 │
└──────┬──────────────┬─────┘
noul/隐私/英文│ │中文 choice/score, 选项>20
▼ ▼
┌────────────┐ ┌────────────┐
│ Laya 本地 │ │ Jev 云端 │
│ MPS, 零延迟 │ │ HTTPS API │
│ 确定性输出 │ │ │
└─────┬──────┘ └──────┬─────┘
│ 故障互备降级(_fallback) │
▼ ▼
┌────────────────────────────┐
│ 答案 + _engine/_latency_ms │
│ + --log-journal → journal │
└────────────────────────────┘
核心设计原则:路由在题目粒度,不在请求粒度——同一次调用里的多个问题可以分属不同引擎,混合返回。
入口签名与路由核心(节选自 ~/.openclaw/models/laya/unified_judge.py,5.8KB):
def route_question(state_text, q):
# 规则按 2026-09-30 实测标定,优先级从上到下
t = q["type"] # noul / choice / score
is_cn = has_cjk(state_text + question_text(q))
n_opts = len(q.get("criteria", []))
if t == "noul": # 是非题:Laya noul 头极稳
return "laya" # 任意语言,含隐私敏感场景
if is_cn and t in ("choice", "score"):
return "jev" # 中文细粒度 → 云端
if n_opts > 20:
return "jev" # 选项过多 Laya 会糊
return "laya" # 英文全原语走本地
def judge(state, questions, mode="auto"):
groups = {}
if mode == "auto":
for k, q in questions.items():
groups.setdefault(route_question(...), {})[k] = q
for eng, qs in groups.items():
try:
answers.update(laya_engine(...) if eng=="laya" else jev_engine(...))
except Exception as e:
# 故障互备:整组切到另一引擎,答案带 _fallback 标记
fb = "jev" if eng == "laya" else "laya"
answers.update(engine(fb)(...标记 _fallback=f"{eng}→{fb}"))
return answers每个答案自带元数据三件套:_engine(谁答的)/ _latency_ms(耗时)/ _fallback(是否降级,正常缺席)。这是后续判断画像的数据底座。
# Key 从 env 读,绝不进代码字面量(三层防脱敏污染)
# ~/.openclaw/workspace/.secrets/typesafe.env (chmod 600)
TS_API_KEY=$(grep '^TS_API_KEY=' ~/.openclaw/workspace/.secrets/typesafe.env | cut -d= -f2)
# 关键:参数名是 criteria 不是 options!
# choice 用对象数组,score 用数值数组
curl --noproxy '*' https://api.typesafe.ai/judge/v1/run \
-H "Authorization: Bearer $TS_API_KEY" \
-d '{
"state": "客户邮件:…请尽快确认费率…",
"questions": [{
"id": "route",
"type": "choice",
"question": "这条消息应路由到哪个部门?",
"criteria": [ # ← choice: 对象数组
{"label": "技术"}, {"label": "销售"},
{"label": "账单"}, {"label": "其他"}
]
}]}'
# 响应
{ "choice": "账单", "confidence": 0.94,
"probabilities": {"账单": 0.94, "销售": 0.06, ...} }① 必须绕代理:本机 127.0.0.1:7897 会劫持请求——curl 加 --noproxy '*';Python 用 build_opener(ProxyHandler({})) 空 opener。
② 显示层脱敏陷阱:工具回显里 Key 显示为 ***,复制回代码会变成真 403。凡从回显复制的代码,先全文搜字面 ***。
③ 成本:约 $0.0002/判断;延迟 700~800ms。
from laya_lightspeed.client import LayaModel
# 坑:laya.load("multilingual") 会走 HF 在线解析 → 必须给本地绝对路径
MODEL = "/Users/mac/.openclaw/models/laya/weights/multilingual"
m = LayaModel.from_pretrained(MODEL) # 底座 ModernBERT
out = m.run({
"state": "用户要求全额退款,情绪激烈",
"questions": [{"type": "noul",
"question": "客户是否明确要求退款?"}]
})
# → noul: 0.995, confidence: 0.995 (multilingual 权重, 中文)| checkpoint | 大小 | 用途 | 中文表现 |
|---|---|---|---|
weights/(EN root) | 843MB | 英文原语全类型 | noul 0.968 / choice 0.37 ✗ |
weights/typed-decisions/ | 843MB | 类型化决策头 | 同上量级 |
weights/multilingual/ | 644MB | 中文 noul 生产主力 | noul 0.995 ✓ / choice 0.45 ✗ |
① 底座 ModernBertForMaskedLM 预训练语料以英文为主;
② 分词碎片化:21 汉字 → 31 token(膨胀比 1.48),head_max_len=192/256 预算被吃掉;
③ 决策头训练数据英文为主,置信度校准在中文分布外——noul 靠粗粒度池化幸存,choice 需要细粒度语义比对就糊。这就是路由把中文 choice/score 硬性划给云端的原因:知道自己不行也是能力。
def act_on(answer, threshold=0.8):
if answer.get("_fallback"):
log("降级答案,人工复核"); return ESCALATE
if answer["confidence"] >= threshold:
return EXECUTE(answer)
# 低把握自动重问一次取均值(工程优化项,2026-09-29 提出)
retry = judge_same_question()
if avg(conf, retry) >= threshold: return EXECUTE(...)
return ESCALATE # 机器不硬拍# unified_judge.py --log-journal:每次判断自动落一条
python3 unified_judge.py state.json questions.json --log-journal
# journal.jsonl 实际条目(2026-09-30 首条)
{"ts":"2026-09-30T12:31+08:00", "agent":"hiro", "type":"decision",
"scene":"客户邮件:…请尽快确认费率…",
"action":"路由[jev+laya] sensitive[noul/laya/208ms] route[choice/jev/765ms]",
"tags":["dual-engine","direction-c"]}这是"判断画像闭环"的采集端:攒够 50 条后做路由正确率复盘,≥95% 才推广方向 A(记忆喂先例)。
| 方向 | 机制 | 状态 | 达标线 |
|---|---|---|---|
| A 记忆喂先例 | 判断前检索 journal 历史同场景先例,拼进 state 做先验 | 设计中 | decision 条目 ≥50 且路由正确率 ≥95% |
| B 引擎做遗忘曲线 | 入 journal 前判"与近 5 条是否重复"→合并;周复盘判"经验是否过时"→衰减 | 设计中 | 重复条目率 ↓30% |
| C 判断画像闭环 | --log-journal 采集引擎/延迟/置信度 → 月度复盘修订路由 | ✅ 已上线 | 方向 A 的前置条件 |
不融合铁律:什么值得记住(价值判断)永远人工规则 + 复核;引擎只做效率和把关,不做取舍。
| 场景 | 引擎 | 结果 | 延迟 |
|---|---|---|---|
| 中文退款 noul | Laya multilingual | conf 0.995,判断正确 | 0.5s(首问 3.1s 含预热) |
| 中文部门 choice | Jev | conf 0.94~1.0,判断正确 | 757~772ms |
| 同题三连问一致性 | Laya | 极差 0.0000(完全确定) | — |
| 隐私脱敏闸(记忆 v3) | Laya | conf 0.999 | 208~265ms |
| 故障降级演练 | 互备 | 自动切换 + _fallback 标记可审计 | 无感 |
| 中文 choice(对照) | Laya | conf 0.45,不及格 → 已路由隔离 | — |
1️⃣ Laya 权重放 /tmp 被系统清 → 永久目录 ~/.openclaw/models/laya/weights;下载走 snapshot_download API(python3 -m modelscope 不可执行),需 NO_PROXY=modelscope.cn + 12 轮重试守护脚本。
2️⃣ 回显脱敏 *** 被粘进代码 → 真 403;复制回显代码前必搜字面 ***。
3️⃣ 本机代理劫持 → Jev 必须 --noproxy '*';诊断 DNS 时 fake-ip(198.18.x.x)会骗人,用 DoH 交叉验证。
4️⃣ laya.load("multilingual") 走 HF 在线解析 → 必须传本地绝对路径。
5️⃣ criteria ≠ options;choice 传对象数组、score 传数值数组,搞反直接参数错误。
配套资产:unified_judge.py · 三 checkpoint(2.2GB)· journal.jsonl 采集 · 飞书双引擎方法论文档 v2.0(内部)
© 2026 CGL Agent Lab · ← 返回说人话版