不是用LLM测LLM,是用确定性测试覆盖不确定性。
一、问题:你的AI助手,能听懂人话吗?
做AI工具的人,99%的时间都在跟一个问题较劲:
用户说的到底是啥意思?
“帮我看看这个项目能不能投”——这是想做可行性分析。
“查查竞品资料,然后帮我写篇文章总结”——这是两步:先查资料,再写文章。
“帮我写点东西”——这个最坑,“东西”可能是公众号推文、方案文档、代码注释、或者朋友圈文案。
如果路由错了,后面全崩。
我们之前用LLM做意图识别,准确率大概85%。听起来不错?错。剩下的15%全是翻车现场——把写方案路由成写情书,把查资料路由成直接生成,用户当场血压飙升。
试过各种prompt优化、few-shot、chain-of-thought,发现一件事:
LLM做路由,本质上是在猜。猜就有错。
二、灵感来源:TDD不是只给代码用的
我在看superpowers团队的TDD实践时突然想到:
如果他们对AI Agent做测试驱动开发,那我们为什么不能对路由引擎做同样的事?
不是用另一个LLM去测LLM(那还是在猜),而是:
用确定性规则,覆盖真实用户的非确定性表达。
于是有了这套东西。
三、15道“高考题”:真实用户话术
我们收集了15条真实用户输入,覆盖了路由引擎最难搞的场景:
| # | 用户原话 | 考验点 |
|---|---|---|
| 1 | “帮我看看这个项目能不能投” | 单一意图精确匹配 |
| 2 | “查查竞品资料,然后帮我写篇文章总结” | 双意图+依赖排序 |
| 3 | “帮我写个方案” | 泛化触发词vs具体触发词竞争 |
| 4 | “别问了,直接写” | 用户强制覆盖前置关卡 |
| 5 | “看看这个项目靠不靠谱,靠谱就推进,不靠谱就算了” | 条件意图+中止行为 |
| 6 | “帮我把这篇文章去掉AI味,再加点AI味进去” | 矛盾意图检测 |
| 7 | “今天天气怎么样” | 零匹配兜底 |
| 8 | “帮我看看” | 上下文缺失兜底 |
| 9 | “教教我Python怎么用” | 教学类触发词 |
| 10 | “分析一下这份文档,然后帮我写个总结” | analyze→output顺序 |
| 11 | “然后帮我写篇文章” | 连接词多意图识别 |
| 12 | “如果效果好就继续做” | 条件句式识别 |
| 13 | “我要做竞品分析” | 领域锚定验证 |
| 14 | “帮我写一个关于AI的方案” | 具体触发词优先 |
| 15 | “帮我搞一下” | 极度泛化兜底 |
每一道题都有唯一正确答案。不是“大概对”,是“必须对”。
四、三件套:模拟器 + 跑分器 + 防篡改检测
1. router_sim.py — 确定性路由模拟器
不用LLM,纯规则驱动。核心机制8步:
1. 矛盾检测 — “去掉AI味再加AI味” → 直接反问用户
2. 窗口匹配 — 触发词字符必须在输入的 len+2 窗口内聚齐,防止散射误匹配
3. 领域锚定 — 特定领域skill必须输入含对应特征词才生效
4. 泛化消歧 — “帮我写”这类太宽泛的词,遇到具体触发词自动让位
5. 分类排序 — gate→research→analyze→output,保证执行顺序
6. 前置关卡 — 自动插入审核关卡,除非用户说“别问了直接干”
7. 条件识别 — “如果/算了/不能” → 标记on_abort=skip
8. 兜底反问 — 零匹配时给3个选项,不给开放题
2. run_eval.py — 跑分器
对15条用例逐字段比对:
▸ 路由类型对不对?(route/fallback/ask)
▸ skill顺序对不对?
▸ gate插没插?
▸ 覆盖生效了吗?
▸ 条件中止标记了吗?
全部通过=退出码0,有失败=退出码1。CI/CD直接挂钩子,没过不让合并。
3. check_triggers.py — 防篡改检测器
在路由之前先检查配置层:
▸ 重复触发词(两个skill写了一样的触发词)
▸ 包含冲突(A是B的子串,匹配时谁赢?)
▸ 字符集包含(A的多重字符集⊆B,窗口匹配时B可能误吞A)
▸ 空触发词/空列表
▸ 缺category字段(eval排序依赖它)
▸ chain.gate引用了不存在的skill
规则文件的bug,在代码跑之前就被抓出来。
五、效果:从“大概对”到“必须对”
关键不是“我们测了15条全过”,而是——
我故意改坏了一处配置,测试立刻变红。
我把某个skill的前置审核关卡删掉,重新跑测试。结果:
3条用例精确报错,精确到“gate_inserted这个字段期望True实际False”。
改回去,15/15绿。
这才叫测试。不是自己出题自己考,是故意改坏它,看它能不能抓住你。
六、核心认知
LLM适合做“理解”,不适合做“决策”。
路由是决策层的东西——用户说了A,你应该走B这条路径。这个判断不需要“大概对”,需要“必须对”。
能用确定性规则的,就不要用概率。
这也是为什么我们没有用语义匹配/embedding来做路由。规则优先、零依赖、改YAML就生效。一套规则,不同Agent各自读,不锁定任何框架。
七、怎么用
这套方法论是通用的。你可以套到任何领域:
1. 把你的skill列表写进rules.yaml
2. 给每个skill配3-5个触发词
3. 写15条真实用户话术作为测试用例
4. 跑一遍run_eval.py,看有没有意外的路由结果
5. 改一条规则,再跑一遍——如果变红,说明你的测试有覆盖力
八、开源
代码已开源,欢迎参考:
▸ GitHub: github.com/charlotty2026/skill-router
▸ Gitee: gitee.com/fenglinhuoshanmen/skill-router
包含:SKILL.md(Agent指令文件)、rules.yaml(路由规则)、eval/(自测集全套)。
最后一句话:测试不是写完代码补的,是写代码之前就想好的。
夜雨聆风