核心论点:数字员工的工具选择不是"让 LLM 猜",而是一个三层拦截体系——规则过滤→语义匹配→模型确认,85% 的请求在到达 P2 LLM 确认之前,正确意图已被召回至 Top-2 候选。
痛点场景
一家银行上线了数字员工客服,用户问"我的信用卡账单到哪了"。数字员工调用了check-shipping(查物流)工具,返回"暂无物流信息"。用户又问了一遍,数字员工还是调用了错误的工具。
问题出在哪?LLM 在语义理解时把"到哪了"和"物流"关联起来,但用户实际要的是账单查询。
这个案例暴露了工具选择的核心矛盾:纯依赖 LLM 不可靠,纯规则覆盖又不全。下面我们拆解常见的三种失败模式:
失败模式
❌ 纯 LLM 工具选择:让模型猜
很多企业直接把所有工具的描述传给 LLM,让模型自己选择:
最简单的做法——把所有工具描述发给 LLM 让模型自己选。问题是延迟高(~500ms)、整体准确率 92% 但 query-order 等关键意图仅 80%("到哪了"误判为物流)、年成本约 ¥2,400。
既然纯 LLM 不可靠,那反过来只靠规则行不行?
❌ 纯规则匹配:覆盖不全面
有些企业只用关键词匹配:
只用关键词匹配——"退"→退款、"物流"→查物流。问题是覆盖率只有 50%,且易误判(“退一步说"中的"退”)。
纯规则不够,纯 LLM 也不行。还有一个容易被忽视的问题:即使方案选对了,工具本身的描述质量也会影响选择效果。
❌ 工具描述质量差:LLM 看不懂工具是做什么的
很多企业给工具写的描述过于简单或模糊:
工具描述只写了"查订单"——LLM 不知道这个工具能查哪些订单(全部/待付款/已发货)、需要什么参数、返回什么结果。问题:
- 选择错误:相似意图的工具难以区分(“查物流"和"查订单"都包含"查”)
- 参数错误:LLM 不知道该传什么参数,导致工具调用失败
- 学习成本高:需要大量样本才能让 LLM 学会正确选择
解法框架
三层拦截体系
从三种失败模式中我们总结出一个核心思路:工具选择不应该让 LLM 独自承担,而是需要建立多层拦截体系。基于此,设计了 P0→P1→P2 三层拦截策略:
用户输入 → P0 规则过滤(~5ms)→ ✅ 命中(52%)→ 工具选择完成 ↓ 未命中(48%) P1 语义匹配(~20ms)→ ✅ 命中(累计 85%)→ 工具选择完成 ↓ 剩余 15% 模糊 P2 模型确认(~157ms)→ ✅ 累计命中 80% → 工具选择完成核心设计原则:大部分请求在到达 LLM 之前就应该完成工具选择。
三层拦截策略的设计思路是"由简到繁":先用低成本的规则过滤解决大部分请求,再用向量检索补充,最后用小模型兜底。下面我们逐层拆解:
P0 规则过滤:关键词 + 同义词归一化
关键词匹配 + 同义词归一化。"退了吧"→"退款","查一下单"→"查询订单"。同义词映射表从 Skill YAML 的trigger_keywords自动生成,零维护。覆盖 52%,准确率 86.5%。
P0 解决了超过一半的请求,但还有 48% 需要进一步处理。这时候需要引入语义理解能力。
P1 语义匹配:FAISS HNSW 向量检索
P0 未命中时,用 BGE-small-zh-v1.5 将用户输入转为 512 维向量,在 FAISS HNSW 索引中检索最相似的意图样本。意图命中后对高频意图词加权 ×1.5(如"退"命中"退款"意图),进一步缩小候选范围。返回 Top-3 候选,P0+P1 Top-2 召回率 85%。
P0+P1 已经覆盖了大部分场景,但还有 15% 的模糊请求需要最终确认。这时候需要引入小模型做二选一判断。
P2 模型确认:本地小模型二选一
剩余 15% 的模糊请求,用本地部署的 Qwen2.5-1.5B-Instruct(RTX 4070,p50 157ms)对 P1 返回的 Top-3 候选做确认。如果 P2 的选择与 P1 Top-1 不一致,将 Top-3 一并纳入候选,由执行器做最终判断。累计命中 80%。
三层拦截体系的整体效果如何?下面是与纯 LLM 方案的对比:
延迟对比
| 方案 | p50 | p95 | 年成本 |
|---|---|---|---|
| 纯 LLM function calling | 477ms | 672ms | ~¥2,400 |
| P0 阶段(52%请求) | ~25ms | ~30ms | ~¥500 |
| P2 阶段(15%请求) | ~157ms | ~312ms | ~¥2,500 |
实战案例:shop-agent 的工具选择流水线
在 shop-agent 项目中,我们实现了完整的三层工具选择流水线:
架构图
关键设计决策
为什么是 P0→P1→P2 这个顺序?
- 零成本先跑(P0,解决 52%)→ 语义补缺(P1,Top-2 到 85%)→ LLM 兜底(P2,仅 15% 触发)
为什么用本地小模型做 P2?
- 云端 LLM 的 p99 延迟抖动(500ms+)
- 本地 Qwen2.5-1.5B-Instruct 在 RTX 4070 上 p50 仅 157ms
为什么只做候选集确认?
- P0+P1 已经把 5 个意图筛选为 Top-3 候选
- 从 3 个中选 1 个的问题复杂度远低于从 5 个中选 1 个
理解了设计思路和实战实现后,下面是落地时需要检查的事项:
落地检查清单
[ ] 梳理所有工具的 trigger_keywords(从 Skill YAML 自动抽取) [ ] 构建意图向量索引(BGE-small + FAISS HNSW) [ ] 部署本地小模型(Qwen2.5-1.5B-Instruct) [ ] 实现意图→工具映射表(O(1) 查表) [ ] 设置 P0/P1/P2 阈值(推荐:P0 关键词匹配、P1 Top-2 相似度 > 0.65) [ ] 配置交叉校验逻辑(P2 与 P1 不一致时纳入 Top-2) [ ] 建立监控指标(各层命中率、延迟、误判率) [ ] 准备降级方案(Embedding 不可用时跳过 P1,仅用 P0+P2)