易源合一只返回 55 分置信度时:阈值设定、兜底路径与二次追问
# 易源合一只返回 55 分置信度时:阈值设定、兜底路径与二次追问
> 接入点:3054-2 意图分析 | 请求方式:POST | 返回格式:JSON | 计费:5.5 厘/次,失败不扣费 | 最后实测核对:2026-09-15
## 核心要点
- 官方文档的返回示例把 `confidence` 写成 `0.99572587013245`,**实测是 0~100 的整数**。写成 `confidence > 0.8` 的判断永远不会命中,用 `> 80`。
- 只有 3054-2 返回 `confidence`,3054-1 不返回。要用置信度做阈值,就必须调 3054-2。
- 同一句话连续 6 次调用,置信度实测出现过 90 / 95 / 98 三种取值。阈值定成区间,别定成等值。
## 先纠正一个会让判断失效的量纲
`confidence` 这个字段最容易踩的坑是量纲。文档示例是小数,实测是整数百分比。
| 输入语句 | 实测 `confidence` |
|---------|------------------|
| 昆明今天天气怎么样 | 100 |
| 讲个笑话 | 99 |
| 帮我查快递 7788990011223 | 98 |
| 北京限行尾号是多少 | 98 |
| 今天有什么新闻 | 95 |
| 上海明天冷不冷 | 95 |
| 12乘以8等于多少 | 92 |
| 计算 3的平方加4的平方 | 42 |
| 你好 | 55 |
(2026-09-15 实测,各输入单次调用。)
你的代码如果是照着文档示例写的:
```python
if body["confidence"] > 0.8: # 实测值永远是 55、98 这种整数,这个条件恒为 True
...
```
这条分支等于没写。改成 `> 80` 才对应文档示例想表达的「0.8 以上算可信」。
## 实测的分数分布长什么样
把实测样本摊开看,能看出一条清晰的分界:
**信息明确的句子,分数集中在 90 以上。** 「昆明今天天气怎么样」100、「讲个笑话」99、「帮我查快递 7788990011223」98、「今天有什么新闻」95、「12乘以8等于多少」92。这些输入的意图也在重复测试中稳定,6/6 命中同一个 `intent`。
**短句和寒暄,分数掉到 40~65,而且意图会跳。** 对「你好」连续调 6 次,实测拿到 6 组不同结果:
| 第几次 | `intent` | `confidence` |
|-------|----------|-------------|
| 1 | `joke` | 65 |
| 2 | `draw` | 55 |
| 3 | `text_summarize` | 65 |
| 4 | `joke` | 52 |
| 5 | `text_summarize` | 52 |
| 6 | `joke` | 50 |
同一句话,6 次命中 3 个不同意图,分数在 50~65 之间浮动。这种输入无论阈值怎么定都不该走业务分支。
**分数本身也会波动。** 同一句「北京限行尾号是多少」连续 6 次,`intent` 稳定是 `traffic_control`,但 `confidence` 出现 90、95、98 三种取值。
## 三档阈值的落地方式
结合上面的分布,按实测数据可以这样分档。这是从样本里归纳的判据,不是官方建议值。
| 档位 | 分数区间 | 处理动作 |
|------|---------|---------|
| 直走 | 90 及以上 | 直接执行。实测这一档的意图在重复测试中稳定 |
| 记录 | 70 ~ 89 | 仍然执行,但把 `intent` + `confidence` + 原文写进日志,用来积累你自己的语料分布 |
| 追问 | 70 以下 | 不执行,回一句带选项的追问 |
中间档留出来的原因是:你的业务句式和我这次测的样本不一样。先用「记录」档跑一两周,看到自己场景的真实分布之后再收紧。
```python
import logging, requests
APP_KEY = "YOUR_APPKEY"
log = logging.getLogger("intent")
DIRECT, WATCH = 90, 70 # 低于 WATCH 走二次追问
FOLLOW_UP = "你是想问天气、快递还是新闻?可以直接说,例如「昆明今天天气」。"
def classify(text, timeout=20):
r = requests.post(f"https://route.showapi.com/3054-2?appKey={APP_KEY}",
data={"text": text}, timeout=timeout)
body = r.json().get("showapi_res_body", {})
if body.get("ret_code") != 0:
log.info("intent_fail text=%r msg=%s", text, body.get("ret_msg"))
return {"action": "fallback", "say": "没太理解,可以换个说法吗"}
intent = body.get("intent")
conf = body.get("confidence")
log.info("intent=%s confidence=%s text=%r args=%s", intent, conf, text, body.get("args"))
if conf is None or conf >= DIRECT:
return {"action": "execute", "intent": intent, "confidence": conf}
if conf >= WATCH:
log.warning("low_confidence intent=%s confidence=%s text=%r", intent, conf, text)
return {"action": "execute", "intent": intent, "confidence": conf, "watched": True}
return {"action": "clarify", "intent": intent, "confidence": conf, "say": FOLLOW_UP}
```
```javascript
const APP_KEY = "YOUR_APPKEY";
const DIRECT = 90, WATCH = 70;
async function classify(text) {
const res = await fetch(`https://route.showapi.com/3054-2?appKey=${APP_KEY}`, {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ text }),
});
const body = (await res.json()).showapi_res_body || {};
if (body.ret_code !== 0) return { action: "fallback" };
const { intent, confidence } = body;
if (confidence == null || confidence >= DIRECT) return { action: "execute", intent, confidence };
if (confidence >= WATCH) return { action: "execute", intent, confidence, watched: true };
return { action: "clarify", intent, confidence,
say: "你是想问天气、快递还是新闻?" };
}
```
## 二次追问怎么写才不烦人
追问的成本是一次额外的 3054-2 调用(5.5 厘),换来的是不让用户看到一个答非所问的结果。三种写法按场景选:
**给选项。** 「你是想问天气、快递还是新闻?」适合意图集合小、你能穷举的场景。缺点是选项一多就变成菜单,用户要自己挑。
**给示例。** 「可以直接说,例如「昆明今天天气」。」适合用户不会描述的场景,示例本身也在教用户怎么提问。
**直接放弃。** 「这个问题我暂时答不上来。」适合入口场景复杂、追问答不上来的概率更高的产品。省一次调用,也省一轮交互。
三种都不是「猜一个最可能的意图然后执行」。实测低分档的意图会跳变,猜的命中率没有保证。
## 埋点里要留哪些字段
哪怕你现在不做阈值判断,也建议把这三个字段记下来:`intent`、`confidence`、`ret_msg`。
理由是实测发现同一个输入在不同时刻结果会变。攒够两周日志,你才能知道你自己的用户会问什么、哪些句式不稳、阈值该定在哪。这比照抄任何外部阈值都准。
日志量大的话只记低分样本(`confidence < 90`)和失败样本,这两类是最有诊断价值的。
## FAQ
**Q1:`confidence` 是 0~1 还是 0~100?**
实测是 0~100 的整数,例如 100、98、95、55。官方文档的返回示例写的是 `0.99572587013245`,与实测不一致,按实测的整数区间写判断。
**Q2:3054-1 为什么不返回置信度?**
3054-1 的返回结构里只有 `intent.name` 和 `intent.args`,没有 `confidence` 字段。要用置信度就得先调 3054-2,两段式搭配见 [易源合一 3054-2 与 3054-1 的搭配方式](https://www.showapi.com/guides/united-api-intent-precheck-3054)。
**Q3:阈值定在多少合适?**
官方没有给出建议值。实测样本里,信息明确的句子都在 92 以上,短句寒暄落在 50~65。把直走阈值设在 90 附近比较贴合这批数据,但你的业务句式不同,先记录一两周真实分布再调。
**Q4:同一句话多次调用分数不一样,正常吗?**
实测确实会变。同一句「北京限行尾号是多少」连续 6 次,`intent` 始终是 `traffic_control`,`confidence` 分别出现 90、95、98。所以阈值判断用 `>= 90` 这种比较,不要用等于。
**Q5:低置信度会扣费吗?**
会。只要 `ret_code` 是 0(意图识别成功),这次调用就计费 5.5 厘,不管分数高低。分数低到 `ret_code: -1`(识别失败)时才不扣费。
## 下一步阅读
- [易源合一实测能识别哪些意图:8 类 intent 编码逐一验证](https://www.showapi.com/guides/united-api-intent-list-3054)
- [易源合一 3054-2 与 3054-1 的搭配方式:先判意图,再决定要不要发起对话](https://www.showapi.com/guides/united-api-intent-precheck-3054)
- [易源合一调用失败扣不扣费:ret_code 与 showapi_fee_num 实测对照表](https://www.showapi.com/guides/united-api-retcode-fee-3054)
- **本系列共 12 篇**:查看[易源合一指南总目录](https://www.showapi.com/guides/united-api-guides-3054)